You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

12 KiB

后端结构

本文档详细介绍 Rust 后端的代码结构、模块功能和核心实现。

目录结构

src-tauri/src/
├── commands/           # Tauri 命令(前端调用入口)
├── discovery/          # UDP 设备发现
├── websocket/          # WebSocket 聊天
├── http/               # HTTP 文件传输
├── tls/                # TLS 加密
├── database/           # SQLite 数据库
├── models/             # 数据模型
├── utils/              # 工具函数
├── state.rs            # 全局状态
├── main.rs             # 程序入口
└── lib.rs              # 库入口

核心模块详解

1. Commands 模块

Tauri 命令是前端与后端通信的桥梁。

discovery_commands.rs

// 启动设备发现服务
#[tauri::command]
pub async fn start_discovery(app: AppHandle) -> CommandResult<()>;

// 停止设备发现服务
#[tauri::command]
pub async fn stop_discovery() -> CommandResult<()>;

// 获取在线设备列表
#[tauri::command]
pub async fn get_online_devices() -> CommandResult<Vec<DeviceInfo>>;

// 获取本机设备信息
#[tauri::command]
pub fn get_local_device() -> CommandResult<DeviceInfo>;

chat_commands.rs

// 启动 WebSocket 服务
#[tauri::command]
pub async fn start_ws_server(app: AppHandle) -> CommandResult<()>;

// 连接到指定设备
#[tauri::command]
pub async fn connect_to_device(device_id: String) -> CommandResult<()>;

// 发送聊天消息
#[tauri::command]
pub async fn send_chat_message(
    device_id: String,
    content: String,
    message_type: String,
) -> CommandResult<ChatMessage>;

// 获取聊天历史
#[tauri::command]
pub async fn get_chat_history(
    device_id: String,
    limit: Option<usize>,
    offset: Option<usize>,
) -> CommandResult<Vec<ChatMessage>>;

file_commands.rs

// 启动 HTTP 文件服务
#[tauri::command]
pub async fn start_http_server(app: AppHandle) -> CommandResult<()>;

// 选择要发送的文件
#[tauri::command]
pub async fn select_file(app: AppHandle) -> CommandResult<Option<FileMetadata>>;

// 发送文件
#[tauri::command]
pub async fn send_file(
    app: AppHandle,
    device_id: String,
    file_id: String,
    file_path: String,
) -> CommandResult<FileTransfer>;

// 取消传输
#[tauri::command]
pub async fn cancel_transfer(file_id: String) -> CommandResult<()>;

// 获取传输历史
#[tauri::command]
pub async fn get_transfer_history(
    device_id: String,
    limit: Option<usize>,
) -> CommandResult<Vec<FileTransfer>>;

// 打开文件位置
#[tauri::command]
pub async fn open_file_location(path: String) -> CommandResult<()>;

config_commands.rs

// 获取应用配置
#[tauri::command]
pub fn get_app_config() -> CommandResult<AppConfig>;

// 更新设备名称
#[tauri::command]
pub async fn update_device_name(name: String) -> CommandResult<()>;

// 更新下载目录
#[tauri::command]
pub fn update_download_dir(path: String) -> CommandResult<()>;

2. Discovery 模块

UDP 广播设备发现服务。

service.rs

pub struct DiscoveryService {
    socket: Arc<UdpSocket>,
    local_device: DeviceInfo,
    running: Arc<AtomicBool>,
}

impl DiscoveryService {
    // 创建服务
    pub async fn new(local_device: DeviceInfo, port: u16) -> Result<Self>;
    
    // 启动广播和监听
    pub async fn start(&self, app: AppHandle);
    
    // 停止服务
    pub fn stop(&self);
    
    // 发送广播
    async fn broadcast(&self);
    
    // 处理收到的消息
    async fn handle_message(&self, data: &[u8], addr: SocketAddr, app: &AppHandle);
}

manager.rs

pub struct DeviceManager {
    devices: DashMap<String, DeviceInfo>,
}

impl DeviceManager {
    // 添加/更新设备
    pub fn add_or_update(&self, device: DeviceInfo);
    
    // 移除设备
    pub fn remove(&self, device_id: &str);
    
    // 获取设备
    pub fn get(&self, device_id: &str) -> Option<DeviceInfo>;
    
