diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main.rs | 48 | ||||
-rw-r--r-- | src/requests/device.rs | 42 | ||||
-rw-r--r-- | src/requests/start.rs | 73 |
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 @@ | |||
1 | use std::fmt::Display; | ||
2 | |||
1 | use clap::{Parser, Subcommand}; | 3 | use clap::{Parser, Subcommand}; |
2 | use config::SETTINGS; | 4 | use config::SETTINGS; |
3 | use error::CliError; | 5 | use error::CliError; |
@@ -21,7 +23,9 @@ struct Args { | |||
21 | enum Commands { | 23 | enum 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 | ||
49 | fn main() -> Result<(), CliError> { | 55 | #[tokio::main] |
56 | async 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 | ||
90 | fn format_url(path: &str) -> Result<String, CliError> { | 97 | fn 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 | ||
106 | enum Protocols { | ||
107 | Http, | ||
108 | Websocket, | ||
109 | } | ||
110 | |||
111 | impl 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)] |
99 | struct ErrorResponse { | 121 | struct 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 @@ | |||
1 | use crate::{error::CliError, default_headers, format_url}; | 1 | use crate::{error::CliError, default_headers, format_url, Protocols}; |
2 | 2 | ||
3 | pub fn put(id: String, mac: String, broadcast_addr: String) -> Result<(), CliError> { | 3 | pub 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 | ||
23 | pub fn get(id: String) -> Result<(), CliError> { | 26 | pub 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 | ||
38 | pub fn post(id: String, mac: String, broadcast_addr: String) -> Result<(), CliError> { | 43 | pub 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 @@ | |||
1 | use std::time::Duration; | ||
2 | |||
3 | use futures_util::{StreamExt, SinkExt}; | ||
4 | use indicatif::{ProgressBar, ProgressStyle}; | ||
1 | use reqwest::StatusCode; | 5 | use reqwest::StatusCode; |
2 | use serde::Deserialize; | 6 | use serde::Deserialize; |
7 | use tokio_tungstenite::{connect_async, tungstenite::Message}; | ||
3 | 8 | ||
4 | use crate::{config::SETTINGS, error::CliError, default_headers, ErrorResponse}; | 9 | use crate::{error::CliError, default_headers, ErrorResponse, format_url, Protocols}; |
5 | 10 | ||
6 | pub fn start(id: String) -> Result<(), CliError> { | 11 | pub 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 | ||
65 | async 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)] |
46 | struct StartResponse { | 92 | struct StartResponse { |
47 | boot: bool, | 93 | boot: bool, |
48 | id: String, | 94 | id: String, |
95 | uuid: String, | ||
49 | } | 96 | } |