summaryrefslogtreecommitdiff
path: root/libs/all_in_one/src/utils.rs
diff options
context:
space:
mode:
Diffstat (limited to 'libs/all_in_one/src/utils.rs')
-rw-r--r--libs/all_in_one/src/utils.rs82
1 files changed, 82 insertions, 0 deletions
diff --git a/libs/all_in_one/src/utils.rs b/libs/all_in_one/src/utils.rs
new file mode 100644
index 0000000..159d98d
--- /dev/null
+++ b/libs/all_in_one/src/utils.rs
@@ -0,0 +1,82 @@
+use anyhow::Result;
+use config::{Config, Environment, File};
+use leash::Component;
+use serde::de::DeserializeOwned;
+use serde_json::Value;
+use shared::config::Settings;
+use tokio::{
+ runtime::Runtime,
+ sync::{mpsc, oneshot::Sender},
+ task::JoinHandle,
+};
+use tracing::{
+ debug,
+ log::{error, info},
+};
+
+/// Represents a all in one instance
+pub struct AllInOneInstance {
+ pub runtime: Runtime,
+ pub(crate) handles: Vec<(&'static str, Sender<()>, JoinHandle<()>)>,
+}
+
+/// Loads the settings from a component using a string
+fn load_settings_for<T: Default + DeserializeOwned + Clone>(
+ settings: &str,
+ name: &str,
+) -> Result<Settings<T>> {
+ let value: Value = serde_json::from_str(settings)?;
+ let section: T = serde_json::from_value(value.get(name).unwrap().clone())?;
+ let mut settings: Settings<T> = serde_json::from_value(value)?;
+ settings.config = section;
+
+ Ok(settings)
+}
+
+pub(crate) fn start_component<T: Component>(
+ json: &str,
+ error_sender: mpsc::Sender<anyhow::Error>,
+ runtime: &Runtime,
+) -> Result<(&'static str, Sender<()>, JoinHandle<()>)> {
+ let name = T::SERVICE_NAME;
+ let instance = T::new();
+
+ // We setup stop signals
+ let (stop, signal) = tokio::sync::oneshot::channel();
+ let settings = load_settings_for(json, name)?;
+
+ let handle = runtime.spawn(async move {
+ debug!("starting component {}", name);
+ match instance.start(settings, signal).await {
+ Ok(_) => info!("Component {} gracefully exited", name),
+ Err(error) => {
+ error!("Component {} exited with error {}", name, error);
+ error_sender
+ .send(error)
+ .await
+ .expect("Couldn't send the error notification to the error mpsc");
+ }
+ }
+ });
+
+ Ok((name, stop, handle))
+}
+
+pub(crate) fn load_config_file() -> Result<Value> {
+ let mut builder = Config::builder();
+
+ builder = builder.add_source(File::with_name("config/default"));
+ let mode = std::env::var("ENV").unwrap_or_else(|_| "development".into());
+ info!("Configuration Environment: {}", mode);
+
+ builder = builder.add_source(File::with_name(&format!("config/{mode}")).required(false));
+ builder = builder.add_source(File::with_name("config/local").required(false));
+
+ let env = Environment::with_prefix("NOVA").separator("__");
+ // we can configure each component using environment variables
+ builder = builder.add_source(env);
+
+ let config: Value = builder.build()?.try_deserialize()?;
+
+ Ok(config)
+}