1use std::sync::Arc;
13
14use ek_cfg::LoadOutcome;
15use ek_cfg::Store as CfgStore;
16use ek_core::cfg_face::CfgHost;
17use ek_core::main_engine::MainEngine;
18use ek_core::plugin::Plugin;
19use ek_core::section::SectionMap;
20
21use crate::pluginwin::WinState;
22use crate::state::UiShared;
23
24const NS_DM: &str = "dm";
27const NS_OMS: &str = "oms";
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub enum FaceKind {
32 Dm,
34 Oms,
36 Tq,
38 Ctp,
40}
41
42pub struct CfgBridge {
44 pub cfg: Option<CfgStore>,
46 pub shared: Arc<UiShared>,
48}
49
50impl CfgBridge {
51 #[must_use]
53 pub fn new(shared: &Arc<UiShared>) -> Self {
54 Self {
55 cfg: CfgStore::eco().ok(),
56 shared: Arc::clone(shared),
57 }
58 }
59}
60
61impl CfgHost for CfgBridge {
62 fn cfg_save(&self, ns: &str, map: &SectionMap) -> Result<(), String> {
63 match &self.cfg {
64 Some(c) => c.store(ns, map).map_err(|e| e.to_string()),
65 None => Err("档案托底根不可用(Store::eco 失败)".to_string()),
66 }
67 }
68
69 fn cfg_load(&self, ns: &str) -> Result<Option<SectionMap>, String> {
70 match &self.cfg {
71 Some(c) => match c.load(ns) {
72 Ok(LoadOutcome::Loaded { map, .. }) => Ok(Some(map)),
73 Ok(LoadOutcome::Fresh) => Ok(None),
74 Err(e) => Err(e.to_string()),
75 },
76 None => Err("档案托底根不可用(Store::eco 失败)".to_string()),
77 }
78 }
79
80 fn log(&self, line: &str) {
81 self.shared.log_line(line);
82 }
83}
84
85#[derive(Default)]
87pub struct FaceStates {
88 pub dm: ek_dm::ui_face::DmUiState,
90 pub oms: ek_oms::ui_face::OmsUiState,
92 pub tq: ek_tq::ui_face::TqUiState,
94 pub wins: std::collections::HashMap<String, WinState>,
96}
97
98impl FaceStates {
99 #[must_use]
101 pub fn new() -> Self {
102 Self::default()
103 }
104}
105
106#[must_use]
108pub fn face_of(engine: &MainEngine, name: &str) -> Option<FaceKind> {
109 if engine
110 .get_typed::<ek_dm::plugin::DmPlugin>(name)
111 .is_some_and(|p| p.as_configurable().is_some())
112 {
113 return Some(FaceKind::Dm);
114 }
115 if engine
116 .get_typed::<ek_oms::plugin::OmsPlugin>(name)
117 .is_some_and(|p| p.as_configurable().is_some())
118 {
119 return Some(FaceKind::Oms);
120 }
121 if engine
122 .get_typed::<ek_tq::plugin::TqPlugin>(name)
123 .is_some_and(|p| p.as_configurable().is_some())
124 {
125 return Some(FaceKind::Tq);
126 }
127 if engine
128 .get_typed::<ek_ctp::plugin::CtpPlugin>(name)
129 .is_some_and(|p| p.as_configurable().is_some())
130 {
131 return Some(FaceKind::Ctp);
132 }
133 None
134}
135
136#[must_use]
138pub fn mounted(engine: &MainEngine) -> Vec<(String, String)> {
139 let mut out: Vec<(String, String)> = Vec::new();
140 for name in engine.plugin_names() {
141 let title = match face_of(engine, &name) {
142 Some(FaceKind::Dm) => "数据管理器 dm",
143 Some(FaceKind::Oms) => "统一受理 oms",
144 Some(FaceKind::Tq) => "天勤桥 tq",
145 Some(FaceKind::Ctp) => "行情网关 ctp",
146 None => continue,
147 };
148 out.push((name, title.to_string()));
149 }
150 out
151}
152
153pub fn apply_section(engine: &MainEngine, ns: &str, section: &SectionMap) -> Option<String> {
156 let rep = match ns {
158 NS_DM => {
159 let p = engine.get_typed::<ek_dm::plugin::DmPlugin>(ns)?;
160 p.as_configurable()?.apply_config(section).ok()?
161 }
162 NS_OMS => {
163 let p = engine.get_typed::<ek_oms::plugin::OmsPlugin>(ns)?;
164 p.as_configurable()?.apply_config(section).ok()?
165 }
166 _ => {
167 let mut found = None;
169 for name in engine.plugin_names() {
170 if let Some(kind) = face_of(engine, &name) {
171 let hit = match kind {
172 FaceKind::Tq => engine
173 .get_typed::<ek_tq::plugin::TqPlugin>(&name)
174 .and_then(|p| {
175 let c = p.as_configurable()?;
176 (c.config_ns() == ns).then(|| c.apply_config(section).ok())
177 }),
178 FaceKind::Ctp => engine
179 .get_typed::<ek_ctp::plugin::CtpPlugin>(&name)
180 .and_then(|p| {
181 let c = p.as_configurable()?;
182 (c.config_ns() == ns).then(|| c.apply_config(section).ok())
183 }),
184 _ => None,
185 };
186 if let Some(Some(r)) = hit {
187 found = Some(r);
188 break;
189 }
190 }
191 }
192 found?
193 }
194 };
195 Some(format!(
196 "受理 采纳{}/待重启{}",
197 rep.adopted.len(),
198 rep.deferred.len()
199 ))
200}
201
202pub fn render_face(
204 ui: &mut egui::Ui,
205 engine: &MainEngine,
206 name: &str,
207 host: &dyn CfgHost,
208 fs: &mut FaceStates,
209) -> bool {
210 match face_of(engine, name) {
211 Some(FaceKind::Dm) => {
212 let Some(p) = engine.get_typed::<ek_dm::plugin::DmPlugin>(name) else {
213 ui.label("dm 壳取不到(未装配?)");
214 return false;
215 };
216 ek_dm::ui_face::render(ui, &p, host, &mut fs.dm)
217 }
218 Some(FaceKind::Oms) => {
219 let Some(p) = engine.get_typed::<ek_oms::plugin::OmsPlugin>(name) else {
220 ui.label("oms 壳取不到(未装配?)");
221 return false;
222 };
223 ek_oms::ui_face::render(ui, &p, host, &mut fs.oms)
224 }
225 Some(FaceKind::Tq) => {
226 let Some(p) = engine.get_typed::<ek_tq::plugin::TqPlugin>(name) else {
227 ui.label("tq 壳取不到(未装配?)");
228 return false;
229 };
230 ek_tq::ui_face::render(ui, &p, host, &mut fs.tq)
231 }
232 Some(FaceKind::Ctp) => {
233 let Some(p) = engine.get_typed::<ek_ctp::plugin::CtpPlugin>(name) else {
234 ui.label("ctp 壳取不到(未装配?)");
235 return false;
236 };
237 let st = fs.wins.entry(name.to_string()).or_default();
238 crate::pluginwin::render_window(ui, p.as_ref(), host, st)
239 }
240 None => {
241 ui.label(format!("{name}:无自带面(不在挂载表)"));
242 false
243 }
244 }
245}