diff options
| author | metamuffin <metamuffin@disroot.org> | 2025-11-14 22:43:21 +0100 |
|---|---|---|
| committer | metamuffin <metamuffin@disroot.org> | 2025-11-14 22:43:21 +0100 |
| commit | a4d828cfa4ba9ff7ae4e21df49b2f3f9c695e4fa (patch) | |
| tree | 05806e218a7ba3a53ab0a5df9b664be97e472edb | |
| parent | 057031d68d0ab93aa6cc668bb5e37ad575a8ff8f (diff) | |
| download | gnix-a4d828cfa4ba9ff7ae4e21df49b2f3f9c695e4fa.tar gnix-a4d828cfa4ba9ff7ae4e21df49b2f3f9c695e4fa.tar.bz2 gnix-a4d828cfa4ba9ff7ae4e21df49b2f3f9c695e4fa.tar.zst | |
add back watch option
| -rw-r--r-- | Cargo.lock | 74 | ||||
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | src/control_socket.rs | 6 | ||||
| -rw-r--r-- | src/main.rs | 97 |
4 files changed, 156 insertions, 23 deletions
@@ -190,7 +190,7 @@ version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ - "bitflags", + "bitflags 2.10.0", "cexpr", "clang-sys", "itertools", @@ -206,6 +206,12 @@ dependencies = [ [[package]] name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" @@ -534,6 +540,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] + +[[package]] name = "futures" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -689,10 +704,10 @@ dependencies = [ "humansize", "hyper", "hyper-util", - "inotify", "log", "markup", "mime_guess", + "notify", "percent-encoding", "pin-project", "quinn", @@ -922,11 +937,9 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" dependencies = [ - "bitflags", - "futures-core", + "bitflags 2.10.0", "inotify-sys", "libc", - "tokio", ] [[package]] @@ -1035,6 +1048,26 @@ dependencies = [ ] [[package]] +name = "kqueue" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + +[[package]] name = "libc" version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1142,6 +1175,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ "libc", + "log", "wasi", "windows-sys 0.61.2", ] @@ -1157,6 +1191,30 @@ dependencies = [ ] [[package]] +name = "notify" +version = "8.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" +dependencies = [ + "bitflags 2.10.0", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "log", + "mio", + "notify-types", + "walkdir", + "windows-sys 0.60.2", +] + +[[package]] +name = "notify-types" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d" + +[[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1450,7 +1508,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags", + "bitflags 2.10.0", ] [[package]] @@ -1630,7 +1688,7 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b369d18893388b345804dc0007963c99b7d665ae71d275812d828c6f089640" dependencies = [ - "bitflags", + "bitflags 2.10.0", "core-foundation", "core-foundation-sys", "libc", @@ -2094,7 +2152,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -44,7 +44,7 @@ pin-project = "1.1.10" serde = { version = "1.0.228", features = ["derive"] } serde_yml = "0.0.12" serde_json = "1.0.145" -inotify = "0.11.0" +notify = "8.2.0" clap = { version = "4.5.51", features = ["derive"] } # Logging diff --git a/src/control_socket.rs b/src/control_socket.rs index c56c632..5d0a3e1 100644 --- a/src/control_socket.rs +++ b/src/control_socket.rs @@ -18,13 +18,13 @@ use tokio::{ #[derive(Serialize, Deserialize)] #[serde(rename_all = "snake_case")] -enum ControlSocketRequest { +pub enum ControlSocketRequest { Config(ConfigPackage), } #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] -enum ControlSocketResponse { +pub enum ControlSocketResponse { Ok, Error(String), } @@ -76,7 +76,7 @@ async fn handle_control_socket_conn(state: Arc<State>, conn: UnixStream) -> Resu Ok(()) } -async fn handle_control_socket_request( +pub async fn handle_control_socket_request( state: Arc<State>, request: ControlSocketRequest, ) -> Result<ControlSocketResponse> { diff --git a/src/main.rs b/src/main.rs index 3f437ba..b59c325 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,7 +22,9 @@ pub mod modules; use crate::{ config::ConfigPackage, - control_socket::{cs_client_reload, serve_control_socket}, + control_socket::{ + cs_client_reload, handle_control_socket_request, serve_control_socket, ControlSocketRequest, + }, generation::Generation, }; use aes_gcm_siv::{aead::generic_array::GenericArray, Aes256GcmSiv, KeyInit}; @@ -46,9 +48,11 @@ use hyper::{ use hyper_util::rt::{TokioExecutor, TokioIo}; use log::{debug, error, info, warn, LevelFilter}; use modules::NodeContext; +use notify::{RecursiveMode, Watcher}; use std::{ + future::Future, net::{IpAddr, SocketAddr}, - path::PathBuf, + path::{Path, PathBuf}, process::exit, str::FromStr, sync::Arc, @@ -57,8 +61,9 @@ use tokio::{ net::TcpListener, signal::ctrl_c, spawn, - sync::{RwLock, Semaphore}, + sync::{mpsc::channel, RwLock, Semaphore}, }; +use users::{get_user_by_name, switch::set_current_uid}; pub struct State { pub crypto_key: Aes256GcmSiv, @@ -72,7 +77,7 @@ pub struct State { #[derive(Parser)] struct Args { #[arg(long)] - setuid: Option<String>, + user: Option<String>, #[arg(long)] control_socket: Option<PathBuf>, #[arg(short, long)] @@ -102,17 +107,33 @@ async fn main() -> anyhow::Result<()> { let cs_path = args .control_socket .ok_or(anyhow!("reload needs control socket path"))?; - match cs_client_reload(&cs_path, config_package).await { - Ok(()) => { - exit(0); - } - Err(e) => { - eprintln!("Error: {e}"); - exit(1); + if args.watch { + watch_config(&args.config, || async { + let config_package = ConfigPackage::new(&args.config)?; + cs_client_reload(&cs_path, config_package).await?; + info!("Config updated"); + Ok(()) + }) + .await?; + exit(1); + } else { + match cs_client_reload(&cs_path, config_package).await { + Ok(()) => { + exit(0); + } + Err(e) => { + eprintln!("Error: {e}"); + exit(1); + } } } } + if let Some(username) = args.user { + let user = get_user_by_name(&username).ok_or(anyhow!("user for setuid not found"))?; + set_current_uid(user.uid()).context("setuid")?; + } + let generation = Generation::new(config_package)?; let state = Arc::new(State { crypto_key: aes_gcm_siv::Aes256GcmSiv::new(GenericArray::from_slice( @@ -125,6 +146,27 @@ async fn main() -> anyhow::Result<()> { generation: RwLock::new(Arc::new(generation)), }); + if args.watch { + let state = state.clone(); + spawn(async move { + if let Err(e) = watch_config(&args.config, || async { + let config_package = ConfigPackage::new(&args.config)?; + handle_control_socket_request( + state.clone(), + ControlSocketRequest::Config(config_package), + ) + .await?; + info!("Config updated"); + Ok(()) + }) + .await + { + error!("{e:?}"); + exit(1) + } + }); + } + if let Some(path) = args.control_socket { let state = state.clone(); tokio::spawn(async move { @@ -493,3 +535,36 @@ async fn service( Ok(resp) } + +async fn watch_config<R: Future<Output = Result<()>>>( + path: &Path, + mut reload: impl FnMut() -> R, +) -> Result<()> { + let (tx, mut rx) = channel(1); + let mut w = notify::recommended_watcher(move |r| { + let _ = tx.blocking_send(r); + })?; + w.watch(path.parent().unwrap(), RecursiveMode::NonRecursive)?; + + let path = path.canonicalize()?; + while let Some(r) = rx.recv().await { + match r { + Ok(ev) => { + if matches!( + ev.kind, + notify::EventKind::Access(notify::event::AccessKind::Close( + notify::event::AccessMode::Write + )) | notify::EventKind::Modify(notify::event::ModifyKind::Data(_)) + ) && ev.paths.contains(&path) + { + if let Err(e) = reload().await { + error!("Error: {e:#}") + } + } + } + Err(e) => error!("watch error: {e:#}"), + } + } + + Ok(()) +} |