continuwuity/src/service/config/mod.rs

97 lines
2.4 KiB
Rust

use std::{ops::Deref, path::PathBuf, sync::Arc};
use async_trait::async_trait;
use conduwuit::{
Result, Server,
config::{Config, check},
error, implement,
};
use url::Url;
use crate::registration_tokens::{ValidToken, ValidTokenSource};
pub struct Service {
server: Arc<Server>,
}
const SIGNAL: &str = "SIGUSR1";
impl Service {
/// Get the registration token set in the config file, if it exists.
#[must_use]
pub fn get_config_file_token(&self) -> Option<ValidToken> {
self.registration_token
.clone()
.map(|token| ValidToken { token, source: ValidTokenSource::Config })
}
/// Get the base domain to use for user-facing URLs.
#[must_use]
pub fn get_client_domain(&self) -> Url {
self.well_known.client.clone().unwrap_or_else(|| {
let host = self.server_name.host();
format!("https://{host}")
.as_str()
.try_into()
.expect("server name should be a valid host")
})
}
}
#[async_trait]
impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Arc::new(Self { server: args.server.clone() }))
}
async fn worker(self: Arc<Self>) -> Result {
while self.server.running() {
if self.server.signal.subscribe().recv().await == Ok(SIGNAL) {
if let Err(e) = self.handle_reload() {
error!("Failed to reload config: {e}");
}
}
}
Ok(())
}
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Deref for Service {
type Target = Arc<Config>;
#[inline]
fn deref(&self) -> &Self::Target { &self.server.config }
}
#[implement(Service)]
fn handle_reload(&self) -> Result {
if self.server.config.config_reload_signal {
#[cfg(all(feature = "systemd", target_os = "linux"))]
sd_notify::notify(false, &[
sd_notify::NotifyState::Reloading,
sd_notify::NotifyState::monotonic_usec_now().expect("Failed to read monotonic time"),
])
.expect("failed to notify systemd of reloading state");
let config_paths = self.server.config.config_paths.clone().unwrap_or_default();
self.reload(&config_paths)?;
#[cfg(all(feature = "systemd", target_os = "linux"))]
sd_notify::notify(false, &[sd_notify::NotifyState::Ready])
.expect("failed to notify systemd of ready state");
}
Ok(())
}
#[implement(Service)]
pub fn reload(&self, paths: &[PathBuf]) -> Result<Arc<Config>> {
let old = self.server.config.clone();
let new = Config::load(paths).and_then(|raw| Config::new(&raw))?;
check::reload(&old, &new)?;
self.server.config.update(new)
}