summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/error.rs2
-rw-r--r--src/main.rs28
-rw-r--r--src/requests/device.rs4
-rw-r--r--src/requests/start.rs113
4 files changed, 110 insertions, 37 deletions
diff --git a/src/error.rs b/src/error.rs
index d35991b..27fc7a6 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -4,6 +4,7 @@ pub enum CliError {
4 Reqwest(reqwest::Error), 4 Reqwest(reqwest::Error),
5 Config(config::ConfigError), 5 Config(config::ConfigError),
6 Serde(serde_json::Error), 6 Serde(serde_json::Error),
7 WsResponse,
7} 8}
8 9
9impl Debug for CliError { 10impl Debug for CliError {
@@ -12,6 +13,7 @@ impl Debug for CliError {
12 Self::Reqwest(err) => { err.fmt(f) }, 13 Self::Reqwest(err) => { err.fmt(f) },
13 Self::Config(err) => { err.fmt(f) }, 14 Self::Config(err) => { err.fmt(f) },
14 Self::Serde(err) => { err.fmt(f) }, 15 Self::Serde(err) => { err.fmt(f) },
16 Self::WsResponse => { f.write_str("Error in Response") },
15 } 17 }
16 } 18 }
17} 19}
diff --git a/src/main.rs b/src/main.rs
index 3e1388b..d7c985f 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,8 +1,9 @@
1use std::fmt::Display; 1use std::{fmt::Display, time::Duration};
2 2
3use clap::{Parser, Subcommand}; 3use clap::{Parser, Subcommand};
4use config::SETTINGS; 4use config::SETTINGS;
5use error::CliError; 5use error::CliError;
6use indicatif::{ProgressBar, ProgressStyle, MultiProgress};
6use requests::{start::start, device}; 7use requests::{start::start, device};
7use reqwest::header::{HeaderMap, HeaderValue}; 8use reqwest::header::{HeaderMap, HeaderValue};
8use serde::Deserialize; 9use serde::Deserialize;
@@ -11,7 +12,15 @@ mod config;
11mod error; 12mod error;
12mod requests; 13mod requests;
13 14
14/// webol http client 15static OVERVIEW_STYLE: &str = "{spinner:.green} {wide_msg}({elapsed})";
16static OVERVIEW_ERROR: &str = "✗ {wide_msg}({elapsed})";
17static OVERVIEW_DONE: &str = "✓ {wide_msg}({elapsed})";
18static DEFAULT_STYLE: &str = " {spinner:.green} {wide_msg}";
19static DONE_STYLE: &str = " ✓ {wide_msg}";
20static ERROR_STYLE: &str = " ✗ {wide_msg}";
21static TICK_SPEED: u64 = 1000 / 16;
22
23/// webol client
15#[derive(Parser)] 24#[derive(Parser)]
16#[command(author, version, about, long_about = None)] 25#[command(author, version, about, long_about = None)]
17struct Args { 26struct Args {
@@ -103,6 +112,21 @@ fn format_url(path: &str, protocol: Protocols) -> Result<String, CliError> {
103 )) 112 ))
104} 113}
105 114
115fn add_pb(mp: &MultiProgress, template: &str, message: String) -> ProgressBar {
116 let pb = mp.add(ProgressBar::new(1));
117 pb.set_style(ProgressStyle::with_template(template).unwrap());
118 pb.enable_steady_tick(Duration::from_millis(TICK_SPEED));
119 pb.set_message(message);
120
121 pb
122}
123
124fn finish_pb(pb: ProgressBar, message: String, template: &str) {
125 pb.set_style(ProgressStyle::with_template(template).unwrap());
126 pb.finish_with_message(message);
127
128}
129
106enum Protocols { 130enum Protocols {
107 Http, 131 Http,
108 Websocket, 132 Websocket,
diff --git a/src/requests/device.rs b/src/requests/device.rs
index f7754a4..cbc838e 100644
--- a/src/requests/device.rs
+++ b/src/requests/device.rs
@@ -1,8 +1,10 @@
1use crate::{error::CliError, default_headers, format_url, Protocols}; 1use crate::{error::CliError, default_headers, format_url, Protocols};
2 2
3pub async fn put(id: String, mac: String, broadcast_addr: String, ip: String) -> Result<(), CliError> { 3pub async fn put(id: String, mac: String, broadcast_addr: String, ip: String) -> Result<(), CliError> {
4 let url = format_url("device", Protocols::Http)?;
5 println!("{}", url);
4 let res = reqwest::Client::new() 6 let res = reqwest::Client::new()
5 .put(format_url("device", Protocols::Http)?) 7 .put(url)
6 .headers(default_headers()?) 8 .headers(default_headers()?)
7 .body( 9 .body(
8 format!( 10 format!(
diff --git a/src/requests/start.rs b/src/requests/start.rs
index d0c4411..882b154 100644
--- a/src/requests/start.rs
+++ b/src/requests/start.rs
@@ -1,29 +1,19 @@
1use std::time::Duration;
2
3use futures_util::{StreamExt, SinkExt}; 1use futures_util::{StreamExt, SinkExt};
4use indicatif::{ProgressBar, ProgressStyle}; 2use indicatif::MultiProgress;
5use reqwest::StatusCode; 3use reqwest::StatusCode;
6use serde::Deserialize; 4use serde::Deserialize;
7use tokio_tungstenite::{connect_async, tungstenite::Message}; 5use tokio_tungstenite::{connect_async, tungstenite::Message};
8 6
9use crate::{error::CliError, default_headers, ErrorResponse, format_url, Protocols}; 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};
10 8
11pub async fn start(id: String, ping: bool) -> Result<(), CliError> { 9pub async fn start(id: String, ping: bool) -> Result<(), CliError> {
12 10
13 let send_start = ProgressBar::new(1); 11 let send_start = MultiProgress::new();
12 let overview = add_pb(&send_start, OVERVIEW_STYLE, format!("start {}", id));
14 13
15 // TODO: calculate average start-time on server 14 // TODO: calculate average start-time on server
16 send_start.set_style(
17 ProgressStyle::with_template("{spinner:.green} ({elapsed}) {wide_msg}")
18 .unwrap()
19 .tick_chars("|/-\\\\")
20 );
21
22 let url = format_url("start", Protocols::Http)?; 15 let url = format_url("start", Protocols::Http)?;
23 16 let connect = add_pb(&send_start, DEFAULT_STYLE, format!("connect to {}", url));
24 send_start.set_message(format!("connect to {}", url));
25 send_start.enable_steady_tick(Duration::from_millis(125));
26
27 let res = reqwest::Client::new() 17 let res = reqwest::Client::new()
28 .post(url) 18 .post(url)
29 .headers(default_headers()?) 19 .headers(default_headers()?)
@@ -33,7 +23,9 @@ pub async fn start(id: String, ping: bool) -> Result<(), CliError> {
33 .send() 23 .send()
34 .await 24 .await
35 .map_err(CliError::Reqwest)?; 25 .map_err(CliError::Reqwest)?;
26 finish_pb(connect, "connected, got response".to_string(), DONE_STYLE);
36 27
28 let res_pb = add_pb(&send_start, DEFAULT_STYLE, "analyzing response".to_string());
37 match res.status() { 29 match res.status() {
38 StatusCode::OK => { 30 StatusCode::OK => {
39 let body = serde_json::from_str::<StartResponse>( 31 let body = serde_json::from_str::<StartResponse>(
@@ -42,11 +34,16 @@ pub async fn start(id: String, ping: bool) -> Result<(), CliError> {
42 .map_err(CliError::Serde)?; 34 .map_err(CliError::Serde)?;
43 35
44 if body.boot { 36 if body.boot {
45 send_start.println("connected, sent start packet"); 37 finish_pb(res_pb, "sent start packet".to_string(), DONE_STYLE);
46 } 38 }
47 39
48 if ping { 40 if ping {
49 send_start.println(status_socket(body.uuid, &send_start).await?.to_string()); 41 let status = status_socket(body.uuid, &send_start).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 }
50 } 47 }
51 }, 48 },
52 _ => { 49 _ => {
@@ -55,37 +52,63 @@ pub async fn start(id: String, ping: bool) -> Result<(), CliError> {
55 ) 52 )
56 .map_err(CliError::Serde)?; 53 .map_err(CliError::Serde)?;
57 54
58 println!("got error: {}", body.error); 55 res_pb.finish_with_message(format!("got error: {}", body.error));
59 } 56 }
60 } 57 }
61 58
62 Ok(()) 59 Ok(())
63} 60}
64 61
65async fn status_socket(uuid: String, pb: &ProgressBar) -> Result<bool, CliError> { 62async fn status_socket(uuid: String, pb: &MultiProgress) -> Result<bool, CliError> {
66 pb.set_message("setup websocket"); 63 // TODO: Remove unwraps
67 64 let ws_pb = add_pb(pb, DEFAULT_STYLE, "connect to websocket".to_string());
68 let (mut ws_stream, _response) = connect_async(format_url("status", Protocols::Websocket)?) 65 let (mut ws_stream, _response) = connect_async(format_url("status", Protocols::Websocket)?)
69 .await 66 .await
70 .expect("Failed to connect"); 67 .expect("Failed to connect");
71 pb.println("connected to websocket"); 68 finish_pb(ws_pb, "connected to websocket".to_string(), DONE_STYLE);
72 69
73 pb.set_message("send uuid message"); 70 ws_stream.send(Message::Text(uuid.clone())).await.unwrap();
74 ws_stream.send(Message::Text(uuid)).await.unwrap();
75 pb.println("sent uuid message");
76 71
77 pb.set_message("wait for message"); 72 let msg_pb = add_pb(pb, DEFAULT_STYLE, "await message".to_string());
78 let msg = ws_stream.next().await.unwrap(); 73 let msg = ws_stream.next().await.unwrap();
74 finish_pb(msg_pb, "received message".to_string(), DONE_STYLE);
79 75
80 pb.println(format!("msg: {:?}", msg));
81
82 ws_stream.close(None).await.unwrap(); 76 ws_stream.close(None).await.unwrap();
83 pb.println("connection closed");
84 // TODO: Check for correct UUID and timeout
85 pb.set_message("verifying message");
86 if msg.is_ok() { return Ok(true) }
87 77
88 Ok(false) 78 let v_pb = add_pb(pb, DEFAULT_STYLE, "verify response".to_string());
79 let res = verify_response(msg.unwrap().to_string(), uuid)?;
80 match res {
81 Verified::WrongUuid => {
82 finish_pb(v_pb, "returned wrong uuid".to_string(), ERROR_STYLE);
83 Ok(false)
84 },
85 Verified::ResponseType(res_type) => {
86 match res_type {
87 ResponseType::Start => {
88 finish_pb(v_pb, "device started".to_string(), DONE_STYLE);
89 Ok(true)
90 },
91 ResponseType::Timeout => {
92 finish_pb(v_pb, "ping timed out".to_string(), ERROR_STYLE);
93 Ok(false)
94 },
95 ResponseType::NotFound => {
96 finish_pb(v_pb, "unknown uuid".to_string(), ERROR_STYLE);
97 Ok(false)
98 },
99 }
100 }
101 }
102}
103
104fn verify_response(res: String, org_uuid: String) -> Result<Verified, CliError> {
105 let spl: Vec<&str> = res.split('_').collect();
106 let res_type = spl[0];
107 let uuid = spl[1];
108
109 if uuid != org_uuid { return Ok(Verified::WrongUuid) };
110
111 Ok(Verified::ResponseType(ResponseType::from(res_type)?))
89} 112}
90 113
91#[derive(Debug, Deserialize)] 114#[derive(Debug, Deserialize)]
@@ -94,3 +117,25 @@ struct StartResponse {
94 id: String, 117 id: String,
95 uuid: String, 118 uuid: String,
96} 119}
120
121enum Verified {
122 ResponseType(ResponseType),
123 WrongUuid
124}
125
126enum ResponseType {
127 Start,
128 Timeout,
129 NotFound,
130}
131
132impl ResponseType {
133 fn from(value: &str) -> Result<Self, CliError> {
134 match value {
135 "start" => Ok(ResponseType::Start),
136 "timeout" => Ok(ResponseType::Timeout),
137 "notfound" => Ok(ResponseType::NotFound),
138 _ => Err(CliError::WsResponse),
139 }
140 }
141}