ek-station 0.1.9

Station for the ek ecosystem: headless plugin host bootstrap - assembles ek-core MainEngine from a compile-time plugin factory table, runs the svctl supervisor service (list/start/remove over bus ask) and a headless main (readiness marker + graceful close).
Documentation
//! # factory —— 编译期插件工厂表(DV-2:v1 不做 dylib 动态加载)。
//!
//! 每个登记项 = 注册名 + 文档串 + `fn() -> Arc<dyn Plugin>` 零参构造。
//! 构造固定用生态缺省配置(`DmConfig::minute("dm")`/
//! `OmsPlugin::builder().risk_gates(ek_risk::standard_gates(..))`(0.1.7 装配
//! 口径)/`CtpPlugin::new(CtpConfig::default()` → 注册名 "ctp",native 特性关 =
//! 纯逻辑驱动)/`SimGatewayPlugin::new()` → 注册名 "sim",0.1.8 纸面网关入表
//! ——SimNow 登不上时切换的本地模拟流,无头可跑);参数化配置进 S3 配置面(届时
//! build 签名升级为 `fn(&SectionMap) -> Result<...>`,本表只换实现不改面)。

use ek_core::plugin::Plugin;
use ek_ctp::plugin::{CtpConfig, CtpPlugin};
use ek_dm::plugin::{DmConfig, DmPlugin};
use ek_oms::plugin::OmsPlugin;
/// 一个可装配的插件种类。
#[derive(Clone)]
pub struct PlugKind {
    /// 工厂注册名(svctl.start 的 `factory` 参数;**不必然**等于插件注册名,
    /// 如多网关实例同工厂 —— v1 两者一致)。
    pub name: &'static str,
    /// 一行用途说明(观测页提示用)。
    pub doc: &'static str,
    /// 零参构造(测试探针需要捕获共享槽,故用 `Arc<dyn Fn>`;零捕获闭包同样适配)。
    pub build: std::sync::Arc<dyn Fn() -> std::sync::Arc<dyn Plugin> + Send + Sync>,
}

/// 缺省工厂表:ek 生态当前已发布插件的全部登记。
#[must_use]
pub fn default_kinds() -> Vec<PlugKind> {
    vec![
        PlugKind {
            name: "dm",
            doc: "数据管理器(KlineManager;eTick.→eBar. 单源批)",
            build: std::sync::Arc::new(|| {
                std::sync::Arc::new(DmPlugin::new(DmConfig::minute("dm")))
            }),
        },
        PlugKind {
            name: "oms",
            doc: "OMS 中枢(入账 + 查询 + 五段管线;地板三件 + ek-risk 三闸装配)",
            build: std::sync::Arc::new(|| {
                // 0.1.7 装配口径:缺省限额(DESIGN ek-risk §6「不阻塞但保守」)。
                std::sync::Arc::new(
                    OmsPlugin::builder()
                        .risk_gates(ek_risk::standard_gates(&ek_risk::RiskLimits::default()))
                        .build(),
                )
            }),
        },
        PlugKind {
            name: "ctp",
            doc: "CTP 网关(native 关 = 纯逻辑驱动;账号经 {gw}.configure 手工注入,插件不读配置文件)",
            build: std::sync::Arc::new(|| {
                // ctp-native 特性开 → 随包 SDK 传输 + 流目录 target/ctp-flow;
                // 关 → 纯逻辑驱动(现行为)。账号缺省空:connect 空地址守卫跳过,
                // 等 configure 手工注入(0.3.0 D-CONFIGURE 定盘)。
                #[cfg(feature = "ctp-native")]
                {
                    CtpPlugin::with_native(CtpConfig::default(), "target/ctp-flow")
                }
                #[cfg(not(feature = "ctp-native"))]
                {
                    std::sync::Arc::new(CtpPlugin::new(CtpConfig::default()))
                }
            }),
        },
        PlugKind {
            name: ek_paper::matcher::SIM_NAME,
            doc: "纸面网关(ek-paper;与 ek-ctp 四口契约同构,eBar./eTick. 驱动 FIFO 撮合 —— SimNow 登不上时切换的本地模拟流)",
            build: std::sync::Arc::new(|| {
                std::sync::Arc::new(ek_paper::plugin::SimGatewayPlugin::new())
            }),
        },
    ]
}

/// 委托式包装:把异构的 `Arc<dyn Plugin>` 抬成 `add_plugin` 泛型点可用的具体类型
/// (ek-core 0.3.0 的 `impl Plugin` 是 `Sized` 泛型面 —— BD-U6:ek-core 已发布不可改)。
///
/// 纪律钉:`get_typed` 的 downcast 不穿透本包装(nt 语义拿内层裸 Arc),
/// 类型面一律走各插件自报的 ask 契约(生态铁律:插件不直调)。
pub struct DynPlugin {
    inner: std::sync::Arc<dyn Plugin>,
}

impl DynPlugin {
    /// 包装已建好的插件对象(直接给出 `Arc<Self>`,调用点即 add_plugin 形参)。
    pub fn wrap(inner: std::sync::Arc<dyn Plugin>) -> std::sync::Arc<Self> {
        std::sync::Arc::new(Self { inner })
    }
}

impl Plugin for DynPlugin {
    fn name(&self) -> &str {
        self.inner.name()
    }

    fn deps(&self) -> &[&str] {
        self.inner.deps()
    }

    fn routes(&self) -> Vec<std::borrow::Cow<'static, str>> {
        self.inner.routes()
    }

    fn mailbox_cap(&self) -> usize {
        self.inner.mailbox_cap()
    }

    fn version(&self) -> std::borrow::Cow<'static, str> {
        self.inner.version()
    }

    fn services(&self) -> Vec<ek_core::service::ServiceDesc> {
        self.inner.services()
    }

    fn on_init(&self, ctx: &ek_core::context::PluginContext) {
        self.inner.on_init(ctx);
    }

    fn on_start(&self) {
        self.inner.on_start();
    }

    fn on_stop(&self) {
        self.inner.on_stop();
    }

    fn on_mail(&self, event: &ek_event::Event) {
        self.inner.on_mail(event);
    }
}