diff --git a/common/modules/mixly-modules/common/app.js b/common/modules/mixly-modules/common/app.js index 2d02bd79..254ca55e 100644 --- a/common/modules/mixly-modules/common/app.js +++ b/common/modules/mixly-modules/common/app.js @@ -27,6 +27,7 @@ goog.require('Mixly.Web.BU'); goog.require('Mixly.Web.FS'); goog.require('Mixly.Web.File'); goog.require('Mixly.Web.Serial'); +goog.require('Mixly.WebSocket.File'); goog.require('Mixly.WebSocket.Serial'); goog.require('Mixly.WebSocket.ArduShell'); goog.provide('Mixly.App'); diff --git a/common/modules/mixly-modules/deps.json b/common/modules/mixly-modules/deps.json index 90b7fba0..4f0c96c0 100644 --- a/common/modules/mixly-modules/deps.json +++ b/common/modules/mixly-modules/deps.json @@ -47,6 +47,7 @@ "Mixly.Web.FS", "Mixly.Web.File", "Mixly.Web.Serial", + "Mixly.WebSocket.File", "Mixly.WebSocket.Serial", "Mixly.WebSocket.ArduShell" ], @@ -1752,14 +1753,7 @@ { "path": "/web-socket/file.js", "require": [ - "layui", - "Blockly", - "Mixly.XML", - "Mixly.MFile", - "Mixly.Boards", - "Mixly.LayerExt", - "Mixly.Msg", - "Mixly.WebSocket.Socket" + "Mixly.Web.File" ], "provide": [ "Mixly.WebSocket.File" @@ -1782,7 +1776,8 @@ { "path": "/web-socket/socket.js", "require": [ - "io", + "Mixly.Debug", + "Mixly.StatusBarsManager", "Mixly.WebSocket", "Mixly.WebSocket.Serial", "Mixly.WebSocket.ArduShell" @@ -1794,6 +1789,7 @@ { "path": "/web-socket/web-socket.js", "require": [ + "io", "Mixly" ], "provide": [ diff --git a/common/modules/mixly-modules/electron/arduino-shell.js b/common/modules/mixly-modules/electron/arduino-shell.js index cfb38139..b151c152 100644 --- a/common/modules/mixly-modules/electron/arduino-shell.js +++ b/common/modules/mixly-modules/electron/arduino-shell.js @@ -504,10 +504,10 @@ ArduShell.runCmd = (layerNum, type, cmd, code, sucFunc) => { let message = ''; if (info.code) { message = (type === 'compile' ? Msg.Lang['shell.compileFailed'] : Msg.Lang['shell.uploadFailed']); - statusBarTerminal.addValue("==" + message + "==\n"); + statusBarTerminal.addValue("\n==" + message + "==\n"); } else { message = (type === 'compile' ? Msg.Lang['shell.compileSucc'] : Msg.Lang['shell.uploadSucc']); - statusBarTerminal.addValue(`==${message}(${Msg.Lang['shell.timeCost']} ${info.time})==\n`); + statusBarTerminal.addValue(`\n==${message}(${Msg.Lang['shell.timeCost']} ${info.time})==\n`); sucFunc(); } layer.msg(message, { time: 1000 }); diff --git a/common/modules/mixly-modules/web-socket/arduino-shell.js b/common/modules/mixly-modules/web-socket/arduino-shell.js index 7dfcc611..9a10268e 100644 --- a/common/modules/mixly-modules/web-socket/arduino-shell.js +++ b/common/modules/mixly-modules/web-socket/arduino-shell.js @@ -25,12 +25,24 @@ const { Serial } = WebSocket; class WebSocketArduShell { static { + this.mixlySocket = null; this.socket = null; this.shell = null; - this.init = function (socket) { - this.socket = socket; + this.getSocket = function () { + return this.socket; + } + + this.getMixlySocket = function () { + return this.mixlySocket; + } + + this.init = function (mixlySocket) { + this.mixlySocket = mixlySocket; + this.socket = mixlySocket.getSocket(); this.shell = new WebSocketArduShell(); + const socket = this.socket; + socket.on('arduino.dataEvent', (data) => { const { mainStatusBarTabs } = Mixly; const statusBarTerminal = mainStatusBarTabs.getStatusBarById('output'); @@ -57,7 +69,10 @@ class WebSocketArduShell { .then((info) => { this.endCallback(info.code, info.time); }) - .catch(Debug.error); + .catch((error) => { + Debug.error(error); + statusBarTerminal.addValue(`==${Msg.Lang['shell.compileFailed']}==\n`); + }); } this.initUpload = function () { @@ -83,7 +98,6 @@ class WebSocketArduShell { } mainStatusBarTabs.add('serial', port); mainStatusBarTabs.changeTo(port); - const statusBarSerial = mainStatusBarTabs.getStatusBarById(port); statusBarSerial.open() .then(() => { const baudRates = code.match(/(?<=Serial.begin[\s]*\([\s]*)[0-9]*(?=[\s]*\))/g); @@ -95,7 +109,10 @@ class WebSocketArduShell { }) .catch(Debug.error); }) - .catch(Debug.error); + .catch((error) => { + Debug.error(error); + statusBarTerminal.addValue(`==${Msg.Lang['shell.uploadFailed']}==\n`); + }); } this.endCallback = function (code, time) { @@ -105,10 +122,10 @@ class WebSocketArduShell { let message = ''; if (code) { message = (this.shell.isCompiling() ? Msg.Lang['shell.compileFailed'] : Msg.Lang['shell.uploadFailed']); - statusBarTerminal.addValue('==' + message + '==\n'); + statusBarTerminal.addValue(`\n==${message}==\n`); } else { message = (this.shell.isCompiling() ? Msg.Lang['shell.compileSucc'] : Msg.Lang['shell.uploadSucc']); - statusBarTerminal.addValue(`==${message}(${Msg.Lang['shell.timeCost']} ${ + statusBarTerminal.addValue(`\n==${message}(${Msg.Lang['shell.timeCost']} ${ dayjs.duration(time).format('HH:mm:ss.SSS') })==\n`); } @@ -129,9 +146,14 @@ class WebSocketArduShell { await this.showProgress(); const key = Boards.getSelectedBoardCommandParam(); const config = { key, code }; - WebSocketArduShell.socket.emit('arduino.compile', config, (response) => { - const [error, result] = response; + const mixlySocket = WebSocketArduShell.getMixlySocket(); + mixlySocket.emit('arduino.compile', config, (response) => { this.hideProgress(); + if (response.error) { + reject(response.error); + return; + } + const [error, result] = response; if (error) { reject(error); } else { @@ -148,9 +170,14 @@ class WebSocketArduShell { await this.showProgress(); const key = Boards.getSelectedBoardCommandParam(); const config = { key, code, port }; - WebSocketArduShell.socket.emit('arduino.upload', config, (response) => { - const [error, result] = response; + const mixlySocket = WebSocketArduShell.getMixlySocket(); + mixlySocket.emit('arduino.upload', config, (response) => { this.hideProgress(); + if (response.error) { + reject(response.error); + return; + } + const [error, result] = response; if (error) { reject(error); } else { @@ -162,7 +189,12 @@ class WebSocketArduShell { async kill() { return new Promise(async (resolve, reject) => { - WebSocketArduShell.socket.emit('arduino.kill', (response) => { + const mixlySocket = WebSocketArduShell.getMixlySocket(); + mixlySocket.emit('arduino.kill', (response) => { + if (response.error) { + reject(response.error); + return; + } const [error, result] = response; if (error) { reject(error); diff --git a/common/modules/mixly-modules/web-socket/file.js b/common/modules/mixly-modules/web-socket/file.js index 5681ed1f..c06cc82a 100644 --- a/common/modules/mixly-modules/web-socket/file.js +++ b/common/modules/mixly-modules/web-socket/file.js @@ -1,182 +1,11 @@ goog.loadJs('web', () => { -goog.require('layui'); -goog.require('Blockly'); -goog.require('Mixly.XML'); -goog.require('Mixly.MFile'); -goog.require('Mixly.Boards'); -goog.require('Mixly.LayerExt'); -goog.require('Mixly.Msg'); -goog.require('Mixly.WebSocket.Socket'); +goog.require('Mixly.Web.File'); goog.provide('Mixly.WebSocket.File'); -const { - XML, - MFile, - Boards, - LayerExt, - Msg -} = Mixly; -const { Socket, File } = Mixly.WebSocket; -const boardType = Boards.getType(); +const { Web, WebSocket } = Mixly; -const { form } = layui; - -File.saveToCloud = () => { - Socket.connect((WS) => { - layer.closeAll(); - }, () => { - layer.prompt({ - title: Blockly.Msg.MSG['save_ser'], - shade: LayerExt.SHADE_ALL, - value: 'main.mix', - success: function(layero, index) { - $(layero).find('input').attr('spellcheck', false); - } - }, function(value, index, elem) { - layer.close(index); - const extname = value.substring(value.lastIndexOf('.')).toLowerCase(); - let saveType = []; - MFile.saveFilters.map((filter) => { - saveType = [ ...saveType, ...filter.extensions ]; - }); - if (!saveType.includes(extname.substring(1))) { - layer.msg(Msg.Lang['文件后缀错误'], { - time: 1000 - }); - return; - } - let data; - switch (extname) { - case '.mix': - data = MFile.getMix(); - break; - case '.ino': - case '.py': - data = MFile.getCode(); - default: - layer.msg(Msg.Lang['文件后缀错误'], { - time: 1000 - }); - } - if (!data) { - return; - } - Socket.sendCommand({ - obj: 'File', - func: 'saveAs', - args: [ boardType, value, data ] - }); - }); - }); -} - -File.saveSuccess = (filename) => { - layer.msg(filename + ' ' + Msg.Lang['保存成功'], { - time: 1000 - }); -} - -File.saveError = (filename, error) => { - layer.msg(filename + ' ' + '保存失败', { - time: 1000 - }); -} - -File.openFromCloud = () => { - Socket.sendCommand({ - obj: 'File', - func: 'getUserFilesInfo', - args: [ boardType ] - }); -} - -File.showOpenDialog = (filesObj) => { - const $options = $('#mixly-selector-type'); - $options.empty(); - filesObj.map(file => { - $options.append($(``)); - }); - form.render(); - - let initBtnClicked = false; - - const layerNum = layer.open({ - type: 1, - id: "serial-select", - title: "请选择需要打开的文件:", - area: ['350px', '150px'], - content: $('#mixly-selector-div'), - shade: Mixly.LayerExt.SHADE_ALL, - resize: false, - closeBtn: 0, - success: function (layero) { - $('#serial-select').css('height', '180px'); - $('#serial-select').css('overflow', 'inherit'); - $(".layui-layer-page").css("z-index", "198910151"); - $("#mixly-selector-btn1").off("click").click(() => { - layer.close(layerNum); - }); - $("#mixly-selector-btn2").click(() => { - layer.close(layerNum); - initBtnClicked = true; - }); - }, - end: function () { - $("#mixly-selector-btn1").off("click"); - $("#mixly-selector-btn2").off("click"); - $('#mixly-selector-div').css('display', 'none'); - $(".layui-layer-shade").remove(); - if (!initBtnClicked) { - return; - } - const selectedFilePath = $('#mixly-selector-type option:selected').val(); - Socket.sendCommand({ - obj: 'File', - func: 'open', - args: [ boardType, selectedFilePath ] - }); - } - }); -} - -File.open = (extname, data) => { - switch (extname) { - case '.mix': - case '.xml': - Editor.mainEditor.drag.full('POSITIVE'); - try { - data = XML.convert(data, true); - data = data.replace(/\\(u[0-9a-fA-F]{4})/g, function (s) { - return unescape(s.replace(/\\(u[0-9a-fA-F]{4})/g, '%$1')); - }); - } catch (error) { - console.log(error); - } - MFile.parseMix($(data), false, false, (message) => { - Editor.blockEditor.scrollCenter(); - Blockly.hideChaff(); - }); - break; - case '.ino': - case '.py': - Editor.mainEditor.drag.full('NEGATIVE'); - Editor.codeEditor.setValue(data, -1); - break; - } -} - -File.openSuccess = (filename) => { - layer.msg(filename + ' ' + '打开成功', { - time: 1000 - }); -} - -File.openError = (filename, error) => { - layer.msg(filename + ' ' + '打开失败', { - time: 1000 - }); -} +WebSocket.File = Web.File; }); \ No newline at end of file diff --git a/common/modules/mixly-modules/web-socket/serial.js b/common/modules/mixly-modules/web-socket/serial.js index 382fa5ee..cbd07099 100644 --- a/common/modules/mixly-modules/web-socket/serial.js +++ b/common/modules/mixly-modules/web-socket/serial.js @@ -22,6 +22,7 @@ const { class WebSocketSerial extends Serial { static { this.eventRegistry = new Registry(); + this.mixlySocket = null; this.socket = null; this.getConfig = function () { @@ -36,16 +37,24 @@ class WebSocketSerial extends Serial { return Serial.getCurrentPortsName(); } + this.renderSelectBox = function (ports) { + return Serial.renderSelectBox(ports); + } + this.getPorts = async function () { return new Promise((resolve, reject) => { - this.socket.emit('serial.getPorts', (response) => { - const [error, result] = response; - if (error) { - reject(error); - } else { - resolve(result); - } - }); + if (this.socket.connected) { + this.socket.emit('serial.getPorts', (response) => { + const [error, result] = response; + if (error) { + reject(error); + } else { + resolve(result); + } + }); + } else { + resolve([]); + } }); } @@ -57,8 +66,10 @@ class WebSocketSerial extends Serial { .catch(Debug.error); } - this.init = function (socket) { - this.socket = socket; + this.init = function (mixlySocket) { + this.mixlySocket = mixlySocket; + this.socket = mixlySocket.getSocket(); + const socket = this.socket; socket.on('serial.attachEvent', () => { this.refreshPorts(); @@ -118,6 +129,10 @@ class WebSocketSerial extends Serial { return this.socket; } + this.getMixlySocket = function () { + return this.mixlySocket; + } + this.getEventRegistry = function () { return this.eventRegistry; } @@ -127,7 +142,9 @@ class WebSocketSerial extends Serial { super(port); this.#addEventsListener_(); const socket = WebSocketSerial.getSocket(); - socket.emit('serial.create', port); + if (socket.connected) { + socket.emit('serial.create', port); + } } #addEventsListener_() { @@ -164,8 +181,12 @@ class WebSocketSerial extends Serial { return; } baud = baud ?? this.getBaudRate(); - const socket = WebSocketSerial.getSocket(); - socket.emit('serial.open', this.getPortName(), baud, (response) => { + const mixlySocket = WebSocketSerial.getMixlySocket(); + mixlySocket.emit('serial.open', currentPort, baud, (response) => { + if (response.error) { + reject(response.error); + return; + } const [error, result] = response; if (error) { this.onError(error); @@ -186,8 +207,13 @@ class WebSocketSerial extends Serial { return; } super.close(); - const socket = WebSocketSerial.getSocket(); - socket.emit('serial.close', this.getPortName(), (response) => { + const mixlySocket = WebSocketSerial.getMixlySocket(); + mixlySocket.emit('serial.close', this.getPortName(), (response) => { + if (response.error) { + this.onClose(1); + resolve(response.error); + return; + } const [error, result] = response; if (error) { reject(error); @@ -206,8 +232,12 @@ class WebSocketSerial extends Serial { resolve(); return; } - const socket = WebSocketSerial.getSocket(); - socket.emit('serial.setBaudRate', this.getPortName(), baud, (response) => { + const mixlySocket = WebSocketSerial.getMixlySocket(); + mixlySocket.emit('serial.setBaudRate', this.getPortName(), baud, (response) => { + if (response.error) { + reject(response.error); + return; + } const [error,] = response; if (error) { reject(error); @@ -225,8 +255,12 @@ class WebSocketSerial extends Serial { resolve(); return; } - const socket = WebSocketSerial.getSocket(); - socket.emit('serial.send', this.getPortName(), data, (response) => { + const mixlySocket = WebSocketSerial.getMixlySocket(); + mixlySocket.emit('serial.send', this.getPortName(), data, (response) => { + if (response.error) { + reject(response.error); + return; + } const [error, result] = response; if (error) { reject(error); @@ -251,8 +285,12 @@ class WebSocketSerial extends Serial { resolve(); return; } - const socket = WebSocketSerial.getSocket(); - socket.emit('serial.setDTRAndRTS', this.getPortName(), dtr, rts, (response) => { + const mixlySocket = WebSocketSerial.getMixlySocket(); + mixlySocket.emit('serial.setDTRAndRTS', this.getPortName(), dtr, rts, (response) => { + if (response.error) { + reject(response.error); + return; + } const [error, result] = response; if (error) { reject(error); @@ -297,8 +335,12 @@ class WebSocketSerial extends Serial { eventRegistry.unregister(`${port}-close`); super.dispose() .then(() => { - const socket = WebSocketSerial.getSocket(); - socket.emit('serial.dispose', port, ([error, result]) => { + const mixlySocket = WebSocketSerial.getMixlySocket(); + mixlySocket.emit('serial.dispose', port, ([error, result]) => { + if (response.error) { + resolve(); + return; + } if (error) { reject(error); } else { diff --git a/common/modules/mixly-modules/web-socket/socket.js b/common/modules/mixly-modules/web-socket/socket.js index 0309a8f3..84bb1565 100644 --- a/common/modules/mixly-modules/web-socket/socket.js +++ b/common/modules/mixly-modules/web-socket/socket.js @@ -1,25 +1,77 @@ goog.loadJs('web', () => { -goog.require('io'); +goog.require('Mixly.Debug'); +goog.require('Mixly.StatusBarsManager'); goog.require('Mixly.WebSocket'); goog.require('Mixly.WebSocket.Serial'); goog.require('Mixly.WebSocket.ArduShell'); goog.provide('Mixly.WebSocket.Socket'); -const { WebSocket } = Mixly; -const { Socket, Serial, ArduShell } = WebSocket; +const { + Debug, + StatusBarsManager, + WebSocket +} = Mixly; + +const { + Socket, + Serial, + ArduShell +} = WebSocket; Socket.init = function () { - const socket = io('wss://127.0.0.1:4000', { + const mixlySocket = new WebSocket('wss://127.0.0.1:4000', { path: '/mixly-socket/', + reconnection: true, reconnectionDelayMax: 10000, transports: ['websocket'], protocols: ['my-protocol-v1'] }); - Serial.init(socket); - ArduShell.init(socket); + const socket = mixlySocket.getSocket(); + + socket.on('connect', () => { + Serial.getPorts() + .then((ports) => { + let portsName = []; + for (let port of ports) { + portsName.push(port.name); + } + const { mainStatusBarTabs } = Mixly; + let keys = mainStatusBarTabs.keys(); + const statusBarType = StatusBarsManager.typesRegistry.getItem('serial'); + for (let key of keys) { + const statusBar = mainStatusBarTabs.getStatusBarById(key); + if (!(statusBar instanceof statusBarType)) { + continue; + } + const portName = statusBar.getPortName(); + if (!portsName.includes(portName)) { + continue; + } + socket.emit('serial.create', portName); + } + Serial.renderSelectBox(ports); + }) + .catch(Debug.error); + }); + + socket.on('disconnect', () => { + const { mainStatusBarTabs } = Mixly; + let keys = mainStatusBarTabs.keys(); + const statusBarType = StatusBarsManager.typesRegistry.getItem('serial'); + for (let key of keys) { + const statusBar = mainStatusBarTabs.getStatusBarById(key); + if (statusBar instanceof statusBarType) { + statusBar.close().catch(Debug.error); + } + } + Serial.refreshPorts(); + }); + + Serial.init(mixlySocket); + ArduShell.init(mixlySocket); } }); diff --git a/common/modules/mixly-modules/web-socket/web-socket.js b/common/modules/mixly-modules/web-socket/web-socket.js index c045b486..b2040e8a 100644 --- a/common/modules/mixly-modules/web-socket/web-socket.js +++ b/common/modules/mixly-modules/web-socket/web-socket.js @@ -1,6 +1,36 @@ goog.loadJs('web', () => { +goog.require('io'); goog.require('Mixly'); goog.provide('Mixly.WebSocket'); + +class WebSocket { + #socket_ = null; + constructor(path, option) { + this.#socket_ = io(path, option); + } + + emit(eventName, ...args) { + if (this.isConnected()) { + return this.#socket_.emit(eventName, ...args); + } else { + const callback = args.pop(); + callback({ + error: new Error('socket is not connected') + }); + } + } + + getSocket() { + return this.#socket_; + } + + isConnected() { + return this.#socket_?.connected; + } +} + +Mixly.WebSocket = WebSocket; + }); \ No newline at end of file