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.
538 lines
12 KiB
Markdown
538 lines
12 KiB
Markdown
# 后端结构
|
|
|
|
本文档详细介绍 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
|
|
|
|
```rust
|
|
// 启动设备发现服务
|
|
#[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
|
|
|
|
```rust
|
|
// 启动 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
|
|
|
|
```rust
|
|
// 启动 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
|
|
|
|
```rust
|
|
// 获取应用配置
|
|
#[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
|
|
|
|
```rust
|
|
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
|
|
|
|
```rust
|
|
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
|
|
|
|
```rust
|
|
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
|
|
|
|
```rust
|
|
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
|
|
|
|
```rust
|
|
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
|
|
|
|
```rust
|
|
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
|
|
|
|
```rust
|
|
// 文件上传处理
|
|
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
|
|
|
|
```rust
|
|
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
|
|
|
|
```rust
|
|
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
|
|
|
|
```rust
|
|
// 构建服务端 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
|
|
|
|
```rust
|
|
// 初始化数据库表结构
|
|
pub fn init_database(conn: &Connection) -> Result<()>;
|
|
|
|
// 表结构:
|
|
// - chat_messages: 聊天消息
|
|
// - file_transfers: 文件传输记录
|
|
// - known_devices: 已知设备
|
|
// - app_settings: 应用设置
|
|
```
|
|
|
|
#### repository.rs
|
|
|
|
```rust
|
|
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
|
|
|
|
```rust
|
|
#[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
|
|
|
|
```rust
|
|
#[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
|
|
|
|
```rust
|
|
#[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
|
|
|
|
```rust
|
|
// 事件名称常量
|
|
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 模块
|
|
|
|
全局应用状态管理。
|
|
|
|
```rust
|
|
// 全局单例
|
|
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` 定义统一的错误类型:
|
|
|
|
```rust
|
|
#[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/
|
|
```
|