use anyhow::Result; use showen_v2::core::config::AppConfig; use showen_v2::core::plugin_loader::PluginLoader; use showen_v2::core::service_manager::ServiceManager; #[cfg(not(test))] use showen_v2::core::version_manager::VersionManager; use showen_v2::plugins::{ ble::BlePlugin, device::DevicePlugin, http::HttpPlugin, screen::ScreenPlugin, video::VideoPlugin, wifi::WifiPlugin, }; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; fn main() -> Result<()> { // 解析命令行参数 let args: Vec = std::env::args().collect(); // 处理 --validate 参数 if args.contains(&"--validate".to_string()) { let config_path = args .iter() .skip_while(|arg| *arg != "--config") .nth(1) .cloned() .unwrap_or_else(|| "configs/dog_state_machine.json".to_string()); println!("验证配置文件: {}", config_path); let config = AppConfig::from_file(&config_path)?; config.validate_paths()?; println!("✓ 配置文件有效"); return Ok(()); } // 获取配置文件路径 let config_path = args .iter() .skip_while(|arg| *arg != "--config") .nth(1) .cloned() .or_else(|| args.get(1).cloned()) .unwrap_or_else(|| "configs/dog_state_machine.json".to_string()); println!("ShowenV2 — 数字生命窗口平台"); println!("加载配置: {}", config_path); let config = AppConfig::from_file(&config_path)?; config.validate_paths()?; let mut manager = ServiceManager::new(config); // 按依赖顺序注册插件 // 独立插件:device, screen, wifi, video, ble // 依赖插件:http (依赖 video) println!("注册插件..."); manager.register(Box::new(DevicePlugin::new_default())); println!(" ✓ DevicePlugin"); manager.register(Box::new(ScreenPlugin::new())); println!(" ✓ ScreenPlugin"); manager.register(Box::new(WifiPlugin::new())); println!(" ✓ WifiPlugin"); manager.register(Box::new(VideoPlugin::new())); println!(" ✓ VideoPlugin"); manager.register(Box::new(BlePlugin::new())); println!(" ✓ BlePlugin"); manager.register(Box::new(HttpPlugin::new())); println!(" ✓ HttpPlugin"); // 加载动态插件 let plugin_store = std::path::Path::new("plugin_store"); if plugin_store.exists() { println!("扫描动态插件..."); #[cfg(not(test))] manager.set_version_manager(VersionManager::new(PluginLoader::new(plugin_store))); let loader = PluginLoader::new(plugin_store); match loader.load_registry() { Ok(registry) => { for (plugin_id, entry) in ®istry.plugins { if !entry.enabled { println!(" - {plugin_id} (禁用)"); continue; } match loader.load_plugin(plugin_id, Some(&entry.active_version)) { Ok((plugin, manifest)) => { manager.register_dynamic_with_manifest( Box::new(plugin), manifest.error_policy, entry.max_errors, manifest.required_capabilities, manifest.capabilities, manifest.auto_test, ); println!(" ✓ {} v{} (动态)", plugin_id, entry.active_version); } Err(e) => { eprintln!(" ✗ {} v{} 加载失败: {e}", plugin_id, entry.active_version); } } } } Err(e) => { eprintln!("读取插件注册表失败: {e}"); } } } // 设置 Ctrl+C 信号处理 let running = Arc::new(AtomicBool::new(true)); let r = running.clone(); let shutdown_tx = manager.sender(); ctrlc::set_handler(move || { println!("\n收到退出信号,正在关闭..."); r.store(false, Ordering::SeqCst); // 注入 Shutdown 消息,唤醒主消息循环并触发优雅停机 let _ = shutdown_tx.send(showen_v2::core::message::Envelope { from: "signal".to_string(), to: showen_v2::core::message::Destination::Manager, message: showen_v2::core::message::Message::Shutdown, }); })?; println!("启动所有插件..."); manager.start_all()?; println!("ShowenV2 运行中... (按 Ctrl+C 退出)"); // 运行主循环 while running.load(Ordering::SeqCst) { manager.run()?; } println!("正在停止所有插件..."); manager.stop_all()?; println!("ShowenV2 已退出"); Ok(()) }