summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock2
-rw-r--r--Cargo.toml2
-rw-r--r--README.md44
-rw-r--r--src/error.rs8
-rw-r--r--src/routes/device.rs27
-rw-r--r--src/routes/start.rs9
-rw-r--r--src/services/ping.rs4
-rw-r--r--src/storage.rs2
8 files changed, 77 insertions, 21 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 5261edf..4b5d730 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1837,7 +1837,7 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
1837 1837
1838[[package]] 1838[[package]]
1839name = "webol" 1839name = "webol"
1840version = "0.4.0" 1840version = "0.4.1"
1841dependencies = [ 1841dependencies = [
1842 "axum", 1842 "axum",
1843 "axum-macros", 1843 "axum-macros",
diff --git a/Cargo.toml b/Cargo.toml
index 1b7db8e..68ba060 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "webol" 2name = "webol"
3version = "0.4.0" 3version = "0.4.1"
4edition = "2021" 4edition = "2021"
5 5
6# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 6# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
diff --git a/README.md b/README.md
index 03779a1..e84d646 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,4 @@
1# webol 1# webol
2
3## Config 2## Config
4Default `config.toml`: 3Default `config.toml`:
5```toml 4```toml
@@ -12,9 +11,7 @@ timeoffset = 0 # i8
12method = "none" # "none"|"key" 11method = "none" # "none"|"key"
13secret = "" # String 12secret = "" # String
14``` 13```
15
16## Docker 14## Docker
17
18minimal `docker-compose.yaml`: 15minimal `docker-compose.yaml`:
19```yaml 16```yaml
20services: 17services:
@@ -27,3 +24,44 @@ services:
27 - ./logs:/logs 24 - ./logs:/logs
28 network_mode: host 25 network_mode: host
29``` 26```
27# Usage
28## Register Device
29A device is registered with a PUT request to the server with a JSON representation of the device as payload.
30| field | description | example |
31|--------------|------------------------------------------------------------------------|-------------------|
32| server-ip | ip of the webol server, including its port | webol.local:7229 |
33| secret | secret set in the server settings | password |
34| device-id | any string, "name" of the device | foo |
35| mac-address | mac address of the device | 12:34:56:AB:CD:EF |
36| broadcast-ip | broadcast ip of the network, including the port Wake-on-Lan listens on | 10.0.1.255:7 |
37| device-ip | (**optional**) ip of the device, used for ping feature | 10.0.1.47 |
38
39Examples using curl with and without authentification enabled on the server.
40### With Authentification
41```sh
42curl -X PUT http://<server-ip>/device \
43 -H 'Authorization: <secret>' \
44 -H 'Content-Type: application/json' \
45 -d '{
46 "id": "<device-id>",
47 "mac": "<mac-address>",
48 "broadcast_addr": "<broadcast-ip>",
49 "ip": "<device-ip>"
50 }'
51```
52### Without Authentification
53```sh
54curl -X PUT http://<server-ip>/device \
55 -H 'Content-Type: application/json' \
56 -d '{
57 "id": "<device-id>",
58 "mac": "<mac-address>",
59 "broadcast_addr": "<broadcast-ip>",
60 "ip": "<device-ip>"
61 }'
62```
63## Start Device
64The easiest way to start a device is using a GET request with its id:
65```sh
66curl http://<server-ip>/start/<device-id>
67``` \ No newline at end of file
diff --git a/src/error.rs b/src/error.rs
index 2d70592..b8a078b 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -46,11 +46,13 @@ pub enum Error {
46 #[from] 46 #[from]
47 source: io::Error, 47 source: io::Error,
48 }, 48 },
49
50 #[error("No ip set for device but ping requested")]
51 NoIpOnPing,
49} 52}
50 53
51impl IntoResponse for Error { 54impl IntoResponse for Error {
52 fn into_response(self) -> Response { 55 fn into_response(self) -> Response {
53 // error!("{}", self.to_string());
54 let (status, error_message) = match self { 56 let (status, error_message) = match self {
55 Self::Json { source } => { 57 Self::Json { source } => {
56 error!("{source}"); 58 error!("{source}");
@@ -80,6 +82,10 @@ impl IntoResponse for Error {
80 Self::IpParse { source } => { 82 Self::IpParse { source } => {
81 error!("{source}"); 83 error!("{source}");
82 (StatusCode::INTERNAL_SERVER_ERROR, "Server Error") 84 (StatusCode::INTERNAL_SERVER_ERROR, "Server Error")
85 },
86 Self::NoIpOnPing => {
87 error!("Ping requested but no ip given");
88 (StatusCode::BAD_REQUEST, "No Ip saved for requested device, but device started")
83 } 89 }
84 }; 90 };
85 let body = Json(json!({ 91 let body = Json(json!({
diff --git a/src/routes/device.rs b/src/routes/device.rs
index 49361f2..f767eab 100644
--- a/src/routes/device.rs
+++ b/src/routes/device.rs
@@ -36,7 +36,7 @@ pub struct DPayload {
36 id: String, 36 id: String,
37 mac: String, 37 mac: String,
38 broadcast_addr: String, 38 broadcast_addr: String,
39 ip: String, 39 ip: Option<String>,
40} 40}
41 41
42#[utoipa::path( 42#[utoipa::path(
@@ -48,15 +48,17 @@ pub struct DPayload {
48 ), 48 ),
49 security((), ("api_key" = [])) 49 security((), ("api_key" = []))
50)] 50)]
51pub async fn put( 51pub async fn put(Json(payload): Json<DPayload>) -> Result<Json<Value>, Error> {
52 Json(payload): Json<DPayload>,
53) -> Result<Json<Value>, Error> {
54 info!( 52 info!(
55 "add device {} ({}, {}, {})", 53 "add device {} ({}, {}, {:?})",
56 payload.id, payload.mac, payload.broadcast_addr, payload.ip 54 payload.id, payload.mac, payload.broadcast_addr, payload.ip
57 ); 55 );
58 56
59 let ip = IpNetwork::from_str(&payload.ip)?; 57 let ip = if let Some(ip_s) = payload.ip {
58 Some(IpNetwork::from_str(&ip_s)?)
59 } else {
60 None
61 };
60 let mac = MacAddress::from_str(&payload.mac)?; 62 let mac = MacAddress::from_str(&payload.mac)?;
61 let device = Device { 63 let device = Device {
62 id: payload.id, 64 id: payload.id,
@@ -79,14 +81,17 @@ pub async fn put(
79 ), 81 ),
80 security((), ("api_key" = [])) 82 security((), ("api_key" = []))
81)] 83)]
82pub async fn post( 84pub async fn post(Json(payload): Json<DPayload>) -> Result<Json<Value>, Error> {
83 Json(payload): Json<DPayload>,
84) -> Result<Json<Value>, Error> {
85 info!( 85 info!(
86 "edit device {} ({}, {}, {})", 86 "edit device {} ({}, {}, {:?})",
87 payload.id, payload.mac, payload.broadcast_addr, payload.ip 87 payload.id, payload.mac, payload.broadcast_addr, payload.ip
88 ); 88 );
89 let ip = IpNetwork::from_str(&payload.ip)?; 89
90 let ip = if let Some(ip_s) = payload.ip {
91 Some(IpNetwork::from_str(&ip_s)?)
92 } else {
93 None
94 };
90 let mac = MacAddress::from_str(&payload.mac)?; 95 let mac = MacAddress::from_str(&payload.mac)?;
91 let times = Device::read(&payload.id)?.times; 96 let times = Device::read(&payload.id)?.times;
92 97
diff --git a/src/routes/start.rs b/src/routes/start.rs
index bbc6ab8..192a54a 100644
--- a/src/routes/start.rs
+++ b/src/routes/start.rs
@@ -69,6 +69,9 @@ fn send_wol(
69 let dev_id = device.id.clone(); 69 let dev_id = device.id.clone();
70 let uuid = if let Some(pl) = payload { 70 let uuid = if let Some(pl) = payload {
71 if pl.ping.is_some_and(|ping| ping) { 71 if pl.ping.is_some_and(|ping| ping) {
72 if device.ip.is_none() {
73 return Err(Error::NoIpOnPing);
74 }
72 Some(setup_ping(state, device)) 75 Some(setup_ping(state, device))
73 } else { 76 } else {
74 None 77 None
@@ -86,8 +89,10 @@ fn send_wol(
86 89
87fn setup_ping(state: Arc<crate::AppState>, device: Device) -> String { 90fn setup_ping(state: Arc<crate::AppState>, device: Device) -> String {
88 let mut uuid: Option<String> = None; 91 let mut uuid: Option<String> = None;
92 // Safe: Only called when ip is set
93 let ip = device.ip.unwrap();
89 for (key, value) in state.ping_map.clone() { 94 for (key, value) in state.ping_map.clone() {
90 if value.ip == device.ip { 95 if value.ip == ip {
91 debug!("service already exists"); 96 debug!("service already exists");
92 uuid = Some(key); 97 uuid = Some(key);
93 break; 98 break;
@@ -103,7 +108,7 @@ fn setup_ping(state: Arc<crate::AppState>, device: Device) -> String {
103 state.ping_map.insert( 108 state.ping_map.insert(
104 uuid_gen.clone(), 109 uuid_gen.clone(),
105 PingValue { 110 PingValue {
106 ip: device.ip, 111 ip,
107 eta: get_eta(device.clone().times), 112 eta: get_eta(device.clone().times),
108 online: false, 113 online: false,
109 }, 114 },
diff --git a/src/services/ping.rs b/src/services/ping.rs
index 1bf022d..4e0ffcf 100644
--- a/src/services/ping.rs
+++ b/src/services/ping.rs
@@ -28,7 +28,9 @@ pub async fn spawn(
28 28
29 let mut msg: Option<BroadcastCommand> = None; 29 let mut msg: Option<BroadcastCommand> = None;
30 while msg.is_none() { 30 while msg.is_none() {
31 let ping = surge_ping::ping(device.ip.ip(), &payload).await; 31 // Safe: Only called when ip is set
32 let ip = device.ip.unwrap();
33 let ping = surge_ping::ping(ip.ip(), &payload).await;
32 34
33 if let Err(ping) = ping { 35 if let Err(ping) = ping {
34 let ping_timeout = matches!(ping, surge_ping::SurgeError::Timeout { .. }); 36 let ping_timeout = matches!(ping, surge_ping::SurgeError::Timeout { .. });
diff --git a/src/storage.rs b/src/storage.rs
index 0da245b..52c2e60 100644
--- a/src/storage.rs
+++ b/src/storage.rs
@@ -18,7 +18,7 @@ pub struct Device {
18 pub id: String, 18 pub id: String,
19 pub mac: MacAddress, 19 pub mac: MacAddress,
20 pub broadcast_addr: String, 20 pub broadcast_addr: String,
21 pub ip: IpNetwork, 21 pub ip: Option<IpNetwork>,
22 pub times: Option<Vec<i64>>, 22 pub times: Option<Vec<i64>>,
23} 23}
24 24