feat: 动态载入node-serialport和node-usb避免nwjs下server异常

This commit is contained in:
王立帮
2025-05-22 22:14:02 +08:00
parent 8de021439e
commit 958413b03a
15 changed files with 251 additions and 40 deletions

3
.gitignore vendored
View File

@@ -8,4 +8,5 @@ yarn.lock
dist
/temp
/arduino-cli
/certs
/bundle.cjs
/nw_cache

26
cert/server.crt Normal file
View File

@@ -0,0 +1,26 @@
-----BEGIN CERTIFICATE-----
MIIEXjCCAsagAwIBAgIQawifoA3zcQJDuoDTSaOE7DANBgkqhkiG9w0BAQsFADCB
hTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMS0wKwYDVQQLDCRERVNL
VE9QLVZQMU4zNzJcVXNlckBERVNLVE9QLVZQMU4zNzIxNDAyBgNVBAMMK21rY2Vy
dCBERVNLVE9QLVZQMU4zNzJcVXNlckBERVNLVE9QLVZQMU4zNzIwHhcNMjUwNTIy
MTAzNDM4WhcNMjcwODIyMTAzNDM4WjBYMScwJQYDVQQKEx5ta2NlcnQgZGV2ZWxv
cG1lbnQgY2VydGlmaWNhdGUxLTArBgNVBAsMJERFU0tUT1AtVlAxTjM3MlxVc2Vy
QERFU0tUT1AtVlAxTjM3MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
APJR4a5Xjf7MTkUocnqH2HqvhArI7hV7XZDbKPBJSlcyQUGKFRBXA7vrHg7YlVCZ
4vKHieUKNNNaPLUUVRGzjV2W6JFCmtYyoLBSijIxjEcT9iNHT8ndF3vx+ExfQmRB
qYvmGWCvnZ5NpF807ZIbabSmF7ZLrl6atp437SZ3a+xTCsGIkJf9JQvIfj5Un9tR
ed6h/P0mOJGlxzq28yljUTpgolU2iCLnE4zlnNttkm1o+X0CnhtqK2oO0h0x7Nlz
UkMvl4Y0CiUZpqG0r3Fy8JRrM7ZXf4EXTzT2uTQVI9+Hh4T+lBqCJ4QZXqJWrQ3a
EqQ1+3NWRfWe/41Oq+rkKSkCAwEAAaN2MHQwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
JQQMMAoGCCsGAQUFBwMBMB8GA1UdIwQYMBaAFIb2OJENGB0jIgBAczrFu8nddW/m
MCwGA1UdEQQlMCOCCWxvY2FsaG9zdIcErBhRrIcEqf4ojYcEwKjMAYcEfwAAATAN
BgkqhkiG9w0BAQsFAAOCAYEAe+oeVFZfEtz7dOSpqELA937hN4buhIGgB+gLZV1O
3HR5fh22lVl3CldcxdGoGWcpWurrd37DVBtM04OHOzS1R6cMeXlksRe6hPBRT0F2
D/9dtr2n8vIEEjRv2C6heuU8uSHHzgsD5PSSRdbCJ5UkoEMqVhbH2G5y7SBLc3uY
GnTb+BLA2+CP5IJIScXi0CGh/NN+fLEm8zYmxfeR5aP8O40DS0NobyM+wiv0UUsw
d0CK6GS/0iOFB05f/pGINiFRsgN5l1O0FXnWCt043XO10yqOG2yw6rB1NsvzsAuG
D2wl8BcAres9qT87Ac80h1lXDJ0gZIJxNUSJBPJxJ9c8U9NVrXMXMMBkYrXFbdQH
J7cQ8/yQjkz4aqHEtt1Z+9bdx/1WEKsgoXtyZEYiGE97rD9kZ+7qJHFkDAKI3wS2
eD14gFISoPt/X3eV+rbfrdcyUrIqesTXT7wF/L8+6XIrhRXXlq4S1zGZOf4HryH2
QLD0nwTcDhtpz7m7wKANkXga
-----END CERTIFICATE-----

28
cert/server.key Normal file
View File

