监控模块 优化

This commit is contained in:
zhongluofeng
2026-07-24 18:16:34 +08:00
parent e8267c244f
commit 7e6149355e
15 changed files with 2148 additions and 234 deletions
+123
View File
@@ -0,0 +1,123 @@
// network_monitor.rs — 网速监控模块
//
// 职责:
// - 后台每秒采样所有网络接口的收发字节数
// - 计算与上一次采样的差值(速率,bytes/s)
// - 聚合所有接口得到总下载/上传速率
// - 通过 Tauri 事件 "monitor-network" 推送给前端
//
// 设计说明:
// - 不依赖 ThingHKThingHK 当前不支持网络传感器扩展)
// - 使用 sysinfo crate 的 Networks(轻量、跨平台)
// - 采样间隔与 Kernel 快通道一致(1s),保证 UI 曲线流畅
// - 前端通过监听事件更新 UI,无需主动 invoke
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;
use serde::Serialize;
use sysinfo::Networks;
use tauri::{AppHandle, Emitter};
/// 推送给前端的网速数据
#[derive(Serialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct NetworkSpeed {
/// 下载速率(bytes/s),所有接口聚合
pub download_bps: u64,
/// 上传速率(bytes/s),所有接口聚合
pub upload_bps: u64,
/// 时间戳(ms
pub timestamp: u64,
}
/// 网速监控器:后台任务采样并 emit 事件。
///
/// 使用方式:
/// 1. app.manage(NetworkMonitor::new()) 注册到 Tauri State
/// 2. 在 setup 中调用 NetworkMonitor::start(&app) 启动后台采样
/// 3. 前端监听 "monitor-network" 事件
pub struct NetworkMonitor {
/// 是否正在运行(用于 start/stop 幂等控制)
running: Arc<AtomicBool>,
}
impl NetworkMonitor {
pub fn new() -> Self {
Self {
running: Arc::new(AtomicBool::new(false)),
}
}
/// 启动后台网速采样任务。幂等:重复调用不会启动多个任务。
pub fn start(self: Arc<Self>, app: AppHandle) {
if self.running.swap(true, Ordering::SeqCst) {
return; // 已在运行
}
let running = self.running.clone();
tauri::async_runtime::spawn(async move {
// sysinfo Networks 需要可变借用,放在独立线程的本地变量
let mut networks = Networks::new_with_refreshed_list();
// 首次采样仅记录基线,不 emit(速率需要两次采样差值)
let mut last_rx: u64 = networks.iter().map(|(_, data)| data.total_received()).sum();
let mut last_tx: u64 = networks.iter().map(|(_, data)| data.total_transmitted()).sum();
// 1s 间隔采样(与 Kernel 快通道一致)
let mut interval = tokio::time::interval(Duration::from_secs(1));
// 跳过第一次立即触发(已记录基线)
interval.tick().await;
loop {
interval.tick().await;
if !running.load(Ordering::SeqCst) {
break;
}
// 刷新网络数据(sysinfo 0.32: refresh() 刷新接口列表和统计数据)
networks.refresh();
let cur_rx: u64 = networks.iter().map(|(_, data)| data.total_received()).sum();
let cur_tx: u64 = networks.iter().map(|(_, data)| data.total_transmitted()).sum();
// 速率 = 当前累计 - 上次累计(sysinfo 的 total_received 是单调递增的累计值)
// 若接口移除/添加可能导致差值为负或异常大,做饱和减法保护
let download_bps = cur_rx.saturating_sub(last_rx);
let upload_bps = cur_tx.saturating_sub(last_tx);
last_rx = cur_rx;
last_tx = cur_tx;
let speed = NetworkSpeed {
download_bps,
upload_bps,
timestamp: chrono::Local::now().timestamp_millis() as u64,
};
// emit 给前端(失败忽略:窗口可能未就绪)
let _ = app.emit("monitor-network", &speed);
}
eprintln!("[network] 网速采样任务已退出");
});
}
/// 停止后台采样
#[allow(dead_code)]
pub fn stop(&self) {
self.running.store(false, Ordering::SeqCst);
}
}
impl Default for NetworkMonitor {
fn default() -> Self {
Self::new()
}
}
/// Tauri 命令:获取网速监控是否运行
#[tauri::command]
pub fn network_monitor_status(
state: tauri::State<'_, NetworkMonitor>,
) -> bool {
state.running.load(Ordering::SeqCst)
}