use std::sync::Arc;
use ek_cfg::LoadOutcome;
use ek_cfg::Store as CfgStore;
use ek_core::cfg_face::CfgHost;
use ek_core::main_engine::MainEngine;
use ek_core::plugin::Plugin;
use ek_core::section::SectionMap;
use crate::pluginwin::WinState;
use crate::state::UiShared;
const NS_DM: &str = "dm";
const NS_OMS: &str = "oms";
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FaceKind {
Dm,
Oms,
Tq,
Ctp,
}
pub struct CfgBridge {
pub cfg: Option<CfgStore>,
pub shared: Arc<UiShared>,
}
impl CfgBridge {
#[must_use]
pub fn new(shared: &Arc<UiShared>) -> Self {
Self {
cfg: CfgStore::eco().ok(),
shared: Arc::clone(shared),
}
}
}
impl CfgHost for CfgBridge {
fn cfg_save(&self, ns: &str, map: &SectionMap) -> Result<(), String> {
match &self.cfg {
Some(c) => c.store(ns, map).map_err(|e| e.to_string()),
None => Err("档案托底根不可用(Store::eco 失败)".to_string()),
}
}
fn cfg_load(&self, ns: &str) -> Result<Option<SectionMap>, String> {
match &self.cfg {
Some(c) => match c.load(ns) {
Ok(LoadOutcome::Loaded { map, .. }) => Ok(Some(map)),
Ok(LoadOutcome::Fresh) => Ok(None),
Err(e) => Err(e.to_string()),
},
None => Err("档案托底根不可用(Store::eco 失败)".to_string()),
}
}
fn log(&self, line: &str) {
self.shared.log_line(line);
}
}
#[derive(Default)]
pub struct FaceStates {
pub dm: ek_dm::ui_face::DmUiState,
pub oms: ek_oms::ui_face::OmsUiState,
pub tq: ek_tq::ui_face::TqUiState,
pub wins: std::collections::HashMap<String, WinState>,
}
impl FaceStates {
#[must_use]
pub fn new() -> Self {
Self::default()
}
}
fn with_plugin<T: Plugin + 'static, R>(
engine: &MainEngine,
name: &str,
f: impl FnOnce(&T) -> R,
) -> Option<R> {
let arc = engine.plugin_arc(name)?;
let any = arc.as_any()?;
any.downcast_ref::<T>().map(f)
}
fn face_probe<T: Plugin + 'static>(engine: &MainEngine, name: &str) -> bool {
with_plugin(engine, name, |p: &T| p.as_configurable().is_some()).unwrap_or(false)
}
#[must_use]
pub fn dm_intervals(engine: &MainEngine) -> Option<Vec<i64>> {
with_plugin(engine, ek_ui_ns_dm(), |p: &ek_dm::plugin::DmPlugin| {
p.intervals_snapshot()
})
}
fn ek_ui_ns_dm() -> &'static str {
NS_DM
}
#[must_use]
pub fn face_of(engine: &MainEngine, name: &str) -> Option<FaceKind> {
if face_probe::<ek_dm::plugin::DmPlugin>(engine, name) {
return Some(FaceKind::Dm);
}
if face_probe::<ek_oms::plugin::OmsPlugin>(engine, name) {
return Some(FaceKind::Oms);
}
if face_probe::<ek_tq::plugin::TqPlugin>(engine, name) {
return Some(FaceKind::Tq);
}
if face_probe::<ek_ctp::plugin::CtpPlugin>(engine, name) {
return Some(FaceKind::Ctp);
}
None
}
#[must_use]
pub fn mounted(engine: &MainEngine) -> Vec<(String, String)> {
let mut out: Vec<(String, String)> = Vec::new();
for name in engine.plugin_names() {
let title = match face_of(engine, &name) {
Some(FaceKind::Dm) => "数据管理器 dm",
Some(FaceKind::Oms) => "统一受理 oms",
Some(FaceKind::Tq) => "天勤桥 tq",
Some(FaceKind::Ctp) => "行情网关 ctp",
None => continue,
};
out.push((name, title.to_string()));
}
out
}
pub fn apply_section(engine: &MainEngine, ns: &str, section: &SectionMap) -> Option<String> {
let rep = match ns {
NS_DM => with_plugin(engine, ns, |p: &ek_dm::plugin::DmPlugin| {
p.as_configurable()?.apply_config(section).ok()
})??,
NS_OMS => with_plugin(engine, ns, |p: &ek_oms::plugin::OmsPlugin| {
p.as_configurable()?.apply_config(section).ok()
})??,
_ => {
let mut found = None;
for name in engine.plugin_names() {
if let Some(kind) = face_of(engine, &name) {
let hit = match kind {
FaceKind::Tq => {
with_plugin(engine, &name, |p: &ek_tq::plugin::TqPlugin| {
let c = p.as_configurable()?;
(c.config_ns() == ns).then(|| c.apply_config(section).ok())
})
}
FaceKind::Ctp => {
with_plugin(engine, &name, |p: &ek_ctp::plugin::CtpPlugin| {
let c = p.as_configurable()?;
(c.config_ns() == ns).then(|| c.apply_config(section).ok())
})
}
_ => None,
};
if let Some(r) = hit.flatten().flatten() {
found = Some(r);
break;
}
}
}
found?
}
};
Some(format!(
"受理 采纳{}/待重启{}",
rep.adopted.len(),
rep.deferred.len()
))
}
pub fn render_face(
ui: &mut egui::Ui,
engine: &MainEngine,
name: &str,
host: &dyn CfgHost,
fs: &mut FaceStates,
) -> bool {
match face_of(engine, name) {
Some(FaceKind::Dm) => {
let Some(hit) = with_plugin(engine, name, |p: &ek_dm::plugin::DmPlugin| {
ek_dm::ui_face::render(ui, p, host, &mut fs.dm)
}) else {
ui.label("dm 壳取不到(未装配?)");
return false;
};
hit
}
Some(FaceKind::Oms) => {
let Some(hit) = with_plugin(engine, name, |p: &ek_oms::plugin::OmsPlugin| {
ek_oms::ui_face::render(ui, p, host, &mut fs.oms)
}) else {
ui.label("oms 壳取不到(未装配?)");
return false;
};
hit
}
Some(FaceKind::Tq) => {
let Some(hit) = with_plugin(engine, name, |p: &ek_tq::plugin::TqPlugin| {
ek_tq::ui_face::render(ui, p, host, &mut fs.tq)
}) else {
ui.label("tq 壳取不到(未装配?)");
return false;
};
hit
}
Some(FaceKind::Ctp) => {
let Some(arc) = engine.plugin_arc(name) else {
ui.label("ctp 壳取不到(未装配?)");
return false;
};
let st = fs.wins.entry(name.to_string()).or_default();
crate::pluginwin::render_window(ui, arc.as_ref(), host, st)
}
None => {
ui.label(format!("{name}:无自带面(不在挂载表)"));
false
}
}
}