use std::sync::Arc;
use ek_core::error::PluginError;
use ek_core::main_engine::MainEngine;
use ek_core::plugin::Plugin;
use crate::factory::PlugKind;
use crate::supervisor::Supervisor;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct StationConfig {
pub plugins: Vec<String>,
}
impl StationConfig {
#[must_use]
pub fn demo() -> Self {
Self {
plugins: vec!["cfg".to_string(), "dm".to_string(), "oms".to_string()],
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum StationError {
UnknownKind(String),
Core(PluginError),
Cfg(String),
ApplyRejected {
ns: String,
reason: String,
},
NsDuplicate(String),
}
impl std::fmt::Display for StationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
StationError::UnknownKind(k) => write!(f, "unknown factory kind: {k}"),
StationError::Core(e) => write!(f, "host rejected: {e:?}"),
StationError::Cfg(e) => write!(f, "cfg load failed: {e}"),
StationError::ApplyRejected { ns, reason } => {
write!(f, "cfg apply rejected [{ns}]: {reason}")
}
StationError::NsDuplicate(ns) => write!(f, "config ns duplicate: {ns}"),
}
}
}
impl std::error::Error for StationError {}
impl From<PluginError> for StationError {
fn from(e: PluginError) -> Self {
StationError::Core(e)
}
}
pub fn boot(
engine: &Arc<MainEngine>,
kinds: &[PlugKind],
cfg: &StationConfig,
) -> Result<(), StationError> {
boot_with_cfg(engine, kinds, cfg, None)
}
fn assemble(
engine: &Arc<MainEngine>,
kinds: &[PlugKind],
cfg: &StationConfig,
store: Option<&ek_cfg::Store>,
) -> Result<Arc<Supervisor>, StationError> {
let sup = Arc::new(Supervisor::new(
Arc::clone(engine),
kinds.to_vec(),
store.cloned(),
));
let mut built: Vec<Arc<dyn Plugin>> = Vec::with_capacity(cfg.plugins.len());
for name in &cfg.plugins {
let kind = kinds
.iter()
.find(|k| k.name == *name)
.ok_or_else(|| StationError::UnknownKind(name.clone()))?;
built.push((kind.build)());
}
warn_if_cfg_missing(kinds, cfg);
crate::cfgload::ns_probe_all(&built)?;
engine.add_plugin(Arc::clone(&sup))?;
for plugin in built {
crate::cfgload::apply_persisted(plugin.as_ref(), store)?;
engine.add_plugin(crate::factory::DynPlugin::wrap(plugin))?;
}
Ok(sup)
}
fn warn_if_cfg_missing(kinds: &[PlugKind], cfg: &StationConfig) {
if !cfg.plugins.iter().any(|n| n == "cfg") && kinds.iter().any(|k| k.name == "cfg") {
eprintln!(
"[ek-cfg] 启用清单不含 cfg:配置持久化在运行期以调用方直调兜底(BD-CFG-10/20),托底盘不在路"
);
}
}
pub fn boot_with_cfg(
engine: &Arc<MainEngine>,
kinds: &[PlugKind],
cfg: &StationConfig,
store: Option<&ek_cfg::Store>,
) -> Result<(), StationError> {
assemble(engine, kinds, cfg, store).map(|_| ())
}
pub fn boot_restore_gateways(
engine: &Arc<MainEngine>,
kinds: &[PlugKind],
cfg: &StationConfig,
store: Option<&ek_cfg::Store>,
) -> Result<Vec<String>, StationError> {
let sup = assemble(engine, kinds, cfg, store)?;
match store {
Some(st) => Ok(crate::supervisor::restore_spawn_gateways(&sup, st)),
None => Ok(Vec::new()),
}
}