feat: DevicePlugin Task2 — DevicePlugin骨架 + DeviceBackend trait + 模块注册

This commit is contained in:
showen
2026-03-13 06:32:14 +08:00
parent 4d1b830563
commit 584f65b9f5
5 changed files with 313 additions and 0 deletions

View File

@@ -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<DeviceResponse> {
/// // 处理设备命令
/// Ok(DeviceResponse::Ok)
/// }
///
/// fn capabilities(&self) -> Vec<DeviceCapability> {
/// 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<DeviceResponse>;
/// 返回后端支持的设备能力列表
///
/// 用于声明后端支持哪些设备功能,业务插件可以根据此列表
/// 判断是否可以使用某个功能。
///
/// # 返回
/// 支持的设备能力列表(如 Display, Touch, Battery 等)
fn capabilities(&self) -> Vec<DeviceCapability>;
/// 关闭后端
///
/// 在插件停止时调用,用于清理资源、停止子进程等。
///
/// # 返回
/// - `Ok(())`: 关闭成功
/// - `Err(e)`: 关闭失败,包含错误信息
fn shutdown(&mut self) -> Result<()>;
}

135
src/plugins/device/mod.rs Normal file
View File

@@ -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<PluginContext>,
/// 设备后端实现
backend: Box<dyn DeviceBackend>,
}
impl DevicePlugin {
/// 创建新的 DevicePlugin 实例
///
/// # 参数
/// - `backend`: 设备后端实现(如 LinuxArm64Backend
///
/// # 示例
/// ```ignore
/// let backend = Box::new(LinuxArm64Backend::new());
/// let plugin = DevicePlugin::new(backend);
/// ```
pub fn new(backend: Box<dyn DeviceBackend>) -> 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<String> {
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(())
}
}