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() export function registerIpRouter() { ipcMain.on(IPC_EVENT.DEVICE_SEARCH, searchDevice) // 设备搜索 ipcMain.on(IPC_EVENT.DEVICE_CONNECT, connectDevice) // 设备连接 ipcMain.on(IPC_EVENT.DEVICE_DISCONNECT, disconnectDevice) // 设备断开 } 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 { // 以 IP 为 key,自动去重 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) // 1秒内没有新消息就关闭 }) 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() client.connect(Number(port), ip, () => { event.reply(IPC_EVENT.DEVICE_CONNECT_REPLY, { success: true, ip }) tcpClients.set(ip, client) }) 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(msg.command) } 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 } switch (msg.command) { case 'result': event.sender.send(IPC_EVENT.SENSOR_DATA, { ip, ...msg }) break case 'image': event.sender.send(IPC_EVENT.IMAGE_DATA, { ip, ...msg }) break case 'heartbeat': break default: console.warn('unknow command type:', msg.command) } } }) client.on('error', (err) => { event.reply(IPC_EVENT.DEVICE_CONNECT_REPLY, { success: false, error: err.message }) client.destroy() tcpClients.delete(ip) }) client.on('close', () => { tcpClients.delete(ip) }) } const disconnectDevice = (event, { ip }) => { const client = tcpClients.get(ip) if (client) { client.destroy() tcpClients.delete(ip) event.reply(IPC_EVENT.DEVICE_DISCONNECT_REPLY, { success: true }) } else { event.reply(IPC_EVENT.DEVICE_DISCONNECT_REPLY, { success: false, error: '未连接' }) } }