diff --git a/examples/watcher/main.rs b/examples/watcher/main.rs index 8f7c56272..ea9bcdfde 100644 --- a/examples/watcher/main.rs +++ b/examples/watcher/main.rs @@ -1,10 +1,7 @@ use std::path::PathBuf; use clap::Parser; -use nexus_common::{ - db::DatabaseConfig, file::validate_and_expand_path, get_files_dir_pathbuf, types::DynError, - StackConfig, WatcherConfig, LOG_LEVEL, -}; +use nexus_common::{file::validate_and_expand_path, types::DynError, StackConfig, WatcherConfig}; use nexus_watcher::{service::NexusWatcher, NexusWatcherBuilder}; use pubky_app_specs::PubkyId; @@ -30,12 +27,7 @@ async fn main() -> Result<(), DynError> { PubkyId::try_from("8um71us3fyw6h8wbcxb5ar3rwusy1a6u49956ikzojg3gcwd1dty").unwrap(); let moderation_id = PubkyId::try_from("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").unwrap(); - let stack = StackConfig { - log_level: LOG_LEVEL, - files_path: get_files_dir_pathbuf(), - otlp_endpoint: None, - db: DatabaseConfig::default(), - }; + let stack = StackConfig::default(); let config = WatcherConfig { name: String::from("nexusd.watcher"), testnet: false, diff --git a/nexus-common/src/config/api.rs b/nexus-common/src/config/api.rs index b9ec34f63..78a47cee5 100644 --- a/nexus-common/src/config/api.rs +++ b/nexus-common/src/config/api.rs @@ -2,7 +2,7 @@ use std::net::{IpAddr, Ipv4Addr}; use std::{fmt::Debug, net::SocketAddr}; use super::file::ConfigLoader; -use super::{default_stack, DaemonConfig, StackConfig}; +use super::{DaemonConfig, StackConfig}; use async_trait::async_trait; use serde::{Deserialize, Serialize}; @@ -20,7 +20,7 @@ pub struct ApiConfig { pub public_ip: IpAddr, pub public_addr: SocketAddr, pub pubky_listen_socket: SocketAddr, - #[serde(default = "default_stack")] + #[serde(default)] pub stack: StackConfig, } diff --git a/nexus-common/src/config/file/mod.rs b/nexus-common/src/config/file/mod.rs index 8ed2b9743..e64780f46 100644 --- a/nexus-common/src/config/file/mod.rs +++ b/nexus-common/src/config/file/mod.rs @@ -1,5 +1,5 @@ mod loader; -pub(super) mod reader; +pub(crate) mod reader; pub use loader::ConfigLoader; pub use reader::{default_config_dir_path, validate_and_expand_path, CONFIG_FILE_NAME}; diff --git a/nexus-common/src/config/file/reader.rs b/nexus-common/src/config/file/reader.rs index 439a56fe8..d68012fce 100644 --- a/nexus-common/src/config/file/reader.rs +++ b/nexus-common/src/config/file/reader.rs @@ -6,7 +6,10 @@ use std::path::{Component, PathBuf}; /// /// See [default_config_dir_path] to use this as [PathBuf] pub const DEFAULT_HOME_DIR: &str = ".pubky-nexus"; + +/// The default config TOML content embedded in the binary pub(crate) const DEFAULT_CONFIG_TOML: &str = include_str!("../../../default.config.toml"); + /// The sole configuration file name recognized by nexus pub const CONFIG_FILE_NAME: &str = "config.toml"; diff --git a/nexus-common/src/config/mod.rs b/nexus-common/src/config/mod.rs index d770687f9..b02209d70 100644 --- a/nexus-common/src/config/mod.rs +++ b/nexus-common/src/config/mod.rs @@ -1,21 +1,6 @@ use serde::{Deserialize, Serialize}; use std::{fmt::Debug, path::PathBuf, sync::OnceLock}; -pub const LOG_LEVEL: Level = Level::Info; - -/// Path to the directory where static files are stored. To access this as a [PathBuf], use [get_files_dir_pathbuf]. -pub const FILES_DIR: &str = "~/.pubky-nexus/static/files"; -static FILES_DIR_PATHBUF: OnceLock = OnceLock::new(); -/// See [FILES_DIR] -pub fn get_files_dir_pathbuf() -> PathBuf { - FILES_DIR_PATHBUF - .get_or_init(|| { - validate_and_expand_path(PathBuf::from(FILES_DIR)) - .expect("Hardcoded FILES_DIR should be a valid directory path") - }) - .clone() -} - // All the tests run inside their own crate therefore the default directory does not apply pub const FILES_DIR_TEST: &str = "./static/files"; static FILES_DIR_TEST_PATHBUF: OnceLock = OnceLock::new(); @@ -36,7 +21,7 @@ mod watcher; pub use api::ApiConfig; pub use daemon::DaemonConfig; -pub use stack::{default_stack, StackConfig}; +pub use stack::StackConfig; pub use watcher::WatcherConfig; use crate::file::validate_and_expand_path; diff --git a/nexus-common/src/config/stack.rs b/nexus-common/src/config/stack.rs index 8fa06ceac..3fdd2bcbd 100644 --- a/nexus-common/src/config/stack.rs +++ b/nexus-common/src/config/stack.rs @@ -1,8 +1,19 @@ -use crate::{db::DatabaseConfig, get_files_dir_pathbuf}; +use crate::{db::DatabaseConfig, file::reader::DEFAULT_CONFIG_TOML}; use serde::{Deserialize, Deserializer, Serialize}; -use std::{fmt::Debug, path::PathBuf}; +use std::{fmt::Debug, path::PathBuf, sync::OnceLock}; -use super::{file::validate_and_expand_path, Level, LOG_LEVEL}; +use super::{file::validate_and_expand_path, Level}; + +static DEFAULT_STACK_CONFIG: OnceLock = OnceLock::new(); + +/// Intermediary struct used in deserializing [StackConfig] from `default.config.toml` +/// +/// This is done because we don't know the full structure of the config.toml , but we +/// do know it contains a `[stack]` section with [StackConfig]. +#[derive(Deserialize)] +struct DefaultConfig { + stack: StackConfig, +} fn deserialize_and_expand<'de, D>(deserializer: D) -> Result where @@ -21,18 +32,18 @@ pub struct StackConfig { pub db: DatabaseConfig, } -/// Utility function -pub fn default_stack() -> StackConfig { - StackConfig::default() +/// Returns the default stack config parsed from `default.config.toml` +pub(crate) fn get_default_stack_config() -> &'static StackConfig { + DEFAULT_STACK_CONFIG.get_or_init(|| { + let config: DefaultConfig = toml::from_str(DEFAULT_CONFIG_TOML) + .expect("embedded default.config.toml should be valid TOML"); + config.stack + }) } impl Default for StackConfig { + /// Extracted from `default.config.toml` fn default() -> Self { - Self { - log_level: LOG_LEVEL, - files_path: get_files_dir_pathbuf(), - otlp_endpoint: None, - db: DatabaseConfig::default(), - } + get_default_stack_config().clone() } } diff --git a/nexus-common/src/config/watcher.rs b/nexus-common/src/config/watcher.rs index aed0329c0..6e0a1cef0 100644 --- a/nexus-common/src/config/watcher.rs +++ b/nexus-common/src/config/watcher.rs @@ -1,5 +1,5 @@ use super::file::ConfigLoader; -use super::{default_stack, DaemonConfig, StackConfig}; +use super::{DaemonConfig, StackConfig}; use async_trait::async_trait; use pubky_app_specs::PubkyId; use serde::{Deserialize, Serialize}; @@ -43,7 +43,7 @@ pub struct WatcherConfig { pub monitored_homeservers_limit: usize, /// Sleep between every full run (over all monitored homeservers), in milliseconds pub watcher_sleep: u64, - #[serde(default = "default_stack")] + #[serde(default)] pub stack: StackConfig, // Moderation pub moderation_id: PubkyId, diff --git a/nexus-common/src/db/config/neo4j.rs b/nexus-common/src/db/config.rs similarity index 67% rename from nexus-common/src/db/config/neo4j.rs rename to nexus-common/src/db/config.rs index ef15950f3..85966c1f2 100644 --- a/nexus-common/src/db/config/neo4j.rs +++ b/nexus-common/src/db/config.rs @@ -1,11 +1,23 @@ use serde::{Deserialize, Serialize}; +use std::fmt::Debug; -pub const NEO4J_URI: &str = "bolt://localhost:7687"; -pub const NEO4J_USER: &str = "neo4j"; -pub const NEO4J_PASS: &str = "12345678"; +use crate::StackConfig; + +// TODO Does this need to be pub? Isn't this only relevant for default deser where JSOn field isn't set? pub const DEFAULT_SLOW_QUERY_THRESHOLD_MS: u64 = 100; -// Create temporal struct to wrap database config +fn default_neo4j_user() -> String { + String::from("neo4j") +} + +fn default_slow_query_logging_threshold_ms() -> u64 { + DEFAULT_SLOW_QUERY_THRESHOLD_MS +} + +fn default_slow_query_logging_enabled() -> bool { + true +} + #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] pub struct Neo4JConfig { pub uri: String, @@ -31,27 +43,22 @@ pub struct Neo4JConfig { pub slow_query_logging_include_cypher: bool, } -fn default_neo4j_user() -> String { - String::from("neo4j") -} - -fn default_slow_query_logging_threshold_ms() -> u64 { - DEFAULT_SLOW_QUERY_THRESHOLD_MS +impl Default for Neo4JConfig { + /// Extracted from `default.config.toml` via [StackConfig] > [DatabaseConfig] > [Neo4JConfig] + fn default() -> Self { + DatabaseConfig::default().neo4j + } } -fn default_slow_query_logging_enabled() -> bool { - true +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] +pub struct DatabaseConfig { + pub redis: String, + pub neo4j: Neo4JConfig, } -impl Default for Neo4JConfig { +impl Default for DatabaseConfig { + /// Extracted from `default.config.toml` via [StackConfig] > [DatabaseConfig] fn default() -> Self { - Self { - uri: String::from(NEO4J_URI), - user: String::from(NEO4J_USER), - password: String::from(NEO4J_PASS), - slow_query_logging_threshold_ms: DEFAULT_SLOW_QUERY_THRESHOLD_MS, - slow_query_logging_enabled: true, - slow_query_logging_include_cypher: false, - } + StackConfig::default().db } } diff --git a/nexus-common/src/db/config/mod.rs b/nexus-common/src/db/config/mod.rs deleted file mode 100644 index 5e4952bbd..000000000 --- a/nexus-common/src/db/config/mod.rs +++ /dev/null @@ -1,22 +0,0 @@ -use serde::{Deserialize, Serialize}; -use std::fmt::Debug; - -mod neo4j; -pub use neo4j::{Neo4JConfig, DEFAULT_SLOW_QUERY_THRESHOLD_MS}; - -pub const REDIS_URI: &str = "redis://localhost:6379"; - -#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] -pub struct DatabaseConfig { - pub redis: String, - pub neo4j: Neo4JConfig, -} - -impl Default for DatabaseConfig { - fn default() -> Self { - Self { - redis: String::from(REDIS_URI), - neo4j: Neo4JConfig::default(), - } - } -} diff --git a/nexus-watcher/tests/event_processor/utils/watcher.rs b/nexus-watcher/tests/event_processor/utils/watcher.rs index c1f5e5cd4..8e62b15c1 100644 --- a/nexus-watcher/tests/event_processor/utils/watcher.rs +++ b/nexus-watcher/tests/event_processor/utils/watcher.rs @@ -2,7 +2,6 @@ use anyhow::{anyhow, Error, Result}; use base32::{encode, Alphabet}; use chrono::Utc; use nexus_common::db::PubkyConnector; -use nexus_common::get_files_dir_pathbuf; use nexus_common::get_files_dir_test_pathbuf; use nexus_common::models::event::Event; use nexus_common::models::event::EventProcessorError; @@ -348,7 +347,7 @@ pub async fn retrieve_and_handle_event_line( event_line: &str, moderation: Arc, ) -> Result<(), EventProcessorError> { - match Event::parse_event(event_line, get_files_dir_pathbuf())? { + match Event::parse_event(event_line, get_files_dir_test_pathbuf())? { Some(event) => handle(&event, moderation).await, None => Ok(()), }