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:
@@ -9,6 +9,7 @@ pub struct Envelope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 消息目的地
|
/// 消息目的地
|
||||||
|
#[derive(Clone)]
|
||||||
pub enum Destination {
|
pub enum Destination {
|
||||||
/// 点对点发送给指定插件
|
/// 点对点发送给指定插件
|
||||||
Plugin(&'static str),
|
Plugin(&'static str),
|
||||||
@@ -19,12 +20,19 @@ pub enum Destination {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 所有插件间通信的类型安全消息
|
/// 所有插件间通信的类型安全消息
|
||||||
|
#[derive(Clone)]
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
// ── 播放控制 ──
|
// ── 播放控制 ──
|
||||||
PlayerCommand(PlayerCommand),
|
PlayerCommand(PlayerCommand),
|
||||||
PlayerStatus(PlayerStatusData),
|
PlayerStatus(PlayerStatusData),
|
||||||
Trigger { name: String, value: String },
|
Trigger {
|
||||||
StateChanged { old_state: String, new_state: String },
|
name: String,
|
||||||
|
value: String,
|
||||||
|
},
|
||||||
|
StateChanged {
|
||||||
|
old_state: String,
|
||||||
|
new_state: String,
|
||||||
|
},
|
||||||
|
|
||||||
// ── 屏幕管理 ──
|
// ── 屏幕管理 ──
|
||||||
ScreenLockRequest(bool),
|
ScreenLockRequest(bool),
|
||||||
@@ -33,7 +41,10 @@ pub enum Message {
|
|||||||
// ── 网络 ──
|
// ── 网络 ──
|
||||||
WifiCommand(WifiCommand),
|
WifiCommand(WifiCommand),
|
||||||
WifiResult(String),
|
WifiResult(String),
|
||||||
WifiProvisioned { ssid: String, ip: String },
|
WifiProvisioned {
|
||||||
|
ssid: String,
|
||||||
|
ip: String,
|
||||||
|
},
|
||||||
|
|
||||||
// ── 配置 ──
|
// ── 配置 ──
|
||||||
ConfigReloaded(Arc<AppConfig>),
|
ConfigReloaded(Arc<AppConfig>),
|
||||||
@@ -44,9 +55,13 @@ pub enum Message {
|
|||||||
PluginReady(&'static str),
|
PluginReady(&'static str),
|
||||||
|
|
||||||
// ── 扩展(未来插件用) ──
|
// ── 扩展(未来插件用) ──
|
||||||
Custom { kind: String, payload: String },
|
Custom {
|
||||||
|
kind: String,
|
||||||
|
payload: String,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub enum PlayerCommand {
|
pub enum PlayerCommand {
|
||||||
Play,
|
Play,
|
||||||
Pause,
|
Pause,
|
||||||
@@ -66,6 +81,7 @@ pub struct PlayerStatusData {
|
|||||||
pub current_video: Option<String>,
|
pub current_video: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub enum WifiCommand {
|
pub enum WifiCommand {
|
||||||
Scan,
|
Scan,
|
||||||
Connect { ssid: String, password: String },
|
Connect { ssid: String, password: String },
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ pub struct ServiceManager {
|
|||||||
config: Arc<AppConfig>,
|
config: Arc<AppConfig>,
|
||||||
tx: mpsc::Sender<Envelope>,
|
tx: mpsc::Sender<Envelope>,
|
||||||
rx: mpsc::Receiver<Envelope>,
|
rx: mpsc::Receiver<Envelope>,
|
||||||
|
running: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServiceManager {
|
impl ServiceManager {
|
||||||
@@ -20,6 +21,7 @@ impl ServiceManager {
|
|||||||
config: Arc::new(config),
|
config: Arc::new(config),
|
||||||
tx,
|
tx,
|
||||||
rx,
|
rx,
|
||||||
|
running: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +53,9 @@ impl ServiceManager {
|
|||||||
/// 主消息循环(阻塞)
|
/// 主消息循环(阻塞)
|
||||||
pub fn run(&mut self) -> Result<()> {
|
pub fn run(&mut self) -> Result<()> {
|
||||||
println!("[ServiceManager] 进入主消息循环");
|
println!("[ServiceManager] 进入主消息循环");
|
||||||
loop {
|
self.running = true;
|
||||||
|
|
||||||
|
while self.running {
|
||||||
let envelope = match self.rx.recv() {
|
let envelope = match self.rx.recv() {
|
||||||
Ok(env) => env,
|
Ok(env) => env,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
@@ -72,19 +76,25 @@ impl ServiceManager {
|
|||||||
}
|
}
|
||||||
Destination::Broadcast => {
|
Destination::Broadcast => {
|
||||||
let from = envelope.from;
|
let from = envelope.from;
|
||||||
|
let msg = envelope.message;
|
||||||
|
|
||||||
for plugin in &mut self.plugins {
|
for plugin in &mut self.plugins {
|
||||||
// 不回送给发送者
|
|
||||||
if plugin.id() == from {
|
if plugin.id() == from {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Broadcast 需要重建 Message(Message 不是 Clone)
|
|
||||||
// 对于 Broadcast 我们跳过非 Shutdown 消息的深拷贝问题
|
if let Err(e) = plugin.handle_message(msg.clone()) {
|
||||||
// 实际实现中 Shutdown 是最关键的广播消息
|
eprintln!(
|
||||||
|
"[ServiceManager] 插件 '{}' 处理广播消息失败: {}",
|
||||||
|
plugin.id(),
|
||||||
|
e
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// 处理 Shutdown
|
}
|
||||||
if matches!(envelope.message, Message::Shutdown) {
|
|
||||||
|
if matches!(msg, Message::Shutdown) {
|
||||||
println!("[ServiceManager] 收到 Shutdown 广播");
|
println!("[ServiceManager] 收到 Shutdown 广播");
|
||||||
break;
|
self.running = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Destination::Manager => {
|
Destination::Manager => {
|
||||||
@@ -113,8 +123,19 @@ impl ServiceManager {
|
|||||||
match msg {
|
match msg {
|
||||||
Message::Shutdown => {
|
Message::Shutdown => {
|
||||||
println!("[ServiceManager] 收到 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 => {
|
Message::ConfigReloadRequest => {
|
||||||
println!("[ServiceManager] 收到配置重载请求");
|
println!("[ServiceManager] 收到配置重载请求");
|
||||||
|
|||||||
Reference in New Issue
Block a user