Update: 更新socket工作模式
This commit is contained in:
30
package-lock.json
generated
30
package-lock.json
generated
@@ -9,12 +9,15 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"await-to-js": "^3.0.0",
|
||||||
"commander": "^12.1.0",
|
"commander": "^12.1.0",
|
||||||
"express": "^4.21.1",
|
"express": "^4.21.1",
|
||||||
"fs-extra": "^11.2.0",
|
"fs-extra": "^11.2.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
|
"mitt": "^3.0.1",
|
||||||
"serialport": "^12.0.0",
|
"serialport": "^12.0.0",
|
||||||
"shelljs": "^0.8.5",
|
"shelljs": "^0.8.5",
|
||||||
|
"shortid": "^2.2.16",
|
||||||
"simple-git": "^3.27.0",
|
"simple-git": "^3.27.0",
|
||||||
"socket.io": "^4.8.1",
|
"socket.io": "^4.8.1",
|
||||||
"usb": "^2.14.0"
|
"usb": "^2.14.0"
|
||||||
@@ -270,6 +273,14 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/array-flatten/-/array-flatten-1.1.1.tgz",
|
"resolved": "https://registry.npmmirror.com/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
|
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/await-to-js": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/await-to-js/-/await-to-js-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/balanced-match": {
|
"node_modules/balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
@@ -917,11 +928,21 @@
|
|||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mitt": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="
|
||||||
|
},
|
||||||
"node_modules/ms": {
|
"node_modules/ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz",
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
},
|
},
|
||||||
|
"node_modules/nanoid": {
|
||||||
|
"version": "2.1.11",
|
||||||
|
"resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-2.1.11.tgz",
|
||||||
|
"integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA=="
|
||||||
|
},
|
||||||
"node_modules/negotiator": {
|
"node_modules/negotiator": {
|
||||||
"version": "0.6.3",
|
"version": "0.6.3",
|
||||||
"resolved": "https://registry.npmmirror.com/negotiator/-/negotiator-0.6.3.tgz",
|
"resolved": "https://registry.npmmirror.com/negotiator/-/negotiator-0.6.3.tgz",
|
||||||
@@ -1235,6 +1256,15 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/shortid": {
|
||||||
|
"version": "2.2.16",
|
||||||
|
"resolved": "https://registry.npmmirror.com/shortid/-/shortid-2.2.16.tgz",
|
||||||
|
"integrity": "sha512-Ugt+GIZqvGXCIItnsL+lvFJOiN7RYqlGy7QE41O3YC1xbNSeDGIRO7xg2JJXIAj1cAGnOeC1r7/T9pgrtQbv4g==",
|
||||||
|
"deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
|
||||||
|
"dependencies": {
|
||||||
|
"nanoid": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/side-channel": {
|
"node_modules/side-channel": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.6.tgz",
|
"resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.6.tgz",
|
||||||
|
|||||||
@@ -13,12 +13,15 @@
|
|||||||
"author": "Mixly Team",
|
"author": "Mixly Team",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"await-to-js": "^3.0.0",
|
||||||
"commander": "^12.1.0",
|
"commander": "^12.1.0",
|
||||||
"express": "^4.21.1",
|
"express": "^4.21.1",
|
||||||
"fs-extra": "^11.2.0",
|
"fs-extra": "^11.2.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
|
"mitt": "^3.0.1",
|
||||||
"serialport": "^12.0.0",
|
"serialport": "^12.0.0",
|
||||||
"shelljs": "^0.8.5",
|
"shelljs": "^0.8.5",
|
||||||
|
"shortid": "^2.2.16",
|
||||||
"simple-git": "^3.27.0",
|
"simple-git": "^3.27.0",
|
||||||
"socket.io": "^4.8.1",
|
"socket.io": "^4.8.1",
|
||||||
"usb": "^2.14.0"
|
"usb": "^2.14.0"
|
||||||
|
|||||||
1
src/common/config.js
Normal file
1
src/common/config.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export const DEBUG = false;
|
||||||
18
src/common/debug.js
Normal file
18
src/common/debug.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { DEBUG } from './config';
|
||||||
|
|
||||||
|
const Debug = {};
|
||||||
|
|
||||||
|
for (let key in console) {
|
||||||
|
if (typeof console[key] !== 'function') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Debug[key] = (...args) => {
|
||||||
|
if (DEBUG) {
|
||||||
|
console[key](...args);
|
||||||
|
} else {
|
||||||
|
console.log(`[${key.toUpperCase()}]`, ...args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Debug;
|
||||||
36
src/common/events-base.js
Normal file
36
src/common/events-base.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import Events from './events';
|
||||||
|
|
||||||
|
|
||||||
|
export default class EventsBase {
|
||||||
|
#events_ = new Events();
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
bind(type, func) {
|
||||||
|
return this.#events_.bind(type, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
unbind(id) {
|
||||||
|
this.#events_.unbind(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
addEventsType(eventsType) {
|
||||||
|
this.#events_.addType(eventsType);
|
||||||
|
}
|
||||||
|
|
||||||
|
runEvent(eventsType, ...args) {
|
||||||
|
return this.#events_.run(eventsType, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
offEvent(eventsType) {
|
||||||
|
this.#events_.off(eventsType);
|
||||||
|
}
|
||||||
|
|
||||||
|
resetEvent() {
|
||||||
|
this.#events_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
disposeEvent() {
|
||||||
|
this.resetEvent();
|
||||||
|
this.#events_ = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
86
src/common/events.js
Normal file
86
src/common/events.js
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
// import mitt from 'mitt';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import shortid from 'shortid';
|
||||||
|
import Debug from './debug';
|
||||||
|
import Registry from './registry';
|
||||||
|
|
||||||
|
|
||||||
|
export default class Events {
|
||||||
|
#eventsType_ = [];
|
||||||
|
#events_ = new Registry();
|
||||||
|
|
||||||
|
constructor(eventsType = []) {
|
||||||
|
this.#eventsType_ = eventsType;
|
||||||
|
}
|
||||||
|
|
||||||
|
addType(eventsType) {
|
||||||
|
this.#eventsType_ = _.uniq(_.concat([this.#eventsType_, eventsType]));
|
||||||
|
}
|
||||||
|
|
||||||
|
exist(type) {
|
||||||
|
if (!this.#eventsType_.includes(type)) {
|
||||||
|
Debug.warn(`${type} event does not exist under the class`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bind(type, func) {
|
||||||
|
if (!this.exist(type)) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
const id = shortid.generate();
|
||||||
|
let typeEvent = this.#events_.getItem(type);
|
||||||
|
if (!typeEvent) {
|
||||||
|
typeEvent = new Registry();
|
||||||
|
this.#events_.register(type, typeEvent);
|
||||||
|
}
|
||||||
|
typeEvent.register(id, func);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
unbind(id) {
|
||||||
|
for (let [_, value] of this.#events_.getAllItems()) {
|
||||||
|
let typeEvent = value;
|
||||||
|
if (!typeEvent.getItem(id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
typeEvent.unregister(id);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
off(type) {
|
||||||
|
if (this.#events_.getItem(type)) {
|
||||||
|
this.#events_.unregister(type);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
run(type, ...args) {
|
||||||
|
let outputs = [];
|
||||||
|
if (!this.exist(type)) {
|
||||||
|
return outputs;
|
||||||
|
}
|
||||||
|
const eventsFunc = this.#events_.getItem(type);
|
||||||
|
if (!eventsFunc) {
|
||||||
|
return outputs;
|
||||||
|
}
|
||||||
|
for (let [_, func] of eventsFunc.getAllItems()) {
|
||||||
|
outputs.push(func(...args));
|
||||||
|
}
|
||||||
|
return outputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
this.#events_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
length(type) {
|
||||||
|
const typeEvent = this.#events_.getItem(type);
|
||||||
|
if (typeEvent) {
|
||||||
|
return typeEvent.length();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
60
src/common/registry.js
Normal file
60
src/common/registry.js
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
export default class Registry {
|
||||||
|
#registry_ = new Map();
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
this.#registry_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
validate(keys) {
|
||||||
|
if (!(keys instanceof Array)) {
|
||||||
|
keys = [keys];
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
register(keys, value) {
|
||||||
|
keys = this.validate(keys);
|
||||||
|
for (let key of keys) {
|
||||||
|
if (this.#registry_.has(key)) {
|
||||||
|
Debug.warn(`${key}已存在,不可重复注册`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
this.#registry_.set(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unregister(keys) {
|
||||||
|
keys = this.validate(keys);
|
||||||
|
for (let key of keys) {
|
||||||
|
if (!this.#registry_.has(key)) {
|
||||||
|
Debug.warn(`${key}不存在,无需取消注册`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
this.#registry_.delete(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
length() {
|
||||||
|
return this.#registry_.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasKey(key) {
|
||||||
|
return this.#registry_.has(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
keys() {
|
||||||
|
return [...this.#registry_.keys()];
|
||||||
|
}
|
||||||
|
|
||||||
|
getItem(key) {
|
||||||
|
return this.#registry_.get(key) ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
getAllItems() {
|
||||||
|
return this.#registry_;
|
||||||
|
}
|
||||||
|
}
|
||||||
171
src/common/serial.js
Normal file
171
src/common/serial.js
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
import os from 'node:os';
|
||||||
|
import { ChildProcess } from 'node:child_process';
|
||||||
|
import {
|
||||||
|
SerialPort,
|
||||||
|
ReadlineParser,
|
||||||
|
ByteLengthParser
|
||||||
|
} from 'serialport';
|
||||||
|
import EventsBase from './events-base';
|
||||||
|
|
||||||
|
|
||||||
|
export default class Serial extends EventsBase {
|
||||||
|
static {
|
||||||
|
this.portsName = [];
|
||||||
|
|
||||||
|
this.getCurrentPortsName = function () {
|
||||||
|
return this.portsName;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getPorts = async function () {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (os.platform() === 'linux') {
|
||||||
|
ChildProcess.exec('ls /dev/ttyACM* /dev/tty*USB*', (_, stdout, stderr) => {
|
||||||
|
let portsName = MArray.unique(stdout.split('\n'));
|
||||||
|
let newPorts = [];
|
||||||
|
for (let i = 0; i < portsName.length; i++) {
|
||||||
|
if (!portsName[i]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
newPorts.push({
|
||||||
|
vendorId: 'None',
|
||||||
|
productId: 'None',
|
||||||
|
name: portsName[i]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
resolve(newPorts);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
SerialPort.list().then(ports => {
|
||||||
|
let newPorts = [];
|
||||||
|
for (let i = 0; i < ports.length; i++) {
|
||||||
|
let port = ports[i];
|
||||||
|
newPorts.push({
|
||||||
|
vendorId: port.vendorId,
|
||||||
|
productId: port.productId,
|
||||||
|
name: port.path
|
||||||
|
});
|
||||||
|
}
|
||||||
|
resolve(newPorts);
|
||||||
|
}).catch(reject);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#serialport_ = null;
|
||||||
|
#parserBytes_ = null;
|
||||||
|
#parserLine_ = null;
|
||||||
|
#port_ = null;
|
||||||
|
|
||||||
|
constructor(port) {
|
||||||
|
this.#port_ = port;
|
||||||
|
this.addEventsType(['buffer', 'String', 'error', 'open', 'close']);
|
||||||
|
}
|
||||||
|
|
||||||
|
#addEventsListener_() {
|
||||||
|
this.#parserBytes_.on('data', (buffer) => {
|
||||||
|
this.runEvent('buffer', buffer);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.#parserLine_.on('data', (str) => {
|
||||||
|
this.runEvent('String', str);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.#serialport_.on('error', (error) => {
|
||||||
|
this.runEvent('error', error);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.#serialport_.on('open', () => {
|
||||||
|
this.runEvent('open');
|
||||||
|
});
|
||||||
|
|
||||||
|
this.#serialport_.on('close', () => {
|
||||||
|
this.runEvent('close');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getPortName() {
|
||||||
|
return this.#port_;
|
||||||
|
}
|
||||||
|
|
||||||
|
async open(baud) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.#serialport_ = new SerialPort({
|
||||||
|
path: this.getPortName(),
|
||||||
|
baudRate: baud, // 波特率
|
||||||
|
dataBits: 8, // 数据位
|
||||||
|
parity: 'none', // 奇偶校验
|
||||||
|
stopBits: 1, // 停止位
|
||||||
|
flowControl: false,
|
||||||
|
autoOpen: false // 不自动打开
|
||||||
|
}, false);
|
||||||
|
this.#parserBytes_ = this.#serialport_.pipe(new ByteLengthParser({ length: 1 }));
|
||||||
|
this.#parserLine_ = this.#serialport_.pipe(new ReadlineParser());
|
||||||
|
this.#serialport_.open((error) => {
|
||||||
|
if (error) {
|
||||||
|
reject(error);
|
||||||
|
} else {
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.#addEventsListener_();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async close() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.#serialport_.close((error) => {
|
||||||
|
if (error) {
|
||||||
|
reject(error);
|
||||||
|
} else {
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async setBaudRate(baud) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.#serialport_.update({ baudRate: baud }, (error) => {
|
||||||
|
if (error) {
|
||||||
|
reject(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async send(data) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.#serialport_.write(data, (error) => {
|
||||||
|
if (error) {
|
||||||
|
reject(error);
|
||||||
|
} else {
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async setDTRAndRTS(dtr, rts) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.#serialport_.set({ dtr, rts }, (error) => {
|
||||||
|
if (error) {
|
||||||
|
reject(error);
|
||||||
|
} else {
|
||||||
|
super.setDTRAndRTS(dtr, rts);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose() {
|
||||||
|
this.disposeEvent();
|
||||||
|
this.#serialport_ = null;
|
||||||
|
this.#parserBytes_ = null;
|
||||||
|
this.#parserLine_ = null;
|
||||||
|
this.#port_ = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
23
src/web-socket/socket.js
Normal file
23
src/web-socket/socket.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { Server } from 'socket.io';
|
||||||
|
import to from 'await-to-js';
|
||||||
|
import Serial from '../common/serial';
|
||||||
|
import Debug from '../common/debug';
|
||||||
|
|
||||||
|
|
||||||
|
export default class Socket {
|
||||||
|
#io_ = null;
|
||||||
|
constructor(httpsServer, options) {
|
||||||
|
this.#io_ = new Server(httpsServer, options);
|
||||||
|
this.#io_.on('connection', (socket) => {
|
||||||
|
this.#addEventsListener_(socket);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#addEventsListener_(socket) {
|
||||||
|
socket.on('serial/get-ports', async () => {
|
||||||
|
const [error, result] = await to(Serial.getPorts());
|
||||||
|
error && Debug.error(error);
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user