diff --git a/Cargo.lock b/Cargo.lock index 0aa6e54..9253aaf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -515,10 +515,12 @@ dependencies = [ "futures", "git2", "log", + "os_path", "rand 0.8.5", "regex", "serde", "serde_json", + "serde_jsonc", "simple-error", "taurus", "thiserror", @@ -2575,6 +2577,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "os_path" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "360a6ecb129f544ba5ae18776ca8779cf3cf979c8133e9eefe9464ea74741f6b" +dependencies = [ + "regex", + "serde", +] + [[package]] name = "os_pipe" version = "1.2.1" @@ -3357,6 +3369,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_jsonc" +version = "1.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a58154381df481a41b7536101c0daccdaf2426f244334074c4c77b89b6253a7" +dependencies = [ + "itoa 1.0.11", + "ryu", + "serde", +] + [[package]] name = "serde_repr" version = "0.1.19" diff --git a/clover-hub/Cargo.toml b/clover-hub/Cargo.toml index 1dd8c5c..f281b89 100644 --- a/clover-hub/Cargo.toml +++ b/clover-hub/Cargo.toml @@ -49,3 +49,5 @@ taurus = { git = "https://github.com/Reboot-Codes/taurus" } bollard = "0.17.1" simple-error = "0.3.1" git2 = "0.19.0" +os_path = "0.8.0" +serde_jsonc = "1.0.108" diff --git a/clover-hub/src/main.rs b/clover-hub/src/main.rs index f85800d..b3d8fc8 100644 --- a/clover-hub/src/main.rs +++ b/clover-hub/src/main.rs @@ -159,6 +159,7 @@ async fn wait_for_signal_impl() { #[tokio::main] async fn main() -> Result<(), Box> { + // TODO:: Create a logger that will send logs to a FIFO buffer to send over WS via EvtBuzz env_logger::Builder::new() .parse_filters(&env::var("CLOVER_LOG").unwrap_or("info".to_string())) .init(); diff --git a/clover-hub/src/server/appd/mod.rs b/clover-hub/src/server/appd/mod.rs index a896801..1395020 100644 --- a/clover-hub/src/server/appd/mod.rs +++ b/clover-hub/src/server/appd/mod.rs @@ -24,8 +24,9 @@ pub async fn appd_main( ) { info!("Starting AppDaemon..."); + let docker_path = store.config.lock().await.docker_daemon.clone(); // TODO: Move to parameterized config from store! - match Docker::connect_with_unix(&store.config.docker_daemon.clone(), 120, API_DEFAULT_VERSION) { + match Docker::connect_with_unix(&docker_path, 120, API_DEFAULT_VERSION) { Ok(docker_conn) => { let docker = Arc::new(docker_conn); diff --git a/clover-hub/src/server/evtbuzz/models.rs b/clover-hub/src/server/evtbuzz/models.rs index a709980..ea2fb39 100644 --- a/clover-hub/src/server/evtbuzz/models.rs +++ b/clover-hub/src/server/evtbuzz/models.rs @@ -80,7 +80,7 @@ pub struct UserConfig { // TODO: Add options for making certain models ephemeral or persistent. #[derive(Debug, Clone)] pub struct Store { - pub config: Arc, + pub config: Arc>, pub users: Arc>>, pub api_keys: Arc>>, pub clients: Arc>>, @@ -103,7 +103,7 @@ pub struct CoreUserConfigs { impl Store { pub fn new() -> Self { Store { - config: Arc::new(Config { docker_daemon: "/run/user/1000/podman/podman.sock".to_string() }), + config: Arc::new(Mutex::new(Default::default())), users: Arc::new(Mutex::new(HashMap::new())), api_keys: Arc::new(Mutex::new(HashMap::new())), clients: Arc::new(Mutex::new(HashMap::new())), diff --git a/clover-hub/src/server/mod.rs b/clover-hub/src/server/mod.rs index 85a9ecf..20aaa34 100644 --- a/clover-hub/src/server/mod.rs +++ b/clover-hub/src/server/mod.rs @@ -188,6 +188,24 @@ pub async fn server_main(data_dir: &String, port: u16, cancellation_token: Cance }, warehouse::Error::FailedToCreateDataDir { error } => { error!("Failed to create data directory! Please create `{}` and set the proper permissions manually, then re-run the server. Failed due to:\n{}", data_dir.clone(), error); + }, + warehouse::Error::FailedToCheckConfigFile { error } => { + error!("Failed to check existence of config file, due to:\n{}", error); + }, + warehouse::Error::FailedToCreateConfigFile { error } => { + error!("Failed to create the configuration file, due to:\n{}", error); + }, + warehouse::Error::FailedToOpenConfigFile { error } => { + error!("Failed to open config file, due to:\n{}", error); + }, + warehouse::Error::FailedToParseConfigFile { error } => { + error!("Failed to parse configuration file, due to:\n{}", error); + }, + warehouse::Error::FailedToReadConfigFile { error } => { + error!("Failed to read configuration file, due to:\n{}", error); + }, + warehouse::Error::FailedToWriteToConfigFile { error } => { + error!("Failed to write to the configuration file, due to:\n{}", error); } } diff --git a/clover-hub/src/server/warehouse/config/models.rs b/clover-hub/src/server/warehouse/config/models.rs index 1a1879e..2f6cdbe 100644 --- a/clover-hub/src/server/warehouse/config/models.rs +++ b/clover-hub/src/server/warehouse/config/models.rs @@ -1,4 +1,14 @@ -#[derive(Debug, Clone)] +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct Config { pub docker_daemon: String, } + +impl Default for Config { + fn default() -> Self { + Config { + docker_daemon: "/run/user/1000/podman/podman.sock".to_string() + } + } +} diff --git a/clover-hub/src/server/warehouse/mod.rs b/clover-hub/src/server/warehouse/mod.rs index 7ee4a28..c081692 100644 --- a/clover-hub/src/server/warehouse/mod.rs +++ b/clover-hub/src/server/warehouse/mod.rs @@ -1,13 +1,17 @@ pub mod config; pub mod manifest; +use config::models::Config; +use os_path::OsPath; +use std::io::{Read, Write}; use std::sync::Arc; use std::fs; -use log::debug; +use log::{debug, info}; use simple_error::SimpleError; use crate::server::evtbuzz::models::Store; +// TODO: Move to snafu crate. #[derive(Debug, Clone)] pub enum Error { FailedToCheckDataDir { @@ -15,6 +19,24 @@ pub enum Error { }, FailedToCreateDataDir { error: SimpleError + }, + FailedToCheckConfigFile { + error: SimpleError + }, + FailedToOpenConfigFile { + error: SimpleError + }, + FailedToCreateConfigFile { + error: SimpleError + }, + FailedToWriteToConfigFile { + error: SimpleError + }, + FailedToParseConfigFile { + error: SimpleError + }, + FailedToReadConfigFile { + error: SimpleError } } @@ -51,8 +73,69 @@ pub async fn setup_warehouse(data_dir: String, store: Arc) -> Result<(), } } + let warehouse_path = OsPath::from(data_dir.clone()); + // Read configuration and load defaults otherwise - + let config_file_path = warehouse_path.join("/config.jsonc"); + match err { + Some(_) => {}, + None => { + match fs::exists(config_file_path.clone()) { + Ok(config_file_exists) => { + if !config_file_exists { + match fs::File::create(config_file_path.clone()) { + Ok(mut file) => { + match file.write_all(serde_jsonc::to_string::(&Default::default()).unwrap().as_bytes()) { + Ok(_) => { + info!("Wrote default config!"); + }, + Err(e) => { + err = Some(Err(Error::FailedToWriteToConfigFile { error: SimpleError::from(e) })) + } + } + }, + Err(e) => { + err = Some(Err(Error::FailedToCreateConfigFile { error: SimpleError::from(e) })) + } + } + } + }, + Err(e) => { + err = Some(Err(Error::FailedToCheckConfigFile { error: SimpleError::from(e) })); + } + } + } + } + + match err { + Some(_) => {}, + None => { + match fs::File::open(config_file_path) { + Ok(mut config_file) => { + let mut contents = String::new(); + match config_file.read_to_string(&mut contents) { + Ok(_) => { + match serde_jsonc::from_str::(&contents) { + Ok(config_values) => { + *store.config.lock().await = config_values; + debug!("Loaded config!"); + }, + Err(e) => { + err = Some(Err(Error::FailedToParseConfigFile { error: SimpleError::from(e) })) + } + } + }, + Err(e) => { + err = Some(Err(Error::FailedToReadConfigFile { error: SimpleError::from(e) })) + } + } + }, + Err(e) => { + err = Some(Err(Error::FailedToOpenConfigFile { error: SimpleError::from(e) })) + } + } + } + } // Read repo data and load into applicable areas in the store. diff --git a/docs/docs/components/00-intro.md b/docs/docs/components/00-intro.md index ca54ce7..eba86fb 100644 --- a/docs/docs/components/00-intro.md +++ b/docs/docs/components/00-intro.md @@ -8,7 +8,7 @@ The Rust-based nerve centre for all communication between modules, their compone ## CORE -Sensible default applications, lovingly designed parts, and dynamic expression packs to get you started. All parts are build using best-practices, and are considered to be fully supported and used as an immutable fallback when it comes to software. +Sensible default applications, lovingly designed parts, and dynamic expression packs to get you started. All parts are built using best-practices, and are considered to be fully supported and used as an immutable fallback when it comes to software. ## Spanner