ek-ui 0.9.21

ek 生态常驻主界面(egui/eframe):插件即界面——观测页 + 日志页,车头与 UI 同插件
Documentation
//! 一次性运维小工具:给**已在册**账户段补/改行情侧(md_addr / md_user / md_password)。
//!
//! 场景(0.9.10 实扫):220380 的 24 小时套档案只登记了 td(40001),md 空 =
//! 行情会话与行情侧合约流起不来 → oms 腿缺合约 → 发单被 P1 拒。
//! 载入-改-存(与账户面板「编辑→保存」同形;写口 `write_account` 按设计拒绝
//! 同 td 前置重复登记,所以补档走段面直改)。密码明文只过内存,不落打印。

fn main() {
    let args: Vec<String> = std::env::args().skip(1).collect();
    let (Some(gw), Some(md_addr)) = (args.first(), args.get(1)) else {
        eprintln!("用法: set_md <网关名> <md_addr>");
        std::process::exit(2);
    };
    let ns = format!("ctp.{gw}");
    let store = ek_cfg::Store::eco().expect("档案根");
    let map0 = match store.load(&ns) {
        Ok(ek_cfg::LoadOutcome::Loaded { map, .. }) => map,
        Ok(ek_cfg::LoadOutcome::Fresh) => {
            eprintln!("段 {ns} 不存在(先在面板/CLI 登记)");
            std::process::exit(1);
        }
        Err(e) => {
            eprintln!("段读不动: {e:?}");
            std::process::exit(1);
        }
    };
    let td_user = map0.get_plain("td_user").unwrap_or_default().to_string();
    // 密库:md 凭据 = td 同密(SimNow 口径),写进本段密库键(明文只过内存)。
    let td_ns_pw = ek_cfg::secret::get(&ns, "gw_td_password")
        .map(|v| String::from_utf8_lossy(v.as_bytes()).to_string())
        .unwrap_or_default();
    if td_ns_pw.is_empty() {
        eprintln!("本段密库无 gw_td_password,md 凭据无从复制(先在面板存过密码)");
        std::process::exit(1);
    }
    ek_cfg::secret::register(
        &ns,
        "gw_md_password",
        ek_cfg::SecretValue::from_bytes(td_ns_pw),
    )
    .expect("密库登记");
    // 段面载入-改-存(链式 Field API,与 write_account 同形)。
    let map = map0
        .set("md_addr", ek_core::Field::plain(md_addr.trim()))
        .set("md_user", ek_core::Field::plain(td_user.trim()))
        .set("md_password", ek_core::Field::secret("gw_md_password"));
    store.save(&ns, &map).expect("段存档");
    println!("已补档 {ns}: md_addr={md_addr}(md 凭据 = 密库引用)");
}