初始化提交
This commit is contained in:
188
common/modules/mixly-modules/workers/common/serial-worker.js
Normal file
188
common/modules/mixly-modules/workers/common/serial-worker.js
Normal file
@@ -0,0 +1,188 @@
|
||||
class SerialWorker {
|
||||
#receiveBuffer_ = [];
|
||||
#bufferLength_ = 0;
|
||||
#encoder_ = new TextEncoder();
|
||||
#decoder_ = new TextDecoder('utf-8');
|
||||
#baud_ = 115200;
|
||||
#dtr_ = false;
|
||||
#rts_ = false;
|
||||
#isOpened_ = false;
|
||||
#port_ = '';
|
||||
constructor(port) {
|
||||
this.#port_ = port;
|
||||
this.resetBuffer();
|
||||
}
|
||||
|
||||
decodeBuffer(buffer) {
|
||||
let output = '';
|
||||
for (let i in buffer) {
|
||||
output += this.decodeByte();
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/* UTF-8编码方式
|
||||
* ------------------------------------------------------------
|
||||
* |1字节 0xxxxxxx |
|
||||
* |2字节 110xxxxx 10xxxxxx |
|
||||
* |3字节 1110xxxx 10xxxxxx 10xxxxxx |
|
||||
* |4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
|
||||
* |5字节 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx |
|
||||
* |6字节 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx|
|
||||
* ------------------------------------------------------------
|
||||
**/
|
||||
decodeByte(byte) {
|
||||
let output = '';
|
||||
if ((byte & 0x80) === 0x00) {
|
||||
// 1字节
|
||||
this.#receiveBuffer_ = [];
|
||||
this.#bufferLength_ = 0;
|
||||
output += String.fromCharCode(byte);
|
||||
} else if ((byte & 0xc0) === 0x80) {
|
||||
/*
|
||||
* 2字节以上的中间字节,10xxxxxx
|
||||
* 如果没有起始头,则丢弃这个字节
|
||||
* 如果不是2字节及以上的起始头,则丢弃这个字节
|
||||
**/
|
||||
if (!this.#receiveBuffer_.length || this.#bufferLength_ < 2) {
|
||||
return output;
|
||||
}
|
||||
this.#receiveBuffer_.push(byte);
|
||||
if (this.#bufferLength_ === this.#receiveBuffer_.length) {
|
||||
output += this.#decoder_.decode(new Uint8Array(this.#receiveBuffer_));
|
||||
this.#receiveBuffer_ = [];
|
||||
}
|
||||
} else {
|
||||
// 2字节以上的起始头
|
||||
if (this.#receiveBuffer_) {
|
||||
this.#receiveBuffer_ = [];
|
||||
}
|
||||
this.#bufferLength_ = this.#getBufferLength_(byte);
|
||||
this.#receiveBuffer_.push(byte);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
#getBufferLength_(data) {
|
||||
let len = 2;
|
||||
if ((data & 0xFC) === 0xFC) {
|
||||
len = 6;
|
||||
} else if ((data & 0xF8) === 0xF8) {
|
||||
len = 5;
|
||||
} else if ((data & 0xF0) === 0xF0) {
|
||||
len = 4;
|
||||
} else if ((data & 0xE0) === 0xE0) {
|
||||
len = 3;
|
||||
} else if ((data & 0xC0) === 0xC0) {
|
||||
len = 2;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
resetBuffer() {
|
||||
this.#receiveBuffer_ = [];
|
||||
this.#bufferLength_ = 0;
|
||||
}
|
||||
|
||||
open() {}
|
||||
|
||||
close() {}
|
||||
|
||||
toggle() {
|
||||
if (this.isOpened()) {
|
||||
this.close();
|
||||
} else {
|
||||
this.open();
|
||||
}
|
||||
}
|
||||
|
||||
setBaudRate(baud) {
|
||||
this.#baud_ = baud;
|
||||
}
|
||||
|
||||
setDTR(dtr) {
|
||||
this.#dtr_ = dtr;
|
||||
}
|
||||
|
||||
setRTS(rts) {
|
||||
this.#rts_ = rts;
|
||||
}
|
||||
|
||||
setDTRAndRTS(dtr, rts) {
|
||||
this.#dtr_ = dtr;
|
||||
this.#rts_ = rts;
|
||||
}
|
||||
|
||||
getPortName() {
|
||||
return this.#port_;
|
||||
}
|
||||
|
||||
getBaudRate() {
|
||||
return this.#baud_;
|
||||
}
|
||||
|
||||
getDTR() {
|
||||
return this.#dtr_;
|
||||
}
|
||||
|
||||
getRTS() {
|
||||
return this.#rts_;
|
||||
}
|
||||
|
||||
sendString(str) {}
|
||||
|
||||
sendBuffer(buffer) {}
|
||||
|
||||
onBuffer(buffer) {
|
||||
const data = this.decodeBuffer(buffer);
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
self.postMessage({
|
||||
port: this.getPortName(),
|
||||
event: 'onBuffer',
|
||||
message: data
|
||||
});
|
||||
}
|
||||
|
||||
onOpen() {
|
||||
this.#isOpened_ = true;
|
||||
self.postMessage({
|
||||
port: this.getPortName(),
|
||||
event: 'onOpen'
|
||||
});
|
||||
}
|
||||
|
||||
onClose(code) {
|
||||
this.#isOpened_ = false;
|
||||
self.postMessage({
|
||||
port: this.getPortName(),
|
||||
event: 'onClose',
|
||||
message: code
|
||||
});
|
||||
}
|
||||
|
||||
onError(error) {
|
||||
self.postMessage({
|
||||
port: this.getPortName(),
|
||||
event: 'onError',
|
||||
message: error
|
||||
});
|
||||
}
|
||||
|
||||
isOpened() {
|
||||
return this.#isOpened_;
|
||||
}
|
||||
|
||||
config(info) {
|
||||
if (typeof info !== Object) {
|
||||
return;
|
||||
}
|
||||
this.#baud_ = info.baud;
|
||||
this.setBaudRate(this.#baud_);
|
||||
this.#dtr_ = info.dtr;
|
||||
this.setDTR(this.#dtr_);
|
||||
this.#rts_ = info.rts;
|
||||
this.setDTR(this.#rts_);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
const chokidar = require('chokidar');
|
||||
|
||||
let watchedPath = {};
|
||||
|
||||
const watch = function(inPath) {
|
||||
if (watchedPath[watchedPath]) {
|
||||
return;
|
||||
}
|
||||
watchedPath[inPath] = chokidar.watch(inPath, {
|
||||
persistent: true,
|
||||
depth: 0,
|
||||
ignoreInitial: true
|
||||
});
|
||||
|
||||
watchedPath[inPath].on('add', (actionPath, stats) => {
|
||||
self.postMessage({
|
||||
watcher: inPath,
|
||||
event: 'add',
|
||||
path: actionPath,
|
||||
stats
|
||||
});
|
||||
});
|
||||
|
||||
watchedPath[inPath].on('addDir', (actionPath, stats) => {
|
||||
self.postMessage({
|
||||
watcher: inPath,
|
||||
event: 'addDir',
|
||||
path: actionPath,
|
||||
stats
|
||||
});
|
||||
});
|
||||
|
||||
watchedPath[inPath].on('unlink', (actionPath, stats) => {
|
||||
self.postMessage({
|
||||
watcher: inPath,
|
||||
event: 'unlink',
|
||||
path: actionPath,
|
||||
stats
|
||||
});
|
||||
});
|
||||
|
||||
watchedPath[inPath].on('unlinkDir', (actionPath, stats) => {
|
||||
self.postMessage({
|
||||
watcher: inPath,
|
||||
event: 'unlinkDir',
|
||||
path: actionPath,
|
||||
stats
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const unwatch = function(inPath) {
|
||||
if (!watchedPath[inPath]) {
|
||||
return;
|
||||
}
|
||||
watchedPath[inPath].close();
|
||||
delete watchedPath[inPath];
|
||||
}
|
||||
|
||||
self.addEventListener('message', function(event) {
|
||||
if (event.data.func === 'watch') {
|
||||
watch(...event.data.args);
|
||||
} else if (event.data.func === 'unwatch') {
|
||||
unwatch(...event.data.args);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,92 @@
|
||||
importScripts('../common/serial-worker.js');
|
||||
const lodash_fp = require('lodash/fp');
|
||||
const child_process = require('node:child_process');
|
||||
const serialport = require('serialport');
|
||||
|
||||
const {
|
||||
SerialPort,
|
||||
ReadlineParser,
|
||||
ByteLengthParser
|
||||
} = serialport;
|
||||
|
||||
const portsOperator = {};
|
||||
|
||||
class NodeSerialWorker extends SerialWorker {
|
||||
#serialport_ = null;
|
||||
#parserBytes_ = null;
|
||||
constructor(port) {
|
||||
super(port);
|
||||
}
|
||||
|
||||
#addEventsListener_() {
|
||||
this.#parserBytes_.on('data', (buffer) => {
|
||||
this.onBuffer(buffer);
|
||||
});
|
||||
|
||||
this.#serialport_.on('error', (error) => {
|
||||
this.onError(error);
|
||||
this.onClose(1);
|
||||
});
|
||||
|
||||
this.#serialport_.on('open', () => {
|
||||
this.onOpen();
|
||||
});
|
||||
|
||||
this.#serialport_.on('close', () => {
|
||||
this.onClose(1);
|
||||
});
|
||||
}
|
||||
|
||||
open() {
|
||||
super.open();
|
||||
this.#serialport_ = new SerialPort({
|
||||
path: this.getPortName(),
|
||||
baudRate: this.getBaudRate() - 0, // 波特率
|
||||
dataBits: 8, // 数据位
|
||||
parity: 'none', // 奇偶校验
|
||||
stopBits: 1, // 停止位
|
||||
flowControl: false,
|
||||
autoOpen: false // 不自动打开
|
||||
}, false);
|
||||
this.#parserBytes_ = this.#serialport_.pipe(new ByteLengthParser({ length: 1 }));
|
||||
this.#serialport_.open((error) => {
|
||||
if (error) {
|
||||
this.onError(error);
|
||||
// this.onClose(1);
|
||||
}
|
||||
});
|
||||
this.#addEventsListener_();
|
||||
}
|
||||
|
||||
close() {
|
||||
super.close();
|
||||
if (this.isOpened()) {
|
||||
try {
|
||||
this.#serialport_.close();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onBuffer(buffer) {
|
||||
super.onBuffer(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
const create = (port) => {
|
||||
if (!portsOperator[port]) {
|
||||
portsOperator[port] = new NodeSerialWorker(port);
|
||||
}
|
||||
portsOperator[port].open();
|
||||
}
|
||||
|
||||
self.addEventListener('message', function(event) {
|
||||
console.log(event.data);
|
||||
const { port, type } = event.data;
|
||||
if (type === 'open') {
|
||||
create(port);
|
||||
} else if (type === 'close') {
|
||||
portsOperator[port] && portsOperator[port].close();
|
||||
}
|
||||
});
|
||||
132
common/modules/mixly-modules/workers/web/file-system-access.js
Normal file
132
common/modules/mixly-modules/workers/web/file-system-access.js
Normal file
@@ -0,0 +1,132 @@
|
||||
importScripts('../../../web-modules/workerpool.min.js');
|
||||
importScripts('../../../web-modules/browserfs.min.js');
|
||||
|
||||
let fs = BrowserFS.fs;
|
||||
|
||||
const createPromise = function(func, ...args) {
|
||||
return new Promise((resolve, reject) => {
|
||||
func(...args, function() {
|
||||
resolve([...arguments]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const addFileSystemHandler = function(filesystem) {
|
||||
return new Promise((resolve, reject) => {
|
||||
BrowserFS.configure({
|
||||
fs: "FileSystemAccess",
|
||||
options: { handle: filesystem }
|
||||
}, function (error) {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
fs = BrowserFS.fs;
|
||||
resolve('/' + filesystem.name);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const rename = function(oldPath, newPath) {
|
||||
return createPromise(fs.rename, oldPath, newPath);
|
||||
}
|
||||
|
||||
const stat = function(p) {
|
||||
return createPromise(fs.stat, p);
|
||||
}
|
||||
|
||||
const open = function(p, flag, mode) {
|
||||
return createPromise(fs.open, p, flag, mode);
|
||||
}
|
||||
|
||||
const unlink = function(p) {
|
||||
return createPromise(fs.unlink, p);
|
||||
}
|
||||
|
||||
const rmdir = function(p) {
|
||||
return createPromise(fs.rmdir, p);
|
||||
}
|
||||
|
||||
const mkdir = function(p, mode) {
|
||||
return createPromise(fs.mkdir, p, mode);
|
||||
}
|
||||
|
||||
const readdir = function(p) {
|
||||
return createPromise(fs.readdir, p);
|
||||
}
|
||||
|
||||
const exists = function(p) {
|
||||
return createPromise(fs.exists, p);
|
||||
}
|
||||
|
||||
const realpath = function(p) {
|
||||
return createPromise(fs.realpath, p);
|
||||
}
|
||||
|
||||
const truncate = function(p, len) {
|
||||
return createPromise(fs.truncate, p, len);
|
||||
}
|
||||
|
||||
const readFile = function(fname, encoding, flag) {
|
||||
return createPromise(fs.readFile, fname, encoding);
|
||||
}
|
||||
|
||||
const writeFile = function(fname, data, encoding, flag, mode) {
|
||||
return createPromise(fs.writeFile, fname, data, encoding, flag, mode);
|
||||
}
|
||||
|
||||
const appendFile = function(fname, data, encoding, flag, mode) {
|
||||
return createPromise(fs.appendFile, fname, data, encoding, flag, mode);
|
||||
}
|
||||
|
||||
const chmod = function(p, mode) {
|
||||
return createPromise(fs.chmod, p, mode);
|
||||
}
|
||||
|
||||
const chown = function(p, new_uid, new_gid) {
|
||||
return createPromise(fs.chown, p, new_uid, new_gid);
|
||||
}
|
||||
|
||||
const utimes = function(p, atime, mtime) {
|
||||
return createPromise(fs.utimes, p, atime, mtime);
|
||||
}
|
||||
|
||||
const link = function(srcpath, dstpath) {
|
||||
return createPromise(fs.link, srcpath, dstpath);
|
||||
}
|
||||
|
||||
const symlink = function(srcpath, dstpath, type) {
|
||||
return createPromise(fs.symlink, srcpath, dstpath, type);
|
||||
}
|
||||
|
||||
const readlink = function(p) {
|
||||
return createPromise(fs.readlink, p);
|
||||
}
|
||||
|
||||
const syncClose = function(method, fd) {
|
||||
return fs.syncClose(method, fd);
|
||||
}
|
||||
|
||||
workerpool.worker({
|
||||
addFileSystemHandler,
|
||||
rename,
|
||||
stat,
|
||||
open,
|
||||
unlink,
|
||||
rmdir,
|
||||
mkdir,
|
||||
readdir,
|
||||
exists,
|
||||
realpath,
|
||||
truncate,
|
||||
readFile,
|
||||
writeFile,
|
||||
appendFile,
|
||||
chmod,
|
||||
chown,
|
||||
utimes,
|
||||
link,
|
||||
symlink,
|
||||
readlink,
|
||||
syncClose
|
||||
});
|
||||
123
common/modules/mixly-modules/workers/web/serial-worker.js
Normal file
123
common/modules/mixly-modules/workers/web/serial-worker.js
Normal file
@@ -0,0 +1,123 @@
|
||||
// importScripts('../../web-modules/workerpool.min.js');
|
||||
const workerpool = require('../../web-modules/workerpool.min.js');
|
||||
|
||||
const encoder = new TextEncoder();
|
||||
const decoder = new TextDecoder('utf-8');
|
||||
|
||||
class SerialWorker {
|
||||
constructor(serial) {
|
||||
this.serial = serial;
|
||||
this.receiveBuffer = [];
|
||||
this.receiveStr = '';
|
||||
this.bufferLength = 0;
|
||||
const test = setInterval(() => {
|
||||
const message = generateRandomString(5);
|
||||
this.onData(encoder.encode(message));
|
||||
}, 1000);
|
||||
setTimeout(() => {
|
||||
clearInterval(test);
|
||||
}, 120 * 1000);
|
||||
}
|
||||
|
||||
onOpen() {
|
||||
|
||||
}
|
||||
|
||||
onData(data) {
|
||||
/* UTF-8编码方式
|
||||
* ------------------------------------------------------------
|
||||
* |1字节 0xxxxxxx |
|
||||
* |2字节 110xxxxx 10xxxxxx |
|
||||
* |3字节 1110xxxx 10xxxxxx 10xxxxxx |
|
||||
* |4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
|
||||
* |5字节 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx |
|
||||
* |6字节 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx|
|
||||
* ------------------------------------------------------------
|
||||
*/
|
||||
for (let i in data) {
|
||||
if ((data[i] & 0x80) === 0x00) {
|
||||
// 1字节
|
||||
this.receiveBuffer = [];
|
||||
this.bufferLength = 0;
|
||||
this.receiveStr += String.fromCharCode(data[i]);
|
||||
} else if ((data[i] & 0xc0) === 0x80) {
|
||||
// 2字节以上的中间字节,10xxxxxx
|
||||
// 如果没有起始头,则丢弃这个字节
|
||||
if (!this.receiveBuffer.length) {
|
||||
return;
|
||||
}
|
||||
// 如果不是2字节及以上的起始头,则丢弃这个字节
|
||||
if (this.bufferLength < 2) {
|
||||
return;
|
||||
}
|
||||
this.receiveBuffer.push(data[i]);
|
||||
if (this.bufferLength === this.receiveBuffer.length) {
|
||||
this.receiveStr += decoder.decode(new Uint8Array(this.receiveBuffer));
|
||||
this.receiveBuffer = [];
|
||||
}
|
||||
} else {
|
||||
// 2字节以上的起始头
|
||||
if (this.receiveBuffer) {
|
||||
this.receiveBuffer = [];
|
||||
}
|
||||
this.bufferLength = this.#getBufferLength(data[i]);
|
||||
this.receiveBuffer.push(data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onError() {
|
||||
|
||||
}
|
||||
|
||||
onClose() {
|
||||
|
||||
}
|
||||
|
||||
#getBufferLength(data) {
|
||||
let len = 2;
|
||||
if ((data & 0xFC) === 0xFC) {
|
||||
len = 6;
|
||||
} else if ((data & 0xF8) === 0xF8) {
|
||||
len = 5;
|
||||
} else if ((data & 0xF0) === 0xF0) {
|
||||
len = 4;
|
||||
} else if ((data & 0xE0) === 0xE0) {
|
||||
len = 3;
|
||||
} else if ((data & 0xC0) === 0xC0) {
|
||||
len = 2;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
const createSerialWork = function(serial) {
|
||||
return new Promise((resolve, reject) => {
|
||||
console.log(serial)
|
||||
const serialWork = new SerialWorker(serial);
|
||||
const test = setInterval(() => {
|
||||
const data = serialWork.receiveStr;
|
||||
serialWork.receiveStr = '';
|
||||
workerpool.workerEmit({
|
||||
status: 'data',
|
||||
data: data
|
||||
});
|
||||
}, 5000);
|
||||
setTimeout(() => {
|
||||
workerpool.workerEmit({
|
||||
status: 'close'
|
||||
});
|
||||
resolve();
|
||||
}, 120 * 1000);
|
||||
});
|
||||
}
|
||||
|
||||
function generateRandomString() {
|
||||
return '1234';
|
||||
}
|
||||
|
||||
|
||||
workerpool.worker({
|
||||
createSerialWork,
|
||||
generateRandomString
|
||||
});
|
||||
Reference in New Issue
Block a user