tuwunel_service/config/
mod.rs1use std::{iter, ops::Deref, path::Path, sync::Arc};
2
3use async_trait::async_trait;
4use tuwunel_core::{
5 Result, Server,
6 config::{Config, check},
7 error, implement,
8};
9
10pub struct Service {
11 server: Arc<Server>,
12}
13
14const SIGNAL: &str = "SIGUSR1";
15
16#[async_trait]
17impl crate::Service for Service {
18 fn build(args: &crate::Args<'_>) -> Result<Arc<Self>> {
19 Ok(Arc::new(Self { server: args.server.clone() }))
20 }
21
22 async fn worker(self: Arc<Self>) -> Result {
23 let mut signaled = self.server.signal.subscribe();
24 while self.server.is_running() {
25 tokio::select! {
26 () = self.server.until_shutdown() => break,
27 signal = signaled.recv() => if signal != Ok(SIGNAL) { continue; },
28 }
29
30 if let Err(e) = self.handle_reload() {
31 error!("Failed to reload config: {e}");
32 }
33 }
34
35 Ok(())
36 }
37
38 fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
39}
40
41impl Deref for Service {
42 type Target = Arc<Config>;
43
44 #[inline]
45 fn deref(&self) -> &Self::Target { &self.server.config }
46}
47
48#[implement(Service)]
49fn handle_reload(&self) -> Result {
50 if self.server.config.config_reload_signal {
51 #[cfg(all(feature = "systemd", target_os = "linux"))]
52 sd_notify::notify(false, &[
53 sd_notify::NotifyState::Reloading,
54 sd_notify::NotifyState::monotonic_usec_now().expect("failed to get monotonic time"),
55 ])
56 .expect("failed to notify systemd of reloading state");
57
58 self.reload(iter::empty())?;
59
60 #[cfg(all(feature = "systemd", target_os = "linux"))]
61 sd_notify::notify(false, &[sd_notify::NotifyState::Ready])
62 .expect("failed to notify systemd of ready state");
63 }
64
65 Ok(())
66}
67
68#[implement(Service)]
69pub fn reload<'a, I>(&self, paths: I) -> Result<Arc<Config>>
70where
71 I: Iterator<Item = &'a Path>,
72{
73 let old = self.server.config.clone();
74 let new = Config::load(paths).and_then(|raw| Config::new(&raw))?;
75
76 check::reload(&old, &new)?;
77 self.server.config.update(new)
78}