Files
JoyD/Windows/CS/Framework4.0/Updater/src/main.rs

309 lines
10 KiB
Rust
Raw Normal View History

use serde::{Deserialize, Serialize};
use std::fs;
use std::path::PathBuf;
2026-04-07 15:47:23 +08:00
use std::pin::Pin;
2026-04-07 13:21:31 +08:00
use std::process::Command;
2026-04-07 15:09:44 +08:00
use cube_lib::websocket::{WebSocketClient, WebSocketConfig};
2026-04-07 13:21:31 +08:00
/// Updater 自身配置AppData/Updater/config.json
/// 只负责 Updater 自己的行为参数,连接地址从公共 config.json 加载
#[derive(Debug, Serialize, Deserialize)]
struct Config {
2026-04-07 13:21:31 +08:00
/// 调试模式true 时保留控制台窗口并输出日志
debug_mode: bool,
}
impl Default for Config {
fn default() -> Self {
2026-04-07 13:21:31 +08:00
Self { debug_mode: false }
}
}
2026-04-07 13:21:31 +08:00
/// 获取 Updater 自身配置路径 AppData/Updater/config.json
fn get_updater_config_path() -> PathBuf {
let exe_path = std::env::current_exe().expect("Failed to get executable path");
2026-04-07 13:21:31 +08:00
let drive = exe_path
.parent()
.and_then(|p| p.as_os_str().to_str())
.and_then(|s| s.split('\\').next())
.unwrap_or("C:");
let appdata = PathBuf::from(format!("{}/AppData", drive));
let updater_dir = appdata.join("Updater");
let _ = fs::create_dir_all(&updater_dir);
updater_dir.join("config.json")
}
2026-04-07 13:21:31 +08:00
/// 获取公共配置路径 AppData/config.json与 BootLoader 同级)
fn get_public_config_path() -> PathBuf {
let exe_path = std::env::current_exe().expect("Failed to get executable path");
let drive = exe_path
.parent()
.and_then(|p| p.as_os_str().to_str())
.and_then(|s| s.split('\\').next())
.unwrap_or("C:");
PathBuf::from(format!("{}/AppData/config.json", drive))
}
/// 加载 Updater 自身配置;若文件不存在则写入默认值
fn load_updater_config() -> Config {
let config_path = get_updater_config_path();
if config_path.exists() {
2026-04-07 13:21:31 +08:00
if let Ok(content) = fs::read_to_string(&config_path) {
if let Ok(config) = serde_json::from_str::<Config>(&content) {
return config;
2026-04-07 10:42:37 +08:00
}
}
}
2026-04-07 13:21:31 +08:00
// 文件不存在或解析失败 → 写入默认值
let default_config = Config::default();
if let Ok(content) = serde_json::to_string_pretty(&default_config) {
let _ = fs::write(&config_path, content);
}
default_config
}
2026-04-07 13:21:31 +08:00
/// 从公共 config.json 读取 ServerUrl 字段
fn resolve_ws_url() -> String {
let config_path = get_public_config_path();
if let Ok(content) = fs::read_to_string(&config_path) {
if let Ok(json) = serde_json::from_str::<serde_json::Value>(&content) {
if let Some(url) = json.get("ServerUrl").and_then(|v| v.as_str()) {
return url.to_string();
}
}
}
// 读取失败 → 降级到默认值
"ws://127.0.0.1:8087/ws".to_string()
}
2026-04-07 16:41:10 +08:00
/// 从公共 config.json 读取 DeviceNumber 字段
fn resolve_device_number() -> String {
let config_path = get_public_config_path();
if let Ok(content) = fs::read_to_string(&config_path) {
if let Ok(json) = serde_json::from_str::<serde_json::Value>(&content) {
// 尝试多个可能的字段名
if let Some(id) = json.get("DeviceNumber").and_then(|v| v.as_str()) {
if !id.is_empty() {
return id.to_string();
}
}
if let Some(id) = json.get("StationId").and_then(|v| v.as_str()) {
if !id.is_empty() {
return id.to_string();
}
}
if let Some(id) = json.get("Station").and_then(|v| v.as_str()) {
if !id.is_empty() {
return id.to_string();
}
}
}
}
// 读取失败 → 降级到默认值
"UNKNOWN".to_string()
}
2026-04-07 13:21:31 +08:00
fn is_process_running(process_name: &str) -> bool {
use std::process::id;
let current_pid = id().to_string();
let output = Command::new("tasklist")
.args(["/FI", &format!("IMAGENAME eq {}", process_name), "/FO", "CSV"])
.output()
.expect("Failed to execute tasklist");
let output_str = String::from_utf8_lossy(&output.stdout);
let lines: Vec<&str> = output_str.lines().collect();
let mut count = 0;
for line in lines {
if line.contains(&format!("\"{}\"", process_name)) && !line.contains(&current_pid) {
count += 1;
}
}
count > 0
}
2026-04-07 15:09:44 +08:00
/// 运行 Updater使用 CubeLib 内置的自动重连)
async fn run_updater(debug_mode: bool) {
// 加载初始 URL
let server_url = resolve_ws_url();
2026-04-07 13:21:31 +08:00
if debug_mode {
2026-04-07 15:09:44 +08:00
println!("========================================");
println!("Updater 启动 (调试模式)");
println!("服务器地址: {}", server_url);
println!("自动重连: 启用 (指数退避: 1s - 30s)");
println!("========================================");
2026-04-07 13:21:31 +08:00
}
2026-04-07 15:09:44 +08:00
// 创建 WebSocket 配置(启用自动重连)
let config = WebSocketConfig::new(&server_url)
.with_client_type("Updater")
.with_debug(debug_mode)
.with_reconnect(true) // 启用自动重连
.with_reconnect_delay(1000) // 初始延迟 1s
.with_max_reconnect_delay(30000); // 最大延迟 30s
2026-04-07 13:21:31 +08:00
2026-04-07 15:09:44 +08:00
// 创建 WebSocket 客户端
let mut client = WebSocketClient::new(config);
2026-04-07 13:21:31 +08:00
2026-04-07 15:09:44 +08:00
// 设置连接成功回调
let debug_clone = debug_mode;
client.on_connected(move |url| {
if debug_clone {
println!("[已连接] {}", url);
}
});
// 设置消息接收回调
let debug_for_msg = debug_mode;
client.on_message(move |msg_type, data| {
if debug_for_msg {
println!("[消息] 类型: {}, 数据: {:?}", msg_type, data);
}
// 处理 FileVer 响应
if msg_type == "FileVer" {
if let Some(version) = data.get("version").and_then(|v| v.as_str()) {
println!("[版本] BootLoader.exe 版本: {}", version);
2026-04-07 13:21:31 +08:00
}
}
2026-04-07 15:09:44 +08:00
});
// 设置断开连接回调
let debug_for_disconnect = debug_mode;
client.on_disconnected(move || {
if debug_for_disconnect {
println!("[断开] 连接已断开");
}
});
// 设置错误回调
client.on_error(|error| {
eprintln!("[错误] WebSocket: {}", error);
});
2026-04-07 15:47:23 +08:00
// 设置首次连接回调 - 发送 GetFileVer 命令
let debug_for_first = debug_mode;
2026-04-07 16:41:10 +08:00
let device_number = resolve_device_number();
2026-04-07 15:47:23 +08:00
client.on_first_connect(move |_url, sender| {
2026-04-07 16:41:10 +08:00
let device_number = device_number.clone();
2026-04-07 15:47:23 +08:00
Box::pin(async move {
if debug_for_first {
println!("[首次连接] 发送 GetFileVer 命令...");
}
2026-04-07 16:41:10 +08:00
// 构造 GetFileVer 消息 - Type在前DeviceNumber从公共配置读取file_list数组
// 注意:手动拼接字符串确保 Type 在 JSON 的第一位serde_json::json! 会按字母排序)
let msg_str = format!(
r#"{{"Type":"GetFileVer","DeviceNumber":"{}","Data":{{"file_list":["BootLoader.exe"]}}}}"#,
device_number
);
if debug_for_first {
println!("[首次连接] GetFileVer 已发送: {}", msg_str);
}
2026-04-07 15:47:23 +08:00
// 通过 sender 发送消息 (使用 .lock().await)
let sender_guard = sender.lock().await;
if let Some(ref tx) = *sender_guard {
let _ = tx.try_send(cube_lib::websocket::OutgoingMessage::Text(msg_str));
}
}) as Pin<Box<dyn std::future::Future<Output = ()> + Send + Sync>>
});
2026-04-07 15:09:44 +08:00
// 设置重连回调 - 在每次重连前重新加载配置
let debug_for_reconnect = debug_mode;
client.on_reconnecting(move |attempt, url_arc| {
Box::pin(async move {
if debug_for_reconnect {
println!("[重连] 第 {} 次重连中...", attempt);
}
// 重新读取配置文件并更新 URL
let new_url = resolve_ws_url();
// 更新 CubeLib 内部的 URL (使用 .lock().await)
*url_arc.lock().await = new_url.clone();
if debug_for_reconnect {
println!("[配置] 已重新加载,服务器地址: {}", new_url);
}
}) as Pin<Box<dyn std::future::Future<Output = ()> + Send + Sync>>
});
// 设置重连成功回调 - 每次重连成功后也发送 GetFileVer
let debug_for_reconnected = debug_mode;
2026-04-07 16:41:10 +08:00
let device_number = resolve_device_number();
client.on_reconnected(move |_url, sender| {
2026-04-07 16:41:10 +08:00
let device_number = device_number.clone();
Box::pin(async move {
if debug_for_reconnected {
println!("[重连成功] 发送 GetFileVer 命令...");
}
2026-04-07 16:41:10 +08:00
// 构造 GetFileVer 消息 - Type在前DeviceNumber从公共配置读取file_list数组
let msg_str = format!(
r#"{{"Type":"GetFileVer","DeviceNumber":"{}","Data":{{"file_list":["BootLoader.exe"]}}}}"#,
device_number
);
if debug_for_reconnected {
println!("[重连成功] GetFileVer 已发送: {}", msg_str);
}
// 通过 sender 发送消息
let sender_guard = sender.lock().await;
if let Some(ref tx) = *sender_guard {
let _ = tx.try_send(cube_lib::websocket::OutgoingMessage::Text(msg_str));
}
}) as Pin<Box<dyn std::future::Future<Output = ()> + Send + Sync>>
2026-04-07 15:09:44 +08:00
});
// 连接CubeLib 会自动处理重连)
if debug_mode {
println!("[启动] 开始连接...");
}
// connect() 会等待 websocket_loop 完全结束(包括所有重连)
client.connect().await;
if debug_mode {
println!("[启动] 连接已结束");
}
if debug_mode {
println!("Updater 已停止");
2026-04-07 10:42:37 +08:00
}
}
#[tokio::main]
async fn main() {
2026-04-07 13:21:31 +08:00
// 检查是否已有 Updater 进程在运行
if is_process_running("Updater.exe") {
return;
}
// 加载 Updater 自身配置debug_mode
let config = load_updater_config();
// 非 debug 模式下释放控制台,后台静默运行
2026-04-07 11:04:06 +08:00
if !config.debug_mode {
#[cfg(windows)]
{
use windows::Win32::System::Console;
use windows::Win32::Foundation::HWND;
unsafe {
let console = Console::GetConsoleWindow();
if console != HWND::default() {
let _ = Console::FreeConsole();
}
}
}
}
2026-04-07 13:21:31 +08:00
2026-04-07 15:09:44 +08:00
// 运行 Updater
run_updater(config.debug_mode).await;
2026-04-07 13:21:31 +08:00
2026-04-07 15:09:44 +08:00
if config.debug_mode {
println!("Updater 已退出");
}
}