    // 获取所有设备
    pub fn get_all(&self) -> Vec<DeviceInfo>;
    
    // 清理过期设备
    pub fn cleanup_stale(&self, max_age: Duration) -> Vec<String>;
}

3. WebSocket 模块

WebSocket 实时聊天服务。

server.rs

pub struct WsServer {
    port: u16,
    running: Arc<AtomicBool>,
}

impl WsServer {
    // 启动服务
    pub async fn start(&self, app: AppHandle, connection_manager: ConnectionManager);
    
    // 处理新连接
    async fn handle_connection(
        stream: TcpStream,
        addr: SocketAddr,
        app: AppHandle,
        connection_manager: ConnectionManager,
    );
}

client.rs

pub struct WsClient;

impl WsClient {
    // 连接到设备
    pub async fn connect(
        device: &DeviceInfo,
        local_device: &DeviceInfo,
        connection_manager: &ConnectionManager,
    ) -> Result<()>;
    
    // 发送消息
    pub async fn send_message(
        connection_manager: &ConnectionManager,
        device_id: &str,
        message: &str,
    ) -> Result<()>;
}

connection.rs

pub struct ConnectionManager {
    // device_id -> write half of WebSocket
    connections: DashMap<String, SplitSink<WebSocketStream<TcpStream>, Message>>,
}

impl ConnectionManager {
    // 添加连接
    pub fn add(&self, device_id: String, sink: SplitSink<...>);
    
    // 移除连接
    pub fn remove(&self, device_id: &str);
    
    // 发送消息
    pub async fn send(&self, device_id: &str, message: &str) -> Result<()>;
    
    // 检查连接状态
    pub fn is_connected(&self, device_id: &str) -> bool;
}

4. HTTP 模块

HTTPS 文件传输服务。

server.rs

pub struct HttpServer {
    port: u16,
}

impl HttpServer {
    // 启动服务
    pub async fn start(&self, app: AppHandle, download_dir: PathBuf) -> Result<()>;
    
    // 创建路由
    fn create_router(app: AppHandle, download_dir: PathBuf) -> Router;
}

handlers.rs

// 文件上传处理
pub async fn upload_handler(
    State(state): State<AppState>,
    mut multipart: Multipart,
) -> impl IntoResponse;

// 文件下载处理
pub async fn download_handler(
    Path(file_id): Path<String>,
    State(state): State<AppState>,
) -> impl IntoResponse;

client.rs

pub struct HttpClient {
    app_handle: Arc<RwLock<Option<AppHandle>>>,
}

impl HttpClient {
    // 上传文件(支持取消)
    pub async fn upload_file_with_cancel(
        &self,
        device: &DeviceInfo,
        file_path: &PathBuf,
        file_id: &str,
        from_device: &str,
        cancel_token: CancellationToken,
    ) -> Result<()>;
    
    // 发送进度事件
    fn emit_progress(&self, file_id: &str, progress: f64, ...);
}

5. TLS 模块

TLS 证书生成和配置。

certificate.rs

pub struct CertificateManager;

impl CertificateManager {
    // 加载或生成证书
    pub fn load_or_generate(data_dir: &Path) -> Result<(Vec<Certificate>, PrivateKey)>;
    
    // 生成自签名证书
    fn generate_self_signed() -> Result<(Certificate, PrivateKey)>;
}

config.rs

// 构建服务端 TLS 配置
pub fn build_server_config(certs: Vec<Certificate>, key: PrivateKey) -> Result<ServerConfig>;

// 构建客户端 TLS 配置(跳过证书验证)
pub fn build_client_config() -> Result<ClientConfig>;

6. Database 模块

SQLite 数据库操作。

schema.rs

// 初始化数据库表结构
pub fn init_database(conn: &Connection) -> Result<()>;

// 表结构:
// - chat_messages: 聊天消息
// - file_transfers: 文件传输记录
// - known_devices: 已知设备
// - app_settings: 应用设置

repository.rs

pub struct Database;

impl Database {
    // 消息操作
    pub fn save_message(message: &ChatMessage) -> Result<()>;
    pub fn get_chat_history(device_id: &str, limit: usize, offset: usize) -> Result<Vec<ChatMessage>>;
    
