unc_dyn_configs/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use serde::{Deserialize, Serialize};
4use std::path::PathBuf;
5use std::sync::Arc;
6use tokio::sync::broadcast::Sender;
7use unc_chain_configs::UpdateableClientConfig;
8use unc_o11y::log_config::LogConfig;
9use unc_primitives::static_clock::StaticClock;
10
11mod metrics;
12
13#[derive(Serialize, Deserialize, Clone, Default)]
14/// Contains the latest state of configs which can be updated at runtime.
15pub struct UpdateableConfigs {
16    /// Contents of the file LOG_CONFIG_FILENAME.
17    pub log_config: Option<LogConfig>,
18    /// Contents of the `config.json` corresponding to the mutable fields of `ClientConfig`.
19    pub client_config: Option<UpdateableClientConfig>,
20}
21
22/// Pushes the updates to listeners.
23#[derive(Default)]
24pub struct UpdateableConfigLoader {
25    /// Notifies receivers about the new config values available.
26    tx: Option<Sender<Result<UpdateableConfigs, Arc<UpdateableConfigLoaderError>>>>,
27}
28
29#[derive(thiserror::Error, Debug)]
30#[non_exhaustive]
31pub enum UpdateableConfigLoaderError {
32    #[error("Failed to parse a dynamic config file {file:?}: {err:?}")]
33    Parse { file: PathBuf, err: serde_json::Error },
34    #[error("Can't open or read a dynamic config file {file:?}: {err:?}")]
35    OpenAndRead { file: PathBuf, err: std::io::Error },
36    #[error("Can't open or read the config file {file:?}: {err:?}")]
37    ConfigFileError { file: PathBuf, err: anyhow::Error },
38    #[error("One or multiple dynamic config files reload errors {0:?}")]
39    Errors(Vec<UpdateableConfigLoaderError>),
40    #[error("No home dir set")]
41    NoHomeDir(),
42}
43
44impl UpdateableConfigLoader {
45    pub fn new(
46        updateable_configs: UpdateableConfigs,
47        tx: Sender<Result<UpdateableConfigs, Arc<UpdateableConfigLoaderError>>>,
48    ) -> Self {
49        let mut result = Self { tx: Some(tx) };
50        result.reload(Ok(updateable_configs));
51        result
52    }
53
54    pub fn reload(
55        &mut self,
56        updateable_configs: Result<UpdateableConfigs, UpdateableConfigLoaderError>,
57    ) {
58        match updateable_configs {
59            Ok(updateable_configs) => {
60                unc_o11y::reload_log_config(updateable_configs.log_config.as_ref());
61                self.tx.as_ref().map(|tx| tx.send(Ok(updateable_configs.clone())));
62                Self::update_metrics();
63            }
64            Err(err) => {
65                self.tx.as_ref().map(|tx| tx.send(Err(Arc::new(err))));
66            }
67        }
68    }
69
70    fn update_metrics() {
71        metrics::CONFIG_RELOAD_TIMESTAMP.set(StaticClock::utc().timestamp());
72        metrics::CONFIG_RELOADS.inc();
73    }
74}