[WIP] A simple wake-on-lan service

add configuration

vielle.dev f72d92f0 ffeab5ff

verified
+534 -2
+1
.gitignore
··· 1 1 /target 2 + wol.toml
+414
Cargo.lock
··· 3 3 version = 4 4 4 5 5 [[package]] 6 + name = "bitflags" 7 + version = "2.10.0" 8 + source = "registry+https://github.com/rust-lang/crates.io-index" 9 + checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" 10 + 11 + [[package]] 12 + name = "bytes" 13 + version = "1.11.1" 14 + source = "registry+https://github.com/rust-lang/crates.io-index" 15 + checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" 16 + 17 + [[package]] 18 + name = "cfg-if" 19 + version = "1.0.4" 20 + source = "registry+https://github.com/rust-lang/crates.io-index" 21 + checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" 22 + 23 + [[package]] 24 + name = "equivalent" 25 + version = "1.0.2" 26 + source = "registry+https://github.com/rust-lang/crates.io-index" 27 + checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 28 + 29 + [[package]] 30 + name = "errno" 31 + version = "0.3.14" 32 + source = "registry+https://github.com/rust-lang/crates.io-index" 33 + checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" 34 + dependencies = [ 35 + "libc", 36 + "windows-sys 0.61.2", 37 + ] 38 + 39 + [[package]] 40 + name = "hashbrown" 41 + version = "0.16.1" 42 + source = "registry+https://github.com/rust-lang/crates.io-index" 43 + checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" 44 + 45 + [[package]] 46 + name = "indexmap" 47 + version = "2.13.0" 48 + source = "registry+https://github.com/rust-lang/crates.io-index" 49 + checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" 50 + dependencies = [ 51 + "equivalent", 52 + "hashbrown", 53 + ] 54 + 55 + [[package]] 56 + name = "libc" 57 + version = "0.2.182" 58 + source = "registry+https://github.com/rust-lang/crates.io-index" 59 + checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" 60 + 61 + [[package]] 62 + name = "lock_api" 63 + version = "0.4.14" 64 + source = "registry+https://github.com/rust-lang/crates.io-index" 65 + checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" 66 + dependencies = [ 67 + "scopeguard", 68 + ] 69 + 70 + [[package]] 71 + name = "mio" 72 + version = "1.1.1" 73 + source = "registry+https://github.com/rust-lang/crates.io-index" 74 + checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" 75 + dependencies = [ 76 + "libc", 77 + "wasi", 78 + "windows-sys 0.61.2", 79 + ] 80 + 81 + [[package]] 82 + name = "parking_lot" 83 + version = "0.12.5" 84 + source = "registry+https://github.com/rust-lang/crates.io-index" 85 + checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" 86 + dependencies = [ 87 + "lock_api", 88 + "parking_lot_core", 89 + ] 90 + 91 + [[package]] 92 + name = "parking_lot_core" 93 + version = "0.9.12" 94 + source = "registry+https://github.com/rust-lang/crates.io-index" 95 + checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" 96 + dependencies = [ 97 + "cfg-if", 98 + "libc", 99 + "redox_syscall", 100 + "smallvec", 101 + "windows-link", 102 + ] 103 + 104 + [[package]] 105 + name = "pin-project-lite" 106 + version = "0.2.16" 107 + source = "registry+https://github.com/rust-lang/crates.io-index" 108 + checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 109 + 110 + [[package]] 111 + name = "proc-macro2" 112 + version = "1.0.106" 113 + source = "registry+https://github.com/rust-lang/crates.io-index" 114 + checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" 115 + dependencies = [ 116 + "unicode-ident", 117 + ] 118 + 119 + [[package]] 120 + name = "quote" 121 + version = "1.0.44" 122 + source = "registry+https://github.com/rust-lang/crates.io-index" 123 + checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" 124 + dependencies = [ 125 + "proc-macro2", 126 + ] 127 + 128 + [[package]] 129 + name = "redox_syscall" 130 + version = "0.5.18" 131 + source = "registry+https://github.com/rust-lang/crates.io-index" 132 + checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" 133 + dependencies = [ 134 + "bitflags", 135 + ] 136 + 137 + [[package]] 138 + name = "scopeguard" 139 + version = "1.2.0" 140 + source = "registry+https://github.com/rust-lang/crates.io-index" 141 + checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 142 + 143 + [[package]] 144 + name = "serde" 145 + version = "1.0.228" 146 + source = "registry+https://github.com/rust-lang/crates.io-index" 147 + checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" 148 + dependencies = [ 149 + "serde_core", 150 + "serde_derive", 151 + ] 152 + 153 + [[package]] 154 + name = "serde_core" 155 + version = "1.0.228" 156 + source = "registry+https://github.com/rust-lang/crates.io-index" 157 + checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" 158 + dependencies = [ 159 + "serde_derive", 160 + ] 161 + 162 + [[package]] 163 + name = "serde_derive" 164 + version = "1.0.228" 165 + source = "registry+https://github.com/rust-lang/crates.io-index" 166 + checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" 167 + dependencies = [ 168 + "proc-macro2", 169 + "quote", 170 + "syn", 171 + ] 172 + 173 + [[package]] 174 + name = "serde_spanned" 175 + version = "1.0.4" 176 + source = "registry+https://github.com/rust-lang/crates.io-index" 177 + checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" 178 + dependencies = [ 179 + "serde_core", 180 + ] 181 + 182 + [[package]] 183 + name = "signal-hook-registry" 184 + version = "1.4.8" 185 + source = "registry+https://github.com/rust-lang/crates.io-index" 186 + checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" 187 + dependencies = [ 188 + "errno", 189 + "libc", 190 + ] 191 + 192 + [[package]] 193 + name = "smallvec" 194 + version = "1.15.1" 195 + source = "registry+https://github.com/rust-lang/crates.io-index" 196 + checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" 197 + 198 + [[package]] 199 + name = "socket2" 200 + version = "0.6.2" 201 + source = "registry+https://github.com/rust-lang/crates.io-index" 202 + checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" 203 + dependencies = [ 204 + "libc", 205 + "windows-sys 0.60.2", 206 + ] 207 + 208 + [[package]] 209 + name = "syn" 210 + version = "2.0.116" 211 + source = "registry+https://github.com/rust-lang/crates.io-index" 212 + checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb" 213 + dependencies = [ 214 + "proc-macro2", 215 + "quote", 216 + "unicode-ident", 217 + ] 218 + 219 + [[package]] 220 + name = "thiserror" 221 + version = "2.0.18" 222 + source = "registry+https://github.com/rust-lang/crates.io-index" 223 + checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" 224 + dependencies = [ 225 + "thiserror-impl", 226 + ] 227 + 228 + [[package]] 229 + name = "thiserror-impl" 230 + version = "2.0.18" 231 + source = "registry+https://github.com/rust-lang/crates.io-index" 232 + checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" 233 + dependencies = [ 234 + "proc-macro2", 235 + "quote", 236 + "syn", 237 + ] 238 + 239 + [[package]] 240 + name = "tokio" 241 + version = "1.49.0" 242 + source = "registry+https://github.com/rust-lang/crates.io-index" 243 + checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" 244 + dependencies = [ 245 + "bytes", 246 + "libc", 247 + "mio", 248 + "parking_lot", 249 + "pin-project-lite", 250 + "signal-hook-registry", 251 + "socket2", 252 + "tokio-macros", 253 + "windows-sys 0.61.2", 254 + ] 255 + 256 + [[package]] 257 + name = "tokio-macros" 258 + version = "2.6.0" 259 + source = "registry+https://github.com/rust-lang/crates.io-index" 260 + checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" 261 + dependencies = [ 262 + "proc-macro2", 263 + "quote", 264 + "syn", 265 + ] 266 + 267 + [[package]] 268 + name = "toml" 269 + version = "1.0.2+spec-1.1.0" 270 + source = "registry+https://github.com/rust-lang/crates.io-index" 271 + checksum = "d1dfefef6a142e93f346b64c160934eb13b5594b84ab378133ac6815cb2bd57f" 272 + dependencies = [ 273 + "indexmap", 274 + "serde_core", 275 + "serde_spanned", 276 + "toml_datetime", 277 + "toml_parser", 278 + "toml_writer", 279 + "winnow", 280 + ] 281 + 282 + [[package]] 283 + name = "toml_datetime" 284 + version = "1.0.0+spec-1.1.0" 285 + source = "registry+https://github.com/rust-lang/crates.io-index" 286 + checksum = "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e" 287 + dependencies = [ 288 + "serde_core", 289 + ] 290 + 291 + [[package]] 292 + name = "toml_parser" 293 + version = "1.0.9+spec-1.1.0" 294 + source = "registry+https://github.com/rust-lang/crates.io-index" 295 + checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" 296 + dependencies = [ 297 + "winnow", 298 + ] 299 + 300 + [[package]] 301 + name = "toml_writer" 302 + version = "1.0.6+spec-1.1.0" 303 + source = "registry+https://github.com/rust-lang/crates.io-index" 304 + checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" 305 + 306 + [[package]] 307 + name = "unicode-ident" 308 + version = "1.0.24" 309 + source = "registry+https://github.com/rust-lang/crates.io-index" 310 + checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" 311 + 312 + [[package]] 313 + name = "wasi" 314 + version = "0.11.1+wasi-snapshot-preview1" 315 + source = "registry+https://github.com/rust-lang/crates.io-index" 316 + checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" 317 + 318 + [[package]] 319 + name = "windows-link" 320 + version = "0.2.1" 321 + source = "registry+https://github.com/rust-lang/crates.io-index" 322 + checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" 323 + 324 + [[package]] 325 + name = "windows-sys" 326 + version = "0.60.2" 327 + source = "registry+https://github.com/rust-lang/crates.io-index" 328 + checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" 329 + dependencies = [ 330 + "windows-targets", 331 + ] 332 + 333 + [[package]] 334 + name = "windows-sys" 335 + version = "0.61.2" 336 + source = "registry+https://github.com/rust-lang/crates.io-index" 337 + checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" 338 + dependencies = [ 339 + "windows-link", 340 + ] 341 + 342 + [[package]] 343 + name = "windows-targets" 344 + version = "0.53.5" 345 + source = "registry+https://github.com/rust-lang/crates.io-index" 346 + checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" 347 + dependencies = [ 348 + "windows-link", 349 + "windows_aarch64_gnullvm", 350 + "windows_aarch64_msvc", 351 + "windows_i686_gnu", 352 + "windows_i686_gnullvm", 353 + "windows_i686_msvc", 354 + "windows_x86_64_gnu", 355 + "windows_x86_64_gnullvm", 356 + "windows_x86_64_msvc", 357 + ] 358 + 359 + [[package]] 360 + name = "windows_aarch64_gnullvm" 361 + version = "0.53.1" 362 + source = "registry+https://github.com/rust-lang/crates.io-index" 363 + checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" 364 + 365 + [[package]] 366 + name = "windows_aarch64_msvc" 367 + version = "0.53.1" 368 + source = "registry+https://github.com/rust-lang/crates.io-index" 369 + checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" 370 + 371 + [[package]] 372 + name = "windows_i686_gnu" 373 + version = "0.53.1" 374 + source = "registry+https://github.com/rust-lang/crates.io-index" 375 + checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" 376 + 377 + [[package]] 378 + name = "windows_i686_gnullvm" 379 + version = "0.53.1" 380 + source = "registry+https://github.com/rust-lang/crates.io-index" 381 + checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" 382 + 383 + [[package]] 384 + name = "windows_i686_msvc" 385 + version = "0.53.1" 386 + source = "registry+https://github.com/rust-lang/crates.io-index" 387 + checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" 388 + 389 + [[package]] 390 + name = "windows_x86_64_gnu" 391 + version = "0.53.1" 392 + source = "registry+https://github.com/rust-lang/crates.io-index" 393 + checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" 394 + 395 + [[package]] 396 + name = "windows_x86_64_gnullvm" 397 + version = "0.53.1" 398 + source = "registry+https://github.com/rust-lang/crates.io-index" 399 + checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" 400 + 401 + [[package]] 402 + name = "windows_x86_64_msvc" 403 + version = "0.53.1" 404 + source = "registry+https://github.com/rust-lang/crates.io-index" 405 + checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" 406 + 407 + [[package]] 408 + name = "winnow" 409 + version = "0.7.14" 410 + source = "registry+https://github.com/rust-lang/crates.io-index" 411 + checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" 412 + 413 + [[package]] 6 414 name = "wol" 7 415 version = "0.1.0" 416 + dependencies = [ 417 + "serde", 418 + "thiserror", 419 + "tokio", 420 + "toml", 421 + ]
+4
Cargo.toml
··· 4 4 edition = "2024" 5 5 6 6 [dependencies] 7 + serde = { version = "1.0.228", features = ["derive"] } 8 + thiserror = "2.0.18" 9 + tokio = { version = "1.49.0", features = ["full"] } 10 + toml = "1.0.2"
+34
src/config.rs
··· 1 + use serde::Deserialize; 2 + use std::{collections::HashMap, fs::File, io::Read, path::PathBuf}; 3 + use thiserror::Error; 4 + 5 + #[derive(Deserialize, Debug)] 6 + pub struct Config { 7 + #[serde(default = "default_binding")] 8 + pub binding: String, 9 + #[serde(deserialize_with = "crate::mac::deserialize_mac_hashmap")] 10 + pub targets: HashMap<String, crate::mac::MacAddress>, 11 + } 12 + 13 + fn default_binding() -> String { 14 + "0.0.0.0:3000".to_string() 15 + } 16 + 17 + impl Config { 18 + pub fn load(path: PathBuf) -> Result<Self, ConfigError> { 19 + let mut file = File::open(path)?; 20 + let mut contents = String::new(); 21 + file.read_to_string(&mut contents)?; 22 + 23 + let config: Self = toml::from_str(&contents)?; 24 + return Ok(config); 25 + } 26 + } 27 + 28 + #[derive(Error, Debug)] 29 + pub enum ConfigError { 30 + #[error("Io error: {}", .0)] 31 + Io(#[from] std::io::Error), 32 + #[error("Deserialize error: {}", .0)] 33 + Serde(#[from] toml::de::Error), 34 + }
+56
src/mac.rs
··· 1 + use std::{collections::HashMap, fmt::Display, num::ParseIntError, str::FromStr}; 2 + 3 + use serde::{Deserialize, Deserializer, de::Error}; 4 + use thiserror::Error; 5 + 6 + #[derive(Clone, Debug)] 7 + pub struct MacAddress([u8; 6]); 8 + 9 + impl Display for MacAddress { 10 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 11 + write!( 12 + f, 13 + "{:X}:{:X}:{:X}:{:X}:{:X}:{:X}", 14 + self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5] 15 + ) 16 + } 17 + } 18 + 19 + #[derive(Error, Debug)] 20 + pub enum MacAddressError { 21 + #[error("Integer error: {}", .0)] 22 + ParseInt(#[from] ParseIntError), 23 + #[error("Mac address to short")] 24 + TooShort, 25 + } 26 + 27 + impl FromStr for MacAddress { 28 + type Err = MacAddressError; 29 + 30 + fn from_str(s: &str) -> Result<Self, Self::Err> { 31 + let mut parts = s.split(":"); 32 + let mut address: [u8; 6] = [0, 0, 0, 0, 0, 0]; 33 + for i in 0..address.len() { 34 + address[i] = u8::from_str_radix(parts.next().ok_or(MacAddressError::TooShort)?, 16)?; 35 + } 36 + Ok(MacAddress(address)) 37 + } 38 + } 39 + 40 + pub fn deserialize_mac_hashmap<'de, D>(de: D) -> Result<HashMap<String, MacAddress>, D::Error> 41 + where 42 + D: Deserializer<'de>, 43 + { 44 + HashMap::<String, String>::deserialize(de)? 45 + .into_iter() 46 + .map::<Result<_, MacAddressError>, _>(|(k, v)| Ok((k, MacAddress::from_str(&v)?))) 47 + .collect::<Result<_, _>>() 48 + .map_err(Error::custom) 49 + } 50 + 51 + pub fn deserialize_mac<'de, D>(de: D) -> Result<MacAddress, D::Error> 52 + where 53 + D: Deserializer<'de>, 54 + { 55 + MacAddress::from_str(&String::deserialize(de)?).map_err(Error::custom) 56 + }
+25 -2
src/main.rs
··· 1 - fn main() { 2 - println!("Hello, world!"); 1 + use std::path::PathBuf; 2 + 3 + mod config; 4 + 5 + #[derive(thiserror::Error, Debug)] 6 + enum Error { 7 + #[error("Config error: {}", .0)] 8 + Config(#[from] config::ConfigError), 9 + } 10 + 11 + #[tokio::main] 12 + async fn main() -> () { 13 + async fn main() -> Result<(), Error> { 14 + let config = config::Config::load(PathBuf::from("./wol.toml"))?; 15 + println!("Binding to {}", config.binding); 16 + for (k, v) in config.targets { 17 + println!("target: {k}: {v}"); 18 + } 19 + Ok(()) 20 + } 21 + 22 + let res = main().await; 23 + if let Err(err) = res { 24 + eprintln!("{}", err); 25 + } 3 26 }