From f4d3d921460b606a9ff6686c9bb9a79bf546f264 Mon Sep 17 00:00:00 2001 From: FxQnLr Date: Thu, 2 Nov 2023 21:01:16 +0100 Subject: baseline ping --- src/requests/start.rs | 73 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 13 deletions(-) (limited to 'src/requests/start.rs') diff --git a/src/requests/start.rs b/src/requests/start.rs index 30f65b9..d0c4411 100644 --- a/src/requests/start.rs +++ b/src/requests/start.rs @@ -1,37 +1,57 @@ +use std::time::Duration; + +use futures_util::{StreamExt, SinkExt}; +use indicatif::{ProgressBar, ProgressStyle}; use reqwest::StatusCode; use serde::Deserialize; +use tokio_tungstenite::{connect_async, tungstenite::Message}; -use crate::{config::SETTINGS, error::CliError, default_headers, ErrorResponse}; +use crate::{error::CliError, default_headers, ErrorResponse, format_url, Protocols}; -pub fn start(id: String) -> Result<(), CliError> { - let res = reqwest::blocking::Client::new() - .post( - format!( - "{}/start", - SETTINGS.get_string("server").map_err(CliError::Config)? - ) - ) +pub async fn start(id: String, ping: bool) -> Result<(), CliError> { + + let send_start = ProgressBar::new(1); + + // TODO: calculate average start-time on server + send_start.set_style( + ProgressStyle::with_template("{spinner:.green} ({elapsed}) {wide_msg}") + .unwrap() + .tick_chars("|/-\\\\") + ); + + let url = format_url("start", Protocols::Http)?; + + send_start.set_message(format!("connect to {}", url)); + send_start.enable_steady_tick(Duration::from_millis(125)); + + let res = reqwest::Client::new() + .post(url) .headers(default_headers()?) .body( - format!(r#"{{"id": "{}"}}"#, id) + format!(r#"{{"id": "{}", "ping": {}}}"#, id, ping) ) .send() + .await .map_err(CliError::Reqwest)?; match res.status() { StatusCode::OK => { let body = serde_json::from_str::( - &res.text().map_err(CliError::Reqwest)? + &res.text().await.map_err(CliError::Reqwest)? ) .map_err(CliError::Serde)?; if body.boot { - println!("successfully started {}", body.id); + send_start.println("connected, sent start packet"); + } + + if ping { + send_start.println(status_socket(body.uuid, &send_start).await?.to_string()); } }, _ => { let body = serde_json::from_str::( - &res.text().map_err(CliError::Reqwest)? + &res.text().await.map_err(CliError::Reqwest)? ) .map_err(CliError::Serde)?; @@ -42,8 +62,35 @@ pub fn start(id: String) -> Result<(), CliError> { Ok(()) } +async fn status_socket(uuid: String, pb: &ProgressBar) -> Result { + pb.set_message("setup websocket"); + + let (mut ws_stream, _response) = connect_async(format_url("status", Protocols::Websocket)?) + .await + .expect("Failed to connect"); + pb.println("connected to websocket"); + + pb.set_message("send uuid message"); + ws_stream.send(Message::Text(uuid)).await.unwrap(); + pb.println("sent uuid message"); + + pb.set_message("wait for message"); + let msg = ws_stream.next().await.unwrap(); + + pb.println(format!("msg: {:?}", msg)); + + ws_stream.close(None).await.unwrap(); + pb.println("connection closed"); + // TODO: Check for correct UUID and timeout + pb.set_message("verifying message"); + if msg.is_ok() { return Ok(true) } + + Ok(false) +} + #[derive(Debug, Deserialize)] struct StartResponse { boot: bool, id: String, + uuid: String, } -- cgit v1.2.3 From 344af3ff7c9493b4e2c6eee134b9b341eaabf736 Mon Sep 17 00:00:00 2001 From: FxQnLr Date: Tue, 7 Nov 2023 12:58:12 +0100 Subject: add ping support and readable output --- .gitignore | 1 + src/error.rs | 2 + src/main.rs | 28 +++++++++++- src/requests/device.rs | 4 +- src/requests/start.rs | 113 ++++++++++++++++++++++++++++++++++--------------- webol-cli.toml | 2 +- 6 files changed, 112 insertions(+), 38 deletions(-) (limited to 'src/requests/start.rs') diff --git a/.gitignore b/.gitignore index 13a2081..f337b94 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target /postgres-data +webol-cli.toml 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 { Reqwest(reqwest::Error), Config(config::ConfigError), Serde(serde_json::Error), + WsResponse, } impl Debug for CliError { @@ -12,6 +13,7 @@ impl Debug for CliError { Self::Reqwest(err) => { err.fmt(f) }, Self::Config(err) => { err.fmt(f) }, Self::Serde(err) => { err.fmt(f) }, + Self::WsResponse => { f.write_str("Error in Response") }, } } } 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 @@ -use std::fmt::Display; +use std::{fmt::Display, time::Duration}; use clap::{Parser, Subcommand}; use config::SETTINGS; use error::CliError; +use indicatif::{ProgressBar, ProgressStyle, MultiProgress}; use requests::{start::start, device}; use reqwest::header::{HeaderMap, HeaderValue}; use serde::Deserialize; @@ -11,7 +12,15 @@ mod config; mod error; mod requests; -/// webol http client +static OVERVIEW_STYLE: &str = "{spinner:.green} {wide_msg}({elapsed})"; +static OVERVIEW_ERROR: &str = "✗ {wide_msg}({elapsed})"; +static OVERVIEW_DONE: &str = "✓ {wide_msg}({elapsed})"; +static DEFAULT_STYLE: &str = " {spinner:.green} {wide_msg}"; +static DONE_STYLE: &str = " ✓ {wide_msg}"; +static ERROR_STYLE: &str = " ✗ {wide_msg}"; +static TICK_SPEED: u64 = 1000 / 16; + +/// webol client #[derive(Parser)] #[command(author, version, about, long_about = None)] struct Args { @@ -103,6 +112,21 @@ fn format_url(path: &str, protocol: Protocols) -> Result { )) } +fn add_pb(mp: &MultiProgress, template: &str, message: String) -> ProgressBar { + let pb = mp.add(ProgressBar::new(1)); + pb.set_style(ProgressStyle::with_template(template).unwrap()); + pb.enable_steady_tick(Duration::from_millis(TICK_SPEED)); + pb.set_message(message); + + pb +} + +fn finish_pb(pb: ProgressBar, message: String, template: &str) { + pb.set_style(ProgressStyle::with_template(template).unwrap()); + pb.finish_with_message(message); + +} + enum Protocols { Http, 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 @@ use crate::{error::CliError, default_headers, format_url, Protocols}; pub async fn put(id: String, mac: String, broadcast_addr: String, ip: String) -> Result<(), CliError> { + let url = format_url("device", Protocols::Http)?; + println!("{}", url); let res = reqwest::Client::new() - .put(format_url("device", Protocols::Http)?) + .put(url) .headers(default_headers()?) .body( 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 @@ -use std::time::Duration; - use futures_util::{StreamExt, SinkExt}; -use indicatif::{ProgressBar, ProgressStyle}; +use indicatif::MultiProgress; use reqwest::StatusCode; use serde::Deserialize; use tokio_tungstenite::{connect_async, tungstenite::Message}; -use crate::{error::CliError, default_headers, ErrorResponse, format_url, Protocols}; +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}; pub async fn start(id: String, ping: bool) -> Result<(), CliError> { - let send_start = ProgressBar::new(1); + let send_start = MultiProgress::new(); + let overview = add_pb(&send_start, OVERVIEW_STYLE, format!("start {}", id)); // TODO: calculate average start-time on server - send_start.set_style( - ProgressStyle::with_template("{spinner:.green} ({elapsed}) {wide_msg}") - .unwrap() - .tick_chars("|/-\\\\") - ); - let url = format_url("start", Protocols::Http)?; - - send_start.set_message(format!("connect to {}", url)); - send_start.enable_steady_tick(Duration::from_millis(125)); - + let connect = add_pb(&send_start, DEFAULT_STYLE, format!("connect to {}", url)); let res = reqwest::Client::new() .post(url) .headers(default_headers()?) @@ -33,7 +23,9 @@ pub async fn start(id: String, ping: bool) -> Result<(), CliError> { .send() .await .map_err(CliError::Reqwest)?; + finish_pb(connect, "connected, got response".to_string(), DONE_STYLE); + let res_pb = add_pb(&send_start, DEFAULT_STYLE, "analyzing response".to_string()); match res.status() { StatusCode::OK => { let body = serde_json::from_str::( @@ -42,11 +34,16 @@ pub async fn start(id: String, ping: bool) -> Result<(), CliError> { .map_err(CliError::Serde)?; if body.boot { - send_start.println("connected, sent start packet"); + finish_pb(res_pb, "sent start packet".to_string(), DONE_STYLE); } if ping { - send_start.println(status_socket(body.uuid, &send_start).await?.to_string()); + let status = status_socket(body.uuid, &send_start).await?; + if status { + finish_pb(overview, format!("successfully started {}", body.id), OVERVIEW_DONE); + } else { + finish_pb(overview, format!("error while starting {}", body.id), OVERVIEW_ERROR); + } } }, _ => { @@ -55,37 +52,63 @@ pub async fn start(id: String, ping: bool) -> Result<(), CliError> { ) .map_err(CliError::Serde)?; - println!("got error: {}", body.error); + res_pb.finish_with_message(format!("✗ got error: {}", body.error)); } } Ok(()) } -async fn status_socket(uuid: String, pb: &ProgressBar) -> Result { - pb.set_message("setup websocket"); - +async fn status_socket(uuid: String, pb: &MultiProgress) -> Result { + // TODO: Remove unwraps + let ws_pb = add_pb(pb, DEFAULT_STYLE, "connect to websocket".to_string()); let (mut ws_stream, _response) = connect_async(format_url("status", Protocols::Websocket)?) .await .expect("Failed to connect"); - pb.println("connected to websocket"); - - pb.set_message("send uuid message"); - ws_stream.send(Message::Text(uuid)).await.unwrap(); - pb.println("sent uuid message"); + finish_pb(ws_pb, "connected to websocket".to_string(), DONE_STYLE); + + ws_stream.send(Message::Text(uuid.clone())).await.unwrap(); - pb.set_message("wait for message"); + let msg_pb = add_pb(pb, DEFAULT_STYLE, "await message".to_string()); let msg = ws_stream.next().await.unwrap(); + finish_pb(msg_pb, "received message".to_string(), DONE_STYLE); - pb.println(format!("msg: {:?}", msg)); - ws_stream.close(None).await.unwrap(); - pb.println("connection closed"); - // TODO: Check for correct UUID and timeout - pb.set_message("verifying message"); - if msg.is_ok() { return Ok(true) } - Ok(false) + let v_pb = add_pb(pb, DEFAULT_STYLE, "verify response".to_string()); + let res = verify_response(msg.unwrap().to_string(), uuid)?; + match res { + Verified::WrongUuid => { + finish_pb(v_pb, "returned wrong uuid".to_string(), ERROR_STYLE); + Ok(false) + }, + Verified::ResponseType(res_type) => { + match res_type { + ResponseType::Start => { + finish_pb(v_pb, "device started".to_string(), DONE_STYLE); + Ok(true) + }, + ResponseType::Timeout => { + finish_pb(v_pb, "ping timed out".to_string(), ERROR_STYLE); + Ok(false) + }, + ResponseType::NotFound => { + finish_pb(v_pb, "unknown uuid".to_string(), ERROR_STYLE); + Ok(false) + }, + } + } + } +} + +fn verify_response(res: String, org_uuid: String) -> Result { + let spl: Vec<&str> = res.split('_').collect(); + let res_type = spl[0]; + let uuid = spl[1]; + + if uuid != org_uuid { return Ok(Verified::WrongUuid) }; + + Ok(Verified::ResponseType(ResponseType::from(res_type)?)) } #[derive(Debug, Deserialize)] @@ -94,3 +117,25 @@ struct StartResponse { id: String, uuid: String, } + +enum Verified { + ResponseType(ResponseType), + WrongUuid +} + +enum ResponseType { + Start, + Timeout, + NotFound, +} + +impl ResponseType { + fn from(value: &str) -> Result { + match value { + "start" => Ok(ResponseType::Start), + "timeout" => Ok(ResponseType::Timeout), + "notfound" => Ok(ResponseType::NotFound), + _ => Err(CliError::WsResponse), + } + } +} diff --git a/webol-cli.toml b/webol-cli.toml index 7ffb99d..822af46 100644 --- a/webol-cli.toml +++ b/webol-cli.toml @@ -1,2 +1,2 @@ -server = "192.168.178.28:7229" +server = "localhost:7229" key = "aaa" -- cgit v1.2.3 From 9957da9b182ca209ff8caa8f670d3bd7eff154bb Mon Sep 17 00:00:00 2001 From: FxQnLr Date: Fri, 10 Nov 2023 12:23:31 +0100 Subject: add basic eta --- docker-compose.yml | 2 +- src/error.rs | 4 +++- src/main.rs | 6 +++--- src/requests/start.rs | 19 +++++++++++++++---- 4 files changed, 22 insertions(+), 9 deletions(-) (limited to 'src/requests/start.rs') diff --git a/docker-compose.yml b/docker-compose.yml index 0a52d16..3a0ade5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,6 @@ services: webol: - image: ghcr.io/fxqnlr/webol:dev-2 + image: ghcr.io/fxqnlr/webol:dev-6 container_name: webol restart: no depends_on: diff --git a/src/error.rs b/src/error.rs index 27fc7a6..f15c60a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,9 +1,10 @@ -use std::fmt::Debug; +use std::{fmt::Debug, num::ParseIntError}; pub enum CliError { Reqwest(reqwest::Error), Config(config::ConfigError), Serde(serde_json::Error), + Parse(ParseIntError), WsResponse, } @@ -13,6 +14,7 @@ impl Debug for CliError { Self::Reqwest(err) => { err.fmt(f) }, Self::Config(err) => { err.fmt(f) }, Self::Serde(err) => { err.fmt(f) }, + Self::Parse(err) => { err.fmt(f) }, Self::WsResponse => { f.write_str("Error in Response") }, } } diff --git a/src/main.rs b/src/main.rs index d7c985f..204e671 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,9 +12,9 @@ mod config; mod error; mod requests; -static OVERVIEW_STYLE: &str = "{spinner:.green} {wide_msg}({elapsed})"; -static OVERVIEW_ERROR: &str = "✗ {wide_msg}({elapsed})"; -static OVERVIEW_DONE: &str = "✓ {wide_msg}({elapsed})"; +static OVERVIEW_STYLE: &str = "{spinner:.green} ({elapsed}{wide_msg}"; +static OVERVIEW_ERROR: &str = "✗ ({elapsed}) {wide_msg}"; +static OVERVIEW_DONE: &str = "✓ ({elapsed}) {wide_msg}"; static DEFAULT_STYLE: &str = " {spinner:.green} {wide_msg}"; static DONE_STYLE: &str = " ✓ {wide_msg}"; static ERROR_STYLE: &str = " ✗ {wide_msg}"; diff --git a/src/requests/start.rs b/src/requests/start.rs index 882b154..ca4ca44 100644 --- a/src/requests/start.rs +++ b/src/requests/start.rs @@ -1,5 +1,5 @@ use futures_util::{StreamExt, SinkExt}; -use indicatif::MultiProgress; +use indicatif::{MultiProgress, ProgressBar}; use reqwest::StatusCode; use serde::Deserialize; use tokio_tungstenite::{connect_async, tungstenite::Message}; @@ -9,7 +9,7 @@ use crate::{error::CliError, default_headers, ErrorResponse, format_url, Protoco pub async fn start(id: String, ping: bool) -> Result<(), CliError> { let send_start = MultiProgress::new(); - let overview = add_pb(&send_start, OVERVIEW_STYLE, format!("start {}", id)); + let overview = add_pb(&send_start, OVERVIEW_STYLE, format!(") start {}", id)); // TODO: calculate average start-time on server let url = format_url("start", Protocols::Http)?; @@ -38,7 +38,7 @@ pub async fn start(id: String, ping: bool) -> Result<(), CliError> { } if ping { - let status = status_socket(body.uuid, &send_start).await?; + let status = status_socket(body.uuid, &send_start, &overview, id).await?; if status { finish_pb(overview, format!("successfully started {}", body.id), OVERVIEW_DONE); } else { @@ -59,7 +59,7 @@ pub async fn start(id: String, ping: bool) -> Result<(), CliError> { Ok(()) } -async fn status_socket(uuid: String, pb: &MultiProgress) -> Result { +async fn status_socket(uuid: String, pb: &MultiProgress, overview: &ProgressBar, id: String) -> Result { // TODO: Remove unwraps let ws_pb = add_pb(pb, DEFAULT_STYLE, "connect to websocket".to_string()); let (mut ws_stream, _response) = connect_async(format_url("status", Protocols::Websocket)?) @@ -68,6 +68,11 @@ async fn status_socket(uuid: String, pb: &MultiProgress) -> Result Result Result { + let spl: Vec<&str> = msg.split('_').collect(); + if (spl[0] != "eta") || (spl[2] != uuid) { return Err(CliError::WsResponse); }; + Ok(u64::from_str_radix(spl[1], 10).map_err(CliError::Parse)?) +} + fn verify_response(res: String, org_uuid: String) -> Result { let spl: Vec<&str> = res.split('_').collect(); let res_type = spl[0]; -- cgit v1.2.3