ek-ui 0.9.21

ek 生态常驻主界面(egui/eframe):插件即界面——观测页 + 日志页,车头与 UI 同插件
Documentation
//! **克隆既有账户到第二套前置**(0.9.10 一次性配置工具,用户指令「两个账户三条记录」)。
//!
//! 判据面 `u_multi_front_same_account_gets_suffix` 已钉:同账号第二套前置 → 派生名
//! 带 `_2` 后缀。本工具走**同一条生产写口** `appconfig::write_account`:
//! 读源档案(ns `ctp.{src}`)的表单字段 + 从密库取回密码明文(`secret::get`,
//! 只过内存,不落日志/打印),按给定新前置组装 AcctSpec → 写口落新段。
//!
//! 用法:
//! ```text
//! cargo run --features ctp-native,secret-windows --example clone_account -- <src网关名> <td_addr> <md_addr>
//! ```

fn main() {
    let args: Vec<String> = std::env::args().skip(1).collect();
    let (Some(src), Some(td)) = (args.first(), args.get(1)) else {
        eprintln!("用法: clone_account <src网关名> <td_addr> <md_addr>");
        std::process::exit(2);
    };
    let md = args.get(2).cloned().unwrap_or_default();

    let store = ek_cfg::Store::eco().expect("档案根");
    let src_ns = format!("ctp.{src}");
    let map = match store.load(&src_ns) {
        Ok(ek_cfg::LoadOutcome::Loaded { map, .. }) => map,
        Ok(ek_cfg::LoadOutcome::Fresh) => {
            eprintln!("源档案 {src_ns} 不存在");
            std::process::exit(1);
        }
        Err(e) => {
            eprintln!("源档案读不动: {e:?}");
            std::process::exit(1);
        }
    };
    // 密码:从源段密库引用取明文(只过内存,不落日志/打印)。
    let pw_key: &str = map
        .get_secret_key("td_password")
        .filter(|k| !k.is_empty())
        .unwrap_or("td_password");
    let password = ek_cfg::secret::get(&src_ns, pw_key)
        .map(|v| String::from_utf8_lossy(v.as_bytes()).to_string())
        .unwrap_or_default();
    if password.is_empty() {
        eprintln!("源段密库密码取不到(源账户先在有界面的界面里存一次密码)");
        std::process::exit(1);
    }

    let user = map.get_plain("td_user").unwrap_or_default().to_owned();
    let spec = ek_ui::appconfig::AcctSpec {
        broker_id: map.get_plain("broker_id").unwrap_or_default().to_owned(),
        user: user.clone(),
        td_addr: td.to_string(),
        md_addr: md.clone(),
        app_id: map.get_plain("td_app_id").unwrap_or_default().to_owned(),
        auth_code: map.get_plain("td_auth_code").unwrap_or_default().to_owned(),
        classes: map.get_plain("product_classes").unwrap_or_default().to_owned(),
        md_user: if md.is_empty() { String::new() } else { user.clone() },
        // md 前置配同账号同密(SimNow 口径);无 md = 段里不出 md_password。
        md_password: if md.is_empty() { None } else { Some(password.clone()) },
    };
    match ek_ui::appconfig::write_account(&store, &spec, &password) {
        Ok(gw) => println!("克隆成功 → 新段 ctp.{gw}(账号 {user},td {td},md {md})"),
        Err(e) => {
            eprintln!("写口拒绝: {e}");
            std::process::exit(1);
        }
    }
}