@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDyUeGuV43+zE5F
KHJ6h9h6r4QKyO4Ve12Q2yjwSUpXMkFBihUQVwO76x4O2JVQmeLyh4nlCjTTWjy1
FFURs41dluiRQprWMqCwUooyMYxHE/YjR0/J3Rd78fhMX0JkQamL5hlgr52eTaRf
NO2SG2m0phe2S65emraeN+0md2vsUwrBiJCX/SULyH4+VJ/bUXneofz9JjiRpcc6
tvMpY1E6YKJVNogi5xOM5ZzbbZJtaPl9Ap4baitqDtIdMezZc1JDL5eGNAolGaah
tK9xcvCUazO2V3+BF0809rk0FSPfh4eE/pQagieEGV6iVq0N2hKkNftzVkX1nv+N
Tqvq5CkpAgMBAAECggEBALgdVM9FwSL/Et1jLRBClU4qe7ZCEvwJfv8oNgPUfAKi
sYhdpUGEC9dFftIi59iVBCXoq/J1/cs0vfmMGFLZzSh2GAD+zWzAjO1L2arnkMEU
vqjxbwNe1JAdOt60ZlqMtYkRbOjUpnr4XVLlgTjJUVir9kpRWIyTGvw+XBclF8A3
oe856SzNp7sErkNDULrv8EYAjiynlg1NB1s4Ek5t9pxlQcx8G6qRWjVhdvNAarRy
32mmWRkTt58e/I4ZPHHWG9NUHVRqeNK45Ak4dw0dth4j/BShhq+VWCoQmLESHtu7
PU30u+57tC2DuvXUsmWFqGwVkU4g942QHYQicMeCLw0CgYEA+pWBdxtSH2ItwwLv
IyNLCQjzz4Wq/0X8l5K+w98vb53buzSEHWoC/JQkChkAxYppe1dUQwLLX07FgYTp
dAhFuHuJkSil8i6kwLoArNzdybUgQORKps2oi820ANRzFljBBqkcCGGYpbzGu3fd
eEhiUeGALyzzIwt7wtGxfu7aumsCgYEA946mW5pMBcRbQhfT1dfhiCj6HZW47wXh
b7u20tCQOFGpHEcLcwWHaFNUBTTbvrqXYFjI3VKY4adXdvj6Qgc71Tv0mQRiUjxg
dAeV5wwEKCSRelNtbNcsXMe6oxn7jzNdtRn/zzP3OZ9Yo8O4cgQSBthYBx8NLI55
Uv4RWV9zN7sCgYA/mtFY5UNsGeSZulXu6ldyfKY+R6SG1UHvS11GpJEK2NvcYdEj
EjSd3hBjy8LpYV+y4hDOTZhHodv6Kz2CqVLhJ+JcSSAOIA7LqKrhNdLKD0KXlhro
ygz9J4KIL2TjCDY+tZAbBILVltwu25cIn/7s37tEvjkc7R5F7ioKmSBF7wKBgQDe
nnp9j9DjssN6OSE3ga6AGpFpv3WSBRDIwN7Uz9eRveW81yq1ofg12hGJqRIff36X
lt/zH875xdnC1H2AmS62P/djD203lLIMRbIJF2Y5j0D/5zxVD18GhFoTSE9PZJrV
PG8trwaY2/IDOwOIDJ8FZtIqfUMEmY8DEhUZ8NsU9wKBgQCwfDybwBJMQ6uueNW6
MfMlYaiQkoc5G5JjJgLRdXspsVUTsVtKmW3OWMxYjHoX2il1o+SvhNyl6pT6ydK4
X674hLtkCYiXHQvBimNTu5S0/8N/SG5k0NDKEDYHdMLT/s/mMzNofte1Tr8wGXzy
choMXR4QUuGbI/CPicSC+bD9Fg==
-----END PRIVATE KEY-----

View File

@@ -23,14 +23,15 @@
},
"client": {
"path": "./mixly",
"port": 4000
"port": 7000,
"protocol": "https:"
},
"server": {
"path": {
"temp": "./temp"
},
"mode": "all",
"protocol": "wss",
"port": 4000
"protocol": "wss:",
"port": 7000
}
}

