2026-03-09 08:48:05 +01:00
|
|
|
use std::{fs, path::Path, sync::Arc};
|
|
|
|
|
|
|
|
|
|
use anyhow::Context as _;
|
2026-03-10 10:56:42 +01:00
|
|
|
use cfgsync_adapter::{NodeArtifacts, NodeArtifactsCatalog, RegistrationConfigProvider};
|
2026-03-10 09:18:29 +01:00
|
|
|
use cfgsync_core::{CfgSyncBundle, CfgSyncState, ConfigProvider, FileConfigProvider, run_cfgsync};
|
2026-03-09 08:48:05 +01:00
|
|
|
use serde::Deserialize;
|
|
|
|
|
|
|
|
|
|
/// Runtime cfgsync server config loaded from YAML.
|
|
|
|
|
#[derive(Debug, Deserialize, Clone)]
|
|
|
|
|
pub struct CfgSyncServerConfig {
|
|
|
|
|
pub port: u16,
|
|
|
|
|
pub bundle_path: String,
|
2026-03-10 09:18:29 +01:00
|
|
|
#[serde(default)]
|
|
|
|
|
pub registration_flow: bool,
|
2026-03-09 08:48:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl CfgSyncServerConfig {
|
|
|
|
|
/// Loads cfgsync runtime server config from a YAML file.
|
|
|
|
|
pub fn load_from_file(path: &Path) -> anyhow::Result<Self> {
|
|
|
|
|
let config_content = fs::read_to_string(path)
|
|
|
|
|
.with_context(|| format!("failed to read cfgsync config file {}", path.display()))?;
|
|
|
|
|
|
|
|
|
|
serde_yaml::from_str(&config_content)
|
|
|
|
|
.with_context(|| format!("failed to parse cfgsync config file {}", path.display()))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-10 09:18:29 +01:00
|
|
|
fn load_bundle_provider(bundle_path: &Path) -> anyhow::Result<Arc<dyn ConfigProvider>> {
|
2026-03-09 08:48:05 +01:00
|
|
|
let provider = FileConfigProvider::from_yaml_file(bundle_path)
|
|
|
|
|
.with_context(|| format!("loading cfgsync provider from {}", bundle_path.display()))?;
|
|
|
|
|
|
|
|
|
|
Ok(Arc::new(provider))
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-10 09:18:29 +01:00
|
|
|
fn load_materializing_provider(bundle_path: &Path) -> anyhow::Result<Arc<dyn ConfigProvider>> {
|
|
|
|
|
let bundle = load_bundle_yaml(bundle_path)?;
|
|
|
|
|
let catalog = build_node_catalog(bundle);
|
2026-03-10 10:56:42 +01:00
|
|
|
let provider = RegistrationConfigProvider::new(catalog);
|
2026-03-10 09:18:29 +01:00
|
|
|
|
|
|
|
|
Ok(Arc::new(provider))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn load_bundle_yaml(bundle_path: &Path) -> anyhow::Result<CfgSyncBundle> {
|
|
|
|
|
let raw = fs::read_to_string(bundle_path)
|
|
|
|
|
.with_context(|| format!("reading cfgsync bundle from {}", bundle_path.display()))?;
|
|
|
|
|
|
|
|
|
|
serde_yaml::from_str(&raw)
|
|
|
|
|
.with_context(|| format!("parsing cfgsync bundle from {}", bundle_path.display()))
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-10 10:56:42 +01:00
|
|
|
fn build_node_catalog(bundle: CfgSyncBundle) -> NodeArtifactsCatalog {
|
2026-03-10 09:18:29 +01:00
|
|
|
let nodes = bundle
|
|
|
|
|
.nodes
|
|
|
|
|
.into_iter()
|
2026-03-10 10:56:42 +01:00
|
|
|
.map(|node| NodeArtifacts {
|
2026-03-10 09:18:29 +01:00
|
|
|
identifier: node.identifier,
|
|
|
|
|
files: node.files,
|
|
|
|
|
})
|
|
|
|
|
.collect();
|
|
|
|
|
|
2026-03-10 10:56:42 +01:00
|
|
|
NodeArtifactsCatalog::new(nodes)
|
2026-03-10 09:18:29 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-09 08:48:05 +01:00
|
|
|
fn resolve_bundle_path(config_path: &Path, bundle_path: &str) -> std::path::PathBuf {
|
|
|
|
|
let path = Path::new(bundle_path);
|
|
|
|
|
if path.is_absolute() {
|
|
|
|
|
return path.to_path_buf();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
config_path
|
|
|
|
|
.parent()
|
|
|
|
|
.unwrap_or_else(|| Path::new("."))
|
|
|
|
|
.join(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 bundle_path = resolve_bundle_path(config_path, &config.bundle_path);
|
|
|
|
|
|
2026-03-10 09:18:29 +01:00
|
|
|
let state = build_server_state(&config, &bundle_path)?;
|
2026-03-09 08:48:05 +01:00
|
|
|
run_cfgsync(config.port, state).await?;
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-10 09:18:29 +01:00
|
|
|
fn build_server_state(
|
|
|
|
|
config: &CfgSyncServerConfig,
|
|
|
|
|
bundle_path: &Path,
|
|
|
|
|
) -> anyhow::Result<CfgSyncState> {
|
|
|
|
|
let repo = if config.registration_flow {
|
|
|
|
|
load_materializing_provider(bundle_path)?
|
|
|
|
|
} else {
|
|
|
|
|
load_bundle_provider(bundle_path)?
|
|
|
|
|
};
|
2026-03-09 08:48:05 +01:00
|
|
|
|
|
|
|
|
Ok(CfgSyncState::new(repo))
|
|
|
|
|
}
|