325 lines
8.9 KiB
Rust
325 lines
8.9 KiB
Rust
//! # Command - RPC 命令类型系统
|
|
//!
|
|
//! 支持多种类型的命令,每种命令有独立的请求和响应结构。
|
|
//!
|
|
//! ## 设计
|
|
//!
|
|
//! ```text
|
|
//! ┌─────────────────────────────────────────────────────────────┐
|
|
//! │ Command Types │
|
|
//! │ │
|
|
//! │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
//! │ │ Shell │ │ GetInfo │ │ SetVolume │ ... │
|
|
//! │ │ cmd → out │ │ () → Info │ │ vol → () │ │
|
|
//! │ └──────────────┘ └──────────────┘ └──────────────┘ │
|
|
//! │ │
|
|
//! │ ┌──────────────────┐ │
|
|
//! │ │ RpcRequest │ │
|
|
//! │ │ id + Command │ │
|
|
//! │ └────────┬─────────┘ │
|
|
//! │ │ │
|
|
//! │ ▼ │
|
|
//! │ ┌──────────────────┐ │
|
|
//! │ │ RpcResponse │ │
|
|
//! │ │ id + Result │ │
|
|
//! │ └──────────────────┘ │
|
|
//! └─────────────────────────────────────────────────────────────┘
|
|
//! ```
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
// ==================== 命令请求类型 ====================
|
|
|
|
/// Shell 命令请求
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
pub struct ShellRequest {
|
|
/// 要执行的命令
|
|
pub command: String,
|
|
/// 工作目录(可选)
|
|
pub cwd: Option<String>,
|
|
/// 环境变量(可选)
|
|
pub env: Option<Vec<(String, String)>>,
|
|
/// 超时秒数(可选)
|
|
pub timeout_secs: Option<u32>,
|
|
}
|
|
|
|
/// Shell 命令响应
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
|
pub struct ShellResponse {
|
|
pub stdout: String,
|
|
pub stderr: String,
|
|
pub exit_code: i32,
|
|
}
|
|
|
|
/// 获取设备信息请求
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
|
pub struct GetInfoRequest;
|
|
|
|
/// 设备信息响应
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
pub struct DeviceInfo {
|
|
pub model: String,
|
|
pub serial_number: String,
|
|
pub version: String,
|
|
pub uptime_secs: u64,
|
|
pub audio_state: AudioState,
|
|
}
|
|
|
|
/// 音频状态
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
|
pub struct AudioState {
|
|
pub is_recording: bool,
|
|
pub is_playing: bool,
|
|
pub volume: u8,
|
|
}
|
|
|
|
/// 设置音量请求
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
pub struct SetVolumeRequest {
|
|
pub volume: u8, // 0-100
|
|
}
|
|
|
|
/// 设置音量响应
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
pub struct SetVolumeResponse {
|
|
pub previous: u8,
|
|
pub current: u8,
|
|
}
|
|
|
|
/// 文件操作请求
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
pub enum FileRequest {
|
|
/// 读取文件
|
|
Read { path: String },
|
|
/// 写入文件
|
|
Write { path: String, data: Vec<u8> },
|
|
/// 删除文件
|
|
Delete { path: String },
|
|
/// 列出目录
|
|
List { path: String },
|
|
/// 获取文件信息
|
|
Stat { path: String },
|
|
}
|
|
|
|
/// 文件操作响应
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
pub enum FileResponse {
|
|
/// 读取结果
|
|
Data(Vec<u8>),
|
|
/// 写入成功
|
|
Written { bytes: usize },
|
|
/// 删除成功
|
|
Deleted,
|
|
/// 目录列表
|
|
Entries(Vec<FileEntry>),
|
|
/// 文件信息
|
|
Stat(FileStat),
|
|
}
|
|
|
|
/// 文件条目
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
pub struct FileEntry {
|
|
pub name: String,
|
|
pub is_dir: bool,
|
|
pub size: u64,
|
|
}
|
|
|
|
/// 文件状态
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
pub struct FileStat {
|
|
pub size: u64,
|
|
pub is_dir: bool,
|
|
pub modified: u64,
|
|
}
|
|
|
|
/// 系统控制请求
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
pub enum SystemRequest {
|
|
/// 重启
|
|
Reboot,
|
|
/// 关机
|
|
Shutdown,
|
|
/// 获取系统负载
|
|
GetLoad,
|
|
/// 获取内存使用
|
|
GetMemory,
|
|
}
|
|
|
|
/// 系统控制响应
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
pub enum SystemResponse {
|
|
/// 操作已接受
|
|
Accepted,
|
|
/// 系统负载
|
|
Load { one: f32, five: f32, fifteen: f32 },
|
|
/// 内存使用
|
|
Memory { total: u64, used: u64, free: u64 },
|
|
}
|
|
|
|
/// 自定义命令请求(用于扩展)
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
pub struct CustomRequest {
|
|
pub name: String,
|
|
pub payload: Vec<u8>,
|
|
}
|
|
|
|
/// 自定义命令响应
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
pub struct CustomResponse {
|
|
pub payload: Vec<u8>,
|
|
}
|
|
|
|
// ==================== 统一命令枚举 ====================
|
|
|
|
/// RPC 命令 - 统一的请求类型
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
pub enum Command {
|
|
/// 执行 Shell 命令
|
|
Shell(ShellRequest),
|
|
/// 获取设备信息
|
|
GetInfo,
|
|
/// 设置音量
|
|
SetVolume(SetVolumeRequest),
|
|
/// 文件操作
|
|
File(FileRequest),
|
|
/// 系统控制
|
|
System(SystemRequest),
|
|
/// 自定义命令
|
|
Custom(CustomRequest),
|
|
/// Ping(用于测量延迟)
|
|
Ping { timestamp: u64 },
|
|
}
|
|
|
|
/// RPC 结果 - 统一的响应类型
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
pub enum CommandResult {
|
|
/// Shell 命令结果
|
|
Shell(ShellResponse),
|
|
/// 设备信息
|
|
Info(DeviceInfo),
|
|
/// 音量设置结果
|
|
Volume(SetVolumeResponse),
|
|
/// 文件操作结果
|
|
File(FileResponse),
|
|
/// 系统控制结果
|
|
System(SystemResponse),
|
|
/// 自定义命令结果
|
|
Custom(CustomResponse),
|
|
/// Pong 响应
|
|
Pong { timestamp: u64, server_time: u64 },
|
|
/// 错误
|
|
Error(CommandError),
|
|
}
|
|
|
|
/// 命令错误
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
pub struct CommandError {
|
|
pub code: i32,
|
|
pub message: String,
|
|
}
|
|
|
|
impl CommandError {
|
|
pub fn new(code: i32, message: impl Into<String>) -> Self {
|
|
Self {
|
|
code,
|
|
message: message.into(),
|
|
}
|
|
}
|
|
|
|
pub fn not_found(msg: impl Into<String>) -> Self {
|
|
Self::new(-1, msg)
|
|
}
|
|
|
|
pub fn invalid_args(msg: impl Into<String>) -> Self {
|
|
Self::new(-2, msg)
|
|
}
|
|
|
|
pub fn permission_denied(msg: impl Into<String>) -> Self {
|
|
Self::new(-3, msg)
|
|
}
|
|
|
|
pub fn internal(msg: impl Into<String>) -> Self {
|
|
Self::new(-500, msg)
|
|
}
|
|
|
|
pub fn timeout(msg: impl Into<String>) -> Self {
|
|
Self::new(-408, msg)
|
|
}
|
|
|
|
pub fn not_implemented() -> Self {
|
|
Self::new(-501, "Not implemented")
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for CommandError {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "[{}] {}", self.code, self.message)
|
|
}
|
|
}
|
|
|
|
impl std::error::Error for CommandError {}
|
|
|
|
// ==================== 便捷构造方法 ====================
|
|
|
|
impl Command {
|
|
/// 创建 Shell 命令
|
|
pub fn shell(cmd: impl Into<String>) -> Self {
|
|
Self::Shell(ShellRequest {
|
|
command: cmd.into(),
|
|
cwd: None,
|
|
env: None,
|
|
timeout_secs: None,
|
|
})
|
|
}
|
|
|
|
/// 创建带超时的 Shell 命令
|
|
pub fn shell_with_timeout(cmd: impl Into<String>, timeout: u32) -> Self {
|
|
Self::Shell(ShellRequest {
|
|
command: cmd.into(),
|
|
cwd: None,
|
|
env: None,
|
|
timeout_secs: Some(timeout),
|
|
})
|
|
}
|
|
|
|
/// 创建 Ping 命令
|
|
pub fn ping() -> Self {
|
|
Self::Ping {
|
|
timestamp: std::time::SystemTime::now()
|
|
.duration_since(std::time::UNIX_EPOCH)
|
|
.unwrap()
|
|
.as_millis() as u64,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl CommandResult {
|
|
/// 创建成功的 Shell 响应
|
|
pub fn shell_ok(stdout: String) -> Self {
|
|
Self::Shell(ShellResponse {
|
|
stdout,
|
|
stderr: String::new(),
|
|
exit_code: 0,
|
|
})
|
|
}
|
|
|
|
/// 创建错误响应
|
|
pub fn error(err: CommandError) -> Self {
|
|
Self::Error(err)
|
|
}
|
|
|
|
/// 检查是否是错误
|
|
pub fn is_error(&self) -> bool {
|
|
matches!(self, Self::Error(_))
|
|
}
|
|
|
|
/// 获取错误(如果有)
|
|
pub fn as_error(&self) -> Option<&CommandError> {
|
|
match self {
|
|
Self::Error(e) => Some(e),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|