From 5b69519ab136cfed3c072eabbe1368693192c84b Mon Sep 17 00:00:00 2001 From: andrussal Date: Tue, 10 Mar 2026 11:06:16 +0100 Subject: [PATCH] Clarify cfgsync runtime serving modes --- cfgsync/runtime/src/lib.rs | 6 +- cfgsync/runtime/src/server.rs | 110 +++++++++++++++++++++++---- logos/runtime/ext/src/cfgsync/mod.rs | 4 +- 3 files changed, 102 insertions(+), 18 deletions(-) diff --git a/cfgsync/runtime/src/lib.rs b/cfgsync/runtime/src/lib.rs index 7c0a75b..f9b225f 100644 --- a/cfgsync/runtime/src/lib.rs +++ b/cfgsync/runtime/src/lib.rs @@ -4,4 +4,8 @@ mod client; mod server; pub use client::run_cfgsync_client_from_env; -pub use server::{CfgSyncServerConfig, run_cfgsync_server}; +#[doc(hidden)] +pub use server::CfgSyncServerConfig; +pub use server::{ + CfgsyncServerConfig, CfgsyncServingMode, LoadCfgsyncServerConfigError, run_cfgsync_server, +}; diff --git a/cfgsync/runtime/src/server.rs b/cfgsync/runtime/src/server.rs index 9ec5a6d..1090ac0 100644 --- a/cfgsync/runtime/src/server.rs +++ b/cfgsync/runtime/src/server.rs @@ -6,24 +6,102 @@ use cfgsync_core::{ BundleConfigSource, CfgSyncBundle, CfgsyncServerState, NodeConfigSource, run_cfgsync, }; use serde::Deserialize; +use thiserror::Error; /// Runtime cfgsync server config loaded from YAML. #[derive(Debug, Deserialize, Clone)] -pub struct CfgSyncServerConfig { +pub struct CfgsyncServerConfig { pub port: u16, pub bundle_path: String, #[serde(default)] - pub registration_flow: bool, + pub serving_mode: CfgsyncServingMode, } -impl CfgSyncServerConfig { - /// Loads cfgsync runtime server config from a YAML file. - pub fn load_from_file(path: &Path) -> anyhow::Result { - let config_content = fs::read_to_string(path) - .with_context(|| format!("failed to read cfgsync config file {}", path.display()))?; +#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq, Default)] +#[serde(rename_all = "snake_case")] +pub enum CfgsyncServingMode { + #[default] + Bundle, + Registration, +} - serde_yaml::from_str(&config_content) - .with_context(|| format!("failed to parse cfgsync config file {}", path.display())) +#[derive(Debug, Deserialize)] +struct RawCfgsyncServerConfig { + port: u16, + bundle_path: String, + #[serde(default)] + serving_mode: Option, + #[serde(default)] + registration_flow: Option, +} + +#[derive(Debug, Error)] +pub enum LoadCfgsyncServerConfigError { + #[error("failed to read cfgsync config file {path}: {source}")] + Read { + path: String, + #[source] + source: std::io::Error, + }, + #[error("failed to parse cfgsync config file {path}: {source}")] + Parse { + path: String, + #[source] + source: serde_yaml::Error, + }, +} + +impl CfgsyncServerConfig { + /// Loads cfgsync runtime server config from a YAML file. + pub fn load_from_file(path: &Path) -> Result { + let config_path = path.display().to_string(); + let config_content = + fs::read_to_string(path).map_err(|source| LoadCfgsyncServerConfigError::Read { + path: config_path.clone(), + source, + })?; + + let raw: RawCfgsyncServerConfig = + serde_yaml::from_str(&config_content).map_err(|source| { + LoadCfgsyncServerConfigError::Parse { + path: config_path, + source, + } + })?; + + Ok(Self { + port: raw.port, + bundle_path: raw.bundle_path, + serving_mode: raw + .serving_mode + .unwrap_or_else(|| mode_from_legacy_registration_flow(raw.registration_flow)), + }) + } + + #[must_use] + pub fn for_bundle(port: u16, bundle_path: impl Into) -> Self { + Self { + port, + bundle_path: bundle_path.into(), + serving_mode: CfgsyncServingMode::Bundle, + } + } + + #[must_use] + pub fn for_registration(port: u16, bundle_path: impl Into) -> Self { + Self { + port, + bundle_path: bundle_path.into(), + serving_mode: CfgsyncServingMode::Registration, + } + } +} + +fn mode_from_legacy_registration_flow(registration_flow: Option) -> CfgsyncServingMode { + if registration_flow.unwrap_or(false) { + CfgsyncServingMode::Registration + } else { + CfgsyncServingMode::Bundle } } @@ -77,7 +155,7 @@ fn resolve_bundle_path(config_path: &Path, bundle_path: &str) -> std::path::Path /// Loads runtime config and starts cfgsync HTTP server process. pub async fn run_cfgsync_server(config_path: &Path) -> anyhow::Result<()> { - let config = CfgSyncServerConfig::load_from_file(config_path)?; + let config = CfgsyncServerConfig::load_from_file(config_path)?; let bundle_path = resolve_bundle_path(config_path, &config.bundle_path); let state = build_server_state(&config, &bundle_path)?; @@ -87,14 +165,16 @@ pub async fn run_cfgsync_server(config_path: &Path) -> anyhow::Result<()> { } fn build_server_state( - config: &CfgSyncServerConfig, + config: &CfgsyncServerConfig, bundle_path: &Path, ) -> anyhow::Result { - let repo = if config.registration_flow { - load_materializing_provider(bundle_path)? - } else { - load_bundle_provider(bundle_path)? + let repo = match config.serving_mode { + CfgsyncServingMode::Bundle => load_bundle_provider(bundle_path)?, + CfgsyncServingMode::Registration => load_materializing_provider(bundle_path)?, }; Ok(CfgsyncServerState::new(repo)) } + +#[doc(hidden)] +pub type CfgSyncServerConfig = CfgsyncServerConfig; diff --git a/logos/runtime/ext/src/cfgsync/mod.rs b/logos/runtime/ext/src/cfgsync/mod.rs index f607a9c..6bc28cc 100644 --- a/logos/runtime/ext/src/cfgsync/mod.rs +++ b/logos/runtime/ext/src/cfgsync/mod.rs @@ -122,8 +122,8 @@ fn build_cfgsync_server_config() -> Value { ); root.insert( - Value::String("registration_flow".to_string()), - Value::Bool(true), + Value::String("serving_mode".to_string()), + Value::String("registration".to_string()), ); Value::Mapping(root)