core: Message Clone + ServiceManager Broadcast 完整实现

张明远交付:
- Message/PlayerCommand/WifiCommand/Destination 加 derive(Clone)
- Broadcast 分支遍历所有插件转发 msg.clone()
- running 标志控制主循环
- Manager 收到 Shutdown 时先广播给所有插件再停
- cargo check 零 warning

Co-Authored-By: GPT-5.4 <noreply@openai.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
showen
2026-03-12 05:42:53 +08:00
parent b806c71dad
commit 98ba7704dd
2 changed files with 51 additions and 14 deletions

View File

@@ -9,6 +9,7 @@ pub struct Envelope {
}
/// 消息目的地
#[derive(Clone)]
pub enum Destination {
/// 点对点发送给指定插件
Plugin(&'static str),
@@ -19,12 +20,19 @@ pub enum Destination {
}
/// 所有插件间通信的类型安全消息
#[derive(Clone)]
pub enum Message {
// ── 播放控制 ──
PlayerCommand(PlayerCommand),
PlayerStatus(PlayerStatusData),
Trigger { name: String, value: String },
StateChanged { old_state: String, new_state: String },
Trigger {
name: String,
value: String,
},
StateChanged {
old_state: String,
new_state: String,
},
// ── 屏幕管理 ──
ScreenLockRequest(bool),
@@ -33,7 +41,10 @@ pub enum Message {
// ── 网络 ──
WifiCommand(WifiCommand),
WifiResult(String),
WifiProvisioned { ssid: String, ip: String },
WifiProvisioned {
ssid: String,
ip: String,
},
// ── 配置 ──
ConfigReloaded(Arc<AppConfig>),
@@ -44,9 +55,13 @@ pub enum Message {
PluginReady(&'static str),
// ── 扩展(未来插件用) ──
Custom { kind: String, payload: String },
Custom {
kind: String,
payload: String,
},
}
#[derive(Clone)]
pub enum PlayerCommand {
Play,
Pause,
@@ -66,6 +81,7 @@ pub struct PlayerStatusData {
pub current_video: Option<String>,
}
#[derive(Clone)]
pub enum WifiCommand {
Scan,
Connect { ssid: String, password: String },

View File

@@ -10,6 +10,7 @@ pub struct ServiceManager {
config: Arc<AppConfig>,
tx: mpsc::Sender<Envelope>,
rx: mpsc::Receiver<Envelope>,
running: bool,
}
impl ServiceManager {
@@ -20,6 +21,7 @@ impl ServiceManager {
config: Arc::new(config),
tx,
rx,
running: false,
}
}
@@ -51,7 +53,9 @@ impl ServiceManager {
/// 主消息循环(阻塞)
pub fn run(&mut self) -> Result<()> {
println!("[ServiceManager] 进入主消息循环");
loop {
self.running = true;
while self.running {
let envelope = match self.rx.recv() {
Ok(env) => env,
Err(_) => {
@@ -72,19 +76,25 @@ impl ServiceManager {
}
Destination::Broadcast => {
let from = envelope.from;
let msg = envelope.message;
for plugin in &mut self.plugins {
// 不回送给发送者
if plugin.id() == from {
continue;
}
// Broadcast 需要重建 MessageMessage 不是 Clone
// 对于 Broadcast 我们跳过非 Shutdown 消息的深拷贝问题
// 实际实现中 Shutdown 是最关键的广播消息
if let Err(e) = plugin.handle_message(msg.clone()) {
eprintln!(
"[ServiceManager] 插件 '{}' 处理广播消息失败: {}",
plugin.id(),
e
);
}
}
// 处理 Shutdown
if matches!(envelope.message, Message::Shutdown) {
if matches!(msg, Message::Shutdown) {
println!("[ServiceManager] 收到 Shutdown 广播");
break;
self.running = false;
}
}
Destination::Manager => {
@@ -113,8 +123,19 @@ impl ServiceManager {
match msg {
Message::Shutdown => {
println!("[ServiceManager] 收到 Shutdown 指令");
// 通过返回 Err 来退出 run 循环不合适,用标志位
// 实际上 run() 中已经 break 了
let shutdown = Message::Shutdown;
for plugin in &mut self.plugins {
if let Err(e) = plugin.handle_message(shutdown.clone()) {
eprintln!(
"[ServiceManager] 插件 '{}' 处理 Shutdown 失败: {}",
plugin.id(),
e
);
}
}
self.running = false;
}
Message::ConfigReloadRequest => {
println!("[ServiceManager] 收到配置重载请求");