summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.rs48
-rw-r--r--src/requests/device.rs42
-rw-r--r--src/requests/start.rs73
3 files changed, 120 insertions, 43 deletions
diff --git a/src/main.rs b/src/main.rs
index ab7e476..3e1388b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,5 @@
1use std::fmt::Display;
2
1use clap::{Parser, Subcommand}; 3use clap::{Parser, Subcommand};
2use config::SETTINGS; 4use config::SETTINGS;
3use error::CliError; 5use error::CliError;
@@ -21,7 +23,9 @@ struct Args {
21enum Commands { 23enum Commands {
22 Start { 24 Start {
23 /// id of the device 25 /// id of the device
24 id: String 26 id: String,
27 #[arg(short, long)]
28 ping: Option<bool>
25 }, 29 },
26 Device { 30 Device {
27 #[command(subcommand)] 31 #[command(subcommand)]
@@ -34,7 +38,8 @@ enum DeviceCmd {
34 Add { 38 Add {
35 id: String, 39 id: String,
36 mac: String, 40 mac: String,
37 broadcast_addr: String 41 broadcast_addr: String,
42 ip: String
38 }, 43 },
39 Get { 44 Get {
40 id: String, 45 id: String,
@@ -42,27 +47,29 @@ enum DeviceCmd {
42 Edit { 47 Edit {
43 id: String, 48 id: String,
44 mac: String, 49 mac: String,
45 broadcast_addr: String 50 broadcast_addr: String,
51 ip: String
46 }, 52 },
47} 53}
48 54
49fn main() -> Result<(), CliError> { 55#[tokio::main]
56async fn main() -> Result<(), CliError> {
50 let cli = Args::parse(); 57 let cli = Args::parse();
51 58
52 match cli.commands { 59 match cli.commands {
53 Commands::Start { id } => { 60 Commands::Start { id, ping } => {
54 start(id)?; 61 start(id, ping.unwrap_or(true)).await?;
55 }, 62 },
56 Commands::Device { devicecmd } => { 63 Commands::Device { devicecmd } => {
57 match devicecmd { 64 match devicecmd {
58 DeviceCmd::Add { id, mac, broadcast_addr } => { 65 DeviceCmd::Add { id, mac, broadcast_addr, ip } => {
59 device::put(id, mac, broadcast_addr)?; 66 device::put(id, mac, broadcast_addr, ip).await?;
60 }, 67 },
61 DeviceCmd::Get { id } => { 68 DeviceCmd::Get { id } => {
62 device::get(id)?; 69 device::get(id).await?;
63 }, 70 },
64 DeviceCmd::Edit { id, mac, broadcast_addr } => { 71 DeviceCmd::Edit { id, mac, broadcast_addr, ip } => {
65 device::post(id, mac, broadcast_addr)?; 72 device::post(id, mac, broadcast_addr, ip).await?;
66 }, 73 },
67 } 74 }
68 } 75 }
@@ -87,14 +94,29 @@ fn default_headers() -> Result<HeaderMap, CliError> {
87 Ok(map) 94 Ok(map)
88} 95}
89 96
90fn format_url(path: &str) -> Result<String, CliError> { 97fn format_url(path: &str, protocol: Protocols) -> Result<String, CliError> {
91 Ok(format!( 98 Ok(format!(
92 "{}/{}", 99 "{}://{}/{}",
100 protocol,
93 SETTINGS.get_string("server").map_err(CliError::Config)?, 101 SETTINGS.get_string("server").map_err(CliError::Config)?,
94 path 102 path
95 )) 103 ))
96} 104}
97 105
106enum Protocols {
107 Http,
108 Websocket,
109}
110
111impl Display for Protocols {
112 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113 match self {
114 Self::Http => f.write_str("http"),
115 Self::Websocket => f.write_str("ws")
116 }
117 }
118}
119
98#[derive(Debug, Deserialize)] 120#[derive(Debug, Deserialize)]
99struct ErrorResponse { 121struct ErrorResponse {
100 error: String 122 error: String
diff --git a/src/requests/device.rs b/src/requests/device.rs
index 525745a..f7754a4 100644
--- a/src/requests/device.rs
+++ b/src/requests/device.rs
@@ -1,55 +1,63 @@
1use crate::{error::CliError, default_headers, format_url}; 1use crate::{error::CliError, default_headers, format_url, Protocols};
2 2
3pub fn put(id: String, mac: String, broadcast_addr: String) -> Result<(), CliError> { 3pub async fn put(id: String, mac: String, broadcast_addr: String, ip: String) -> Result<(), CliError> {
4 let res = reqwest::blocking::Client::new() 4 let res = reqwest::Client::new()
5 .put(format_url("device")?) 5 .put(format_url("device", Protocols::Http)?)
6 .headers(default_headers()?) 6 .headers(default_headers()?)
7 .body( 7 .body(
8 format!( 8 format!(
9 r#"{{"id": "{}", "mac": "{}", "broadcast_addr": "{}"}}"#, 9 r#"{{"id": "{}", "mac": "{}", "broadcast_addr": "{}", "ip": "{}"}}"#,
10 id, 10 id,
11 mac, 11 mac,
12 broadcast_addr 12 broadcast_addr,
13 ip
13 ) 14 )
14 ) 15 )
15 .send() 16 .send()
17 .await
16 .map_err(CliError::Reqwest)? 18 .map_err(CliError::Reqwest)?
17 .text(); 19 .text()
20 .await;
18 21
19 println!("{:?}", res); 22 println!("{:?}", res);
20 Ok(()) 23 Ok(())
21} 24}
22 25
23pub fn get(id: String) -> Result<(), CliError> { 26pub async fn get(id: String) -> Result<(), CliError> {
24 let res = reqwest::blocking::Client::new() 27 let res = reqwest::Client::new()
25 .get(format_url("device")?) 28 .get(format_url("device", Protocols::Http)?)
26 .headers(default_headers()?) 29 .headers(default_headers()?)
27 .body( 30 .body(
28 format!(r#"{{"id": "{}"}}"#, id) 31 format!(r#"{{"id": "{}"}}"#, id)
29 ) 32 )
30 .send() 33 .send()
34 .await
31 .map_err(CliError::Reqwest)? 35 .map_err(CliError::Reqwest)?
32 .text(); 36 .text()
37 .await;
33 38
34 println!("{:?}", res); 39 println!("{:?}", res);
35 Ok(()) 40 Ok(())
36} 41}
37 42
38pub fn post(id: String, mac: String, broadcast_addr: String) -> Result<(), CliError> { 43pub async fn post(id: String, mac: String, broadcast_addr: String, ip: String) -> Result<(), CliError> {
39 let res = reqwest::blocking::Client::new() 44 let res = reqwest::Client::new()
40 .post(format_url("device")?) 45 .post(format_url("device", Protocols::Http)?)
41 .headers(default_headers()?) 46 .headers(default_headers()?)
42 .body( 47 .body(
43 format!( 48 format!(
44 r#"{{"id": "{}", "mac": "{}", "broadcast_addr": "{}"}}"#, 49 r#"{{"id": "{}", "mac": "{}", "broadcast_addr": "{}", "ip": "{}"}}"#,
45 id, 50 id,
46 mac, 51 mac,
47 broadcast_addr 52 broadcast_addr,
53 ip
48 ) 54 )
49 ) 55 )
50 .send() 56 .send()
57 .await
51 .map_err(CliError::Reqwest)? 58 .map_err(CliError::Reqwest)?
52 .text(); 59 .text()
60 .await;
53 61
54 println!("{:?}", res); 62 println!("{:?}", res);
55 Ok(()) 63 Ok(())
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 @@
1use std::time::Duration;
2
3use futures_util::{StreamExt, SinkExt};
4use indicatif::{ProgressBar, ProgressStyle};
1use reqwest::StatusCode; 5use reqwest::StatusCode;
2use serde::Deserialize; 6use serde::Deserialize;
7use tokio_tungstenite::{connect_async, tungstenite::Message};
3 8
4use crate::{config::SETTINGS, error::CliError, default_headers, ErrorResponse}; 9use crate::{error::CliError, default_headers, ErrorResponse, format_url, Protocols};
5 10
6pub fn start(id: String) -> Result<(), CliError> { 11pub async fn start(id: String, ping: bool) -> Result<(), CliError> {
7 let res = reqwest::blocking::Client::new() 12
8 .post( 13 let send_start = ProgressBar::new(1);
9 format!( 14
10 "{}/start", 15 // TODO: calculate average start-time on server
11 SETTINGS.get_string("server").map_err(CliError::Config)? 16 send_start.set_style(
12 ) 17 ProgressStyle::with_template("{spinner:.green} ({elapsed}) {wide_msg}")
13 ) 18 .unwrap()
19 .tick_chars("|/-\\\\")
20 );
21
22 let url = format_url("start", Protocols::Http)?;
23
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()
28 .post(url)
14 .headers(default_headers()?) 29 .headers(default_headers()?)
15 .body( 30 .body(
16 format!(r#"{{"id": "{}"}}"#, id) 31 format!(r#"{{"id": "{}", "ping": {}}}"#, id, ping)
17 ) 32 )
18 .send() 33 .send()
34 .await
19 .map_err(CliError::Reqwest)?; 35 .map_err(CliError::Reqwest)?;
20 36
21 match res.status() { 37 match res.status() {
22 StatusCode::OK => { 38 StatusCode::OK => {
23 let body = serde_json::from_str::<StartResponse>( 39 let body = serde_json::from_str::<StartResponse>(
24 &res.text().map_err(CliError::Reqwest)? 40 &res.text().await.map_err(CliError::Reqwest)?
25 ) 41 )
26 .map_err(CliError::Serde)?; 42 .map_err(CliError::Serde)?;
27 43
28 if body.boot { 44 if body.boot {
29 println!("successfully started {}", body.id); 45 send_start.println("connected, sent start packet");
46 }
47
48 if ping {
49 send_start.println(status_socket(body.uuid, &send_start).await?.to_string());
30 } 50 }
31 }, 51 },
32 _ => { 52 _ => {
33 let body = serde_json::from_str::<ErrorResponse>( 53 let body = serde_json::from_str::<ErrorResponse>(
34 &res.text().map_err(CliError::Reqwest)? 54 &res.text().await.map_err(CliError::Reqwest)?
35 ) 55 )
36 .map_err(CliError::Serde)?; 56 .map_err(CliError::Serde)?;
37 57
@@ -42,8 +62,35 @@ pub fn start(id: String) -> Result<(), CliError> {
42 Ok(()) 62 Ok(())
43} 63}
44 64
65async fn status_socket(uuid: String, pb: &ProgressBar) -> Result<bool, CliError> {
66 pb.set_message("setup websocket");
67
68 let (mut ws_stream, _response) = connect_async(format_url("status", Protocols::Websocket)?)
69 .await
70 .expect("Failed to connect");
71 pb.println("connected to websocket");
72
73 pb.set_message("send uuid message");
74 ws_stream.send(Message::Text(uuid)).await.unwrap();
75 pb.println("sent uuid message");
76
77 pb.set_message("wait for message");
78 let msg = ws_stream.next().await.unwrap();
79
80 pb.println(format!("msg: {:?}", msg));
81
82 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
88 Ok(false)
89}
90
45#[derive(Debug, Deserialize)] 91#[derive(Debug, Deserialize)]
46struct StartResponse { 92struct StartResponse {
47 boot: bool, 93 boot: bool,
48 id: String, 94 id: String,
95 uuid: String,
49} 96}