refactor: 删除部分多余的代码和注释

This commit is contained in:
mofeng-git
2026-05-01 17:31:04 +08:00
parent 74035f8e12
commit d8e7de74a6
165 changed files with 2960 additions and 9917 deletions

View File

@@ -1,13 +1,10 @@
//! 配置热重载逻辑
//!
//! 从 handlers.rs 中抽取的配置应用函数,负责将配置变更应用到各个子系统。
use std::sync::Arc;
use crate::config::*;
use crate::error::{AppError, Result};
use crate::rtsp::RtspService;
use crate::state::AppState;
use crate::stream_encoder::encoder_type_to_backend;
use crate::video::codec_constraints::{
enforce_constraints_with_stream_manager, StreamCodecConstraints,
};
@@ -32,13 +29,11 @@ async fn reconcile_otg_from_store(state: &Arc<AppState>) -> Result<()> {
.map_err(|e| AppError::Config(format!("OTG reconcile failed: {}", e)))
}
/// 应用 Video 配置变更
pub async fn apply_video_config(
state: &Arc<AppState>,
old_config: &VideoConfig,
new_config: &VideoConfig,
) -> Result<()> {
// 检查配置是否实际变更
if old_config == new_config {
tracing::info!("Video config unchanged, skipping reload");
return Ok(());
@@ -74,7 +69,6 @@ pub async fn apply_video_config(
Ok(())
}
/// 应用 Stream 配置变更
pub async fn apply_stream_config(
state: &Arc<AppState>,
old_config: &StreamConfig,
@@ -82,32 +76,24 @@ pub async fn apply_stream_config(
) -> Result<()> {
tracing::info!("Applying stream config changes...");
// 更新编码器后端
if old_config.encoder != new_config.encoder {
let encoder_backend = new_config.encoder.to_backend();
let encoder_backend = encoder_type_to_backend(new_config.encoder.clone());
tracing::info!(
"Updating encoder backend to: {:?} (from config: {:?})",
encoder_backend,
new_config.encoder
);
state
.stream_manager
.webrtc_streamer()
.update_encoder_backend(encoder_backend)
.await;
state.webrtc.update_encoder_backend(encoder_backend).await;
}
// 更新码率
if old_config.bitrate_preset != new_config.bitrate_preset {
state
.stream_manager
.webrtc_streamer()
.set_bitrate_preset(new_config.bitrate_preset)
.await
.ok(); // Ignore error if no active stream
}
// 更新 ICE 配置 (STUN/TURN)
let ice_changed = old_config.stun_server != new_config.stun_server
|| old_config.turn_server != new_config.turn_server
|| old_config.turn_username != new_config.turn_username
@@ -120,8 +106,7 @@ pub async fn apply_stream_config(
new_config.turn_server
);
state
.stream_manager
.webrtc_streamer()
.webrtc
.update_ice_config(
new_config.stun_server.clone(),
new_config.turn_server.clone(),
@@ -139,7 +124,6 @@ pub async fn apply_stream_config(
Ok(())
}
/// 应用 HID 配置变更
pub async fn apply_hid_config(
state: &Arc<AppState>,
old_config: &HidConfig,
@@ -202,7 +186,6 @@ pub async fn apply_hid_config(
Ok(())
}
/// 应用 MSD 配置变更
pub async fn apply_msd_config(
state: &Arc<AppState>,
old_config: &MsdConfig,
@@ -218,7 +201,6 @@ pub async fn apply_msd_config(
tracing::debug!("Old MSD config: {:?}", old_config);
tracing::debug!("New MSD config: {:?}", new_config);
// Check if MSD enabled state changed
let old_msd_enabled = old_config.enabled;
let new_msd_enabled = new_config.enabled;
let msd_dir_changed = old_config.msd_dir != new_config.msd_dir;
@@ -232,7 +214,6 @@ pub async fn apply_msd_config(
tracing::info!("MSD directory changed: {}", new_config.msd_dir);
}
// Ensure MSD directories exist (msd/images, msd/ventoy)
let msd_dir = new_config.msd_dir_path();
if let Err(e) = std::fs::create_dir_all(msd_dir.join("images")) {
tracing::warn!("Failed to create MSD images directory: {}", e);
@@ -255,7 +236,6 @@ pub async fn apply_msd_config(
reconcile_otg_from_store(state).await?;
// Shutdown existing controller if present
let mut msd_guard = state.msd.write().await;
if let Some(msd) = msd_guard.as_mut() {
if let Err(e) = msd.shutdown().await {
@@ -271,15 +251,12 @@ pub async fn apply_msd_config(
.await
.map_err(|e| AppError::Config(format!("MSD initialization failed: {}", e)))?;
// Set event bus
let events = state.events.clone();
msd.set_event_bus(events).await;
// Store the initialized controller
*state.msd.write().await = Some(msd);
tracing::info!("MSD initialized successfully");
} else {
// MSD disabled - shutdown
tracing::info!("MSD disabled in config, shutting down...");
let mut msd_guard = state.msd.write().await;
@@ -306,7 +283,6 @@ pub async fn apply_msd_config(
Ok(())
}
/// 应用 ATX 配置变更
pub async fn apply_atx_config(
state: &Arc<AppState>,
_old_config: &AtxConfig,
@@ -314,10 +290,8 @@ pub async fn apply_atx_config(
) -> Result<()> {
tracing::info!("Applying ATX config changes...");
// Convert AtxConfig to AtxControllerConfig
let controller_config = new_config.to_controller_config();
// Reload the ATX controller with new configuration
let atx_guard = state.atx.read().await;
if let Some(atx) = atx_guard.as_ref() {
if let Err(e) = atx.reload(controller_config).await {
@@ -326,7 +300,6 @@ pub async fn apply_atx_config(
}
tracing::info!("ATX controller reloaded successfully");
} else {
// ATX controller not initialized, create a new one if enabled
drop(atx_guard);
if new_config.enabled {
@@ -345,7 +318,6 @@ pub async fn apply_atx_config(
Ok(())
}
/// 应用 Audio 配置变更
pub async fn apply_audio_config(
state: &Arc<AppState>,
_old_config: &AudioConfig,
@@ -353,17 +325,14 @@ pub async fn apply_audio_config(
) -> Result<()> {
tracing::info!("Applying audio config changes...");
// Create audio controller config from new config
let audio_config = crate::audio::AudioControllerConfig {
enabled: new_config.enabled,
device: new_config.device.clone(),
quality: crate::audio::AudioQuality::from_str(&new_config.quality),
quality: new_config.quality.parse::<crate::audio::AudioQuality>()?,
};
// Update audio controller
if let Err(e) = state.audio.update_config(audio_config).await {
tracing::error!("Audio config update failed: {}", e);
// Don't fail - audio errors are not critical
} else {
tracing::info!(
"Audio config applied: enabled={}, device={}",
@@ -372,7 +341,6 @@ pub async fn apply_audio_config(
);
}
// Also update WebRTC audio enabled state
if let Err(e) = state
.stream_manager
.set_webrtc_audio_enabled(new_config.enabled)
@@ -383,7 +351,6 @@ pub async fn apply_audio_config(
tracing::info!("WebRTC audio enabled: {}", new_config.enabled);
}
// Reconnect audio sources for existing WebRTC sessions
if new_config.enabled {
state.stream_manager.reconnect_webrtc_audio_sources().await;
}
@@ -391,7 +358,6 @@ pub async fn apply_audio_config(
Ok(())
}
/// Apply stream codec constraints derived from global config.
pub async fn enforce_stream_codec_constraints(state: &Arc<AppState>) -> Result<Option<String>> {
let config = state.config.get();
let constraints = StreamCodecConstraints::from_config(&config);
@@ -400,7 +366,6 @@ pub async fn enforce_stream_codec_constraints(state: &Arc<AppState>) -> Result<O
Ok(enforcement.message)
}
/// 应用 RustDesk 配置变更
pub async fn apply_rustdesk_config(
state: &Arc<AppState>,
old_config: &crate::rustdesk::config::RustDeskConfig,
@@ -411,9 +376,7 @@ pub async fn apply_rustdesk_config(
let mut rustdesk_guard = state.rustdesk.write().await;
let mut credentials_to_save = None;
// Check if service needs to be stopped
if old_config.enabled && !new_config.enabled {
// Disable service
if let Some(ref service) = *rustdesk_guard {
if let Err(e) = service.stop().await {
tracing::error!("Failed to stop RustDesk service: {}", e);
@@ -423,14 +386,12 @@ pub async fn apply_rustdesk_config(
*rustdesk_guard = None;
}
// Check if service needs to be started or restarted
if new_config.enabled {
let need_restart = old_config.rendezvous_server != new_config.rendezvous_server
|| old_config.device_id != new_config.device_id
|| old_config.device_password != new_config.device_password;
if rustdesk_guard.is_none() {
// Create new service
tracing::info!("Initializing RustDesk service...");
let service = crate::rustdesk::RustDeskService::new(
new_config.clone(),
@@ -442,12 +403,10 @@ pub async fn apply_rustdesk_config(
tracing::error!("Failed to start RustDesk service: {}", e);
} else {
tracing::info!("RustDesk service started with ID: {}", new_config.device_id);
// Save generated keypair and UUID to config
credentials_to_save = service.save_credentials();
}
*rustdesk_guard = Some(std::sync::Arc::new(service));
} else if need_restart {
// Restart existing service with new config
if let Some(ref service) = *rustdesk_guard {
if let Err(e) = service.restart(new_config.clone()).await {
tracing::error!("Failed to restart RustDesk service: {}", e);
@@ -456,14 +415,12 @@ pub async fn apply_rustdesk_config(
"RustDesk service restarted with ID: {}",
new_config.device_id
);
// Save generated keypair and UUID to config
credentials_to_save = service.save_credentials();
}
}
}
}
// Save credentials to persistent config store (outside the lock)
drop(rustdesk_guard);
if let Some(updated_config) = credentials_to_save {
tracing::info!("Saving RustDesk credentials to config store...");
@@ -491,7 +448,6 @@ pub async fn apply_rustdesk_config(
Ok(())
}
/// 应用 RTSP 配置变更
pub async fn apply_rtsp_config(
state: &Arc<AppState>,
old_config: &RtspConfig,

View File

@@ -1,5 +1,3 @@
//! ATX configuration handlers
use axum::{extract::State, Json};
use std::sync::Arc;
@@ -11,29 +9,23 @@ use crate::state::AppState;
use super::apply::apply_atx_config;
use super::types::AtxConfigUpdate;
/// Get ATX configuration
pub async fn get_atx_config(State(state): State<Arc<AppState>>) -> Json<AtxConfig> {
Json(state.config.get().atx.clone())
}
/// Update ATX configuration
pub async fn update_atx_config(
State(state): State<Arc<AppState>>,
Json(req): Json<AtxConfigUpdate>,
) -> Result<Json<AtxConfig>> {
// 1. Read current configuration snapshot
let current_config = state.config.get();
let old_atx_config = current_config.atx.clone();
// 2. Validate request, including merged effective serial parameter checks
req.validate_with_current(&old_atx_config)?;
// 3. Ensure ATX serial devices do not conflict with HID CH9329 serial device
let mut merged_atx_config = old_atx_config.clone();
req.apply_to(&mut merged_atx_config);
validate_serial_device_conflict(&merged_atx_config, &current_config.hid)?;
// 4. Persist update into config store
state
.config
.update(|config| {
@@ -41,10 +33,8 @@ pub async fn update_atx_config(
})
.await?;
// 5. Load new config
let new_atx_config = state.config.get().atx.clone();
// 6. Apply to subsystem (hot reload)
if let Err(e) = apply_atx_config(&state, &old_atx_config, &new_atx_config).await {
tracing::error!("Failed to apply ATX config: {}", e);
}

View File

@@ -1,5 +1,3 @@
//! Audio 配置 Handler
use axum::{extract::State, Json};
use std::sync::Arc;
@@ -10,23 +8,18 @@ use crate::state::AppState;
use super::apply::apply_audio_config;
use super::types::AudioConfigUpdate;
/// 获取 Audio 配置
pub async fn get_audio_config(State(state): State<Arc<AppState>>) -> Json<AudioConfig> {
Json(state.config.get().audio.clone())
}
/// 更新 Audio 配置
pub async fn update_audio_config(
State(state): State<Arc<AppState>>,
Json(req): Json<AudioConfigUpdate>,
) -> Result<Json<AudioConfig>> {
// 1. 验证请求
req.validate()?;
// 2. 获取旧配置
let old_audio_config = state.config.get().audio.clone();
// 3. 应用更新到配置存储
state
.config
.update(|config| {
@@ -34,10 +27,8 @@ pub async fn update_audio_config(
})
.await?;
// 4. 获取新配置
let new_audio_config = state.config.get().audio.clone();
// 5. 应用到子系统(热重载)
if let Err(e) = apply_audio_config(&state, &old_audio_config, &new_audio_config).await {
tracing::error!("Failed to apply audio config: {}", e);
}

View File

@@ -14,7 +14,6 @@ pub async fn get_auth_config(State(state): State<Arc<AppState>>) -> Json<AuthCon
Json(auth)
}
/// Update auth configuration
pub async fn update_auth_config(
State(state): State<Arc<AppState>>,
Json(update): Json<AuthConfigUpdate>,

View File

@@ -1,5 +1,3 @@
//! HID 配置 Handler
use axum::{extract::State, Json};
use std::sync::Arc;
@@ -10,23 +8,18 @@ use crate::state::AppState;
use super::apply::apply_hid_config;
use super::types::HidConfigUpdate;
/// 获取 HID 配置
pub async fn get_hid_config(State(state): State<Arc<AppState>>) -> Json<HidConfig> {
Json(state.config.get().hid.clone())
}
/// 更新 HID 配置
pub async fn update_hid_config(
State(state): State<Arc<AppState>>,
Json(req): Json<HidConfigUpdate>,
) -> Result<Json<HidConfig>> {
// 1. 验证请求
req.validate()?;
// 2. 获取旧配置
let old_hid_config = state.config.get().hid.clone();
// 3. 应用更新到配置存储
state
.config
.update(|config| {
@@ -34,10 +27,8 @@ pub async fn update_hid_config(
})
.await?;
// 4. 获取新配置
let new_hid_config = state.config.get().hid.clone();
// 5. 应用到子系统(热重载)
if let Err(e) = apply_hid_config(&state, &old_hid_config, &new_hid_config).await {
tracing::error!("Failed to apply HID config: {}", e);
}

View File

@@ -1,21 +1,3 @@
//! 配置管理 Handler 模块
//!
//! 提供 RESTful 域分离的配置 API
//! - GET /api/config/video - 获取视频配置
//! - PATCH /api/config/video - 更新视频配置
//! - GET /api/config/stream - 获取流配置
//! - PATCH /api/config/stream - 更新流配置
//! - GET /api/config/hid - 获取 HID 配置
//! - PATCH /api/config/hid - 更新 HID 配置
//! - GET /api/config/msd - 获取 MSD 配置
//! - PATCH /api/config/msd - 更新 MSD 配置
//! - GET /api/config/atx - 获取 ATX 配置
//! - PATCH /api/config/atx - 更新 ATX 配置
//! - GET /api/config/audio - 获取音频配置
//! - PATCH /api/config/audio - 更新音频配置
//! - GET /api/config/rustdesk - 获取 RustDesk 配置
//! - PATCH /api/config/rustdesk - 更新 RustDesk 配置
pub(crate) mod apply;
mod types;
@@ -30,7 +12,6 @@ mod stream;
pub(crate) mod video;
mod web;
// 导出 handler 函数
pub use atx::{get_atx_config, update_atx_config};
pub use audio::{get_audio_config, update_audio_config};
pub use auth::{get_auth_config, update_auth_config};
@@ -45,7 +26,6 @@ pub use stream::{get_stream_config, update_stream_config};
pub use video::{get_video_config, update_video_config};
pub use web::{get_web_config, update_web_config};
// 保留全局配置查询(向后兼容)
use axum::{extract::State, Json};
use std::sync::Arc;
@@ -53,13 +33,10 @@ use crate::config::AppConfig;
use crate::state::AppState;
fn sanitize_config_for_api(config: &mut AppConfig) {
// Auth secrets
config.auth.totp_secret = None;
// Stream secrets
config.stream.turn_password = None;
// RustDesk secrets
config.rustdesk.device_password.clear();
config.rustdesk.relay_key = None;
config.rustdesk.public_key = None;
@@ -67,14 +44,11 @@ fn sanitize_config_for_api(config: &mut AppConfig) {
config.rustdesk.signing_public_key = None;
config.rustdesk.signing_private_key = None;
// RTSP secrets
config.rtsp.password = None;
}
/// 获取完整配置
pub async fn get_all_config(State(state): State<Arc<AppState>>) -> Json<AppConfig> {
let mut config = (*state.config.get()).clone();
// 不暴露敏感信息
sanitize_config_for_api(&mut config);
Json(config)
}

View File

@@ -1,5 +1,3 @@
//! MSD 配置 Handler
use axum::{extract::State, Json};
use std::sync::Arc;
@@ -10,23 +8,18 @@ use crate::state::AppState;
use super::apply::apply_msd_config;
use super::types::MsdConfigUpdate;
/// 获取 MSD 配置
pub async fn get_msd_config(State(state): State<Arc<AppState>>) -> Json<MsdConfig> {
Json(state.config.get().msd.clone())
}
/// 更新 MSD 配置
pub async fn update_msd_config(
State(state): State<Arc<AppState>>,
Json(req): Json<MsdConfigUpdate>,
) -> Result<Json<MsdConfig>> {
// 1. 验证请求
req.validate()?;
// 2. 获取旧配置
let old_msd_config = state.config.get().msd.clone();
// 3. 应用更新到配置存储
state
.config
.update(|config| {
@@ -34,10 +27,8 @@ pub async fn update_msd_config(
})
.await?;
// 4. 获取新配置
let new_msd_config = state.config.get().msd.clone();
// 5. 应用到子系统(热重载)
if let Err(e) = apply_msd_config(&state, &old_msd_config, &new_msd_config).await {
tracing::error!("Failed to apply MSD config: {}", e);
}

View File

@@ -7,13 +7,11 @@ use crate::state::AppState;
use super::apply::apply_rtsp_config;
use super::types::{RtspConfigResponse, RtspConfigUpdate, RtspStatusResponse};
/// Get RTSP config
pub async fn get_rtsp_config(State(state): State<Arc<AppState>>) -> Json<RtspConfigResponse> {
let config = state.config.get();
Json(RtspConfigResponse::from(&config.rtsp))
}
/// Get RTSP status (config + service status)
pub async fn get_rtsp_status(State(state): State<Arc<AppState>>) -> Json<RtspStatusResponse> {
let config = state.config.get().rtsp.clone();
let status = {
@@ -28,7 +26,6 @@ pub async fn get_rtsp_status(State(state): State<Arc<AppState>>) -> Json<RtspSta
Json(RtspStatusResponse::new(&config, status))
}
/// Update RTSP config
pub async fn update_rtsp_config(
State(state): State<Arc<AppState>>,
Json(req): Json<RtspConfigUpdate>,

View File

@@ -1,5 +1,3 @@
//! RustDesk 配置 Handler
use axum::{extract::State, Json};
use std::sync::Arc;
@@ -10,18 +8,14 @@ use crate::state::AppState;
use super::apply::apply_rustdesk_config;
use super::types::RustDeskConfigUpdate;
/// RustDesk 配置响应(隐藏敏感信息)
#[derive(Debug, serde::Serialize)]
pub struct RustDeskConfigResponse {
pub enabled: bool,
pub rendezvous_server: String,
pub relay_server: Option<String>,
pub device_id: String,
/// 是否已设置密码
pub has_password: bool,
/// 是否已设置密钥对
pub has_keypair: bool,
/// 是否已设置 relay key
pub has_relay_key: bool,
}
@@ -39,7 +33,6 @@ impl From<&RustDeskConfig> for RustDeskConfigResponse {
}
}
/// RustDesk 状态响应
#[derive(Debug, serde::Serialize)]
pub struct RustDeskStatusResponse {
pub config: RustDeskConfigResponse,
@@ -47,20 +40,17 @@ pub struct RustDeskStatusResponse {
pub rendezvous_status: Option<String>,
}
/// 获取 RustDesk 配置
pub async fn get_rustdesk_config(
State(state): State<Arc<AppState>>,
) -> Json<RustDeskConfigResponse> {
Json(RustDeskConfigResponse::from(&state.config.get().rustdesk))
}
/// 获取 RustDesk 完整状态(配置 + 服务状态)
pub async fn get_rustdesk_status(
State(state): State<Arc<AppState>>,
) -> Json<RustDeskStatusResponse> {
let config = state.config.get().rustdesk.clone();
// 获取服务状态
let (service_status, rendezvous_status) = {
let guard = state.rustdesk.read().await;
if let Some(ref service) = *guard {
@@ -79,18 +69,14 @@ pub async fn get_rustdesk_status(
})
}
/// 更新 RustDesk 配置
pub async fn update_rustdesk_config(
State(state): State<Arc<AppState>>,
Json(req): Json<RustDeskConfigUpdate>,
) -> Result<Json<RustDeskConfigResponse>> {
// 1. 验证请求
req.validate()?;
// 2. 获取旧配置
let old_config = state.config.get().rustdesk.clone();
// 3. 应用更新到配置存储
state
.config
.update(|config| {
@@ -98,15 +84,12 @@ pub async fn update_rustdesk_config(
})
.await?;
// 4. 获取新配置
let new_config = state.config.get().rustdesk.clone();
// 5. 应用到子系统(热重载)
if let Err(e) = apply_rustdesk_config(&state, &old_config, &new_config).await {
tracing::error!("Failed to apply RustDesk config: {}", e);
}
// Share a non-sensitive summary for frontend UX
let constraints = state.stream_manager.codec_constraints().await;
if constraints.rustdesk_enabled || constraints.rtsp_enabled {
tracing::info!(
@@ -118,7 +101,6 @@ pub async fn update_rustdesk_config(
Ok(Json(RustDeskConfigResponse::from(&new_config)))
}
/// 重新生成设备 ID
pub async fn regenerate_device_id(
State(state): State<Arc<AppState>>,
) -> Result<Json<RustDeskConfigResponse>> {
@@ -133,7 +115,6 @@ pub async fn regenerate_device_id(
Ok(Json(RustDeskConfigResponse::from(&new_config)))
}
/// 重新生成设备密码
pub async fn regenerate_device_password(
State(state): State<Arc<AppState>>,
) -> Result<Json<RustDeskConfigResponse>> {
@@ -148,7 +129,6 @@ pub async fn regenerate_device_password(
Ok(Json(RustDeskConfigResponse::from(&new_config)))
}
/// 获取设备密码(已认证用户)
pub async fn get_device_password(State(state): State<Arc<AppState>>) -> Json<serde_json::Value> {
let config = state.config.get().rustdesk.clone();
Json(serde_json::json!({

View File

@@ -1,5 +1,3 @@
//! Stream 配置 Handler
use axum::{extract::State, Json};
use std::sync::Arc;
@@ -9,24 +7,19 @@ use crate::state::AppState;
use super::apply::apply_stream_config;
use super::types::{StreamConfigResponse, StreamConfigUpdate};
/// 获取 Stream 配置
pub async fn get_stream_config(State(state): State<Arc<AppState>>) -> Json<StreamConfigResponse> {
let config = state.config.get();
Json(StreamConfigResponse::from(&config.stream))
}
/// 更新 Stream 配置
pub async fn update_stream_config(
State(state): State<Arc<AppState>>,
Json(req): Json<StreamConfigUpdate>,
) -> Result<Json<StreamConfigResponse>> {
// 1. 验证请求
req.validate()?;
// 2. 获取旧配置
let old_stream_config = state.config.get().stream.clone();
// 3. 应用更新到配置存储
state
.config
.update(|config| {
@@ -34,15 +27,12 @@ pub async fn update_stream_config(
})
.await?;
// 4. 获取新配置
let new_stream_config = state.config.get().stream.clone();
// 5. 应用到子系统(热重载)
if let Err(e) = apply_stream_config(&state, &old_stream_config, &new_stream_config).await {
tracing::error!("Failed to apply stream config: {}", e);
}
// 6. Enforce codec constraints after any stream config update
if let Err(e) = super::apply::enforce_stream_codec_constraints(&state).await {
tracing::error!("Failed to enforce stream codec constraints: {}", e);
}

View File

@@ -2,13 +2,11 @@ use crate::config::*;
use crate::error::AppError;
use crate::rtsp::RtspServiceStatus;
use crate::rustdesk::config::RustDeskConfig;
use crate::video::encoder::BitratePreset;
use base64::{engine::general_purpose::STANDARD, Engine as _};
use serde::{Deserialize, Serialize};
use std::path::Path;
use typeshare::typeshare;
// ===== Auth Config =====
#[typeshare]
#[derive(Debug, Deserialize)]
pub struct AuthConfigUpdate {
@@ -27,7 +25,6 @@ impl AuthConfigUpdate {
}
}
// ===== Video Config =====
#[typeshare]
#[derive(Debug, Deserialize)]
pub struct VideoConfigUpdate {
@@ -92,8 +89,6 @@ impl VideoConfigUpdate {
}
}
// ===== Stream Config =====
/// Stream configuration response (includes has_turn_password)
#[typeshare]
#[derive(Debug, serde::Serialize)]
@@ -212,8 +207,6 @@ impl StreamConfigUpdate {
}
}
// ===== HID Config =====
/// OTG USB device descriptor configuration update
#[typeshare]
#[derive(Debug, Deserialize)]
@@ -364,7 +357,6 @@ impl HidConfigUpdate {
}
}
// ===== MSD Config =====
#[typeshare]
#[derive(Debug, Deserialize)]
pub struct MsdConfigUpdate {
@@ -398,8 +390,6 @@ impl MsdConfigUpdate {
}
}
// ===== ATX Config =====
/// Update for a single ATX key configuration
#[typeshare]
#[derive(Debug, Deserialize)]
@@ -626,7 +616,6 @@ impl AtxConfigUpdate {
}
}
// ===== Audio Config =====
#[typeshare]
#[derive(Debug, Deserialize)]
pub struct AudioConfigUpdate {
@@ -660,8 +649,6 @@ impl AudioConfigUpdate {
}
}
// ===== RustDesk Config =====
/// hbbs/hbbr `-k` relay key: standard Base64 encoding of exactly 32 bytes (typically 44 chars with padding).
fn validate_rustdesk_relay_key(key: &str) -> Result<(), AppError> {
let decoded = STANDARD.decode(key.as_bytes()).map_err(|_| {
@@ -758,7 +745,6 @@ impl RustDeskConfigUpdate {
}
}
// ===== RTSP Config =====
#[typeshare]
#[derive(Debug, serde::Serialize)]
pub struct RtspConfigResponse {
@@ -876,8 +862,6 @@ impl RtspConfigUpdate {
}
}
// ===== Web Config =====
/// Web server settings returned by `GET` / `PATCH /api/config/web`.
///
/// Public API shape: certificate paths on disk are not exposed. The full stored model is `WebConfig` in `config::schema`.

View File

@@ -1,5 +1,3 @@
//! Video 配置 Handler
use axum::{extract::State, Json};
use std::sync::Arc;
@@ -10,23 +8,18 @@ use crate::state::AppState;
use super::apply::apply_video_config;
use super::types::VideoConfigUpdate;
/// 获取 Video 配置
pub async fn get_video_config(State(state): State<Arc<AppState>>) -> Json<VideoConfig> {
Json(state.config.get().video.clone())
}
/// 更新 Video 配置
pub async fn update_video_config(
State(state): State<Arc<AppState>>,
Json(req): Json<VideoConfigUpdate>,
) -> Result<Json<VideoConfig>> {
// 1. 验证请求
req.validate()?;
// 2. 获取旧配置
let old_video_config = state.config.get().video.clone();
// 3. 应用更新到配置存储
state
.config
.update(|config| {
@@ -34,10 +27,8 @@ pub async fn update_video_config(
})
.await?;
// 4. 获取新配置
let new_video_config = state.config.get().video.clone();
// 5. 应用到子系统(热重载)
if let Err(e) = apply_video_config(&state, &old_video_config, &new_video_config).await {
tracing::error!("Failed to apply video config: {}", e);
// 根据用户选择,仅记录错误,不回滚

View File

@@ -1,5 +1,3 @@
//! Web 服务器配置 Handler
use axum::{extract::State, Json};
use axum_server::tls_rustls::RustlsConfig;
use std::sync::Arc;
@@ -9,14 +7,10 @@ use crate::state::AppState;
use super::types::{WebConfigResponse, WebConfigUpdate};
/// 获取 Web 配置
pub async fn get_web_config(
State(state): State<Arc<AppState>>,
) -> Json<WebConfigResponse> {
pub async fn get_web_config(State(state): State<Arc<AppState>>) -> Json<WebConfigResponse> {
Json(WebConfigResponse::from_stored(&state.config.get().web))
}
/// 更新 Web 配置(支持 PEM 证书上传)
pub async fn update_web_config(
State(state): State<Arc<AppState>>,
Json(req): Json<WebConfigUpdate>,
@@ -27,9 +21,13 @@ pub async fn update_web_config(
// Some(Some((cert, key))) = write new cert
// Some(None) = clear custom cert
// None = no cert change
let cert_path_update: Option<Option<(String, String)>> =
if let (Some(cert_pem), Some(key_pem)) = (&req.ssl_cert_pem, &req.ssl_key_pem) {
RustlsConfig::from_pem(cert_pem.as_bytes().to_vec(), key_pem.as_bytes().to_vec())
let cert_path_update: Option<Option<(String, String)>> = if let (
Some(cert_pem),
Some(key_pem),
) =
(&req.ssl_cert_pem, &req.ssl_key_pem)
{
RustlsConfig::from_pem(cert_pem.as_bytes().to_vec(), key_pem.as_bytes().to_vec())
.await
.map_err(|e| {
AppError::BadRequest(
@@ -39,30 +37,30 @@ pub async fn update_web_config(
.into(),
)
})?;
let cert_dir = state.data_dir().join("certs");
tokio::fs::create_dir_all(&cert_dir)
.await
.map_err(|e| AppError::Internal(format!("Failed to create cert dir: {e}")))?;
let cert_path = cert_dir.join("custom.crt");
let key_path = cert_dir.join("custom.key");
tokio::fs::write(&cert_path, cert_pem.as_bytes())
.await
.map_err(|e| AppError::Internal(format!("Failed to write certificate: {e}")))?;
tokio::fs::write(&key_path, key_pem.as_bytes())
.await
.map_err(|e| AppError::Internal(format!("Failed to write private key: {e}")))?;
Some(Some((
cert_path.to_string_lossy().into_owned(),
key_path.to_string_lossy().into_owned(),
)))
} else if req.clear_custom_cert.unwrap_or(false) {
let cert_dir = state.data_dir().join("certs");
let _ = tokio::fs::remove_file(cert_dir.join("custom.crt")).await;
let _ = tokio::fs::remove_file(cert_dir.join("custom.key")).await;
Some(None)
} else {
None
};
let cert_dir = state.data_dir().join("certs");
tokio::fs::create_dir_all(&cert_dir)
.await
.map_err(|e| AppError::Internal(format!("Failed to create cert dir: {e}")))?;
let cert_path = cert_dir.join("custom.crt");
let key_path = cert_dir.join("custom.key");
tokio::fs::write(&cert_path, cert_pem.as_bytes())
.await
.map_err(|e| AppError::Internal(format!("Failed to write certificate: {e}")))?;
tokio::fs::write(&key_path, key_pem.as_bytes())
.await
.map_err(|e| AppError::Internal(format!("Failed to write private key: {e}")))?;
Some(Some((
cert_path.to_string_lossy().into_owned(),
key_path.to_string_lossy().into_owned(),
)))
} else if req.clear_custom_cert.unwrap_or(false) {
let cert_dir = state.data_dir().join("certs");
let _ = tokio::fs::remove_file(cert_dir.join("custom.crt")).await;
let _ = tokio::fs::remove_file(cert_dir.join("custom.key")).await;
Some(None)
} else {
None
};
state
.config
@@ -82,7 +80,9 @@ pub async fn update_web_config(
})
.await?;
Ok(Json(WebConfigResponse::from_stored(&state.config.get().web)))
Ok(Json(WebConfigResponse::from_stored(
&state.config.get().web,
)))
}
#[cfg(test)]