监控模块 优化

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
+182 -9
View File
@@ -42,6 +42,10 @@ export interface MonitorStatus {
ready: boolean
sensorCount: number
restartCount: number
/** 是否为提权模式(通过 UAC 以管理员权限启动) */
elevated: boolean
/** Thing 自身是否以管理员权限运行(永久提权模式) */
thingElevated: boolean
}
export interface MonitorKernelInfo {
@@ -50,6 +54,48 @@ export interface MonitorKernelInfo {
port: number
}
// ===== 硬件监控配置(与 ThingHK HardwareConfig.cs 对应) =====
export interface HardwareTypeInfo {
key: string
name: string
enabled: boolean
requiresAdmin: boolean
}
export interface SensorTypeInfo {
key: string
name: string
enabled: boolean
}
export interface HardwareConfig {
hardware: Record<string, boolean>
sensorTypes: Record<string, boolean>
}
export interface HardwareConfigResponse {
config: HardwareConfig
availableHardware: HardwareTypeInfo[]
availableSensorTypes: SensorTypeInfo[]
}
export interface HardwareConfigUpdateResponse {
success: boolean
restartRequired: boolean
configPath: string | null
}
/** 网速数据(由 Tauri network_monitor 模块推送,独立于 ThingHK Kernel */
export interface NetworkSpeed {
/** 下载速率(bytes/s */
downloadBps: number
/** 上传速率(bytes/s */
uploadBps: number
/** 时间戳(ms */
timestamp: number
}
/** 连接状态机:与后端事件一一对应 */
export type ConnectionState = 'idle' | 'loading' | 'connected' | 'disconnected' | 'error'
@@ -70,9 +116,18 @@ export const useMonitorStore = defineStore('monitor', () => {
const starting = ref(false)
const stopping = ref(false)
/** 网速数据(由 network_monitor 后台任务推送,独立于 Kernel) */
const networkSpeed = ref<NetworkSpeed | null>(null)
/** 是否已完成首次加载(避免初始 null/false 导致 UI 闪烁误导状态) */
const initialized = ref(false)
/** 永久提权标志是否已启用(后续启动自动触发 UAC) */
const elevateOnLaunch = ref(false)
/** 硬件监控配置(可用硬件 + 传感器类型清单 + 当前启用状态) */
const hardwareConfig = ref<HardwareConfigResponse | null>(null)
let unlistenFns: UnlistenFn[] = []
// ===== getters =====
@@ -122,8 +177,6 @@ export const useMonitorStore = defineStore('monitor', () => {
errorMsg.value = null
} catch (e) {
logger.error('获取状态失败: ' + e)
} finally {
initialized.value = true
}
return status.value
}
@@ -169,6 +222,96 @@ export const useMonitorStore = defineStore('monitor', () => {
}
}
/** 以管理员权限重启 Kernel(弹 UAC)。
* 停止当前 Kernel → ShellExecute "runas" → 等待 ready → 重新订阅 SSE。
* 提权后进程不归 ProcessManager 管,停止走 /shutdown 接口。
*/
async function startElevated() {
if (starting.value) return
starting.value = true
errorMsg.value = null
try {
await invoke('monitor_start_elevated')
await refreshStatus()
} catch (e) {
errorMsg.value = String(e)
logger.error('提权启动失败: ' + e)
} finally {
starting.value = false
}
}
/** 永久提权:以管理员权限重启 Thing 自身,ThingHK 子进程会继承管理员权限。
* 非管理员时进程退出;已是管理员时仅设置标志并返回。 */
async function elevateSelf() {
if (starting.value) return
starting.value = true
errorMsg.value = null
try {
await invoke('monitor_elevate_self')
// 命令返回说明已是管理员(非管理员时进程已 exit,不会走到这里)
await refreshElevateOnLaunch()
} catch (e) {
errorMsg.value = String(e)
logger.error('永久提权失败: ' + e)
} finally {
starting.value = false
}
}
/** 刷新永久提权标志状态 */
async function refreshElevateOnLaunch() {
try {
elevateOnLaunch.value = await invoke<boolean>('monitor_get_elevate_on_launch')
} catch (e) {
logger.error('获取提权标志失败: ' + e)
}
return elevateOnLaunch.value
}
/** 取消永久提权:清除标志,下次启动不再触发 UAC(当前会话权限不变) */
async function cancelElevation() {
try {
await invoke('monitor_set_elevate_on_launch', { enabled: false })
await refreshElevateOnLaunch()
} catch (e) {
errorMsg.value = String(e)
logger.error('取消提权失败: ' + e)
}
}
/** 拉取硬件监控配置(可用硬件 + 传感器类型清单 + 当前启用状态) */
async function fetchHardwareConfig() {
try {
hardwareConfig.value = await invoke<HardwareConfigResponse>('monitor_get_hardware_config')
} catch (e) {
logger.error('获取硬件配置失败: ' + e)
}
return hardwareConfig.value
}
/** 保存硬件监控配置。
* 传感器类型过滤热生效;硬件开关变化返回 restartRequired=true。
* 调用方负责根据 restartRequired 决定是否重启 Kernel。 */
async function saveHardwareConfig(
hardware: Record<string, boolean>,
sensorTypes: Record<string, boolean>,
): Promise<HardwareConfigUpdateResponse | null> {
try {
const resp = await invoke<HardwareConfigUpdateResponse>('monitor_set_hardware_config', {
hardware,
sensorTypes,
})
// 刷新本地缓存的配置
await fetchHardwareConfig()
return resp
} catch (e) {
errorMsg.value = String(e)
logger.error('保存硬件配置失败: ' + e)
return null
}
}
/** 主动拉取一次性快照(切回 tab 时立即填充,不等下一个 SSE tick) */
async function fetchSnapshot() {
try {
@@ -196,7 +339,8 @@ export const useMonitorStore = defineStore('monitor', () => {
refreshStatus()
}))
unlistenFns.push(await listen('monitor-loading', () => {
// 状态由 status 轮询反映
// 后端正在等待 Kernel ready,刷新状态以反映 running=true
refreshStatus()
}))
unlistenFns.push(await listen('monitor-disconnected', () => {
logger.warn('SSE 断开,等待自动重连')
@@ -206,6 +350,10 @@ export const useMonitorStore = defineStore('monitor', () => {
errorMsg.value = e.payload?.message ?? 'Kernel 错误'
logger.error('Kernel 错误: ' + JSON.stringify(e.payload))
}))
// 网速监控事件(独立于 Kernel,应用启动即推送)
unlistenFns.push(await listen<NetworkSpeed>('monitor-network', (e) => {
networkSpeed.value = e.payload
}))
}
function unsubscribe() {
@@ -213,13 +361,29 @@ export const useMonitorStore = defineStore('monitor', () => {
unlistenFns = []
}
/** 模块挂载时调用:刷新状态 + 订阅事件 + 拉取一次快照 */
/** 模块挂载时调用:刷新状态 + 订阅事件 + 拉取一次快照
* 首次加载期间 initialized=falseUI 显示 loading 占位(隐藏启动按钮等),
* 避免与后端 setup 异步自动启动竞态导致按钮误显示。 */
async function init() {
await Promise.all([refreshStatus(), refreshKernelInfo()])
await subscribe()
// 若 Kernel 已就绪,立即拉一次快照避免 UI 空白
if (status.value?.ready) {
await fetchSnapshot()
try {
await Promise.all([refreshStatus(), refreshKernelInfo(), refreshElevateOnLaunch()])
await subscribe()
// 若 Kernel 已就绪,立即拉一次快照避免 UI 空白
if (status.value?.ready) {
await fetchSnapshot()
}
// 自动启动竞态修复:setup 中 start_with_subscription 是异步 spawn
// 首次 refreshStatus 可能返回 running=false(进程还未拉起)。
// 若状态仍为 idle,短暂重试以等待自动启动生效。
if (!status.value?.running) {
for (let i = 0; i < 5; i++) {
await new Promise(r => setTimeout(r, 500))
await refreshStatus()
if (status.value?.running) break
}
}
} finally {
initialized.value = true
}
}
@@ -239,6 +403,9 @@ export const useMonitorStore = defineStore('monitor', () => {
starting,
stopping,
initialized,
networkSpeed,
elevateOnLaunch,
hardwareConfig,
// getters
connState,
isLive,
@@ -247,7 +414,13 @@ export const useMonitorStore = defineStore('monitor', () => {
findSensorValue,
refreshStatus,
refreshKernelInfo,
refreshElevateOnLaunch,
start,
startElevated,
elevateSelf,
cancelElevation,
fetchHardwareConfig,
saveHardwareConfig,
stop,
fetchSnapshot,
init,