refactor: P2 清理 - 闭环 check_updates 结果回传 + SDK 文档修正 + DeviceResponse 错误留痕
1. service_manager.rs check_plugin_updates: 返回 Vec<(id, cur, new)>,
调用处通过 Custom { kind: "plugin_updates" } 广播结果,闭环 HTTP
调用方获取检查结果的链路 (CLAUDE.md:163 第3项, 王浩然风险3 建议)
2. plugin-sdk/src/lib.rs broadcast 文档: 替换误导性的 WifiProvisioned
示例为 StateChanged (当前真正闭环的消息),并新增 Phase 2 占位消息
说明,列出 WifiProvisioned/DeviceEvent/CursorVisibility 三个当前无
生产者的变体,提醒开发者不要为其编写业务逻辑 (CLAUDE.md:163 第1项)
3. src/plugins/device/mod.rs handle_message: DeviceResponse::Error
转换时补 eprintln 留痕,避免设备层故障完全静默 (CLAUDE.md:163 第4项,
王浩然风险3 建议: 至少在一处记录 Error 响应)
未处理项:
- 单实例保护 (锁文件/socket 互斥): 需目标机实测锁行为,留给设备端工程师
- unclutter 僵尸 reap: 核查发现 shutdown() 已做 kill+wait+pkill 兜底,
仅 SIGKILL 极端场景残留,不值得加 SIGCHLD handler (过度工程)
- CursorVisibility 变体: 删除会破坏示例插件和测试,倾向 Phase 2 统一清理
注: Windows 开发环境缺 dbus/pkg-config, 无法本地 cargo check;
改动经 rust-analyzer 类型检查零诊断, 待目标机验证.
This commit is contained in:
@@ -518,13 +518,22 @@ impl MessageSender {
|
||||
///
|
||||
/// # let sender: MessageSender = unimplemented!();
|
||||
/// sender.broadcast(
|
||||
/// "network",
|
||||
/// Message::WifiProvisioned {
|
||||
/// ssid: "Office-WiFi".to_string(),
|
||||
/// ip: "192.168.1.8".to_string(),
|
||||
/// "video",
|
||||
/// Message::StateChanged {
|
||||
/// old_state: "idle".to_string(),
|
||||
/// new_state: "playing".to_string(),
|
||||
/// },
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// # 注意:Phase 2 占位消息
|
||||
/// 以下消息变体当前在核心代码中**无生产者**,仅作为 Phase 2 占位保留。
|
||||
/// 插件开发者不应在 `handle_message` 中为其编写业务逻辑(写了也不会被触发),
|
||||
/// 也不应主动广播它们(核心不消费):
|
||||
/// - `Message::WifiProvisioned` — WiFi 配网完成事件(待 WiFi 插件补生产者)
|
||||
/// - `Message::DeviceEvent` — 设备事件上报通道(待 DeviceBackend trait 扩展)
|
||||
/// - `Message::CursorVisibility` — 光标可见性(实际链路已改走
|
||||
/// `DeviceCommand::SetCursorVisible`,此变体仅为向后兼容保留)
|
||||
pub fn broadcast(&self, from: &str, message: Message) {
|
||||
self.send(&Envelope {
|
||||
from: from.to_string(),
|
||||
|
||||
@@ -730,16 +730,24 @@ impl ServiceManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_plugin_updates(&self) -> Result<()> {
|
||||
fn check_plugin_updates(&self) -> Result<Vec<(String, String, String)>> {
|
||||
let repo = self.plugin_repository()?;
|
||||
let registry = self.plugin_loader()?.load_registry()?;
|
||||
let mut updates = Vec::new();
|
||||
|
||||
for (plugin_id, entry) in ®istry.plugins {
|
||||
match repo.check_update(plugin_id, &entry.active_version)? {
|
||||
Some(version) => println!(
|
||||
"[ServiceManager] 插件 '{plugin_id}' 发现可用更新: {} -> {version}",
|
||||
entry.active_version
|
||||
),
|
||||
Some(version) => {
|
||||
println!(
|
||||
"[ServiceManager] 插件 '{plugin_id}' 发现可用更新: {} -> {version}",
|
||||
entry.active_version
|
||||
);
|
||||
updates.push((
|
||||
plugin_id.clone(),
|
||||
entry.active_version.clone(),
|
||||
version,
|
||||
));
|
||||
}
|
||||
None => println!(
|
||||
"[ServiceManager] 插件 '{plugin_id}' 已是最新版本 {}",
|
||||
entry.active_version
|
||||
@@ -747,7 +755,7 @@ impl ServiceManager {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(updates)
|
||||
}
|
||||
|
||||
fn broadcast_plugin_states(&mut self) {
|
||||
@@ -865,8 +873,30 @@ impl ServiceManager {
|
||||
true
|
||||
}
|
||||
"plugin_check_updates" => {
|
||||
if let Err(error) = self.check_plugin_updates() {
|
||||
eprintln!("[ServiceManager] plugin_check_updates 失败: {error}");
|
||||
match self.check_plugin_updates() {
|
||||
Ok(updates) => {
|
||||
// 将检查结果通过 Custom 消息广播,供 HTTP 客户端等消费方获取
|
||||
let payload = serde_json::to_string(
|
||||
&updates
|
||||
.iter()
|
||||
.map(|(id, cur, new)| {
|
||||
serde_json::json!({
|
||||
"id": id,
|
||||
"current_version": cur,
|
||||
"available_version": new,
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.unwrap_or_else(|_| "[]".to_string());
|
||||
self.broadcast_message(Message::Custom {
|
||||
kind: "plugin_updates".to_string(),
|
||||
payload,
|
||||
});
|
||||
}
|
||||
Err(error) => {
|
||||
eprintln!("[ServiceManager] plugin_check_updates 失败: {error}");
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
@@ -121,7 +121,10 @@ impl Plugin for DevicePlugin {
|
||||
let response = match self.backend.handle_command(cmd) {
|
||||
Ok(resp) => resp,
|
||||
Err(e) => {
|
||||
// 将错误转换为 DeviceResponse::Error
|
||||
// 将错误转换为 DeviceResponse::Error,并记录日志
|
||||
// (核心静态插件目前无人消费 DeviceResponse,故至少在此留痕,
|
||||
// 避免设备层故障完全静默——王浩然风险3 建议)
|
||||
eprintln!("[DevicePlugin] 命令处理失败: {e}");
|
||||
crate::core::message::DeviceResponse::Error(e.to_string())
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user