/** * 全局应用状态 * 管理 openclaw 安装状态,供各组件查询 */ import { api } from './tauri-api.js' let _openclawReady = false let _gatewayRunning = false let _platform = '' // 'macos' | 'win32' | ... let _listeners = [] let _gwListeners = [] let _gwStopCount = 0 // 连续检测到"停止"的次数,防抖用 let _isUpgrading = false // 升级/切换版本期间,阻止 setup 跳转 let _userStopped = false // 用户主动停止,不自动拉起 let _autoRestartCount = 0 // 自动重启次数 let _lastRestartTime = 0 // 上次重启时间 const MAX_AUTO_RESTART = 3 // 最大连续自动重启次数 const RESTART_COOLDOWN = 60000 // 重启冷却期 60s let _guardianListeners = [] // 守护放弃时的回调 /** openclaw 是否就绪(CLI 已安装 + 配置文件存在) */ export function isOpenclawReady() { // 升级期间视为就绪,避免跳转到 setup if (_isUpgrading) return true return _openclawReady } /** 标记升级中(阻止 setup 跳转) */ export function setUpgrading(v) { _isUpgrading = !!v } export function isUpgrading() { return _isUpgrading } /** 标记用户主动停止 Gateway(不触发自动重启) */ export function setUserStopped(v) { _userStopped = !!v } /** 重置自动重启计数(用户手动启动后重置) */ export function resetAutoRestart() { _autoRestartCount = 0; _userStopped = false } /** 监听守护放弃事件(连续重启失败后触发,UI 可弹出恢复选项) */ export function onGuardianGiveUp(fn) { _guardianListeners.push(fn) return () => { _guardianListeners = _guardianListeners.filter(cb => cb !== fn) } } /** Gateway 是否正在运行 */ export function isGatewayRunning() { return _gatewayRunning } /** 获取后端平台 ('macos' | 'win32') */ export function getPlatform() { return _platform } export function isMacPlatform() { return _platform === 'macos' } /** 监听 Gateway 状态变化 */ export function onGatewayChange(fn) { _gwListeners.push(fn) return () => { _gwListeners = _gwListeners.filter(cb => cb !== fn) } } /** 检测 openclaw 安装状态 */ export async function detectOpenclawStatus() { try { const [installation, services] = await Promise.allSettled([ api.checkInstallation(), api.getServicesStatus(), ]) const configExists = installation.status === 'fulfilled' && installation.value?.installed if (installation.status === 'fulfilled' && installation.value?.platform) { _platform = installation.value.platform } const cliInstalled = services.status === 'fulfilled' && services.value?.length > 0 && services.value[0]?.cli_installed !== false _openclawReady = configExists && cliInstalled // 顺便检测 Gateway 运行状态 if (services.status === 'fulfilled' && services.value?.length > 0) { _setGatewayRunning(services.value[0]?.running === true) } } catch { _openclawReady = false } _listeners.forEach(fn => { try { fn(_openclawReady) } catch {} }) return _openclawReady } function _setGatewayRunning(val) { const wasRunning = _gatewayRunning const changed = wasRunning !== val _gatewayRunning = val if (changed) { if (val) { // Gateway 恢复运行,重置计数 _autoRestartCount = 0 } else if (wasRunning && !_userStopped && !_isUpgrading && _openclawReady) { // Gateway 意外停止,尝试自动重启 _tryAutoRestart() } _gwListeners.forEach(fn => { try { fn(val) } catch {} }) } } async function _tryAutoRestart() { const now = Date.now() // 冷却期内不重复重启 if (now - _lastRestartTime < RESTART_COOLDOWN) return if (_autoRestartCount >= MAX_AUTO_RESTART) { console.warn(`[guardian] Gateway 已连续自动重启 ${MAX_AUTO_RESTART} 次,停止守护,请手动检查`) _guardianListeners.forEach(fn => { try { fn() } catch {} }) return } _autoRestartCount++ _lastRestartTime = now console.log(`[guardian] Gateway 意外停止,自动重启 (${_autoRestartCount}/${MAX_AUTO_RESTART})...`) try { await api.startService('ai.openclaw.gateway') console.log('[guardian] Gateway 自动重启成功') } catch (e) { console.error('[guardian] Gateway 自动重启失败:', e) } } /** 刷新 Gateway 运行状态(轻量,仅查服务状态) * 防抖:running→stopped 需要连续 2 次检测才切换,避免瞬态误判 */ export async function refreshGatewayStatus() { try { const services = await api.getServicesStatus() if (services?.length > 0) { const nowRunning = services[0]?.running === true if (nowRunning) { _gwStopCount = 0 _setGatewayRunning(true) } else { _gwStopCount++ if (_gwStopCount >= 2 || !_gatewayRunning) { _setGatewayRunning(false) } } } } catch { _gwStopCount++ if (_gwStopCount >= 2) _setGatewayRunning(false) } return _gatewayRunning } let _pollTimer = null /** 启动 Gateway 状态轮询(每 15 秒,避免过于频繁) */ export function startGatewayPoll() { if (_pollTimer) return _pollTimer = setInterval(() => refreshGatewayStatus(), 15000) } export function stopGatewayPoll() { if (_pollTimer) { clearInterval(_pollTimer); _pollTimer = null } } /** 监听状态变化 */ export function onReadyChange(fn) { _listeners.push(fn) return () => { _listeners = _listeners.filter(cb => cb !== fn) } }