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