37
config.json.nw Normal file
View File

@@ -0,0 +1,37 @@
{
"debug": true,
"arduino": {
"path": {
"folder": "./arduino-cli",
"cli": "./arduino-cli/arduino-cli.exe",
"libraries": [
"./arduino-libs/arduino-cli/libraries"
],
"config": "./arduino-cli/arduino-cli.json"
}
},
"micropython": {
"path": {
"ampy": "./mixly/tools/python/ampy_main.py",
"esptool": "./mixly/tools/python/esptool_main.py"
}
},
"python": {
"path": {
"cli": "python3"
}
},
"client": {
"path": "./mixly",
"port": 7000,
"protocol": "http:"
},
"server": {
"path": {
"temp": "./temp"
},
"mode": "compiler",
"protocol": "ws:",
"port": 7000
}
}

2
mixly

Submodule mixly updated: 13463ce183...c3e7039ffa

View File

@@ -3,7 +3,7 @@
"type": "module",
"version": "1.0.0",
"description": "",
"main": "src/index.js",
"main": "./src/index.js",
"scripts": {
"cert:generate": "node ./scripts/cert-generate.js",
"arduino:install": "node ./scripts/arduino-install.js",

72
package.json.nw Normal file
View File

@@ -0,0 +1,72 @@
{
"name": "mixly3-server",
"version": "1.0.0",
"description": "",
"node-main": "./bundle.cjs",
"main": "http://127.0.0.1:7000/mixly",
"node-remote": "http://127.0.0.1:7000/mixly",
"scripts": {
"start": "nw ./ --remote-debugging-port=9222",
"build:prod": "webpack --config=webpack.nw.cjs",
"build:nw:win:x64": "npm run build:prod && build --tasks win-x64 --mirror https://npmmirror.com/mirrors/nwjs/ .",
"build:nw:win:x86": "npm run build:prod && build --tasks win-x86 --mirror https://npmmirror.com/mirrors/nwjs/ .",
"build:nw:linux:x64": "npm run build:prod && build --tasks linux-x64 --mirror https://npmmirror.com/mirrors/nwjs/ .",
"build:nw:mac:x64": "npm run build:prod && build --tasks mac-x64 --mirror https://npmmirror.com/mirrors/nwjs/ ."
},
"window": {
"icon": "mixly/common/media/mixly.png",
"position": "center"
},
"keywords": [
"NW.js",
"server"
],
"repository": {
"type": "git",
"url": "https://gitee.com/bnu_mixly/mixly3-server.git"
},
"author": "Mixly Team",
"license": "MIT",
"dependencies": {
"await-to-js": "^3.0.0",
"better-sse": "^0.14.1",
"commander": "^12.1.0",
"decompress": "^4.2.1",
"decompress-unzip": "^4.0.1",
"express": "^4.21.1",
"fs": "^0.0.1-security",
"fs-extra": "^11.2.0",
"fs-plus": "^3.1.1",
"http": "^0.0.1-security",
"iconv-lite": "^0.6.3",
"lodash": "^4.17.21",
"mitt": "^3.0.1",
"mustache": "^4.2.0",
"node-fetch": "^3.3.2",
"node-forge": "^1.3.1",
"path": "^0.12.7",
"serialport": "^12.0.0",
"shelljs": "^0.9.2",
"shortid": "^2.2.17",
"simple-git": "^3.27.0",
"socket.io": "^4.8.1",
"tar": "^7.4.3",
"url": "^0.11.0",
"usb": "^2.14.0"
},
"build": {
"nwVersion": "0.72.0"
},
"devDependencies": {
"eslint": "^8.57.1",
"eslint-webpack-plugin": "^4.0.1",
"nodemon": "^3.1.10",
"npm-run-all": "^4.1.5",
"nw": "0.72.0-sdk",
"nwjs-builder-phoenix": "^1.15.0",
"webpack": "^5.89.0",
"webpack-cli": "^5.1.4",
"webpack-merge": "^6.0.1",
"webpack-node-externals": "^3.0.0"
}
}

View File

@@ -29,9 +29,10 @@ export const MICROPYTHON = processConfig(CONFIG.micropython);
export const PYTHON = processConfig(CONFIG.python);
export const CURRENT_PLANTFORM = os.platform();
export const TEMP_PATH = path.resolve(process.cwd(), CONFIG.server.path.temp);
export const CLIENT_PATH = path.resolve(process.cwd(), CONFIG.client.path);
export const CERTS_PATH = path.resolve(process.cwd(), 'certs');
export const CLIENT_PORT = CONFIG.client.port;
export const CLIENT_PATH = path.resolve(process.cwd(), CONFIG.client.path);
export const CLIENT_PROTOCOL = CONFIG.client.protocol;
export const SERVER_PORT = CONFIG.server.protocol === 'wss' ? CLIENT_PORT : CONFIG.server.port;
export const SERVER_MODE = CONFIG.server.mode;
export const SERVER_PROTOCOL = CONFIG.server.protocol;

View File

@@ -1,12 +1,17 @@
import { exec } from 'node:child_process';
import {
SerialPort,
ReadlineParser,
ByteLengthParser
} from 'serialport';
import _ from 'lodash';
import EventsBase from './events-base.js';
import { CURRENT_PLANTFORM } from './config.js';
import { CURRENT_PLANTFORM, SERVER_MODE } from './config.js';
let SerialPort, ReadlineParser, ByteLengthParser;
if (SERVER_MODE === 'all') {
const serial = await import('serialport');
SerialPort = serial.SerialPort;
ReadlineParser = serial.ReadlineParser;
ByteLengthParser = serial.ByteLengthParser;
}
export default class Serial extends EventsBase {

View File

@@ -1,6 +1,5 @@
import { Server } from 'socket.io';
import { to } from 'await-to-js';
import { usb } from 'usb';
import path from 'node:path';
import fsExtra from 'fs-extra';
import Serial from './serial.js';
@@ -11,7 +10,7 @@ import ShellMicroPython from './shell-micropython.js';
import ShellAmpy from './shell-ampy.js';
import MString from './mstring.js';
import Boards from './boards.js';
import { TEMP_PATH, CLIENT_PATH } from './config.js';
import { TEMP_PATH, CLIENT_PATH, SERVER_MODE } from './config.js';
export default class Socket {
@@ -37,12 +36,16 @@ export default class Socket {
this.#shellAmpy_.register(socket.id, new ShellAmpy());
this.#addEventsListenerForMode2_(socket);
});
usb.on('attach', (device) => {
this.#namespaceAll_.emit('serial.attachEvent', device);
});
usb.on('detach', (device) => {
this.#namespaceAll_.emit('serial.detachEvent', device);
});
if (SERVER_MODE === 'all') {
import('usb').then(({ usb }) => {
usb.on('attach', (device) => {
this.#namespaceAll_.emit('serial.attachEvent', device);
});
usb.on('detach', (device) => {
this.#namespaceAll_.emit('serial.detachEvent', device);
});
});
}
}
#addEventsListenerForMode1_(socket) {

View File

@@ -2,9 +2,9 @@ import os from 'node:os';
import path from 'node:path';
import fsExtra from 'fs-extra';
import fsPlus from 'fs-plus';
import forge from 'node-forge';
// import forge from 'node-forge';
import shell from 'shelljs';
import _ from 'lodash';
// import _ from 'lodash';
import { CERTS_PATH } from './config.js';
@@ -50,7 +50,7 @@ export function getCertificate() {
data.cert = fsExtra.readFileSync(crtPath);
data.key = fsExtra.readFileSync(keyPath);
}
const cert = forge.pki.certificateFromPem(data.cert);
/* const cert = forge.pki.certificateFromPem(data.cert);
const now = new Date();
const notBefore = cert.validity.notBefore;
const notAfter = cert.validity.notAfter;
@@ -73,6 +73,6 @@ export function getCertificate() {
}
} else {
data = generateCertificate();
}
} */
return data;
}

