// simulator_main.ts - 主进程管理器 import { loadConfig, RawConfig } from "./simulator_config.ts"; import { createModuleLogger, perfMonitor, logMemoryUsage, setDebugLevel, LogLevel } from "./debug_logger.ts"; interface WorkerMessage { type: "init" | "close" | "reconnect"; data?: any; } interface MainMessage { type: "ready" | "error" | "status" | "log" | "device_request"; data?: any; } interface DeviceWorkerMessage { type: "init" | "close" | "reconnect" | "action"; data?: any; } interface DeviceMainMessage { type: "ready" | "error" | "status" | "log" | "reset"; data?: any; } interface AgvWorker { worker: Worker; agvId: string; status: "starting" | "running" | "error" | "stopped"; config: any; } interface DeviceWorker { worker: Worker; deviceId: string; status: "starting" | "running" | "error" | "stopped"; config: any; deviceInfo: { ip: string; port: string; slaveId: string; deviceName: string; protocolType: string; brandName: string; }; } interface DeviceKV { [deviceId: string]: { status: string; createdAt: string; lastActivity: string; deviceInfo: any; // 添加寄存器配置信息 registersConfig?: string; actionParameters?: Array<{ key: string; value: string; }>; }; } // 持久化设备信息接口 interface PersistedDeviceInfo { deviceId: string; deviceInfo: { ip: string; port: string; slaveId: string; deviceName: string; protocolType: string; brandName: string; }; createdAt: string; lastActivity: string; // 添加寄存器配置信息 registersConfig?: string; actionParameters?: Array<{ key: string; value: string; }>; } interface PersistedDevices { devices: PersistedDeviceInfo[]; version: string; lastUpdated: string; } class DevicePersistence { private filePath: string; constructor(filePath: string = "./device_registry.json") { this.filePath = filePath; } async saveDevices(devices: PersistedDeviceInfo[]): Promise { const data: PersistedDevices = { devices, version: "1.0.0", lastUpdated: new Date().toISOString() }; try { await Deno.writeTextFile(this.filePath, JSON.stringify(data, null, 2)); console.log(`📁 Saved ${devices.length} devices to ${this.filePath}`); } catch (error) { console.error(`❌ Failed to save devices: ${(error as Error).message}`); } } async loadDevices(): Promise { try { const data = await Deno.readTextFile(this.filePath); const parsed: PersistedDevices = JSON.parse(data); console.log(`📁 Loaded ${parsed.devices.length} devices from ${this.filePath}`); return parsed.devices || []; } catch (error) { if (error instanceof Deno.errors.NotFound) { console.log(`📁 No existing device registry found at ${this.filePath}`); return []; } console.error(`❌ Failed to load devices: ${(error as Error).message}`); return []; } } async deviceExists(deviceId: string): Promise { const devices = await this.loadDevices(); return devices.some(device => device.deviceId === deviceId); } async addDevice(deviceInfo: PersistedDeviceInfo): Promise { const devices = await this.loadDevices(); // 检查是否已存在,如果存在则更新 const existingIndex = devices.findIndex(d => d.deviceId === deviceInfo.deviceId); if (existingIndex >= 0) { devices[existingIndex] = deviceInfo; console.log(`📝 Updated existing device: ${deviceInfo.deviceId}`); } else { devices.push(deviceInfo); console.log(`📝 Added new device: ${deviceInfo.deviceId}`); } await this.saveDevices(devices); } async removeDevice(deviceId: string): Promise { const devices = await this.loadDevices(); const filteredDevices = devices.filter(d => d.deviceId !== deviceId); if (filteredDevices.length < devices.length) { await this.saveDevices(filteredDevices); console.log(`📝 Removed device: ${deviceId}`); } } } class SimulatorManager { private workers: Map = new Map(); private deviceWorkers: Map = new Map(); private deviceKV: DeviceKV = {}; private config!: RawConfig; private devicePersistence: DevicePersistence; private logger = createModuleLogger("SIMULATOR_MAIN"); constructor() { this.devicePersistence = new DevicePersistence(); this.logger.info("🎯 SimulatorManager initialized"); } async initialize() { this.config = await loadConfig(); console.log("📋 Loaded configuration for", this.config.settings.robotCount, "robots"); console.log("🔧 Device simulator management initialized"); // 恢复持久化的设备 await this.restorePersistedDevices(); } private async restorePersistedDevices() { console.log("🔄 Restoring persisted devices..."); try { const persistedDevices = await this.devicePersistence.loadDevices(); if (persistedDevices.length === 0) { console.log("📱 No persisted devices found"); return; } console.log(`🚀 Starting restoration of ${persistedDevices.length} devices...`); // helper to restore a device with retries on failure const restoreWithRetry = async (pd: PersistedDeviceInfo) => { try { console.log(`🔧 Restoring device: ${pd.deviceId} (${pd.deviceInfo.deviceName})`); await this.createDeviceWorkerFromPersisted(pd); this.deviceKV[pd.deviceId] = { status: "running", createdAt: pd.createdAt, lastActivity: new Date().toISOString(), deviceInfo: pd.deviceInfo, registersConfig: pd.registersConfig, actionParameters: pd.actionParameters }; console.log(`✅ Device ${pd.deviceId} restored successfully`); } catch (error) { console.error(`❌ Failed to restore device ${pd.deviceId}:`, (error as Error).message); setTimeout(() => restoreWithRetry(pd), 5000); } }; for (const persistedDevice of persistedDevices) { restoreWithRetry(persistedDevice); } console.log(`🎉 Device restoration tasks scheduled. Active devices: ${this.getDeviceCount()}`); } catch (error) { console.error("❌ Failed to restore persisted devices:", (error as Error).message); } } private async createDeviceWorkerFromPersisted(persistedDevice: PersistedDeviceInfo): Promise { const { deviceId, deviceInfo } = persistedDevice; // 创建Worker配置 const brokerUrl = `mqtt://${this.config.mqttBroker.host}:${this.config.mqttBroker.port}`; const workerConfig = { deviceId, deviceInfo, vdaInterface: this.config.mqttBroker.vdaInterface, mqtt: { brokerUrl, options: { clean: true, keepalive: 60, } }, vehicle: { manufacturer: this.config.vehicle.manufacturer, serialNumber: deviceId, vdaVersion: this.config.vehicle.vdaVersion, } }; await this.startDeviceWorker(deviceId, deviceInfo, workerConfig); } async startAllWorkers() { console.log(`🚀 Starting ${this.config.settings.robotCount} AGV workers...`); const brokerUrl = `mqtt://${this.config.mqttBroker.host}:${this.config.mqttBroker.port}`; for (let i = 0; i < this.config.settings.robotCount; i++) { const agvId = `${this.config.vehicle.serialNumber}${i}`; const workerConfig = { vdaInterface: this.config.mqttBroker.vdaInterface, zoneSetId: this.config.settings.mapId, mapId: this.config.settings.mapId, vehicle: { manufacturer: this.config.vehicle.manufacturer, serialNumber: agvId, vdaVersion: this.config.vehicle.vdaVersion, }, mqtt: { brokerUrl, options: { clean: true, keepalive: 60, } }, settings: { robotCount: this.config.settings.robotCount, stateFrequency: this.config.settings.stateFrequency, visualizationFrequency: this.config.settings.visualizationFrequency, speed: this.config.settings.speed, }, }; await this.startWorker(agvId, workerConfig); } } private async startWorker(agvId: string, config: any): Promise { if (this.workers.has(agvId)) { console.log(`⚠️ Worker ${agvId} already exists, stopping it first`); await this.stopWorker(agvId); } console.log(`🔧 Creating worker for AGV ${agvId}`); const worker = new Worker(new URL("./simulator.ts", import.meta.url).href, { type: "module", }); const agvWorker: AgvWorker = { worker, agvId, status: "starting", config, }; this.workers.set(agvId, agvWorker); this.setupWorkerHandlers(agvWorker); // 发送初始化消息 worker.postMessage({ type: "init", data: config } as WorkerMessage); // 等待worker准备就绪 return new Promise((resolve, reject) => { const timeout = setTimeout(() => { agvWorker.status = "error"; reject(new Error(`Worker ${agvId} failed to start within timeout`)); }, 15000); // 15秒超时 const originalHandler = worker.onmessage; worker.onmessage = (event: MessageEvent) => { if (event.data.type === "ready") { clearTimeout(timeout); agvWorker.status = "running"; worker.onmessage = originalHandler; console.log(`✅ Worker ${agvId} started successfully`); resolve(); } else if (event.data.type === "error") { clearTimeout(timeout); agvWorker.status = "error"; worker.onmessage = originalHandler; reject(new Error(`Worker ${agvId} failed to start: ${event.data.data?.error}`)); } }; }); } private setupWorkerHandlers(agvWorker: AgvWorker) { const { worker, agvId } = agvWorker; worker.onmessage = (event: MessageEvent) => { const { type, data } = event.data; switch (type) { case "ready": agvWorker.status = "running"; console.log(`✅ AGV ${agvId} is ready`); break; case "error": agvWorker.status = "error"; console.error(`❌ AGV ${agvId} error:`, data?.error); break; case "status": console.log(`📊 AGV ${agvId} status:`, data?.status); if (data?.status === "closed") { agvWorker.status = "stopped"; } break; case "log": // 转发日志到控制台 console.log(data?.message); break; case "device_request": // 处理设备模拟器请求 this.handleDeviceRequest(agvId, data); break; default: console.warn(`Unknown message type from ${agvId}:`, type); } }; worker.onerror = (error) => { agvWorker.status = "error"; console.error(`❌ Worker ${agvId} error:`, error.message); }; worker.onmessageerror = (error) => { console.error(`❌ Message error from worker ${agvId}:`, error); }; } async stopWorker(agvId: string): Promise { const agvWorker = this.workers.get(agvId); if (!agvWorker) { console.warn(`⚠️ Worker ${agvId} not found`); return; } console.log(`🛑 Stopping worker ${agvId}`); return new Promise((resolve) => { const timeout = setTimeout(() => { agvWorker.worker.terminate(); this.workers.delete(agvId); console.log(`🔄 Force terminated worker ${agvId}`); resolve(); }, 5000); agvWorker.worker.onmessage = (event: MessageEvent) => { if (event.data.type === "status" && event.data.data?.status === "closed") { clearTimeout(timeout); agvWorker.worker.terminate(); this.workers.delete(agvId); console.log(`✅ Worker ${agvId} stopped gracefully`); resolve(); } }; agvWorker.worker.postMessage({ type: "close" } as WorkerMessage); }); } async stopAllWorkers(): Promise { console.log("🛑 Stopping all workers..."); const stopPromises = Array.from(this.workers.keys()).map(agvId => this.stopWorker(agvId)); await Promise.all(stopPromises); // 同时停止所有设备模拟器 await this.stopAllDeviceWorkers(); console.log("✅ All workers stopped"); } async resetWorker(agvId: string): Promise { const agvWorker = this.workers.get(agvId); if (!agvWorker) { console.error(`❌ Worker ${agvId} not found`); return; } console.log(`🔄 Resetting worker ${agvId} (restarting worker process)`); const config = agvWorker.config; await this.stopWorker(agvId); await this.startWorker(agvId, config); } async reconnectWorker(agvId: string): Promise { const agvWorker = this.workers.get(agvId); if (!agvWorker) { console.error(`❌ Worker ${agvId} not found`); return; } console.log(`🔌 Reconnecting worker ${agvId}`); agvWorker.worker.postMessage({ type: "reconnect" } as WorkerMessage); } async restartWorker(agvId: string): Promise { const agvWorker = this.workers.get(agvId); if (!agvWorker) { console.error(`❌ Worker ${agvId} not found`); return; } console.log(`🔄 Restarting worker ${agvId}`); const config = agvWorker.config; await this.stopWorker(agvId); await this.startWorker(agvId, config); } getWorkerStatus(agvId?: string) { if (agvId) { const worker = this.workers.get(agvId); return worker ? { agvId, status: worker.status } : null; } return Array.from(this.workers.entries()).map(([id, worker]) => ({ agvId: id, status: worker.status })); } getWorkerCount(): number { return this.workers.size; } // 交互式命令处理 async handleCommand(command: string, args: string[] = []) { const cmd = command.toLowerCase(); switch (cmd) { case "status": if (args[0]) { const status = this.getWorkerStatus(args[0]); if (status && !Array.isArray(status)) { console.log(`📊 AGV ${args[0]}: ${status.status}`); } else { console.log(`❌ AGV ${args[0]} not found`); } } else { const statuses = this.getWorkerStatus(); console.log("📊 AGV Worker Status:"); if (Array.isArray(statuses)) { statuses.forEach((s: any) => console.log(` ${s.agvId}: ${s.status}`)); } // 显示设备状态 console.log(`📱 Device Workers: ${this.getDeviceCount()}`); const deviceKV = this.getDeviceKV(); for (const [deviceId, info] of Object.entries(deviceKV)) { console.log(` ${deviceId}: ${info.status} (${info.deviceInfo.deviceName})`); } } break; case "devices":{ const deviceKV = this.getDeviceKV(); console.log(`📱 Active Device Simulators (${this.getDeviceCount()}):`); for (const [deviceId, info] of Object.entries(deviceKV)) { console.log(` ${deviceId}:`); console.log(` Name: ${info.deviceInfo.deviceName} (${info.deviceInfo.brandName})`); console.log(` Address: ${info.deviceInfo.ip}:${info.deviceInfo.port}/${info.deviceInfo.slaveId}`); console.log(` Protocol: ${info.deviceInfo.protocolType}`); console.log(` Status: ${info.status}`); console.log(` Created: ${info.createdAt}`); console.log(` Last Activity: ${info.lastActivity}`); // 显示寄存器配置信息 if (info.registersConfig) { console.log(` 📝 Registers Configuration:`); try { const registers = JSON.parse(info.registersConfig); console.log(` Total Registers: ${registers.length}`); registers.forEach((reg: any, index: number) => { console.log(` [${index + 1}] ${reg.name}:`); console.log(` Function Code: ${reg.fnCode} (${this.getFunctionCodeDescription(reg.fnCode)})`); console.log(` Address: ${reg.regAddress}`); console.log(` Count: ${reg.regCount}`); }); } catch (error) { console.log(` ❌ Invalid JSON format: ${info.registersConfig}`); } } else { console.log(` 📝 Registers Configuration: None`); } // 显示其他动作参数 if (info.actionParameters && info.actionParameters.length > 0) { console.log(` 🔧 Action Parameters:`); info.actionParameters.forEach((param: any, index: number) => { if (param.key !== "registers") { // registers已经单独显示了 const displayValue = param.value.length > 50 ? param.value.substring(0, 50) + '...' : param.value; console.log(` [${index + 1}] ${param.key}: ${displayValue}`); } }); } console.log(); // 空行分隔 } break; } case "devicestop": if (args[0]) { await this.stopDeviceSimulator(args[0]); } else { console.log("Usage: devicestop "); console.log("Available devices:"); const devices = this.getDeviceKV(); for (const deviceId of Object.keys(devices)) { console.log(` ${deviceId}`); } } break; case "persistent": if (args[0] === "list") { await this.listPersistedDevices(); } else if (args[0] === "clear") { await this.clearPersistedDevices(); } else if (args[0] === "restore") { await this.restorePersistedDevices(); } else { console.log("Usage: persistent "); console.log(" list - Show all persisted devices"); console.log(" clear - Clear all persisted devices"); console.log(" restore - Restore persisted devices (force reload)"); } break; case "start": await this.startAllWorkers(); break; case "stop": if (args[0]) { await this.stopWorker(args[0]); } else { await this.stopAllWorkers(); } break; case "reset": if (args[0]) { await this.resetWorker(args[0]); } else { // 重置所有workers console.log("🔄 Resetting all workers..."); const workerIds = Array.from(this.workers.keys()); for (const agvId of workerIds) { await this.resetWorker(agvId); } } break; case "reconnect": if (args[0]) { await this.reconnectWorker(args[0]); } else { console.log("Usage: reconnect "); } break; case "restart": if (args[0]) { await this.restartWorker(args[0]); } else { console.log("Usage: restart "); } break; case "count": console.log(`📊 Active Workers: ${this.getWorkerCount()}`); console.log(`📱 Active Devices: ${this.getDeviceCount()}`); break; case "debug": if (args[0] === "level") { if (args[1]) { const level = args[1].toUpperCase(); const module = args[2]; try { setDebugLevel(level, module); } catch (error) { console.log(`❌ Invalid debug level: ${level}`); console.log("Valid levels: ERROR, WARN, INFO, DEBUG, TRACE"); } } else { console.log("Usage: debug level [module]"); console.log("Levels: ERROR, WARN, INFO, DEBUG, TRACE"); console.log("Modules: DEVICE_SIMULATOR, MODBUS, MQTT, REGISTER_CONFIG, DEVICE_MANAGER, SIMULATOR_MAIN"); } } else if (args[0] === "memory") { logMemoryUsage("SIMULATOR_MAIN"); } else { console.log(` 🔧 Debug Commands: debug level [module] - Set debug level (ERROR/WARN/INFO/DEBUG/TRACE) debug memory - Show current memory usage Examples: debug level DEBUG - Set global debug level debug level TRACE DEVICE_SIMULATOR - Set module-specific level debug memory - Show memory usage `); } break; case "help": console.log(` 📖 Available Commands: AGV Management: status [agvId] - Show AGV worker status start - Start all AGV workers stop [agvId] - Stop AGV worker(s) reset [agvId] - Reset AGV worker(s) (stop and restart) reconnect - Reconnect AGV worker MQTT restart - Restart AGV worker process count - Show worker and device counts Device Management: devices - List all active device simulators devicestop - Stop specific device simulator persistent list - Show all persisted devices persistent clear - Clear all persisted devices persistent restore - Force restore persisted devices Debug Commands: debug level [module] - Set debug level debug memory - Show memory usage General: help - Show this help quit/exit - Stop all workers and exit `); break; case "quit": case "exit": await this.stopAllWorkers(); Deno.exit(0); break; default: console.log(`❌ Unknown command: ${command}. Type 'help' for available commands.`); } } async startInteractiveMode() { console.log(` 🎮 Interactive Mode Started Type 'help' for available commands Type 'quit' or 'exit' to stop all workers and exit `); // 简单的命令行界面 const encoder = new TextEncoder(); const decoder = new TextDecoder(); while (true) { // 显示提示符 await Deno.stdout.write(encoder.encode("simulator> ")); // 读取用户输入 const buf = new Uint8Array(1024); const n = await Deno.stdin.read(buf); if (n === null) break; const input = decoder.decode(buf.subarray(0, n)).trim(); if (!input) continue; const [command, ...args] = input.split(/\s+/); try { await this.handleCommand(command, args); } catch (error) { console.error(`❌ Command failed:`, (error as Error).message); } } } // 设备模拟器管理方法 private async handleDeviceRequest(agvId: string, data: any): Promise { const { action, deviceInfo, deviceId, originalAction } = data; console.log(`🔧 Handling device request from ${agvId}: ${action}`); switch (action) { case "create": await this.createDeviceSimulator(deviceInfo, originalAction); break; case "stop": await this.stopDeviceSimulator(deviceId); break; case "delete": await this.stopDeviceSimulator(deviceId); break; case "forward": await this.forwardActionToDevice(deviceId, originalAction); break; default: console.warn(`Unknown device action: ${action}`); } } private async createDeviceSimulator(deviceInfo: any, originalAction: any): Promise { const deviceId = `${deviceInfo.ip}-${deviceInfo.port}-${deviceInfo.slaveId}`; console.log(`🆕 Processing device creation request: ${deviceId}`); console.log(`📱 Device: ${deviceInfo.deviceName} (${deviceInfo.brandName})`); console.log(`🔌 Protocol: ${deviceInfo.protocolType}`); // 检查设备模拟器是否已经在运行中 if (this.deviceWorkers.has(deviceId)) { console.log(`⚠️ Device ${deviceId} worker is already running, ignoring duplicate creation request`); console.log(`📡 Forwarding action to existing device instead`); await this.forwardActionToDevice(deviceId, originalAction); return; } // 检查是否在持久化存储中存在(可能是重启后还未恢复的设备) const persistedExists = await this.devicePersistence.deviceExists(deviceId); if (persistedExists) { console.log(`📁 Device ${deviceId} exists in persistent storage but worker not running`); console.log(`🚀 Starting worker for existing persisted device`); } else { console.log(`🆕 Creating new device: ${deviceId}`); } // 创建Worker配置 const brokerUrl = `mqtt://${this.config.mqttBroker.host}:${this.config.mqttBroker.port}`; const workerConfig = { deviceId, deviceInfo, vdaInterface: this.config.mqttBroker.vdaInterface, mqtt: { brokerUrl, options: { clean: true, keepalive: 60, } }, vehicle: { manufacturer: this.config.vehicle.manufacturer, serialNumber: deviceId, vdaVersion: this.config.vehicle.vdaVersion, } }; // Attempt to start the device worker, but proceed regardless of success or failure let startError: Error | null = null; try { await this.startDeviceWorker(deviceId, deviceInfo, workerConfig); } catch (error) { startError = error as Error; console.error(`❌ Failed to start device worker for ${deviceId}:`, startError.message); } // Record and persist the device in all cases const now = new Date().toISOString(); // 提取寄存器配置 const registersParam = originalAction.actionParameters?.find((p: any) => p.key === "registers"); const registersConfig = registersParam?.value; // 更新KV存储 this.deviceKV[deviceId] = { status: startError ? "error" : "running", createdAt: now, lastActivity: now, deviceInfo, registersConfig, actionParameters: originalAction.actionParameters }; // 保存到持久化存储 const persistedDevice: PersistedDeviceInfo = { deviceId, deviceInfo, createdAt: now, lastActivity: now, registersConfig, actionParameters: originalAction.actionParameters }; await this.devicePersistence.addDevice(persistedDevice); // 等待设备模拟器启动完成后发送初始action setTimeout(async () => { await this.forwardActionToDevice(deviceId, originalAction); }, 2000); // Provide a combined status message if (startError) { console.log(`⚠ Device simulator ${deviceId} added but worker start failed: ${startError.message}`); } else { console.log(`✅ Device simulator ${deviceId} created and persisted successfully`); } } private async startDeviceWorker(deviceId: string, deviceInfo: any, config: any): Promise { console.log(`🔧 Starting device worker for ${deviceId}`); const worker = new Worker(new URL("./device_simulator.ts", import.meta.url).href, { type: "module", }); const deviceWorker: DeviceWorker = { worker, deviceId, status: "starting", config, deviceInfo, }; this.deviceWorkers.set(deviceId, deviceWorker); this.setupDeviceWorkerHandlers(deviceWorker); // 发送初始化消息 worker.postMessage({ type: "init", data: config } as DeviceWorkerMessage); // 等待worker准备就绪 return new Promise((resolve, reject) => { const timeout = setTimeout(() => { deviceWorker.status = "error"; reject(new Error(`Device worker ${deviceId} failed to start within timeout`)); }, 15000); const originalHandler = worker.onmessage; worker.onmessage = (event: MessageEvent) => { if (event.data.type === "ready") { clearTimeout(timeout); deviceWorker.status = "running"; worker.onmessage = originalHandler; console.log(`✅ Device worker ${deviceId} started successfully`); resolve(); } else if (event.data.type === "error") { clearTimeout(timeout); deviceWorker.status = "error"; worker.onmessage = originalHandler; reject(new Error(`Device worker ${deviceId} failed to start: ${event.data.data?.error}`)); } }; }); } private setupDeviceWorkerHandlers(deviceWorker: DeviceWorker) { const { worker, deviceId } = deviceWorker; worker.onmessage = (event: MessageEvent) => { const { type, data } = event.data; switch (type) { case "ready": deviceWorker.status = "running"; console.log(`✅ Device ${deviceId} is ready`); break; case "error": deviceWorker.status = "error"; console.error(`❌ Device ${deviceId} error:`, data?.error); break; case "status": console.log(`📊 Device ${deviceId} status:`, data?.status); if (data?.status === "closed") { deviceWorker.status = "stopped"; // 设备 worker 自我关闭时,需要完整清理所有数据 this.handleDeviceWorkerClosure(deviceId); } break; case "log": // 转发日志到控制台 console.log(data?.message); break; case "reset": console.log(`🔄 Worker reset requested for device ${deviceId}: ${data?.reason}`); console.log(`Error: ${data?.error}`); this.handleDeviceWorkerReset(deviceWorker, data); break; default: console.warn(`Unknown message type from device ${deviceId}:`, type); } // 更新最后活动时间 if (this.deviceKV[deviceId]) { this.deviceKV[deviceId].lastActivity = new Date().toISOString(); } }; worker.onerror = (error) => { deviceWorker.status = "error"; console.error(`❌ Device worker ${deviceId} error:`, error.message); }; worker.onmessageerror = (error) => { console.error(`❌ Message error from device worker ${deviceId}:`, error); }; } private async handleDeviceWorkerReset(deviceWorker: DeviceWorker, resetData: any): Promise { const { deviceId } = deviceWorker; console.log(`🔄 Resetting device worker ${deviceId} due to: ${resetData?.reason}`); try { // 终止当前worker deviceWorker.worker.terminate(); // 创建新的worker const newWorker = new Worker(new URL("./device_simulator.ts", import.meta.url).href, { type: "module", }); // 更新worker引用 deviceWorker.worker = newWorker; deviceWorker.status = "starting"; // 重新设置消息处理 this.setupDeviceWorkerHandlers(deviceWorker); // 重新初始化 newWorker.postMessage({ type: "init", data: deviceWorker.config } as DeviceWorkerMessage); console.log(`✅ Device worker ${deviceId} reset completed`); } catch (error) { console.error(`❌ Failed to reset device worker ${deviceId}:`, (error as Error).message); deviceWorker.status = "error"; } } private async forwardActionToDevice(deviceId: string, action: any): Promise { const deviceWorker = this.deviceWorkers.get(deviceId); if (!deviceWorker) { console.warn(`⚠️ Device worker ${deviceId} not found, cannot forward action`); return; } console.log(`📡 Forwarding action to device ${deviceId}: ${action.actionType}`); deviceWorker.worker.postMessage({ type: "action", data: action } as DeviceWorkerMessage); } // 处理设备 worker 自我关闭(如 deviceDelete 触发的关闭) private async handleDeviceWorkerClosure(deviceId: string): Promise { console.log(`🔄 Handling device worker closure for ${deviceId}`); // 清理内存引用 this.cleanupDeviceReferences(deviceId); // 检查是否是 deviceDelete 操作导致的关闭,如果是,则清理持久化数据 // 注意:这里我们需要判断是正常删除还是意外关闭 // 由于 deviceDelete 会主动关闭 worker,我们检查持久化存储中是否仍然存在此设备 try { const deviceExists = await this.devicePersistence.deviceExists(deviceId); if (deviceExists) { console.log(`🗑️ Device ${deviceId} closure appears to be from deviceDelete, cleaning up persistent data...`); await this.cleanupDeviceData(deviceId); } else { console.log(`ℹ️ Device ${deviceId} closure - no persistent data cleanup needed`); } } catch (error) { console.error(`❌ Error checking device existence during closure: ${(error as Error).message}`); } console.log(`✅ Device worker closure handling completed for ${deviceId}`); } // 只停止设备worker,不删除持久化数据(用于应用退出时) private async stopDeviceWorker(deviceId: string): Promise { const deviceWorker = this.deviceWorkers.get(deviceId); if (!deviceWorker) { console.warn(`⚠️ Device worker ${deviceId} not found`); return; } console.log(`🛑 Stopping device worker ${deviceId} (preserving persistence)`); return new Promise((resolve) => { const timeout = setTimeout(() => { deviceWorker.worker.terminate(); this.deviceWorkers.delete(deviceId); delete this.deviceKV[deviceId]; console.log(`🔄 Force terminated device worker ${deviceId}`); resolve(); }, 5000); deviceWorker.worker.onmessage = (event: MessageEvent) => { if (event.data.type === "status" && event.data.data?.status === "closed") { clearTimeout(timeout); deviceWorker.worker.terminate(); this.deviceWorkers.delete(deviceId); delete this.deviceKV[deviceId]; console.log(`✅ Device worker ${deviceId} stopped gracefully`); resolve(); } }; deviceWorker.worker.postMessage({ type: "close" } as DeviceWorkerMessage); }); } // 停止设备模拟器并删除持久化数据(用于明确的设备删除) private async stopDeviceSimulator(deviceId: string): Promise { const deviceWorker = this.deviceWorkers.get(deviceId); if (!deviceWorker) { console.warn(`⚠️ Device worker ${deviceId} not found`); // 即使worker不存在,也要尝试清理持久化数据 await this.cleanupDeviceData(deviceId); return; } console.log(`🛑 Stopping device simulator ${deviceId} (removing all data)`); return new Promise((resolve) => { const timeout = setTimeout(() => { console.log(`⚠️ Timeout waiting for ${deviceId} to close gracefully, forcing termination`); deviceWorker.worker.terminate(); this.cleanupDeviceReferences(deviceId); console.log(`🔄 Force terminated device worker ${deviceId}`); resolve(); }, 5000); deviceWorker.worker.onmessage = (event: MessageEvent) => { if (event.data.type === "status" && event.data.data?.status === "closed") { clearTimeout(timeout); deviceWorker.worker.terminate(); this.cleanupDeviceReferences(deviceId); console.log(`✅ Device worker ${deviceId} stopped gracefully`); resolve(); } }; deviceWorker.worker.postMessage({ type: "close" } as DeviceWorkerMessage); }).then(async () => { // 完整清理所有设备数据 await this.cleanupDeviceData(deviceId); }); } // 清理内存中的设备引用 private cleanupDeviceReferences(deviceId: string): void { console.log(`🧹 Cleaning up device references for ${deviceId}`); // 清理设备Worker映射 if (this.deviceWorkers.has(deviceId)) { this.deviceWorkers.delete(deviceId); console.log(` ✅ Removed device worker reference`); } // 清理设备KV存储 if (this.deviceKV[deviceId]) { delete this.deviceKV[deviceId]; console.log(` ✅ Removed device KV data`); } } // 清理持久化的设备数据 private async cleanupDeviceData(deviceId: string): Promise { console.log(`🗑️ Cleaning up persistent data for ${deviceId}`); try { // 从持久化存储中移除设备 await this.devicePersistence.removeDevice(deviceId); console.log(` ✅ Device ${deviceId} removed from persistent storage`); // 验证删除是否成功 const stillExists = await this.devicePersistence.deviceExists(deviceId); if (stillExists) { console.warn(` ⚠️ Device ${deviceId} still exists in persistent storage after deletion attempt`); } else { console.log(` ✅ Verified: Device ${deviceId} successfully removed from persistent storage`); } } catch (error) { console.error(` ❌ Failed to remove device ${deviceId} from persistent storage:`, (error as Error).message); // 尝试强制清理 console.log(` 🔄 Attempting force cleanup for ${deviceId}`); try { const devices = await this.devicePersistence.loadDevices(); const filteredDevices = devices.filter(d => d.deviceId !== deviceId); await this.devicePersistence.saveDevices(filteredDevices); console.log(` ✅ Force cleanup completed for ${deviceId}`); } catch (forceError) { console.error(` ❌ Force cleanup failed:`, (forceError as Error).message); } } console.log(`🎯 Device ${deviceId} cleanup completed`); } private async stopAllDeviceWorkers(): Promise { console.log("🛑 Stopping all device workers..."); // 使用新的stopDeviceWorker方法,只停止worker但保留持久化数据 const stopPromises = Array.from(this.deviceWorkers.keys()).map(deviceId => this.stopDeviceWorker(deviceId)); await Promise.all(stopPromises); console.log("✅ All device workers stopped"); } getDeviceKV(): DeviceKV { return { ...this.deviceKV }; } getDeviceCount(): number { return this.deviceWorkers.size; } private getFunctionCodeDescription(fnCode: string): string { const descriptions: Record = { "1": "Read Coils (读线圈)", "2": "Read Discrete Inputs (读离散输入)", "3": "Read Holding Registers (读保持寄存器)", "4": "Read Input Registers (读输入寄存器)", "5": "Write Single Coil (写单个线圈)", "6": "Write Single Register (写单个寄存器)", "15": "Write Multiple Coils (写多个线圈)", "16": "Write Multiple Registers (写多个寄存器)" }; return descriptions[fnCode] || `Unknown Function Code (未知功能码 ${fnCode})`; } private async listPersistedDevices() { const devices = await this.devicePersistence.loadDevices(); console.log(`📁 Persisted Devices (${devices.length}):`); devices.forEach((device, index) => { console.log(`${index + 1}. ${device.deviceId}:`); console.log(` Name: ${device.deviceInfo.deviceName} (${device.deviceInfo.brandName})`); console.log(` Address: ${device.deviceInfo.ip}:${device.deviceInfo.port}/${device.deviceInfo.slaveId}`); console.log(` Protocol: ${device.deviceInfo.protocolType}`); console.log(` Created: ${device.createdAt}`); console.log(` Last Activity: ${device.lastActivity}`); // 显示寄存器配置信息 if (device.registersConfig) { console.log(` 📝 Registers Configuration:`); try { const registers = JSON.parse(device.registersConfig); console.log(` Total Registers: ${registers.length}`); registers.forEach((reg: any, regIndex: number) => { console.log(` [${regIndex + 1}] ${reg.name}:`); console.log(` Function Code: ${reg.fnCode} (${this.getFunctionCodeDescription(reg.fnCode)})`); console.log(` Address: ${reg.regAddress}`); console.log(` Count: ${reg.regCount}`); }); } catch (error) { console.log(` ❌ Invalid JSON format: ${device.registersConfig}`); } } else { console.log(` 📝 Registers Configuration: None`); } console.log(); // 空行分隔 }); } private async clearPersistedDevices() { await this.devicePersistence.saveDevices([]); console.log("📁 All persisted devices cleared"); } } // 主程序入口 if (import.meta.main) { const manager = new SimulatorManager(); // 重试配置 const RETRY_CONFIG = { maxRetries: 10, // 最大重试次数 initialDelay: 1000, // 初始延迟 1秒 maxDelay: 30000, // 最大延迟 30秒 backoffMultiplier: 2 // 指数退避倍数 }; let retryCount = 0; let currentDelay = RETRY_CONFIG.initialDelay; // 延迟函数 const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); // 启动函数 const startSimulator = async (): Promise => { try { console.log(`🚀 Starting simulator (attempt ${retryCount + 1}/${RETRY_CONFIG.maxRetries + 1})...`); await manager.initialize(); await manager.startAllWorkers(); console.log(` 🎯 All ${manager.getWorkerCount()} AGV workers started successfully! Starting interactive mode... `); // 重置重试计数器 retryCount = 0; currentDelay = RETRY_CONFIG.initialDelay; return; // 成功启动,退出重试循环 } catch (error) { const errorMessage = (error as Error).message; console.error(`❌ Startup failed (attempt ${retryCount + 1}):`, errorMessage); retryCount++; if (retryCount > RETRY_CONFIG.maxRetries) { console.error(`💥 Maximum retry attempts (${RETRY_CONFIG.maxRetries}) exceeded. Giving up.`); console.error("🔧 Please check your configuration and network connectivity."); Deno.exit(1); } console.log(`⏳ Waiting ${currentDelay / 1000}s before retry ${retryCount + 1}...`); await delay(currentDelay); // 指数退避,但不超过最大延迟 currentDelay = Math.min( currentDelay * RETRY_CONFIG.backoffMultiplier, RETRY_CONFIG.maxDelay ); // 递归重试 return startSimulator(); } }; // 启动模拟器 await startSimulator(); // 处理进程信号 Deno.addSignalListener("SIGINT", async () => { console.log("\n⚠️ Received SIGINT, shutting down..."); await manager.stopAllWorkers(); Deno.exit(0); }); // SIGTERM只在非Windows系统支持 if (Deno.build.os !== "windows") { Deno.addSignalListener("SIGTERM", async () => { console.log("\n⚠️ Received SIGTERM, shutting down..."); await manager.stopAllWorkers(); Deno.exit(0); }); } // 启动交互模式 await manager.startInteractiveMode(); }