    // 传输操作
    pub fn save_file_transfer(transfer: &FileTransfer) -> Result<()>;
    pub fn update_transfer_progress(file_id: &str, progress: f64, ...) -> Result<()>;
    pub fn get_transfer_history(device_id: &str, ...) -> Result<Vec<FileTransfer>>;
    
    // 设备操作
    pub fn save_known_device(device: &DeviceInfo) -> Result<()>;
    pub fn get_known_devices() -> Result<Vec<DeviceInfo>>;
    
    // 设置操作
    pub fn get_setting(key: &str) -> Result<Option<String>>;
    pub fn set_setting(key: &str, value: &str) -> Result<()>;
}

7. Models 模块

数据模型定义。

device.rs

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeviceInfo {
    pub device_id: String,      // UUID
    pub device_name: String,    // 显示名称
    pub ip: String,             // IP 地址
    pub ws_port: u16,           // WebSocket 端口
    pub http_port: u16,         // HTTP 端口
    pub last_seen: i64,         // 最后在线时间
}

message.rs

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChatMessage {
    pub id: String,
    pub from_device: String,
    pub to_device: String,
    pub content: String,
    pub message_type: MessageType,
    pub timestamp: i64,
    pub is_read: bool,
}

file_transfer.rs

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FileTransfer {
    pub file_id: String,
    pub name: String,
    pub size: u64,
    pub progress: f64,
    pub status: TransferStatus,
    pub mime_type: Option<String>,
    pub from_device: String,
    pub to_device: String,
    pub local_path: Option<String>,
    pub created_at: i64,
    pub completed_at: Option<i64>,
    pub transferred_bytes: u64,
}

pub enum TransferStatus {
    Pending,
    Transferring,
    Completed,
    Failed,
    Cancelled,
}

events.rs

// 事件名称常量
pub mod event_names {
    pub const DEVICE_FOUND: &str = "device:found";
    pub const DEVICE_LOST: &str = "device:lost";
    pub const CHAT_MESSAGE: &str = "chat:message";
    pub const FILE_PROGRESS: &str = "file:progress";
}

// 传输进度事件
#[derive(Debug, Clone, Serialize)]
pub struct TransferProgressEvent {
    pub file_id: String,
    pub progress: f64,
    pub transferred_bytes: u64,
    pub total_bytes: u64,
    pub status: TransferStatus,
    pub file_name: Option<String>,
    pub local_path: Option<String>,
}

8. State 模块

全局应用状态管理。

// 全局单例
static APP_STATE: OnceCell<Arc<AppStateInner>> = OnceCell::new();

pub struct AppStateInner {
    pub local_device: RwLock<DeviceInfo>,
    pub device_manager: DeviceManager,
    pub discovery_service: RwLock<Option<DiscoveryService>>,
    pub ws_server: RwLock<Option<WsServer>>,
    pub ws_client: RwLock<Option<WsClient>>,
    pub http_server: RwLock<Option<HttpServer>>,
    pub http_client: HttpClient,
    pub connection_manager: ConnectionManager,
    pub app_data_dir: PathBuf,
    pub transfer_cancellation_tokens: RwLock<HashMap<String, CancellationToken>>,
}

pub struct AppState;

impl AppState {
    pub fn init(app_data_dir: PathBuf) -> Result<()>;
    pub fn get() -> Arc<AppStateInner>;
}

错误处理

使用 thiserror 定义统一的错误类型:

#[derive(Debug, thiserror::Error)]
pub enum AppError {
    #[error("IO error: {0}")]
    Io(#[from] std::io::Error),
    
    #[error("Database error: {0}")]
    Database(#[from] rusqlite::Error),
    
    #[error("WebSocket error: {0}")]
    WebSocket(String),
    
    #[error("TLS error: {0}")]
    Tls(String),
    
    #[error("File transfer error: {0}")]
    FileTransfer(String),
    
    #[error("{0}")]
    General(String),
}

依赖关系

main.rs
    └── lib.rs
         ├── commands/
         │    ├── discovery_commands ──▶ discovery/, state
         │    ├── chat_commands ──────▶ websocket/, database/, state
         │    ├── file_commands ──────▶ http/, database/, state
         │    └── config_commands ────▶ utils/, database/
         ├── state ──────────────────▶ models/, discovery/, websocket/, http/
         └── database/ ──────────────▶ models/