use std::sync::Arc;
use std::time::Duration;
use ek_core::main_engine::MainEngine;
use ek_core::plugin::Plugin;
use ek_dm::plugin::DmConfig;
use ek_station::{PlugKind, StationConfig, default_kinds};
use crate::plugin::{UI_NAME, UiPlugin};
use crate::state::UiShared;
pub fn ui_kinds(shared: &Arc<UiShared>, dm_rt: bool) -> Vec<PlugKind> {
let mut kinds: Vec<PlugKind> = default_kinds()
.into_iter()
.filter(|k| k.name != "dm")
.collect();
kinds.push(PlugKind {
name: "dm",
doc: "数据管理器(KlineManager;real_time 更新门开,行情板/K线页取 eBarUpdate./eBar.)",
build: Arc::new(move || -> Arc<dyn Plugin> {
Arc::new(ek_dm::plugin::DmPlugin::new(DmConfig {
real_time: dm_rt,
..DmConfig::minute("dm")
}))
}),
build_named: None,
});
kinds.push(PlugKind {
name: UI_NAME,
doc: "常驻观测界面(eLog + eTimer 1s 快照;关窗即 stop)",
build: {
let shared = Arc::clone(shared);
Arc::new(move || -> Arc<dyn Plugin> { Arc::new(UiPlugin::new(Arc::clone(&shared))) })
},
build_named: None,
});
kinds
}
pub fn spawn_host_watcher(
engine: &Arc<MainEngine>,
shared: &Arc<UiShared>,
) -> std::thread::JoinHandle<()> {
let engine = Arc::clone(engine);
let shared = Arc::clone(shared);
std::thread::spawn(move || {
while !shared.is_stop() {
std::thread::sleep(Duration::from_millis(120));
}
shared.log_line("[host] 窗口关闭,close_all …");
engine.close_all(Duration::from_secs(3));
shared.log_line("[host] 已收场");
})
}
struct StationApp {
shared: Arc<UiShared>,
}
impl eframe::App for StationApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
crate::render_body(ctx, &self.shared);
ctx.request_repaint_after(Duration::from_secs(1));
}
}
#[derive(Debug, Clone)]
pub struct RunOpts {
pub ready_marker: Option<std::path::PathBuf>,
pub dm_rt: bool,
}
impl Default for RunOpts {
fn default() -> Self {
Self {
ready_marker: None,
dm_rt: true,
}
}
}
impl RunOpts {
pub fn plain() -> Self {
Self::default()
}
}
pub fn run_station_ui(cfg: &StationConfig, opts: &RunOpts) -> Result<(), String> {
let engine = Arc::new(MainEngine::new(None));
let shared = Arc::new(UiShared::new());
ek_station::boot(&engine, &ui_kinds(&shared, opts.dm_rt), cfg)
.map_err(|e| format!("boot: {e:?}"))?;
engine.start().map_err(|e| format!("start: {e:?}"))?;
if let Some(marker) = &opts.ready_marker {
use std::io::Write;
if let Ok(mut f) = std::fs::File::create(marker) {
let _ = f.write_all(crate::launch::READY_TEXT.as_bytes());
} else {
eprintln!("ek-ui: ready marker write failed: {}", marker.display());
}
}
let watcher = spawn_host_watcher(&engine, &shared);
let opts = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default()
.with_inner_size([1280.0, 860.0])
.with_title("ek-station"),
..Default::default()
};
let result = eframe::run_native(
"ek-station",
opts,
Box::new(|cc| {
crate::fonts::apply_cjk_fonts(&cc.egui_ctx); Ok(Box::new(StationApp {
shared: Arc::clone(&shared),
}) as Box<dyn eframe::App>)
}),
);
shared.request_stop();
let _ = watcher.join();
result.map_err(|e| format!("ui: {e:?}"))
}