diff options
author | FxQnLr <[email protected]> | 2024-04-15 21:12:04 +0200 |
---|---|---|
committer | GitHub <[email protected]> | 2024-04-15 21:12:04 +0200 |
commit | ea4f36ea34a4e425ef23e2ae0d4ea210d4a8a145 (patch) | |
tree | d89f0da1841b984c10a6a24997a8733524b75f75 | |
parent | b615f6e34e084d520dcc301058b5926074188500 (diff) | |
parent | 7876dd605a8e4b595436035a87a5151be187c01d (diff) | |
download | webol-ea4f36ea34a4e425ef23e2ae0d4ea210d4a8a145.tar webol-ea4f36ea34a4e425ef23e2ae0d4ea210d4a8a145.tar.gz webol-ea4f36ea34a4e425ef23e2ae0d4ea210d4a8a145.zip |
Merge pull request #36 from FxQnLr/optional_ip
Optional ip and better docs
-rw-r--r-- | Cargo.lock | 2 | ||||
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | README.md | 44 | ||||
-rw-r--r-- | src/error.rs | 8 | ||||
-rw-r--r-- | src/routes/device.rs | 27 | ||||
-rw-r--r-- | src/routes/start.rs | 9 | ||||
-rw-r--r-- | src/services/ping.rs | 4 | ||||
-rw-r--r-- | src/storage.rs | 2 |
8 files changed, 77 insertions, 21 deletions
@@ -1837,7 +1837,7 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" | |||
1837 | 1837 | ||
1838 | [[package]] | 1838 | [[package]] |
1839 | name = "webol" | 1839 | name = "webol" |
1840 | version = "0.4.0" | 1840 | version = "0.4.1" |
1841 | dependencies = [ | 1841 | dependencies = [ |
1842 | "axum", | 1842 | "axum", |
1843 | "axum-macros", | 1843 | "axum-macros", |
@@ -1,6 +1,6 @@ | |||
1 | [package] | 1 | [package] |
2 | name = "webol" | 2 | name = "webol" |
3 | version = "0.4.0" | 3 | version = "0.4.1" |
4 | edition = "2021" | 4 | edition = "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 |
@@ -1,5 +1,4 @@ | |||
1 | # webol | 1 | # webol |
2 | |||
3 | ## Config | 2 | ## Config |
4 | Default `config.toml`: | 3 | Default `config.toml`: |
5 | ```toml | 4 | ```toml |
@@ -12,9 +11,7 @@ timeoffset = 0 # i8 | |||
12 | method = "none" # "none"|"key" | 11 | method = "none" # "none"|"key" |
13 | secret = "" # String | 12 | secret = "" # String |
14 | ``` | 13 | ``` |
15 | |||
16 | ## Docker | 14 | ## Docker |
17 | |||
18 | minimal `docker-compose.yaml`: | 15 | minimal `docker-compose.yaml`: |
19 | ```yaml | 16 | ```yaml |
20 | services: | 17 | services: |
@@ -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 | ||
29 | A 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 | |||
39 | Examples using curl with and without authentification enabled on the server. | ||
40 | ### With Authentification | ||
41 | ```sh | ||
42 | curl -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 | ||
54 | curl -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 | ||
64 | The easiest way to start a device is using a GET request with its id: | ||
65 | ```sh | ||
66 | curl 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 | ||
51 | impl IntoResponse for Error { | 54 | impl 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 | )] |
51 | pub async fn put( | 51 | pub 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 | )] |
82 | pub async fn post( | 84 | pub 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 | ||
87 | fn setup_ping(state: Arc<crate::AppState>, device: Device) -> String { | 90 | fn 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 | ||