[WIP] A simple wake-on-lan service
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

add support for pinning targets

+55 -14
+52 -11
src/config.rs
··· 1 1 use serde::{Deserialize, Serialize}; 2 - use std::{collections::HashMap, fs::File, io::Read, path::PathBuf}; 2 + use std::{ 3 + collections::{HashMap, HashSet}, 4 + fs::File, 5 + io::Read, 6 + path::PathBuf, 7 + }; 3 8 use thiserror::Error; 4 9 5 10 #[derive(Deserialize, Serialize, Debug, Clone)] 6 11 pub struct Config { 7 12 #[serde(default = "default_binding")] 8 - pub binding: String, 9 - pub targets: HashMap<String, Target>, 13 + binding: String, 14 + pinned: Option<Vec<String>>, 15 + targets: HashMap<String, Target>, 10 16 } 11 17 12 18 #[derive(Deserialize, Serialize, Debug, Clone)] ··· 23 29 "0.0.0.0:3000".to_string() 24 30 } 25 31 32 + #[derive(Error, Debug)] 33 + pub enum ConfigError { 34 + #[error("Io error: {}", .0)] 35 + Io(#[from] std::io::Error), 36 + #[error("Deserialize error: {}", .0)] 37 + Serde(#[from] toml::de::Error), 38 + #[error("Unknown item was pinned: {}", .0)] 39 + UnknownPin(String), 40 + #[error("Item was pinned more than once: {}", .0)] 41 + DupePin(String), 42 + } 43 + 26 44 impl Config { 27 45 pub fn load(path: PathBuf) -> Result<Self, ConfigError> { 28 46 let mut file = File::open(path)?; 29 47 let mut contents = String::new(); 30 48 file.read_to_string(&mut contents)?; 49 + let config: Self = toml::from_str(&contents)?; 31 50 32 - let config: Self = toml::from_str(&contents)?; 51 + // all entries in pinned should be keys of targets 52 + let targets = config.targets.keys().collect::<Vec<_>>(); 53 + if let Some(mismatch) = &config 54 + .pinned 55 + .as_ref() 56 + .and_then(|p| p.iter().skip_while(|x| targets.contains(x)).next()) 57 + { 58 + return Err(ConfigError::UnknownPin(mismatch.to_string())); 59 + }; 60 + 61 + let mut uniq = HashSet::<String>::new(); 62 + if let Some(dupe) = &config.pinned.as_ref().and_then(|p| { 63 + p.iter() 64 + .skip_while(move |x| uniq.insert(x.to_string())) 65 + .next() 66 + }) { 67 + return Err(ConfigError::DupePin(dupe.to_string())); 68 + }; 69 + 33 70 return Ok(config); 34 71 } 35 - } 72 + 73 + pub fn get_binding(&self) -> &String { 74 + &self.binding 75 + } 36 76 37 - #[derive(Error, Debug)] 38 - pub enum ConfigError { 39 - #[error("Io error: {}", .0)] 40 - Io(#[from] std::io::Error), 41 - #[error("Deserialize error: {}", .0)] 42 - Serde(#[from] toml::de::Error), 77 + pub fn get_pinned(&self) -> &Option<Vec<String>> { 78 + &self.pinned 79 + } 80 + 81 + pub fn get_targets(&self) -> &HashMap<String, Target> { 82 + &self.targets 83 + } 43 84 }
+3 -3
src/main.rs
··· 18 18 async fn main() -> () { 19 19 async fn main() -> Result<(), Error> { 20 20 let config = config::Config::load(PathBuf::from("./wol.toml"))?; 21 - println!("Binding to {}", config.binding); 22 - for (k, v) in &config.targets { 21 + println!("Binding to {}", config.get_binding()); 22 + for (k, v) in config.get_targets() { 23 23 println!("target: {k}: {} ({:?})", v.mac, v.ip); 24 24 } 25 - let listener = tokio::net::TcpListener::bind(&config.binding).await?; 25 + let listener = tokio::net::TcpListener::bind(config.get_binding()).await?; 26 26 axum::serve(listener, server::router(config)).await?; 27 27 28 28 Ok(())