diff --git a/app/.tool-versions b/app/.tool-versions new file mode 100644 index 0000000..c37874d --- /dev/null +++ b/app/.tool-versions @@ -0,0 +1 @@ +python 2.7.13 diff --git a/app/components/Terminal.js b/app/components/Terminal.js index 00450d3..0d26859 100644 --- a/app/components/Terminal.js +++ b/app/components/Terminal.js @@ -27,7 +27,7 @@ Terminal.applyAddon(winptyCompat); class ReactTerminal extends React.Component { constructor(props) { super(props); - this.HOST = `127.0.0.1:9788`; + this.HOST = `127.0.0.1:${process.env.WORKBENCH_SHELL_PORT}`; this.SOCKET_URL = `ws://${this.HOST}/terminals/`; this.failures = 0; this.interval = null; @@ -320,7 +320,8 @@ class ReactTerminal extends React.Component { // this.term.writeln('Server disconnected!'); // this._connectToServer(); // }; - this.socket.onerror = () => { + this.socket.onerror = (error) => { + console.error(error); this.term.writeln('Critical error, restart Workbench!'); this._connectToServer(); }; diff --git a/app/main/services/server.js b/app/main/services/server.js index 6a0228c..e10a60c 100644 --- a/app/main/services/server.js +++ b/app/main/services/server.js @@ -1,117 +1,119 @@ import defaultShell from '../default-shell'; var terminals = {}; var logs = {}; -const PORT = 9788; -const express = require('express'); -const app = express(); -const pty = require('node-pty-prebuilt'); -const chalk = require('chalk'); -const prefix = chalk.bold.blue; -const bgTaskColor = chalk.green; -function writeLog(...params) { - console.info(prefix('workbench') + ' ' + chalk.bold(bgTaskColor('[terminal]')), bgTaskColor(...params)); -} - -const argv = require('yargs').argv; -const port = argv.port || PORT; -const host = '127.0.0.1'; - -const ALLOWED_ORIGINS = [ - '0.0.0.0', - '127.0.0.1', - 'home.localhost', - 'chrome-extension://' -]; - -app.use(function (req, res, next) { - res.header('Access-Control-Allow-Origin', '*'); - res.header('Access-Control-Allow-Headers', 'X-Requested-With'); - - let origin = req.get('origin'); - let host = req.get('host'); - let foundOrigin = ALLOWED_ORIGINS.find(o => (origin && origin.indexOf(o) >= 0)); - let foundHost = ALLOWED_ORIGINS.find(h => (host && host.indexOf(h) >= 0)); - - if (!foundOrigin && !foundHost) { - res.status(403); - res.send('Go away!'); - res.end(); - return; - } - next(); -}); - -app.use('/', express.static(__dirname + '/../build')); - -require('express-ws')(app); - -app.post('/terminals', function (req, res) { - let shell = defaultShell; - let cols = parseInt(req.query.cols, 10); - let rows = parseInt(req.query.rows, 10); - let term = pty.fork(shell, [], { - name: 'xterm-color', - cols: cols || 80, - rows: rows || 24, - cwd: process.env.PWD, - env: process.env - }); - - // term.write(`powershell.exe -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"\r`) - writeLog('Created terminal with PID: ' + term.pid); - terminals[term.pid] = term; - logs[term.pid] = ''; - term.on('data', function (data) { - logs[term.pid] += data; - }); - res.send(term.pid.toString()); - res.end(); -}); - -app.post('/terminals/:pid/size', function (req, res) { - let pid = parseInt(req.params.pid, 10); - let cols = parseInt(req.query.cols, 10); - let rows = parseInt(req.query.rows, 10); - let term = terminals[pid]; - - term.resize(cols, rows); - writeLog('Resized terminal ' + pid + ' to ' + cols + ' cols and ' + rows + ' rows.'); - res.end(); -}); - -app.ws('/terminals/:pid', function (ws, req) { - var term = terminals[parseInt(req.params.pid, 10)]; - - if (!term) { - ws.send('No such terminal created.'); - return; - } +import getPort from 'get-port'; - writeLog('Connected to terminal ' + term.pid); - ws.send(logs[term.pid]); - term.on('data', function (data) { - // writeLog('Incoming data = ' + data); - try { - ws.send(data); - } catch (ex) { - // The WebSocket is not open, ignore +module.exports = { + startServer: async () => { + const argv = require('yargs').argv; + let port = await getPort({port: argv.port || 9778}); + process.env.WORKBENCH_SHELL_PORT = port; + const express = require('express'); + const app = express(); + const pty = require('node-pty-prebuilt'); + const chalk = require('chalk'); + const prefix = chalk.bold.blue; + const bgTaskColor = chalk.green; + function writeLog(...params) { + console.info(prefix('workbench') + ' ' + chalk.bold(bgTaskColor('[terminal]')), bgTaskColor(...params)); } - }); - ws.on('message', function (msg) { - term.write(msg); - }); - ws.on('close', function () { - term.kill(); - writeLog('Closed terminal ' + term.pid); - // Clean things up - delete terminals[term.pid]; - delete logs[term.pid]; - }); -}); -module.exports = { - startServer() { + const host = '127.0.0.1'; + + const ALLOWED_ORIGINS = [ + '0.0.0.0', + '127.0.0.1', + 'home.localhost', + 'chrome-extension://' + ]; + + app.use(function (req, res, next) { + res.header('Access-Control-Allow-Origin', '*'); + res.header('Access-Control-Allow-Headers', 'X-Requested-With'); + + let origin = req.get('origin'); + let host = req.get('host'); + let foundOrigin = ALLOWED_ORIGINS.find(o => (origin && origin.indexOf(o) >= 0)); + let foundHost = ALLOWED_ORIGINS.find(h => (host && host.indexOf(h) >= 0)); + + if (!foundOrigin && !foundHost) { + res.status(403); + res.send('Go away!'); + res.end(); + return; + } + next(); + }); + + app.use('/', express.static(__dirname + '/../build')); + + require('express-ws')(app); + + app.post('/terminals', function (req, res) { + let shell = defaultShell; + let cols = parseInt(req.query.cols, 10); + let rows = parseInt(req.query.rows, 10); + let term = pty.fork(shell, [], { + name: 'xterm-color', + cols: cols || 80, + rows: rows || 24, + cwd: process.env.PWD, + env: process.env + }); + + // term.write(`powershell.exe -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"\r`) + writeLog('Created terminal with PID: ' + term.pid); + terminals[term.pid] = term; + logs[term.pid] = ''; + term.on('data', function (data) { + logs[term.pid] += data; + }); + res.send(term.pid.toString()); + res.end(); + }); + + app.post('/terminals/:pid/size', function (req, res) { + let pid = parseInt(req.params.pid, 10); + let cols = parseInt(req.query.cols, 10); + let rows = parseInt(req.query.rows, 10); + let term = terminals[pid]; + + term.resize(cols, rows); + writeLog('Resized terminal ' + pid + ' to ' + cols + ' cols and ' + rows + ' rows.'); + res.end(); + }); + + app.ws('/terminals/:pid', function (ws, req) { + var term = terminals[parseInt(req.params.pid, 10)]; + + if (!term) { + ws.send('No such terminal created.'); + return; + } + + writeLog('Connected to terminal ' + term.pid); + ws.send(logs[term.pid]); + + term.on('data', function (data) { + // writeLog('Incoming data = ' + data); + try { + ws.send(data); + } catch (ex) { + // The WebSocket is not open, ignore + } + }); + ws.on('message', function (msg) { + term.write(msg); + }); + ws.on('close', function () { + term.kill(); + writeLog('Closed terminal ' + term.pid); + // Clean things up + delete terminals[term.pid]; + delete logs[term.pid]; + }); + }); return new Promise((resolve, reject) => { if (!port) { writeLog('ERROR: Please provide a port: node ./src/server.js --port=XXXX'); diff --git a/app/package.json b/app/package.json index f7a3140..0688e3f 100644 --- a/app/package.json +++ b/app/package.json @@ -11,7 +11,7 @@ }, "scripts": { "electron-rebuild": "node -r babel-register ../internals/scripts/ElectronRebuild.js", - "postinstall": "yarn electron-rebuild" + "postinstall": "npm run electron-rebuild" }, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index c0c2371..71820b9 100644 --- a/package.json +++ b/package.json @@ -238,6 +238,7 @@ "electron-updater": "^3.1.2", "evilscan": "^1.7.1", "express-ws": "^4.0.0", + "get-port": "^4.1.0", "geval": "^2.2.0", "git-describe": "^4.0.3", "hexdump-nodejs": "^0.1.0",