mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-09-12 18:44:25 +08:00
fix: 修复 MSD 启用时 Ventoy 资源初始化问题 #275
- 将 Ventoy 资源初始化纳入 MSD 控制器启用流程 - 支持运行时启用 MSD,无需重启服务 - 调整验收测试并移除启用后的重启逻辑
This commit is contained in:
18
src/main.rs
18
src/main.rs
@@ -335,24 +335,8 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
let msd = if config.msd.enabled {
|
let msd = if config.msd.enabled {
|
||||||
let ventoy_resource_dir = data_dir.join("ventoy");
|
let ventoy_resource_dir = data_dir.join("ventoy");
|
||||||
if ventoy_resource_dir.exists() {
|
|
||||||
if let Err(e) = ventoy_img::init_resources(&ventoy_resource_dir) {
|
|
||||||
tracing::warn!("Failed to initialize Ventoy resources: {}", e);
|
|
||||||
} else {
|
|
||||||
tracing::info!(
|
|
||||||
"Ventoy resources initialized from {}",
|
|
||||||
ventoy_resource_dir.display()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tracing::warn!(
|
|
||||||
"Ventoy resource directory not found: {}",
|
|
||||||
ventoy_resource_dir.display()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let controller = MsdController::new(otg_service.clone(), config.msd.msd_dir_path());
|
let controller = MsdController::new(otg_service.clone(), config.msd.msd_dir_path());
|
||||||
if let Err(e) = controller.init().await {
|
if let Err(e) = controller.init(&ventoy_resource_dir).await {
|
||||||
tracing::warn!("Failed to initialize MSD controller: {}", e);
|
tracing::warn!("Failed to initialize MSD controller: {}", e);
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::PathBuf;
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
@@ -47,9 +47,21 @@ impl MsdController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn init(&self) -> Result<()> {
|
pub async fn init(&self, ventoy_resource_dir: &Path) -> Result<()> {
|
||||||
info!("Initializing MSD controller");
|
info!("Initializing MSD controller");
|
||||||
|
|
||||||
|
match ventoy_img::init_resources(ventoy_resource_dir) {
|
||||||
|
Ok(()) => info!(
|
||||||
|
"Ventoy resources ready from {}",
|
||||||
|
ventoy_resource_dir.display()
|
||||||
|
),
|
||||||
|
Err(e) => warn!(
|
||||||
|
"Failed to initialize Ventoy resources from {}: {}. Ventoy drive creation will be unavailable, but regular ISO/IMG MSD remains available",
|
||||||
|
ventoy_resource_dir.display(),
|
||||||
|
e
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
if let Err(e) = std::fs::create_dir_all(&self.images_path) {
|
if let Err(e) = std::fs::create_dir_all(&self.images_path) {
|
||||||
warn!("Failed to create images directory: {}", e);
|
warn!("Failed to create images directory: {}", e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -317,7 +317,8 @@ pub async fn apply_msd_config(
|
|||||||
|
|
||||||
let msd =
|
let msd =
|
||||||
crate::msd::MsdController::new(state.otg_service.clone(), new_config.msd_dir_path());
|
crate::msd::MsdController::new(state.otg_service.clone(), new_config.msd_dir_path());
|
||||||
msd.init()
|
let ventoy_resource_dir = state.data_dir().join("ventoy");
|
||||||
|
msd.init(&ventoy_resource_dir)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| AppError::Config(format!("MSD initialization failed: {}", e)))?;
|
.map_err(|e| AppError::Config(format!("MSD initialization failed: {}", e)))?;
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ REPORT_HIDDEN_RESULTS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CATEGORY_RULES = (
|
CATEGORY_RULES = (
|
||||||
("初始化与环境", ("target_", "setup_", "login", "network_", "target_inventory", "stream_codecs", "windows_agent", "ventoy_resources", "msd_restart")),
|
("初始化与环境", ("target_", "setup_", "login", "network_", "target_inventory", "stream_codecs", "windows_agent", "ventoy_resources")),
|
||||||
("视频性能", ("video_", "config_video_")),
|
("视频性能", ("video_", "config_video_")),
|
||||||
("HDMI 画面与颜色", ("hdmi_", "config_video_hdmi_probe")),
|
("HDMI 画面与颜色", ("hdmi_", "config_video_hdmi_probe")),
|
||||||
("HID / MSD / ATX", ("hid_", "msd", "atx_")),
|
("HID / MSD / ATX", ("hid_", "msd", "atx_")),
|
||||||
@@ -71,12 +71,10 @@ DISPLAY_NAMES = {
|
|||||||
"target_reset": "目标机重置",
|
"target_reset": "目标机重置",
|
||||||
"setup_init": "初始化账号",
|
"setup_init": "初始化账号",
|
||||||
"login": "登录",
|
"login": "登录",
|
||||||
"login_after_restart": "重启后登录",
|
|
||||||
"network_latency": "网络延迟",
|
"network_latency": "网络延迟",
|
||||||
"target_inventory": "目标机设备清单",
|
"target_inventory": "目标机设备清单",
|
||||||
"hid_msd_config": "HID/MSD 配置",
|
"hid_msd_config": "HID/MSD 配置",
|
||||||
"ventoy_resources": "Ventoy 资源",
|
"ventoy_resources": "Ventoy 资源",
|
||||||
"msd_restart": "MSD 启用后重启",
|
|
||||||
"video_input_select": "视频输入选择",
|
"video_input_select": "视频输入选择",
|
||||||
"windows_agent": "Windows 配套程序连接",
|
"windows_agent": "Windows 配套程序连接",
|
||||||
"config_video_hdmi_probe": "HDMI 采集配置",
|
"config_video_hdmi_probe": "HDMI 采集配置",
|
||||||
@@ -564,14 +562,12 @@ def summarize_result(result: CheckResult, metrics: list[Metric]) -> str:
|
|||||||
return "数据库已备份,服务已重启"
|
return "数据库已备份,服务已重启"
|
||||||
if name == "setup_init":
|
if name == "setup_init":
|
||||||
return "初始化检查完成"
|
return "初始化检查完成"
|
||||||
if name in {"login", "login_after_restart"}:
|
if name == "login":
|
||||||
return "认证成功"
|
return "认证成功"
|
||||||
if name == "hid_msd_config":
|
if name == "hid_msd_config":
|
||||||
return "已按设备能力配置 HID/MSD"
|
return "已按设备能力配置 HID/MSD"
|
||||||
if name == "ventoy_resources":
|
if name == "ventoy_resources":
|
||||||
return "Ventoy 资源检查完成"
|
return "Ventoy 资源检查完成"
|
||||||
if name == "msd_restart":
|
|
||||||
return "服务重启完成"
|
|
||||||
if name == "video_input_select":
|
if name == "video_input_select":
|
||||||
cases = data.get("cases") or []
|
cases = data.get("cases") or []
|
||||||
return ",".join(f"{c.get('fmt')} {c.get('width')}x{c.get('height')}@{c.get('fps')}" for c in cases if isinstance(c, dict))
|
return ",".join(f"{c.get('fmt')} {c.get('width')}x{c.get('height')}@{c.get('fps')}" for c in cases if isinstance(c, dict))
|
||||||
|
|||||||
@@ -507,6 +507,11 @@ echo "$BACKUP"
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
self.selected_hid_backend = "otg"
|
self.selected_hid_backend = "otg"
|
||||||
|
if not self.args.no_ventoy_sync:
|
||||||
|
try:
|
||||||
|
self.sync_ventoy_resources()
|
||||||
|
except Exception as exc:
|
||||||
|
self.reporter.add("ventoy_resources", "WARN", f"failed to sync Ventoy resources: {exc}")
|
||||||
try:
|
try:
|
||||||
self.api.patch("/config/msd", {"enabled": True})
|
self.api.patch("/config/msd", {"enabled": True})
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
@@ -514,16 +519,6 @@ echo "$BACKUP"
|
|||||||
self.reporter.add("hid_msd_config", "WARN", f"configured OTG HID but failed to enable MSD: {exc}", udc=udc_name)
|
self.reporter.add("hid_msd_config", "WARN", f"configured OTG HID but failed to enable MSD: {exc}", udc=udc_name)
|
||||||
return
|
return
|
||||||
self.reporter.add("hid_msd_config", "PASS", "configured OTG HID and enabled MSD", udc=udc_name)
|
self.reporter.add("hid_msd_config", "PASS", "configured OTG HID and enabled MSD", udc=udc_name)
|
||||||
if not self.args.no_ventoy_sync:
|
|
||||||
try:
|
|
||||||
self.sync_ventoy_resources()
|
|
||||||
except Exception as exc:
|
|
||||||
self.reporter.add("ventoy_resources", "WARN", f"failed to sync Ventoy resources: {exc}")
|
|
||||||
if not self.args.no_msd_restart_after_enable:
|
|
||||||
try:
|
|
||||||
self.restart_target_service("msd_restart", "restarted One-KVM after enabling MSD")
|
|
||||||
except Exception as exc:
|
|
||||||
self.reporter.add("msd_restart", "WARN", f"failed to restart after enabling MSD: {exc}")
|
|
||||||
return
|
return
|
||||||
if serial:
|
if serial:
|
||||||
port = serial[0]["path"]
|
port = serial[0]["path"]
|
||||||
@@ -556,17 +551,6 @@ echo "$BACKUP"
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def restart_target_service(self, check_name: str, detail: str) -> None:
|
|
||||||
if not self.ssh_password and self.args.ssh_password_prompt:
|
|
||||||
self.ssh_password = getpass.getpass(f"SSH password for {self.args.ssh_user}@{self.args.target}: ")
|
|
||||||
ssh = SSHRunner(self.args.target, self.args.ssh_user, self.ssh_password, self.args.ssh_port)
|
|
||||||
code, out, err = ssh.run("systemctl restart one-kvm || service one-kvm restart", timeout=90)
|
|
||||||
if code != 0:
|
|
||||||
raise RuntimeError(err or out or "service restart command failed")
|
|
||||||
self.api.wait_health(timeout=self.args.health_timeout)
|
|
||||||
self.authenticate("login_after_restart", "authenticated after One-KVM restart")
|
|
||||||
self.reporter.add(check_name, "PASS", detail)
|
|
||||||
|
|
||||||
def sync_ventoy_resources(self) -> None:
|
def sync_ventoy_resources(self) -> None:
|
||||||
source_dir = Path(self.args.ventoy_resources_dir) if self.args.ventoy_resources_dir else default_ventoy_resources_dir()
|
source_dir = Path(self.args.ventoy_resources_dir) if self.args.ventoy_resources_dir else default_ventoy_resources_dir()
|
||||||
if not source_dir.exists():
|
if not source_dir.exists():
|
||||||
@@ -2277,7 +2261,6 @@ def build_parser() -> argparse.ArgumentParser:
|
|||||||
run.add_argument("--msd-probe-bytes", type=int, default=1024 * 1024)
|
run.add_argument("--msd-probe-bytes", type=int, default=1024 * 1024)
|
||||||
run.add_argument("--ventoy-resources-dir", default=None, help="local Ventoy resource directory; defaults to repo libs/ventoy-img-rs/resources")
|
run.add_argument("--ventoy-resources-dir", default=None, help="local Ventoy resource directory; defaults to repo libs/ventoy-img-rs/resources")
|
||||||
run.add_argument("--no-ventoy-sync", action="store_true", help="do not copy Ventoy resources to the target before MSD testing")
|
run.add_argument("--no-ventoy-sync", action="store_true", help="do not copy Ventoy resources to the target before MSD testing")
|
||||||
run.add_argument("--no-msd-restart-after-enable", action="store_true", help="do not restart One-KVM after enabling MSD")
|
|
||||||
run.add_argument("--strict-performance", action="store_true", help="fail video results below the expected FPS threshold; default only requires fps > 0")
|
run.add_argument("--strict-performance", action="store_true", help="fail video results below the expected FPS threshold; default only requires fps > 0")
|
||||||
run.add_argument("--no-color", action="store_true", help="disable colored terminal output")
|
run.add_argument("--no-color", action="store_true", help="disable colored terminal output")
|
||||||
run.add_argument("--no-screenshots", action="store_true", help="skip Playwright webpage screenshots")
|
run.add_argument("--no-screenshots", action="store_true", help="skip Playwright webpage screenshots")
|
||||||
|
|||||||
Reference in New Issue
Block a user