From 6f697e56c8d6f0b9b1da87c6f8b68feb379e4bcf Mon Sep 17 00:00:00 2001
From: mofeng-git
Date: Sun, 19 Jul 2026 23:44:34 +0800
Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20windows=20?=
=?UTF-8?q?=E6=9E=84=E5=BB=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/audio/capture_windows.rs | 4 -
src/audio/device_windows.rs | 5 +-
src/web/handlers/config/apply.rs | 85 ++++++-----
src/web/handlers/config/hid.rs | 16 +-
src/web/handlers/config/mod.rs | 1 +
src/web/handlers/config/otg.rs | 141 +++---------------
src/web/handlers/config/usb_update.rs | 203 ++++++++++++++++++++++++++
7 files changed, 278 insertions(+), 177 deletions(-)
create mode 100644 src/web/handlers/config/usb_update.rs
diff --git a/src/audio/capture_windows.rs b/src/audio/capture_windows.rs
index ab283cf0..2f059df3 100644
--- a/src/audio/capture_windows.rs
+++ b/src/audio/capture_windows.rs
@@ -508,9 +508,5 @@ fn device_label(device: &cpal::Device) -> String {
device
.description()
.map(|desc| desc.to_string())
- .or_else(|_| {
- #[allow(deprecated)]
- device.name()
- })
.unwrap_or_else(|_| "Unknown WASAPI capture device".to_string())
}
diff --git a/src/audio/device_windows.rs b/src/audio/device_windows.rs
index c73305a8..8ea1aaba 100644
--- a/src/audio/device_windows.rs
+++ b/src/audio/device_windows.rs
@@ -142,10 +142,7 @@ fn device_labels(device: &cpal::Device) -> DeviceLabels {
}
}
Err(_) => {
- #[allow(deprecated)]
- let display = device
- .name()
- .unwrap_or_else(|_| "Unknown WASAPI capture device".to_string());
+ let display = "Unknown WASAPI capture device".to_string();
DeviceLabels {
display: display.clone(),
search_text: display,
diff --git a/src/web/handlers/config/apply.rs b/src/web/handlers/config/apply.rs
index 741331a9..65d59ef0 100644
--- a/src/web/handlers/config/apply.rs
+++ b/src/web/handlers/config/apply.rs
@@ -355,53 +355,68 @@ pub async fn apply_msd_config(
Ok(())
}
-#[cfg(unix)]
-pub async fn apply_otg_config(
+pub async fn apply_usb_config(
state: &Arc,
old_config: &AppConfig,
new_config: &AppConfig,
) -> Result<()> {
- let transitioning_away_from_otg =
- old_config.hid.backend == HidBackend::Otg && new_config.hid.backend != HidBackend::Otg;
+ #[cfg(unix)]
+ {
+ let transitioning_away_from_otg =
+ old_config.hid.backend == HidBackend::Otg && new_config.hid.backend != HidBackend::Otg;
- if transitioning_away_from_otg {
- apply_hid_config(
+ if transitioning_away_from_otg {
+ apply_hid_config(
+ state,
+ &old_config.hid,
+ &new_config.hid,
+ &new_config.msd,
+ &new_config.otg_network,
+ ConfigApplyOptions::default(),
+ )
+ .await?;
+ } else {
+ reconcile_otg_config(
+ state,
+ &new_config.hid,
+ &new_config.msd,
+ &new_config.otg_network,
+ )
+ .await?;
+ apply_hid_config(
+ state,
+ &old_config.hid,
+ &new_config.hid,
+ &new_config.msd,
+ &new_config.otg_network,
+ ConfigApplyOptions::default(),
+ )
+ .await?;
+ }
+
+ apply_msd_config(
state,
- &old_config.hid,
- &new_config.hid,
+ &old_config.msd,
&new_config.msd,
+ &new_config.hid,
&new_config.otg_network,
ConfigApplyOptions::default(),
)
- .await?;
- } else {
- reconcile_otg_config(
- state,
- &new_config.hid,
- &new_config.msd,
- &new_config.otg_network,
- )
- .await?;
- apply_hid_config(
- state,
- &old_config.hid,
- &new_config.hid,
- &new_config.msd,
- &new_config.otg_network,
- ConfigApplyOptions::default(),
- )
- .await?;
+ .await
}
- apply_msd_config(
- state,
- &old_config.msd,
- &new_config.msd,
- &new_config.hid,
- &new_config.otg_network,
- ConfigApplyOptions::default(),
- )
- .await
+ #[cfg(not(unix))]
+ {
+ apply_hid_config(
+ state,
+ &old_config.hid,
+ &new_config.hid,
+ &new_config.msd,
+ &new_config.otg_network,
+ ConfigApplyOptions::default(),
+ )
+ .await
+ }
}
pub async fn apply_atx_config(
diff --git a/src/web/handlers/config/hid.rs b/src/web/handlers/config/hid.rs
index e5e67a72..3dcf45f6 100644
--- a/src/web/handlers/config/hid.rs
+++ b/src/web/handlers/config/hid.rs
@@ -5,8 +5,8 @@ use crate::config::HidConfig;
use crate::error::Result;
use crate::state::AppState;
-use super::otg::update_otg_config_inner;
-use super::types::{HidConfigUpdate, OtgConfigUpdate};
+use super::types::HidConfigUpdate;
+use super::usb_update::{stage_hid_config_update, update_usb_config};
pub async fn get_hid_config(State(state): State>) -> Json {
Json(state.config.get().hid.clone())
@@ -16,13 +16,9 @@ pub async fn update_hid_config(
State(state): State>,
Json(req): Json,
) -> Result> {
- let response = update_otg_config_inner(
- &state,
- OtgConfigUpdate {
- hid: Some(req),
- ..Default::default()
- },
- )
+ let config = update_usb_config(&state, move |staged| {
+ stage_hid_config_update(&mut staged.hid, &req)
+ })
.await?;
- Ok(Json(response.hid))
+ Ok(Json(config.hid))
}
diff --git a/src/web/handlers/config/mod.rs b/src/web/handlers/config/mod.rs
index 22442630..250d0aff 100644
--- a/src/web/handlers/config/mod.rs
+++ b/src/web/handlers/config/mod.rs
@@ -15,6 +15,7 @@ mod redfish;
mod rtsp;
mod rustdesk;
mod stream;
+mod usb_update;
pub(crate) mod video;
mod vnc;
mod watchdog;
diff --git a/src/web/handlers/config/otg.rs b/src/web/handlers/config/otg.rs
index 3cfed051..b06bee9b 100644
--- a/src/web/handlers/config/otg.rs
+++ b/src/web/handlers/config/otg.rs
@@ -4,13 +4,13 @@ use axum::{extract::State, Json};
use serde::Serialize;
use typeshare::typeshare;
-use crate::config::{HidBackend, HidConfig, MsdConfig, OtgNetworkConfig};
-use crate::error::{AppError, Result};
+use crate::config::{HidConfig, MsdConfig, OtgNetworkConfig};
+use crate::error::Result;
use crate::otg::OtgNetworkStatus;
use crate::state::AppState;
-use super::apply::{apply_otg_config, try_apply_lock};
use super::types::OtgConfigUpdate;
+use super::usb_update::{stage_hid_config_update, update_usb_config};
#[typeshare]
#[derive(Debug, Serialize)]
@@ -32,99 +32,23 @@ pub(super) async fn update_otg_config_inner(
state: &Arc,
request: OtgConfigUpdate,
) -> Result {
- let _guard = try_apply_lock(&state.config_apply_locks.otg, "otg")?;
+ let staged_config = update_usb_config(state, move |staged| {
+ let requested_ch9329_descriptor = match request.hid.as_ref() {
+ Some(update) => stage_hid_config_update(&mut staged.hid, update)?,
+ None => None,
+ };
- if let Some(ref update) = request.hid {
- update.validate()?;
- }
- if let Some(ref update) = request.msd {
- update.validate()?;
- }
-
- let old_config = state.config.get();
- let mut staged_config = (*old_config).clone();
- let requested_ch9329_descriptor = request.hid.as_ref().and_then(|update| {
- update.ch9329_descriptor.as_ref().map(|_| {
- let mut hid = staged_config.hid.clone();
- update.apply_to(&mut hid);
- hid.ch9329_descriptor
- })
- });
-
- if let Some(ref update) = request.hid {
- update.apply_to(&mut staged_config.hid);
- }
- if requested_ch9329_descriptor.is_some() {
- staged_config.hid.ch9329_descriptor = old_config.hid.ch9329_descriptor.clone();
- }
- if let Some(ref update) = request.msd {
- update.apply_to(&mut staged_config.msd);
- }
- if let Some(ref update) = request.network {
- update.apply_to(&mut staged_config.otg_network);
- }
- staged_config.enforce_invariants();
-
- if staged_config.otg_network.enabled
- && (staged_config.otg_network.device_mac.is_empty()
- || staged_config.otg_network.host_mac.is_empty())
- {
- let (device_mac, host_mac) =
- crate::otg::network::resolved_mac_pair(&staged_config.otg_network);
- staged_config.otg_network.device_mac = device_mac;
- staged_config.otg_network.host_mac = host_mac;
- }
- staged_config.hid.validate_otg_functions()?;
- staged_config.otg_network.validate()?;
-
- if let Err(error) = apply_otg_config(state, &old_config, &staged_config).await {
- return Err(rollback_after_failure(state, &staged_config, &old_config, error, false).await);
- }
-
- let descriptor_was_applied = if let Some(ref descriptor) = requested_ch9329_descriptor {
- if staged_config.hid.backend == HidBackend::Ch9329 {
- match state.hid.apply_ch9329_descriptor(descriptor).await {
- Ok(actual) => {
- staged_config.hid.ch9329_descriptor = actual.descriptor;
- true
- }
- Err(error) => {
- return Err(rollback_after_failure(
- state,
- &staged_config,
- &old_config,
- error,
- true,
- )
- .await);
- }
- }
- } else {
- false
+ if let Some(ref update) = request.msd {
+ update.validate()?;
+ update.apply_to(&mut staged.msd);
+ }
+ if let Some(ref update) = request.network {
+ update.apply_to(&mut staged.otg_network);
}
- } else {
- false
- };
- if let Err(error) = state
- .config
- .update(|config| {
- config.hid = staged_config.hid.clone();
- config.msd = staged_config.msd.clone();
- config.otg_network = staged_config.otg_network.clone();
- config.enforce_invariants();
- })
- .await
- {
- return Err(rollback_after_failure(
- state,
- &staged_config,
- &old_config,
- AppError::Config(format!("Failed to persist OTG config after apply: {error}")),
- descriptor_was_applied,
- )
- .await);
- }
+ Ok(requested_ch9329_descriptor)
+ })
+ .await?;
Ok(OtgConfigResponse {
hid: staged_config.hid,
@@ -133,34 +57,3 @@ pub(super) async fn update_otg_config_inner(
status: state.otg_service.network_status().await,
})
}
-
-async fn rollback_after_failure(
- state: &Arc,
- failed_config: &crate::config::AppConfig,
- old_config: &crate::config::AppConfig,
- primary_error: AppError,
- restore_descriptor: bool,
-) -> AppError {
- let mut rollback_errors = Vec::new();
-
- if let Err(error) = apply_otg_config(state, failed_config, old_config).await {
- rollback_errors.push(format!("runtime rollback failed: {error}"));
- }
- if restore_descriptor && old_config.hid.backend == HidBackend::Ch9329 {
- if let Err(error) = state
- .hid
- .apply_ch9329_descriptor(&old_config.hid.ch9329_descriptor)
- .await
- {
- rollback_errors.push(format!("CH9329 descriptor rollback failed: {error}"));
- }
- }
-
- if rollback_errors.is_empty() {
- return primary_error;
- }
-
- let message = format!("{primary_error}; {}", rollback_errors.join("; "));
- state.otg_service.mark_degraded(message.clone()).await;
- AppError::Config(message)
-}
diff --git a/src/web/handlers/config/usb_update.rs b/src/web/handlers/config/usb_update.rs
new file mode 100644
index 00000000..4ed19d2a
--- /dev/null
+++ b/src/web/handlers/config/usb_update.rs
@@ -0,0 +1,203 @@
+use std::sync::Arc;
+
+use crate::config::{AppConfig, Ch9329DescriptorConfig, HidBackend, HidConfig};
+use crate::error::{AppError, Result};
+use crate::state::AppState;
+
+use super::apply::{apply_usb_config, try_apply_lock};
+use super::types::HidConfigUpdate;
+
+pub(super) fn stage_hid_config_update(
+ staged_hid: &mut HidConfig,
+ update: &HidConfigUpdate,
+) -> Result