监控模块 优化
This commit is contained in:
+182
-9
@@ -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=false,UI 显示 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,
|
||||
|
||||
Reference in New Issue
Block a user