View File

@@ -5,21 +5,43 @@ import fsExtra from 'fs-extra';
import express from 'express';
import Socket from './common/socket.js';
import { getCertificate } from './common/utils.js';
import { CLIENT_PATH, CLIENT_PORT, SERVER_PORT, SERVER_MODE, SERVER_PROTOCOL } from './common/config.js';
import {
CLIENT_PATH, CLIENT_PORT, CLIENT_PROTOCOL,
SERVER_MODE, SERVER_PORT, SERVER_PROTOCOL
} from './common/config.js';
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
const app = express();
if (CLIENT_PATH) {
app.use(express.static(CLIENT_PATH));
if (typeof nw === 'object') {
app.use(express.static(path.resolve(CLIENT_PATH, '../')));
} else {
app.use(express.static(CLIENT_PATH));
}
}
const httpsServer = https.createServer(getCertificate(), app);
let httpServer = null;
if (CLIENT_PORT !== SERVER_PORT) {
httpServer = http.createServer()
let staticServer = null;
let socketServer = null;
if (CLIENT_PROTOCOL === 'https:') {
staticServer = https.createServer(getCertificate(), app);
} else {
staticServer = http.createServer(app);
}
if (SERVER_MODE !== 'static') {
const socket = new Socket(httpServer ? httpServer : httpsServer, {
if (CLIENT_PORT === SERVER_PORT) {
socketServer = staticServer;
} else {
if (SERVER_PROTOCOL === 'wss:') {
socketServer = https.createServer(getCertificate());
} else {
socketServer = http.createServer();
}
}
const socket = new Socket(socketServer, {
path: '/mixly-socket/',
maxHttpBufferSize: 1e8,
cors: {
@@ -52,11 +74,11 @@ const mixlyConfig = fsExtra.readJSONSync(mixlyConfigPath);
if (SERVER_MODE === 'compiler') {
mixlyConfig['webCompiler']['enabled'] = true;
mixlyConfig['webCompiler']['url'] = `${SERVER_PROTOCOL}://default:${SERVER_PORT}`;
mixlyConfig['webCompiler']['url'] = `${SERVER_PROTOCOL}//default:${SERVER_PORT}`;
mixlyConfig['webSocket']['enabled'] = false;
} else if (SERVER_MODE === 'all') {
mixlyConfig['webCompiler']['enabled'] = false;
mixlyConfig['webSocket']['url'] = `${SERVER_PROTOCOL}://default:${SERVER_PORT}`;
mixlyConfig['webSocket']['url'] = `${SERVER_PROTOCOL}//default:${SERVER_PORT}`;
mixlyConfig['webSocket']['enabled'] = true;
} else {
mixlyConfig['webCompiler']['enabled'] = false;
@@ -67,13 +89,17 @@ fsExtra.writeJSONSync(mixlyConfigPath, mixlyConfig, {
spaces: ' '
});
httpsServer.listen(CLIENT_PORT);
if (httpServer) {
httpServer.listen(SERVER_PORT);
if (CLIENT_PORT === SERVER_PORT) {
staticServer?.listen(CLIENT_PORT);
} else {
staticServer?.listen(CLIENT_PORT);
socketServer?.listen(SERVER_PORT);
}
if (CLIENT_PATH) {
console.log(`Static服务器正在运行: https://127.0.0.1:${CLIENT_PORT}`);
console.log(`Static服务器正在运行: ${CLIENT_PROTOCOL}//127.0.0.1:${CLIENT_PORT}`);
}
if (SERVER_MODE !== 'static') {
console.log(`Socket.io服务器正在运行: ${SERVER_PROTOCOL}://127.0.0.1:${SERVER_PORT}`);
console.log(`Socket.io服务器正在运行: ${SERVER_PROTOCOL}//127.0.0.1:${SERVER_PORT}`);
}

View File

@@ -9,5 +9,5 @@ module.exports = {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.cjs'
},
externals: [nodeExternals()],
externals: [nodeExternals()]
};

11
webpack.nw.cjs Normal file
View File

@@ -0,0 +1,11 @@
const common = require('./webpack.common.cjs');
const { merge } = require('webpack-merge');
module.exports = merge(common, {
output: {
path: __dirname,
filename: 'bundle.cjs'
},
mode: 'production'
});