监控模块 优化
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
// network_monitor.rs — 网速监控模块
|
||||
//
|
||||
// 职责:
|
||||
// - 后台每秒采样所有网络接口的收发字节数
|
||||
// - 计算与上一次采样的差值(速率,bytes/s)
|
||||
// - 聚合所有接口得到总下载/上传速率
|
||||
// - 通过 Tauri 事件 "monitor-network" 推送给前端
|
||||
//
|
||||
// 设计说明:
|
||||
// - 不依赖 ThingHK(ThingHK 当前不支持网络传感器扩展)
|
||||
// - 使用 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)
|
||||
}
|
||||
Reference in New Issue
Block a user