/* * @Author: 李皓 hao_li_work@163.com * @Date: 2026-07-28 16:31:45 * @LastEditors: 李皓 hao_li_work@163.com * @LastEditTime: 2026-07-28 16:44:07 * @FilePath: \pc\preload.js * @Description: * @Version: 1.0.0 */ const { contextBridge, ipcRenderer } = require('electron') const nodeNet = require('net') const dns = require('dns') /** * 尝试通过 TCP 连接指定端口检测主机是否可达 */ function tryConnect(host, port, timeout) { return new Promise((resolve) => { const socket = new nodeNet.Socket() socket.setTimeout(timeout) socket.on('connect', () => { socket.destroy(); resolve(true) }) socket.on('error', () => { socket.destroy(); resolve(false) }) socket.on('timeout', () => { socket.destroy(); resolve(false) }) socket.connect(port, host) }) } /** * 网络检测对象 */ const networkUtil = { /** * 检测目标主机网络连通性 * @param {string} host - 目标主机地址 * @param {number} timeout - 超时时间(毫秒) * @returns {Promise} - 是否可达 */ async ping(host, timeout) { // 1. 先检查 DNS 能否解析 try { await dns.promises.resolve(host) } catch { return false } // 2. 依次尝试常见端口(443 优先,80 兜底) const ports = [443, 80] for (const port of ports) { const ok = await tryConnect(host, port, timeout) if (ok) return true } return false } } /** * 应用传感器对象 * 静态页面设置 appSensor.onValueCallback = function(obj) { ... } * obj 包含: { method, sensor, value } */ const sensorCallbacks = { onValueCallback: null } const appSensor = { version: '1.0.0', name: 'appSensor', get onValueCallback() { return sensorCallbacks.onValueCallback }, set onValueCallback(fn) { sensorCallbacks.onValueCallback = fn } } // 监听主进程发送的传感器数据 ipcRenderer.on('sensor-data', (_event, data) => { if (sensorCallbacks.onValueCallback) { sensorCallbacks.onValueCallback(data) } }) /** * 应用缓存对象(数据持久化到本地文件) */ const app = { /** * 获取缓存数据 * @param {string} key - 缓存键名 * @returns {Promise} 缓存值 */ getCache(key) { return ipcRenderer.invoke('get-cache', key) }, /** * 设置缓存数据 * @param {string} key - 缓存键名 * @param {any} value - 缓存值(建议传入 JSON.stringify 后的字符串) * @returns {Promise} */ setCache(key, value) { return ipcRenderer.invoke('set-cache', key, value) } } /** * USB Serial JS 桥接对象 * 静态页面可直接使用 usbSerial 或 window.usbSerial * 接口规范: docs/webview-usb-serial.md */ const usbSerialCallbacks = { onDeviceAttached: null, onDeviceDetached: null, onDeviceDiscovered: null, onDeviceProbeResult: null, onDeviceOpened: null, onDeviceState: null, onDeviceData: null } // 监听主进程发送的 usb 事件,转换为回调调用 function setupUsbSerialListeners() { const events = [ ['usb-callback-device-attached', 'onDeviceAttached'], ['usb-callback-device-detached', 'onDeviceDetached'], ['usb-callback-device-discovered', 'onDeviceDiscovered'], ['usb-callback-device-probe-result', 'onDeviceProbeResult'], ['usb-callback-device-opened', 'onDeviceOpened'], ['usb-callback-device-state', 'onDeviceState'], ['usb-callback-device-data', 'onDeviceData'] ] for (const [eventName, cbName] of events) { ipcRenderer.on(eventName, (_event, jsonStr) => { const cb = usbSerialCallbacks[cbName] if (typeof cb === 'function') { cb(jsonStr) } }) } } setupUsbSerialListeners() const usbSerial = { // --- 回调属性(可读写)--- get onDeviceAttached() { return usbSerialCallbacks.onDeviceAttached }, set onDeviceAttached(fn) { usbSerialCallbacks.onDeviceAttached = fn }, get onDeviceDetached() { return usbSerialCallbacks.onDeviceDetached }, set onDeviceDetached(fn) { usbSerialCallbacks.onDeviceDetached = fn }, get onDeviceDiscovered() { return usbSerialCallbacks.onDeviceDiscovered }, set onDeviceDiscovered(fn) { usbSerialCallbacks.onDeviceDiscovered = fn }, get onDeviceProbeResult() { return usbSerialCallbacks.onDeviceProbeResult }, set onDeviceProbeResult(fn) { usbSerialCallbacks.onDeviceProbeResult = fn }, get onDeviceOpened() { return usbSerialCallbacks.onDeviceOpened }, set onDeviceOpened(fn) { usbSerialCallbacks.onDeviceOpened = fn }, get onDeviceState() { return usbSerialCallbacks.onDeviceState }, set onDeviceState(fn) { usbSerialCallbacks.onDeviceState = fn }, get onDeviceData() { return usbSerialCallbacks.onDeviceData }, set onDeviceData(fn) { usbSerialCallbacks.onDeviceData = fn }, // --- 方法 --- startDiscovery() { ipcRenderer.send('usb-start-discovery') }, stopDiscovery() { ipcRenderer.send('usb-stop-discovery') }, getDiscoveredDevices() { return ipcRenderer.invoke('usb-get-discovered') }, deviceProbe(deviceName, portNumber, baudRate, hexCmd, timeoutMs) { ipcRenderer.send('usb-device-probe', { deviceName, portNumber, baudRate, hexCmd, timeoutMs }) }, deviceOpen(deviceName, portNumber, baudRate) { ipcRenderer.send('usb-device-open', { deviceName, portNumber, baudRate }) }, deviceClose(deviceName, portNumber) { ipcRenderer.send('usb-device-close', { deviceName, portNumber }) }, deviceWrite(deviceName, portNumber, hexData) { ipcRenderer.send('usb-device-write', { deviceName, portNumber, hexData }) } } // 安全暴露 API 给渲染进程 contextBridge.exposeInMainWorld('net', networkUtil) contextBridge.exposeInMainWorld('appSensor', appSensor) contextBridge.exposeInMainWorld('app', app) contextBridge.exposeInMainWorld('usbSerial', usbSerial)