import { ipcMain } from 'electron' import dgram from 'dgram' import net from 'net' import { IPC_EVENT } from '../renderer/src/common/ipcEvents.js' import fs from 'fs' // 全局保存所有TCP连接和相关信息 const tcpClients = new Map() // 保存待处理的请求,用于关联响应 const pendingRequests = new Map() export function registerIpRouter() { ipcMain.on(IPC_EVENT.DEVICE_SEARCH, searchDevice) ipcMain.on(IPC_EVENT.DEVICE_CONNECT, connectDevice) ipcMain.on(IPC_EVENT.DEVICE_DISCONNECT, disconnectDevice) ipcMain.handle(IPC_EVENT.SENSORS_GET, sensorLoad) // 改为handle,支持异步返回 } const searchDevice = (event) => { const message = Buffer.from(JSON.stringify({ command: 'name', type: 'get' })) const PORT = 2230 const BROADCAST_ADDR = '255.255.255.255' const udpClient = dgram.createSocket('udp4') let timer = null const resultMap = new Map() udpClient.bind(() => { udpClient.setBroadcast(true) udpClient.send(message, 0, message.length, PORT, BROADCAST_ADDR, (err) => { if (err) { console.error('UDP send failed', err) udpClient.close() } else { console.log('UDP send successful') } }) }) udpClient.on('message', (msg, rinfo) => { try { resultMap.set(rinfo.address, { from: rinfo.address, data: msg.toString() }) } catch (e) { console.error('parse UDP message failed:', e) } if (timer) clearTimeout(timer) timer = setTimeout(() => { udpClient.close() console.log('UDP socket closed after timeout') event.reply && event.reply(IPC_EVENT.DEVICE_SEARCH_REPLY, Array.from(resultMap.values())) }, 1000) }) udpClient.on('error', (err) => { console.error('UDP error:', err) udpClient.close() event.reply && event.reply(IPC_EVENT.DEVICE_SEARCH_REPLY, Array.from(resultMap.values())) }) } const connectDevice = (event, { ip, port }) => { if (!ip || !port) { event.reply(IPC_EVENT.DEVICE_CONNECT_REPLY, { success: false, error: '参数缺失' }) return } if (tcpClients.has(ip)) { event.reply(IPC_EVENT.DEVICE_CONNECT_REPLY, { success: false, error: '已连接' }) return } const client = new net.Socket() // 保存连接信息,包括event sender用于后续通信 const connectionInfo = { client, eventSender: event.sender, ip, port } client.connect(Number(port), ip, () => { event.reply(IPC_EVENT.DEVICE_CONNECT_REPLY, { success: true, ip }) tcpClients.set(ip, connectionInfo) }) let buffer = '' client.on('data', (data) => { buffer += data.toString() let index while ((index = buffer.indexOf('\n')) !== -1) { const line = buffer.slice(0, index) buffer = buffer.slice(index + 1) if (!line.trim()) continue let msg try { msg = JSON.parse(line) console.log('Received command:', `${msg.command}:${msg.type}`) } catch (e) { console.error('TCP data parse error:', e) fs.appendFileSync('error_log.txt', line + '\n') continue } if (!msg || !msg.command) { console.log('invalid msg format:', msg) continue } // 处理TCP响应 handleTcpResponse(ip, msg) } }) client.on('error', (err) => { event.reply(IPC_EVENT.DEVICE_CONNECT_REPLY, { success: false, error: err.message }) client.destroy() tcpClients.delete(ip) // 清理该IP的所有待处理请求 clearPendingRequestsByIp(ip) }) client.on('close', () => { tcpClients.delete(ip) clearPendingRequestsByIp(ip) }) } const disconnectDevice = (event, { ip }) => { const connectionInfo = tcpClients.get(ip) if (connectionInfo) { connectionInfo.client.destroy() tcpClients.delete(ip) clearPendingRequestsByIp(ip) event.reply(IPC_EVENT.DEVICE_DISCONNECT_REPLY, { success: true }) } else { event.reply(IPC_EVENT.DEVICE_DISCONNECT_REPLY, { success: false, error: '未连接' }) } } // 处理TCP响应 const handleTcpResponse = (ip, msg) => { const connectionInfo = tcpClients.get(ip) if (!connectionInfo) return switch (`${msg.command}:${msg.type}`) { case IPC_EVENT.RESULT_REPLY: connectionInfo.eventSender.send(IPC_EVENT.RESULT_REPLY, { ip, ...msg }) break case IPC_EVENT.IMAGE_REPLY: connectionInfo.eventSender.send(IPC_EVENT.IMAGE_REPLY, { ip, ...msg }) break case IPC_EVENT.SENSORS_GET: { const sensorRequest = pendingRequests.get(`${ip}${IPC_EVENT.SENSORS_GET}`) if (sensorRequest) { // 响应传感器加载请求 sensorRequest.resolve({ success: true, data: msg }) pendingRequests.delete(`${ip}${IPC_EVENT.SENSORS_GET}`) } } break case IPC_EVENT.HEARTBEAT_REPLY: // 心跳处理 break default: console.warn('unknown command:', `${msg.command}:${msg.type}`) } } // 传感器加载 - 改为异步处理 const sensorLoad = async (event, { ip }) => { return new Promise((resolve, reject) => { const connectionInfo = tcpClients.get(ip) if (!connectionInfo) { resolve({ success: false, error: '设备未连接' }) return } // 生成请求ID并保存待处理请求 const requestKey = `${ip}${IPC_EVENT.SENSORS_GET}` // 设置超时 const timeout = setTimeout(() => { pendingRequests.delete(requestKey) resolve({ success: false, error: '请求超时' }) }, 10000) // 10秒超时 // 保存请求信息 pendingRequests.set(requestKey, { resolve: (result) => { clearTimeout(timeout) resolve(result) }, reject: (error) => { clearTimeout(timeout) reject(error) }, timestamp: Date.now() }) // 发送传感器加载命令 const command = { command: 'sensors', type: 'get', values: '' } const message = JSON.stringify(command) + '\n\n' connectionInfo.client.write(message, (err) => { if (err) { pendingRequests.delete(requestKey) clearTimeout(timeout) resolve({ success: false, error: err.message }) } }) }) } // 清理指定IP的所有待处理请求 const clearPendingRequestsByIp = (ip) => { const keysToDelete = [] for (const [key, request] of pendingRequests) { if (key.startsWith(`${ip}_`)) { request.resolve({ success: false, error: '连接已断开' }) keysToDelete.push(key) } } keysToDelete.forEach((key) => pendingRequests.delete(key)) }