summaryrefslogtreecommitdiff
path: root/src/requests/start.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/requests/start.rs')
-rw-r--r--src/requests/start.rs189
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 @@
1use futures_util::{StreamExt, SinkExt}; 1use futures_util::{SinkExt, StreamExt};
2use indicatif::{MultiProgress, ProgressBar}; 2use indicatif::{MultiProgress, ProgressBar};
3use reqwest::StatusCode; 3use reqwest::StatusCode;
4use serde::Deserialize; 4use serde::Deserialize;
5use tokio_tungstenite::{connect_async, tungstenite::Message}; 5use tokio_tungstenite::{
6 6 connect_async,
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}; 7 tungstenite::{http::Request, Message},
8 8};
9pub async fn start(id: String, ping: bool) -> Result<(), CliError> { 9
10 10use 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
16pub 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
62async fn status_socket(uuid: String, pb: &MultiProgress, overview: &ProgressBar, id: String) -> Result<bool, CliError> { 64async 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
109fn get_eta(msg: String, uuid: String) -> Result<u64, CliError> { 124fn 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
115fn verify_response(res: String, org_uuid: String) -> Result<Verified, CliError> { 138fn 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
132enum Verified { 157enum Verified {
133 ResponseType(ResponseType), 158 ResponseType(ResponseType),
134 WrongUuid 159 WrongUuid,
135} 160}
136 161
137enum ResponseType { 162enum ResponseType {
@@ -141,12 +166,12 @@ enum ResponseType {
141} 166}
142 167
143impl ResponseType { 168impl 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}