/** * ServiceManager - 服务管理类 * 支持:设置路径、连接、状态查询、启动、停止 * DEBUG模式:开启后在浏览器控制台输出详细调试信息 */ export class ServiceManager { constructor(baseUrl) { // 实例属性 this.baseUrl = 'http://127.0.0.1:5000'; this.logs = []; this.maxLogs = 200; this.pollInterval = 3000; this.pollTimer = null; this.onStatusChange = null; this.previousStatus = new Map(); this.connected = false; if (baseUrl) { this.baseUrl = baseUrl; } this.log('info', `ServiceManager 创建 | API: ${this.baseUrl} | DEBUG: ${ServiceManager.DEBUG}`); } // ============================================ // DEBUG 控制 // ============================================ /** * 开启DEBUG模式 - 在浏览器控制台输出详细信息 */ static enableDebug() { ServiceManager.DEBUG = true; console.log('%c[DEBUG]%c 全局DEBUG模式已开启', 'background:#9b59b6;color:#fff;padding:2px 6px;border-radius:3px', 'color:#9b59b6'); } /** * 关闭DEBUG模式 */ static disableDebug() { ServiceManager.DEBUG = false; console.log('%c[DEBUG]%c 全局DEBUG模式已关闭', 'background:#9b59b6;color:#fff;padding:2px 6px;border-radius:3px', 'color:#9b59b6'); } /** * 获取当前DEBUG状态 */ static isDebugEnabled() { return ServiceManager.DEBUG; } // ============================================ // 内部日志 // ============================================ log(level, message, data) { const entry = { time: new Date().toLocaleTimeString(), level, message, data }; this.logs.push(entry); if (this.logs.length > this.maxLogs) { this.logs.shift(); } // 控制台输出(DEBUG模式下更详细) const timestamp = new Date().toLocaleTimeString(); const prefix = `[${level.toUpperCase()}]`; if (ServiceManager.DEBUG) { const style = this.getConsoleStyle(level); console.log(`%c${timestamp}%c ${prefix}%c ${message}`, 'color:#888', style, 'color:inherit', data || ''); if (data !== undefined) { console.log(`%c${timestamp}%c [DATA]`, 'color:#888', 'color:#3498db', data); } } else if (level === 'error' || level === 'warn') { const style = this.getConsoleStyle(level); console.log(`%c${prefix}%c ${message}`, style, 'color:inherit'); } return entry; } getConsoleStyle(level) { switch (level) { case 'error': return 'background:#e74c3c;color:#fff;padding:2px 6px;border-radius:3px'; case 'warn': return 'background:#f39c12;color:#fff;padding:2px 6px;border-radius:3px'; case 'success': return 'background:#27ae60;color:#fff;padding:2px 6px;border-radius:3px'; case 'info': return 'background:#3498db;color:#fff;padding:2px 6px;border-radius:3px'; case 'debug': return 'background:#9b59b6;color:#fff;padding:2px 6px;border-radius:3px'; default: return 'background:#95a5a6;color:#fff;padding:2px 6px;border-radius:3px'; } } // ============================================ // 配置方法 // ============================================ /** * 设置API地址 * @param url API服务器地址,如 http://127.0.0.1:5000 */ setBaseUrl(url) { this.log('info', `API地址设置: ${this.baseUrl} → ${url}`); this.baseUrl = url; } /** * 获取当前API地址 */ getBaseUrl() { return this.baseUrl; } /** * 设置轮询间隔(毫秒) * @param ms 间隔时间,默认3000ms */ setPollInterval(ms) { this.log('info', `轮询间隔设置: ${this.pollInterval}ms → ${ms}ms`); this.pollInterval = ms; if (this.pollTimer) { this.stopAutoRefresh(); this.startAutoRefresh(); } } /** * 获取轮询间隔 */ getPollInterval() { return this.pollInterval; } // ============================================ // 状态查询 // ============================================ /** * 获取连接状态 */ isConnected() { return this.connected; } /** * 获取所有服务状态 */ async getServicesStatus() { this.log('debug', `GET /api/services`); try { const response = await fetch(`${this.baseUrl}/api/services`); this.log('debug', `响应状态: ${response.status} ${response.statusText}`); if (!response.ok) { this.log('error', `HTTP错误: ${response.status}`); this.connected = false; return []; } const result = await response.json(); this.log('debug', `响应数据: ${JSON.stringify(result)}`); if (result.code === 0 && result.data) { this.connected = true; // 检查状态变化 for (const service of result.data) { const prev = this.previousStatus.get(service.id); if (prev !== undefined && prev !== service.running) { this.log('warn', `状态变化: ${service.name} → ${service.running ? '运行中' : '已停止'}`, { id: service.id, from: prev, to: service.running }); if (this.onStatusChange) { this.onStatusChange(service); } } this.previousStatus.set(service.id, service.running); } this.log('success', `获取服务状态成功: ${result.data.length} 个服务`); return result.data; } this.log('error', `API返回错误: ${result.msg || '未知错误'}`); return []; } catch (error) { this.log('error', `请求失败: ${error.message}`, { error: error.toString(), stack: error.stack }); this.connected = false; return []; } } /** * 获取单个服务状态 * @param id 服务ID */ async getServiceStatus(id) { this.log('debug', `GET /api/services/${id}`); try { const response = await fetch(`${this.baseUrl}/api/services/${id}`); this.log('debug', `响应状态: ${response.status}`); if (!response.ok) { this.log('error', `HTTP错误: ${response.status}`); return null; } const result = await response.json(); this.log('debug', `响应数据: ${JSON.stringify(result)}`); if (result.code === 0 && result.data) { this.log('success', `获取服务 ${id} 状态成功`, result.data); return result.data; } this.log('error', `获取失败: ${result.msg}`); return null; } catch (error) { this.log('error', `请求失败: ${error.message}`); return null; } } // ============================================ // 服务控制 // ============================================ /** * 启动服务 * @param id 服务ID */ async startService(id) { this.log('info', `启动服务: ${id}`); this.log('debug', `POST /api/services/${id}/start`); try { const response = await fetch(`${this.baseUrl}/api/services/${id}/start`, { method: 'POST', headers: { 'Content-Type': 'application/json' } }); this.log('debug', `响应状态: ${response.status}`); const result = await response.json(); this.log('debug', `响应数据: ${JSON.stringify(result)}`); if (result.code === 0) { this.log('success', `启动成功: ${result.msg}`, { pid: result.pid }); return true; } this.log('error', `启动失败: ${result.msg}`); return false; } catch (error) { this.log('error', `启动请求失败: ${error.message}`); return false; } } /** * 停止服务 * @param id 服务ID */ async stopService(id) { this.log('info', `停止服务: ${id}`); this.log('debug', `POST /api/services/${id}/stop`); try { const response = await fetch(`${this.baseUrl}/api/services/${id}/stop`, { method: 'POST', headers: { 'Content-Type': 'application/json' } }); this.log('debug', `响应状态: ${response.status}`); const result = await response.json(); this.log('debug', `响应数据: ${JSON.stringify(result)}`); if (result.code === 0) { this.log('success', `停止成功: ${result.msg}`, { killed: result.killed }); return true; } this.log('error', `停止失败: ${result.msg}`); return false; } catch (error) { this.log('error', `停止请求失败: ${error.message}`); return false; } } // ============================================ // 自动刷新 // ============================================ /** * 启动自动刷新 * @param callback 每次刷新后的回调函数 */ startAutoRefresh(callback) { if (this.pollTimer) { this.log('warn', '自动刷新已在运行中'); return; } this.log('info', `启动自动刷新,间隔: ${this.pollInterval}ms`); const doRefresh = async () => { this.log('debug', '--- 自动刷新触发 ---'); const services = await this.getServicesStatus(); if (callback) { callback(services); } }; doRefresh(); this.pollTimer = setInterval(doRefresh, this.pollInterval); this.log('success', '自动刷新已开始'); } /** * 停止自动刷新 */ stopAutoRefresh() { if (this.pollTimer) { clearInterval(this.pollTimer); this.pollTimer = null; this.log('info', '自动刷新已停止'); } else { this.log('warn', '自动刷新未在运行'); } } /** * 检查自动刷新是否运行中 */ isAutoRefreshRunning() { return this.pollTimer !== null; } // ============================================ // 状态变化回调 // ============================================ /** * 设置状态变化回调 * @param callback 服务状态变化时调用 */ setOnStatusChange(callback) { this.onStatusChange = callback; this.log('info', '状态变化回调已设置'); } // ============================================ // 日志管理 // ============================================ /** * 获取所有日志 */ getLogs() { return [...this.logs]; } /** * 清空日志 */ clearLogs() { this.logs = []; this.log('info', '日志已清空'); } // ============================================ // 销毁 // ============================================ /** * 销毁实例,停止所有定时器 */ destroy() { this.log('info', '销毁 ServiceManager 实例'); this.stopAutoRefresh(); this.logs = []; this.connected = false; } } // 调试开关 ServiceManager.DEBUG = false;