aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfx <[email protected]>2023-10-25 12:53:31 +0200
committerfx <[email protected]>2023-10-25 12:53:31 +0200
commit00dd8a9abee6b9f0cfc37c6f20f30f0d99dfe91a (patch)
tree7906b5836f3ca24686b1b7418c2128b93c33a398
parentf9224ff02e688dec819ab81893320a0611f2a198 (diff)
downloadwebol-00dd8a9abee6b9f0cfc37c6f20f30f0d99dfe91a.tar
webol-00dd8a9abee6b9f0cfc37c6f20f30f0d99dfe91a.tar.gz
webol-00dd8a9abee6b9f0cfc37c6f20f30f0d99dfe91a.zip
runs, no error handling
-rw-r--r--Cargo.lock24
-rw-r--r--Cargo.toml2
-rw-r--r--src/main.rs13
-rw-r--r--src/routes/mod.rs3
-rw-r--r--src/routes/start.rs24
-rw-r--r--src/routes/status.rs12
-rw-r--r--src/services/ping.rs79
7 files changed, 122 insertions, 35 deletions
diff --git a/Cargo.lock b/Cargo.lock
index bf813bf..2650edc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -135,6 +135,18 @@ dependencies = [
135] 135]
136 136
137[[package]] 137[[package]]
138name = "axum-macros"
139version = "0.3.8"
140source = "registry+https://github.com/rust-lang/crates.io-index"
141checksum = "cdca6a10ecad987bda04e95606ef85a5417dcaac1a78455242d72e031e2b6b62"
142dependencies = [
143 "heck",
144 "proc-macro2",
145 "quote",
146 "syn 2.0.38",
147]
148
149[[package]]
138name = "backtrace" 150name = "backtrace"
139version = "0.3.69" 151version = "0.3.69"
140source = "registry+https://github.com/rust-lang/crates.io-index" 152source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2128,6 +2140,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
2128checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" 2140checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
2129 2141
2130[[package]] 2142[[package]]
2143name = "uuid"
2144version = "1.5.0"
2145source = "registry+https://github.com/rust-lang/crates.io-index"
2146checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc"
2147dependencies = [
2148 "getrandom",
2149 "rand",
2150]
2151
2152[[package]]
2131name = "valuable" 2153name = "valuable"
2132version = "0.1.0" 2154version = "0.1.0"
2133source = "registry+https://github.com/rust-lang/crates.io-index" 2155source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2165,6 +2187,7 @@ name = "webol"
2165version = "0.1.0" 2187version = "0.1.0"
2166dependencies = [ 2188dependencies = [
2167 "axum", 2189 "axum",
2190 "axum-macros",
2168 "config", 2191 "config",
2169 "once_cell", 2192 "once_cell",
2170 "serde", 2193 "serde",
@@ -2175,6 +2198,7 @@ dependencies = [
2175 "tokio", 2198 "tokio",
2176 "tracing", 2199 "tracing",
2177 "tracing-subscriber", 2200 "tracing-subscriber",
2201 "uuid",
2178] 2202]
2179 2203
2180[[package]] 2204[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index 9bdc4da..d29a1b3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -17,3 +17,5 @@ config = "0.13.3"
17once_cell = "1.18.0" 17once_cell = "1.18.0"
18sqlx = { version = "0.7.1", features = ["postgres", "runtime-tokio"]} 18sqlx = { version = "0.7.1", features = ["postgres", "runtime-tokio"]}
19surge-ping = "0.8.0" 19surge-ping = "0.8.0"
20axum-macros = "0.3.8"
21uuid = { version = "1.5.0", features = ["v4", "fast-rng"] }
diff --git a/src/main.rs b/src/main.rs
index 124c44e..854b59d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,4 @@
1use std::collections::HashMap;
1use std::env; 2use std::env;
2use std::sync::Arc; 3use std::sync::Arc;
3use axum::{Router, routing::post}; 4use axum::{Router, routing::post};
@@ -5,13 +6,14 @@ use axum::routing::{get, put};
5use sqlx::PgPool; 6use sqlx::PgPool;
6use time::util::local_offset; 7use time::util::local_offset;
7use tokio::sync::broadcast::{channel, Sender}; 8use tokio::sync::broadcast::{channel, Sender};
9use tokio::sync::Mutex;
8use tracing::{info, level_filters::LevelFilter}; 10use tracing::{info, level_filters::LevelFilter};
9use tracing_subscriber::{EnvFilter, fmt::{self, time::LocalTime}, prelude::*}; 11use tracing_subscriber::{EnvFilter, fmt::{self, time::LocalTime}, prelude::*};
10use crate::config::SETTINGS; 12use crate::config::SETTINGS;
11use crate::db::init_db_pool; 13use crate::db::init_db_pool;
12use crate::routes::device::{get_device, post_device, put_device}; 14use crate::routes::device::{get_device, post_device, put_device};
13use crate::routes::start::start; 15use crate::routes::start::start;
14use crate::services::ping::ws_ping; 16use crate::routes::status::status;
15 17
16mod auth; 18mod auth;
17mod config; 19mod config;
@@ -47,15 +49,17 @@ async fn main() {
47 sqlx::migrate!().run(&db).await.unwrap(); 49 sqlx::migrate!().run(&db).await.unwrap();
48 50
49 let (tx, _) = channel(32); 51 let (tx, _) = channel(32);
52
53 let ping_map: HashMap<String, (String, bool)> = HashMap::new();
50 54
51 let shared_state = Arc::new(AppState { db, ping_send: tx }); 55 let shared_state = Arc::new(AppState { db, ping_send: tx, ping_map: Arc::new(Mutex::new(ping_map)) });
52 56
53 let app = Router::new() 57 let app = Router::new()
54 .route("/start", post(start)) 58 .route("/start", post(start))
55 .route("/device", get(get_device)) 59 .route("/device", get(get_device))
56 .route("/device", put(put_device)) 60 .route("/device", put(put_device))
57 .route("/device", post(post_device)) 61 .route("/device", post(post_device))
58 .route("/status", get(ws_ping)) 62 .route("/status", get(status))
59 .with_state(shared_state); 63 .with_state(shared_state);
60 64
61 let addr = SETTINGS.get_string("serveraddr").unwrap_or("0.0.0.0:7229".to_string()); 65 let addr = SETTINGS.get_string("serveraddr").unwrap_or("0.0.0.0:7229".to_string());
@@ -69,4 +73,5 @@ async fn main() {
69pub struct AppState { 73pub struct AppState {
70 db: PgPool, 74 db: PgPool,
71 ping_send: Sender<String>, 75 ping_send: Sender<String>,
72} 76 ping_map: Arc<Mutex<HashMap<String, (String, bool)>>>,
77} \ No newline at end of file
diff --git a/src/routes/mod.rs b/src/routes/mod.rs
index 12fbfab..d5ab0d6 100644
--- a/src/routes/mod.rs
+++ b/src/routes/mod.rs
@@ -1,2 +1,3 @@
1pub mod start; 1pub mod start;
2pub mod device; \ No newline at end of file 2pub mod device;
3pub mod status; \ No newline at end of file
diff --git a/src/routes/start.rs b/src/routes/start.rs
index 863ef16..45e7ec8 100644
--- a/src/routes/start.rs
+++ b/src/routes/start.rs
@@ -4,15 +4,18 @@ use serde::{Deserialize, Serialize};
4use std::sync::Arc; 4use std::sync::Arc;
5use axum::extract::State; 5use axum::extract::State;
6use serde_json::{json, Value}; 6use serde_json::{json, Value};
7use tracing::{debug, info}; 7use tracing::{debug, info, warn};
8use uuid::Uuid;
8use crate::auth::auth; 9use crate::auth::auth;
9use crate::config::SETTINGS; 10use crate::config::SETTINGS;
10use crate::wol::{create_buffer, send_packet}; 11use crate::wol::{create_buffer, send_packet};
11use crate::db::Device; 12use crate::db::Device;
12use crate::error::WebolError; 13use crate::error::WebolError;
13 14
15#[axum_macros::debug_handler]
14pub async fn start(State(state): State<Arc<crate::AppState>>, headers: HeaderMap, Json(payload): Json<StartPayload>) -> Result<Json<Value>, WebolError> { 16pub async fn start(State(state): State<Arc<crate::AppState>>, headers: HeaderMap, Json(payload): Json<StartPayload>) -> Result<Json<Value>, WebolError> {
15 info!("POST request"); 17 info!("POST request");
18 warn!("{:?}", state.ping_map);
16 let secret = headers.get("authorization"); 19 let secret = headers.get("authorization");
17 let authorized = auth(secret).map_err(WebolError::Auth)?; 20 let authorized = auth(secret).map_err(WebolError::Auth)?;
18 if authorized { 21 if authorized {
@@ -38,14 +41,20 @@ pub async fn start(State(state): State<Arc<crate::AppState>>, headers: HeaderMap
38 create_buffer(&device.mac)? 41 create_buffer(&device.mac)?
39 )?; 42 )?;
40 43
41 if payload.ping.is_some_and(|ping| ping) { 44 let uuid = if payload.ping.is_some_and(|ping| ping) {
42 debug!("ping true"); 45 let uuid_gen = Uuid::new_v4().to_string();
43 tokio::spawn(async move { 46 let uuid_genc = uuid_gen.clone();
47 tokio::spawn(async move{
44 debug!("Init ping service"); 48 debug!("Init ping service");
45 crate::services::ping::spawn(state.ping_send.clone()).await 49 state.ping_map.lock().await.insert(uuid_gen, ("192.168.178.94".to_string(), false));
50
51 warn!("{:?}", state.ping_map);
52
53 crate::services::ping::spawn(state.ping_send.clone(), "192.168.178.94".to_string()).await;
46 }); 54 });
47 }; 55 Some(uuid_genc)
48 Ok(Json(json!(StartResponse { id: device.id, boot: true }))) 56 } else { None };
57 Ok(Json(json!(StartResponse { id: device.id, boot: true, uuid })))
49 } else { 58 } else {
50 Err(WebolError::Generic) 59 Err(WebolError::Generic)
51 } 60 }
@@ -61,4 +70,5 @@ pub struct StartPayload {
61struct StartResponse { 70struct StartResponse {
62 id: String, 71 id: String,
63 boot: bool, 72 boot: bool,
73 uuid: Option<String>,
64} 74}
diff --git a/src/routes/status.rs b/src/routes/status.rs
new file mode 100644
index 0000000..cdecf6a
--- /dev/null
+++ b/src/routes/status.rs
@@ -0,0 +1,12 @@
1use std::sync::Arc;
2use axum::extract::{State, WebSocketUpgrade};
3use axum::response::Response;
4use serde::Deserialize;
5use crate::AppState;
6use crate::services::ping::status_websocket;
7
8#[axum_macros::debug_handler]
9pub async fn status(State(state): State<Arc<AppState>>, ws: WebSocketUpgrade) -> Response {
10 // TODO: remove unwrap
11 ws.on_upgrade(move |socket| status_websocket(socket, state.ping_send.clone(), state.ping_map.clone()))
12} \ No newline at end of file
diff --git a/src/services/ping.rs b/src/services/ping.rs
index ff328a5..e3d465d 100644
--- a/src/services/ping.rs
+++ b/src/services/ping.rs
@@ -1,26 +1,29 @@
1use std::borrow::Cow; 1use std::borrow::Cow;
2use std::collections::HashMap;
2use std::sync::Arc; 3use std::sync::Arc;
3 4
4use axum::{extract::{WebSocketUpgrade, ws::WebSocket, State}, response::Response}; 5use axum::extract::{ws::WebSocket};
6use axum::extract::ws::Message;
5use tokio::sync::broadcast::{Sender}; 7use tokio::sync::broadcast::{Sender};
6use tracing::{debug, error, trace}; 8use tokio::sync::Mutex;
9use tracing::{debug, error, trace, warn};
7 10
8use crate::{error::WebolError, AppState}; 11use crate::error::WebolError;
9 12
10pub async fn spawn(tx: Sender<String>) -> Result<(), WebolError> { 13pub async fn spawn(tx: Sender<String>, ip: String) -> Result<(), WebolError> {
11 let payload = [0; 8]; 14 let payload = [0; 8];
12 15
13 let mut cont = true; 16 let mut cont = true;
14 while cont { 17 while cont {
15 let ping = surge_ping::ping( 18 let ping = surge_ping::ping(
16 "127.0.0.1".parse().map_err(WebolError::IpParse)?, 19 ip.parse().map_err(WebolError::IpParse)?,
17 &payload 20 &payload
18 ).await; 21 ).await;
19 22
20 if let Err(ping) = ping { 23 if let Err(ping) = ping {
21 cont = matches!(ping, surge_ping::SurgeError::Timeout { .. }); 24 cont = matches!(ping, surge_ping::SurgeError::Timeout { .. });
22 25
23 debug!("{}", cont); 26 // debug!("{}", cont);
24 27
25 if !cont { 28 if !cont {
26 return Err(ping).map_err(WebolError::Ping) 29 return Err(ping).map_err(WebolError::Ping)
@@ -31,29 +34,59 @@ pub async fn spawn(tx: Sender<String>) -> Result<(), WebolError> {
31 debug!("Ping took {:?}", duration); 34 debug!("Ping took {:?}", duration);
32 cont = false; 35 cont = false;
33 // FIXME: remove unwrap 36 // FIXME: remove unwrap
34 tx.send("Got ping".to_string()).unwrap(); 37 // FIXME: if error: SendError because no listener, then handle the entry directly
38 tx.send(ip.clone());
35 }; 39 };
36 } 40 }
37 41
38 Ok(()) 42 Ok(())
39} 43}
40 44
41// TODO: Status to routes, websocket here
42pub async fn ws_ping(State(state): State<Arc<AppState>>, ws: WebSocketUpgrade) -> Response {
43 ws.on_upgrade(move |socket| handle_socket(socket, state.ping_send.clone()))
44}
45
46// FIXME: Handle commands through enum 45// FIXME: Handle commands through enum
47async fn handle_socket(mut socket: WebSocket, tx: Sender<String>) { 46pub async fn status_websocket(mut socket: WebSocket, tx: Sender<String>, ping_map: Arc<Mutex<HashMap<String, (String, bool)>>>) {
48 // TODO: Understand Cow 47 warn!("{:?}", ping_map);
49 while let message = tx.subscribe().recv().await.unwrap() { 48
50 trace!("GOT = {}", message); 49 let mut uuid: Option<String> = None;
51 if &message == "Got ping" { 50
52 break; 51 trace!("wait for ws message (uuid)");
52 let msg = socket.recv().await;
53 uuid = Some(msg.unwrap().unwrap().into_text().unwrap());
54
55 let uuid = uuid.unwrap();
56
57 trace!("Search for uuid: {:?}", uuid);
58
59 let device = ping_map.lock().await.get(&uuid).unwrap().to_owned();
60
61 trace!("got device: {:?}", device);
62
63 match device.1 {
64 true => {
65 debug!("already started");
66 socket.send(Message::Text(format!("start_{}", uuid))).await.unwrap();
67 socket.close().await.unwrap();
68 },
69 false => {
70 let ip = device.0.to_owned();
71 let mut i = 0;
72 loop{
73 trace!("{}", i);
74 // TODO: Check if older than 10 minutes, close if true
75 trace!("wait for tx message");
76 let message = tx.subscribe().recv().await.unwrap();
77 trace!("GOT = {}", message);
78 if message == ip {
79 trace!("message == ip");
80 break;
81 }
82 i += 1;
83 };
84
85 socket.send(Message::Text(format!("start_{}", uuid))).await.unwrap();
86 socket.close().await.unwrap();
87 tokio::time::sleep(tokio::time::Duration::from_secs(60)).await;
88 ping_map.lock().await.remove(&uuid);
89 warn!("{:?}", ping_map);
53 } 90 }
54 }; 91 }
55 match socket.send(axum::extract::ws::Message::Close(Some(axum::extract::ws::CloseFrame { code: 4000, reason: Cow::Owned("started".to_owned()) }))).await.map_err(WebolError::Axum) {
56 Ok(..) => (),
57 Err(err) => { error!("Server Error: {:?}", err) }
58 };
59} \ No newline at end of file 92} \ No newline at end of file