summaryrefslogtreecommitdiff
path: root/src/requests/start.rs
diff options
context:
space:
mode:
authorFxQnLr <[email protected]>2023-11-17 11:18:31 +0100
committerGitHub <[email protected]>2023-11-17 11:18:31 +0100
commit48190366ac94888811dd4b0b8e6532b35f1a9d10 (patch)
tree8689660d75d0e45af460ed3d144b5a010289c0be /src/requests/start.rs
parent8fab2e7c3a38a91c8f5549b639e7f2ac4ae1a420 (diff)
parent93de8742961287cb9cfd08e68c8afa2347585a73 (diff)
downloadwebol-cli-48190366ac94888811dd4b0b8e6532b35f1a9d10.tar
webol-cli-48190366ac94888811dd4b0b8e6532b35f1a9d10.tar.gz
webol-cli-48190366ac94888811dd4b0b8e6532b35f1a9d10.zip
Merge pull request #1 from FxQnLr/eta
Eta
Diffstat (limited to 'src/requests/start.rs')
-rw-r--r--src/requests/start.rs131
1 files changed, 117 insertions, 14 deletions
diff --git a/src/requests/start.rs b/src/requests/start.rs
index 30f65b9..ca4ca44 100644
--- a/src/requests/start.rs
+++ b/src/requests/start.rs
@@ -1,49 +1,152 @@
1use futures_util::{StreamExt, SinkExt};
2use indicatif::{MultiProgress, ProgressBar};
1use reqwest::StatusCode; 3use reqwest::StatusCode;
2use serde::Deserialize; 4use serde::Deserialize;
5use tokio_tungstenite::{connect_async, tungstenite::Message};
3 6
4use crate::{config::SETTINGS, error::CliError, default_headers, ErrorResponse}; 7use crate::{error::CliError, default_headers, ErrorResponse, format_url, Protocols, OVERVIEW_STYLE, DEFAULT_STYLE, DONE_STYLE, finish_pb, ERROR_STYLE, OVERVIEW_ERROR, OVERVIEW_DONE, add_pb};
5 8
6pub fn start(id: String) -> Result<(), CliError> { 9pub async fn start(id: String, ping: bool) -> Result<(), CliError> {
7 let res = reqwest::blocking::Client::new() 10
8 .post( 11 let send_start = MultiProgress::new();
9 format!( 12 let overview = add_pb(&send_start, OVERVIEW_STYLE, format!(") start {}", id));
10 "{}/start", 13
11 SETTINGS.get_string("server").map_err(CliError::Config)? 14 // TODO: calculate average start-time on server
12 ) 15 let url = format_url("start", Protocols::Http)?;
13 ) 16 let connect = add_pb(&send_start, DEFAULT_STYLE, format!("connect to {}", url));
17 let res = reqwest::Client::new()
18 .post(url)
14 .headers(default_headers()?) 19 .headers(default_headers()?)
15 .body( 20 .body(
16 format!(r#"{{"id": "{}"}}"#, id) 21 format!(r#"{{"id": "{}", "ping": {}}}"#, id, ping)
17 ) 22 )
18 .send() 23 .send()
24 .await
19 .map_err(CliError::Reqwest)?; 25 .map_err(CliError::Reqwest)?;
26 finish_pb(connect, "connected, got response".to_string(), DONE_STYLE);
20 27
28 let res_pb = add_pb(&send_start, DEFAULT_STYLE, "analyzing response".to_string());
21 match res.status() { 29 match res.status() {
22 StatusCode::OK => { 30 StatusCode::OK => {
23 let body = serde_json::from_str::<StartResponse>( 31 let body = serde_json::from_str::<StartResponse>(
24 &res.text().map_err(CliError::Reqwest)? 32 &res.text().await.map_err(CliError::Reqwest)?
25 ) 33 )
26 .map_err(CliError::Serde)?; 34 .map_err(CliError::Serde)?;
27 35
28 if body.boot { 36 if body.boot {
29 println!("successfully started {}", body.id); 37 finish_pb(res_pb, "sent start packet".to_string(), DONE_STYLE);
38 }
39
40 if ping {
41 let status = status_socket(body.uuid, &send_start, &overview, id).await?;
42 if status {
43 finish_pb(overview, format!("successfully started {}", body.id), OVERVIEW_DONE);
44 } else {
45 finish_pb(overview, format!("error while starting {}", body.id), OVERVIEW_ERROR);
46 }
30 } 47 }
31 }, 48 },
32 _ => { 49 _ => {
33 let body = serde_json::from_str::<ErrorResponse>( 50 let body = serde_json::from_str::<ErrorResponse>(
34 &res.text().map_err(CliError::Reqwest)? 51 &res.text().await.map_err(CliError::Reqwest)?
35 ) 52 )
36 .map_err(CliError::Serde)?; 53 .map_err(CliError::Serde)?;
37 54
38 println!("got error: {}", body.error); 55 res_pb.finish_with_message(format!("got error: {}", body.error));
39 } 56 }
40 } 57 }
41 58
42 Ok(()) 59 Ok(())
43} 60}
44 61
62async fn status_socket(uuid: String, pb: &MultiProgress, overview: &ProgressBar, id: String) -> Result<bool, CliError> {
63 // TODO: Remove unwraps
64 let ws_pb = add_pb(pb, DEFAULT_STYLE, "connect to websocket".to_string());
65 let (mut ws_stream, _response) = connect_async(format_url("status", Protocols::Websocket)?)
66 .await
67 .expect("Failed to connect");
68 finish_pb(ws_pb, "connected to websocket".to_string(), DONE_STYLE);
69
70 ws_stream.send(Message::Text(uuid.clone())).await.unwrap();
71
72 // Get ETA
73 let eta_msg = ws_stream.next().await.unwrap().unwrap();
74 let eta = get_eta(eta_msg.into_text().unwrap(), uuid.clone())? + overview.elapsed().as_secs();
75 overview.set_message(format!("/{}) start {}", eta, id));
76
77 let msg_pb = add_pb(pb, DEFAULT_STYLE, "await message".to_string());
78 let msg = ws_stream.next().await.unwrap();
79 finish_pb(msg_pb, "received message".to_string(), DONE_STYLE);
80
81 ws_stream.close(None).await.unwrap();
82
83 let v_pb = add_pb(pb, DEFAULT_STYLE, "verify response".to_string());
84 let res = verify_response(msg.unwrap().to_string(), uuid)?;
85 match res {
86 Verified::WrongUuid => {
87 finish_pb(v_pb, "returned wrong uuid".to_string(), ERROR_STYLE);
88 Ok(false)
89 },
90 Verified::ResponseType(res_type) => {
91 match res_type {
92 ResponseType::Start => {
93 finish_pb(v_pb, "device started".to_string(), DONE_STYLE);
94 Ok(true)
95 },
96 ResponseType::Timeout => {
97 finish_pb(v_pb, "ping timed out".to_string(), ERROR_STYLE);
98 Ok(false)
99 },
100 ResponseType::NotFound => {
101 finish_pb(v_pb, "unknown uuid".to_string(), ERROR_STYLE);
102 Ok(false)
103 },
104 }
105 }
106 }
107}
108
109fn get_eta(msg: String, uuid: String) -> Result<u64, CliError> {
110 let spl: Vec<&str> = msg.split('_').collect();
111 if (spl[0] != "eta") || (spl[2] != uuid) { return Err(CliError::WsResponse); };
112 Ok(u64::from_str_radix(spl[1], 10).map_err(CliError::Parse)?)
113}
114
115fn verify_response(res: String, org_uuid: String) -> Result<Verified, CliError> {
116 let spl: Vec<&str> = res.split('_').collect();
117 let res_type = spl[0];
118 let uuid = spl[1];
119
120 if uuid != org_uuid { return Ok(Verified::WrongUuid) };
121
122 Ok(Verified::ResponseType(ResponseType::from(res_type)?))
123}
124
45#[derive(Debug, Deserialize)] 125#[derive(Debug, Deserialize)]
46struct StartResponse { 126struct StartResponse {
47 boot: bool, 127 boot: bool,
48 id: String, 128 id: String,
129 uuid: String,
130}
131
132enum Verified {
133 ResponseType(ResponseType),
134 WrongUuid
135}
136
137enum ResponseType {
138 Start,
139 Timeout,
140 NotFound,
141}
142
143impl ResponseType {
144 fn from(value: &str) -> Result<Self, CliError> {
145 match value {
146 "start" => Ok(ResponseType::Start),
147 "timeout" => Ok(ResponseType::Timeout),
148 "notfound" => Ok(ResponseType::NotFound),
149 _ => Err(CliError::WsResponse),
150 }
151 }
49} 152}