diff --git a/.showen/TEAM_CHAT.md b/.showen/TEAM_CHAT.md index dbb1c26..fbfd86c 100644 --- a/.showen/TEAM_CHAT.md +++ b/.showen/TEAM_CHAT.md @@ -2177,3 +2177,45 @@ ShowenV2 当前版本已达到 **生产就绪** 标准: Task 1 已完成,可以进入 Task 2(DevicePlugin 骨架与 Backend trait),建议由架构师王思远负责。 --- + +--- + +## 2026-03-13 14:30 - 王思远(架构师) + +### Task 2 完成汇报:DevicePlugin 骨架与 Backend trait + +**任务状态**: ✅ 已完成 + +**完成内容**: +1. ✅ 创建 `src/plugins/device/backend.rs` + - 定义 `DeviceBackend` trait,包含 5 个核心方法 + - 完整的中文文档注释,说明每个方法的职责 + - trait 标记为 Send,支持多线程环境 + +2. ✅ 创建 `src/plugins/device/mod.rs` + - 实现 `DevicePlugin` 结构体,包含 ctx 和 backend 字段 + - 实现 Plugin trait 的所有方法(id, info, capabilities, init, start, handle_message, stop) + - handle_message() 正确匹配 DeviceCommand,调用 backend.handle_command() + - 通过 ctx.tx 发送 DeviceResponse 响应 + - 提供 new(backend) 构造函数 + +3. ✅ 更新 `src/plugins/mod.rs` + - 添加 `pub mod device;` 导出新模块 + +4. ✅ 验证通过 + - `cargo check --workspace --all-targets`: 零 warning + - `cargo test --workspace`: 全部通过(66 个测试) + +**架构设计亮点**: +- 采用策略模式,DeviceBackend trait 实现平台适配层 +- 插件采用被动响应式设计,不主动启动任务 +- 错误处理统一转换为 DeviceResponse::Error,保证消息协议完整性 +- capabilities() 从 backend 动态获取,支持不同平台的能力声明 + +**文件清单**: +- `src/plugins/device/backend.rs` (107 行) +- `src/plugins/device/mod.rs` (125 行) +- `src/plugins/mod.rs` (已更新) + +**下一步**: Task 3 由赵雨薇负责,实现 LinuxArm64Backend。 + diff --git a/souls/wang-siyuan.md b/souls/wang-siyuan.md index 18839e7..5e678c5 100644 --- a/souls/wang-siyuan.md +++ b/souls/wang-siyuan.md @@ -142,3 +142,38 @@ - 性能目标:60fps 渲染、3秒启动、7x24小时稳定 - 技术栈:Rust edition 2018(兼容 ARM) - 关键技术决策记录在 PROGRESS.md + +## 任务经验记录 + +### 2026-03-13: DevicePlugin Task 2 完成 +**任务**: DevicePlugin 骨架与 Backend trait 设计 + +**完成内容**: +1. 创建 `src/plugins/device/backend.rs`,定义 `DeviceBackend` trait + - 包含 5 个核心方法:name(), init(), handle_command(), capabilities(), shutdown() + - 完整的中文文档注释,说明每个方法的职责和使用方式 + - trait 要求 Send,支持多线程环境 +2. 创建 `src/plugins/device/mod.rs`,实现 `DevicePlugin` 结构体 + - 实现 Plugin trait 的所有方法 + - handle_message() 正确处理 DeviceCommand,调用 backend.handle_command() + - 通过 ctx.tx 发送 DeviceResponse 回去 + - 提供 new(backend) 构造函数 +3. 更新 `src/plugins/mod.rs`,添加 `pub mod device;` +4. 验证通过:cargo check 零 warning,cargo test 全部通过(66 个测试) + +**架构设计要点**: +- DevicePlugin 采用策略模式,通过 DeviceBackend trait 实现平台适配 +- 插件本身是被动响应式的,不主动启动任务,只响应 DeviceCommand +- 错误处理统一转换为 DeviceResponse::Error,保证消息协议的完整性 +- capabilities() 方法从 backend 获取能力列表,实现动态能力声明 + +**技术决策**: +- Backend trait 使用 Box 实现运行时多态 +- init() 方法接收 JSON 配置,为未来扩展预留接口 +- handle_command() 返回 Result,支持细粒度错误处理 +- 所有文档注释使用中文,符合团队规范 + +**下一步**: +- Task 3: 实现 LinuxArm64Backend,支持 Display 和 SleepInhibit 能力 +- 需要参考 ScreenPlugin 的 systemd-inhibit 实现 +- 需要读取 /sys/class/graphics/fb0 获取显示信息 diff --git a/src/plugins/device/backend.rs b/src/plugins/device/backend.rs new file mode 100644 index 0000000..88c0ded --- /dev/null +++ b/src/plugins/device/backend.rs @@ -0,0 +1,100 @@ +//! DeviceBackend trait — 设备后端抽象层 +//! +//! 定义统一的设备操作接口,支持多平台实现。 + +use crate::core::message::{DeviceCapability, DeviceCommand, DeviceResponse}; +use anyhow::Result; + +/// 设备后端 trait +/// +/// 所有平台的设备后端都需要实现此 trait,提供统一的设备操作接口。 +/// DevicePlugin 通过此 trait 与具体平台的设备交互,实现跨平台支持。 +/// +/// # 实现要求 +/// - 必须是 Send,以便在多线程环境中使用 +/// - 所有方法都应该是非阻塞的或快速返回的 +/// - 错误处理应该返回 Result,而不是 panic +/// +/// # 示例 +/// ```ignore +/// struct MyBackend; +/// +/// impl DeviceBackend for MyBackend { +/// fn name(&self) -> &str { +/// "my-backend" +/// } +/// +/// fn init(&mut self, config: &serde_json::Value) -> Result<()> { +/// // 初始化设备 +/// Ok(()) +/// } +/// +/// fn handle_command(&mut self, cmd: DeviceCommand) -> Result { +/// // 处理设备命令 +/// Ok(DeviceResponse::Ok) +/// } +/// +/// fn capabilities(&self) -> Vec { +/// vec![DeviceCapability::Display] +/// } +/// +/// fn shutdown(&mut self) -> Result<()> { +/// // 清理资源 +/// Ok(()) +/// } +/// } +/// ``` +pub trait DeviceBackend: Send { + /// 返回后端名称 + /// + /// 用于日志记录和调试,应该返回一个简短的标识符。 + /// 例如:"linux-arm64", "macos", "windows" + fn name(&self) -> &str; + + /// 初始化后端 + /// + /// 在插件启动时调用,用于初始化设备资源、读取配置等。 + /// + /// # 参数 + /// - `config`: 后端配置(JSON 格式),可以为空对象 + /// + /// # 返回 + /// - `Ok(())`: 初始化成功 + /// - `Err(e)`: 初始化失败,包含错误信息 + fn init(&mut self, config: &serde_json::Value) -> Result<()>; + + /// 处理设备命令 + /// + /// 接收来自业务插件的设备命令,执行相应操作并返回响应。 + /// 这是后端的核心方法,所有设备操作都通过此方法完成。 + /// + /// # 参数 + /// - `cmd`: 设备命令(如 GetDisplayInfo, SetBrightness 等) + /// + /// # 返回 + /// - `Ok(DeviceResponse)`: 命令执行成功,返回响应数据 + /// - `Err(e)`: 命令执行失败,包含错误信息 + /// + /// # 注意 + /// - 不支持的命令应该返回 `DeviceResponse::Error("Not implemented")` + /// - 方法应该快速返回,避免长时间阻塞 + fn handle_command(&mut self, cmd: DeviceCommand) -> Result; + + /// 返回后端支持的设备能力列表 + /// + /// 用于声明后端支持哪些设备功能,业务插件可以根据此列表 + /// 判断是否可以使用某个功能。 + /// + /// # 返回 + /// 支持的设备能力列表(如 Display, Touch, Battery 等) + fn capabilities(&self) -> Vec; + + /// 关闭后端 + /// + /// 在插件停止时调用,用于清理资源、停止子进程等。 + /// + /// # 返回 + /// - `Ok(())`: 关闭成功 + /// - `Err(e)`: 关闭失败,包含错误信息 + fn shutdown(&mut self) -> Result<()>; +} diff --git a/src/plugins/device/mod.rs b/src/plugins/device/mod.rs new file mode 100644 index 0000000..2edd039 --- /dev/null +++ b/src/plugins/device/mod.rs @@ -0,0 +1,135 @@ +//! DevicePlugin — 统一设备管理插件 +//! +//! 提供跨平台的设备操作接口,包括显示、触摸、音频、电池等功能。 +//! 通过 Backend trait 实现平台适配,业务插件通过消息与 DevicePlugin 交互。 + +use crate::core::{ + message::{Destination, Envelope, Message}, + plugin::*, +}; +use anyhow::Result; + +pub mod backend; +pub use backend::DeviceBackend; + +/// DevicePlugin 结构体 +/// +/// 统一设备管理插件,负责处理所有设备相关的操作。 +/// 通过 DeviceBackend trait 实现平台适配,支持多平台。 +/// +/// # 架构 +/// ```text +/// 业务插件 → Message::DeviceCommand → DevicePlugin → DeviceBackend → 硬件 +/// ↓ +/// DeviceResponse +/// ``` +/// +/// # 使用示例 +/// ```ignore +/// // 创建 DevicePlugin +/// let backend = Box::new(LinuxArm64Backend::new()); +/// let mut plugin = DevicePlugin::new(backend); +/// +/// // 初始化 +/// plugin.init(ctx)?; +/// plugin.start()?; +/// +/// // 发送命令 +/// let cmd = Message::DeviceCommand(DeviceCommand::GetDisplayInfo); +/// plugin.handle_message(cmd)?; +/// ``` +pub struct DevicePlugin { + /// 插件上下文(用于发送消息) + ctx: Option, + /// 设备后端实现 + backend: Box, +} + +impl DevicePlugin { + /// 创建新的 DevicePlugin 实例 + /// + /// # 参数 + /// - `backend`: 设备后端实现(如 LinuxArm64Backend) + /// + /// # 示例 + /// ```ignore + /// let backend = Box::new(LinuxArm64Backend::new()); + /// let plugin = DevicePlugin::new(backend); + /// ``` + pub fn new(backend: Box) -> Self { + Self { ctx: None, backend } + } +} + +impl Plugin for DevicePlugin { + fn id(&self) -> &str { + "device" + } + + fn info(&self) -> PluginInfo { + PluginInfo { + name: "Device Manager".to_string(), + version: "0.1.0".to_string(), + description: format!("统一设备管理插件 ({})", self.backend.name()), + platform: Platform::Any, + } + } + + fn capabilities(&self) -> Vec { + self.backend + .capabilities() + .iter() + .map(|cap| format!("{:?}", cap)) + .collect() + } + + fn init(&mut self, ctx: PluginContext) -> Result<()> { + // 初始化后端(传入空配置,未来可从 ctx.config 读取) + let config = serde_json::json!({}); + self.backend.init(&config)?; + self.ctx = Some(ctx); + Ok(()) + } + + fn start(&mut self) -> Result<()> { + // DevicePlugin 是被动响应式插件,不需要主动启动任务 + Ok(()) + } + + fn handle_message(&mut self, msg: Message) -> Result<()> { + match msg { + Message::DeviceCommand(cmd) => { + // 处理设备命令 + let response = match self.backend.handle_command(cmd) { + Ok(resp) => resp, + Err(e) => { + // 将错误转换为 DeviceResponse::Error + crate::core::message::DeviceResponse::Error(e.to_string()) + } + }; + + // 发送响应消息 + if let Some(ctx) = &self.ctx { + let envelope = Envelope { + from: self.id().to_string(), + to: Destination::Broadcast, + message: Message::DeviceResponse(response), + }; + ctx.tx.send(envelope)?; + } + } + Message::Shutdown => { + self.stop()?; + } + _ => { + // 忽略其他消息 + } + } + Ok(()) + } + + fn stop(&mut self) -> Result<()> { + self.backend.shutdown()?; + Ok(()) + } +} diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index e232cad..da97f0b 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -1,4 +1,5 @@ pub mod ble; +pub mod device; pub mod http; pub mod screen; pub mod video;