[WIP] A simple wake-on-lan service

expose config as a server endpoint

vielle.dev 13b4c7a6 22b5e3f8

verified
+38 -13
+7 -4
src/config.rs
··· 1 - use serde::Deserialize; 1 + use serde::{Deserialize, Serialize}; 2 2 use std::{collections::HashMap, fs::File, io::Read, path::PathBuf}; 3 3 use thiserror::Error; 4 4 5 - #[derive(Deserialize, Debug, Clone)] 5 + #[derive(Deserialize, Serialize, Debug, Clone)] 6 6 pub struct Config { 7 7 #[serde(default = "default_binding")] 8 8 pub binding: String, 9 9 pub targets: HashMap<String, Target>, 10 10 } 11 11 12 - #[derive(Deserialize, Debug, Clone)] 12 + #[derive(Deserialize, Serialize, Debug, Clone)] 13 13 pub struct Target { 14 - #[serde(deserialize_with = "crate::mac::deserialize_mac")] 14 + #[serde( 15 + deserialize_with = "crate::mac::deserialize_mac", 16 + serialize_with = "crate::mac::serialize_mac" 17 + )] 15 18 pub mac: crate::mac::MacAddress, 16 19 pub ip: Option<String>, 17 20 }
+8 -1
src/mac.rs
··· 1 1 use std::{fmt::Display, net::UdpSocket, num::ParseIntError, str::FromStr}; 2 2 3 - use serde::{Deserialize, Deserializer, de::Error}; 3 + use serde::{Deserialize, Deserializer, Serializer, de::Error}; 4 4 use thiserror::Error; 5 5 6 6 #[derive(Clone, Debug)] ··· 75 75 { 76 76 MacAddress::from_str(&String::deserialize(de)?).map_err(Error::custom) 77 77 } 78 + 79 + pub fn serialize_mac<S>(mac: &MacAddress, se: S) -> Result<S::Ok, S::Error> 80 + where 81 + S: Serializer, 82 + { 83 + se.serialize_str(&mac.to_string()) 84 + }
+2 -2
src/main.rs
··· 22 22 for (k, v) in &config.targets { 23 23 println!("target: {k}: {} ({:?})", v.mac, v.ip); 24 24 } 25 - let listener = tokio::net::TcpListener::bind(config.binding).await?; 26 - axum::serve(listener, server::router()).await?; 25 + let listener = tokio::net::TcpListener::bind(&config.binding).await?; 26 + axum::serve(listener, server::router(config)).await?; 27 27 28 28 Ok(()) 29 29 }
+21 -6
src/server.rs
··· 1 - use axum::{Json, Router, http::Response, routing::post}; 1 + use std::sync::Arc; 2 + 3 + use axum::{ 4 + Json, Router, 5 + extract::State, 6 + http::Response, 7 + routing::{get, post}, 8 + }; 2 9 use serde::Deserialize; 3 10 4 - use crate::mac::MacAddress; 11 + use crate::{config::Config, mac::MacAddress}; 5 12 6 13 include!(concat!(env!("OUT_DIR"), "/mod.rs")); 7 14 8 15 #[derive(Deserialize)] 9 - pub struct WakeRequest { 16 + struct WakeRequest { 10 17 #[serde(deserialize_with = "crate::mac::deserialize_mac")] 11 18 mac: MacAddress, 12 19 } 13 20 14 - pub async fn wake(Json(req): Json<WakeRequest>) -> Result<(), Response<String>> { 21 + async fn wake(Json(req): Json<WakeRequest>) -> Result<(), Response<String>> { 15 22 println!("Waking {}", req.mac); 16 23 req.mac.wake().await.map_err(|err| { 17 24 Response::builder() ··· 22 29 }) 23 30 } 24 31 25 - pub fn router() -> Router { 26 - Router::new().route("/wake", post(wake)).merge(dist::main()) 32 + async fn config(State(conf): State<Arc<Config>>) -> Json<Config> { 33 + Json((*conf).clone()) 34 + } 35 + 36 + pub fn router(conf: Config) -> Router { 37 + Router::new() 38 + .route("/wake", post(wake)) 39 + .route("/config", get(config)) 40 + .with_state(Arc::new(conf)) 41 + .merge(dist::main()) 27 42 }