diff --git a/bin/cncjs-pendant-boilerplate b/bin/cncjs-pendant-boilerplate index 1e9e51e..c13d163 100755 --- a/bin/cncjs-pendant-boilerplate +++ b/bin/cncjs-pendant-boilerplate @@ -2,24 +2,37 @@ var program = require('commander'); var serialport = require('serialport'); +var inquirer = require('inquirer'); +var vorpal = require('vorpal')(); var pkg = require('../package.json'); var serverMain = require('../index'); +var options = {}; program .version(pkg.version) - .usage('-p [options]') + .usage('-s -p [options]') .option('-l, --list', 'list available ports then exit') + .option('-s, --secret', 'the secret key stored in the ~/.cncrc file') .option('-p, --port ', 'path or name of serial port') .option('-b, --baudrate ', 'baud rate (default: 115200)', 115200) .option('--socket-address
', 'socket address or hostname (default: localhost)', 'localhost') .option('--socket-port ', 'socket port (default: 8000)', 8000) - .option('--controller-type ', 'controller type: Grbl|Smoothie|TinyG (default: Grbl)', 'Grbl'); + .option('--controller-type ', 'controller type: Grbl|Smoothie|TinyG (default: Grbl)', 'Grbl') + .option('--access-token-lifetime ', 'access token lifetime in seconds or a time span string (default: 30d)', '30d') -if (process.argv.length > 1) { - program.parse(process.argv); -} +program.parse(process.argv); + +var options = { + secret: program.secret, + port: program.port, + baudrate: program.baudrate, + socketAddress: program.socketAddress, + socketPort: program.socketPort, + controllerType: program.controllerType, + accessTokenLifetime: program.accessTokenLifetime +}; -if (program.list) { +if (options.list) { serialport.list(function(err, ports) { if (err) { console.error(err); @@ -32,15 +45,53 @@ if (program.list) { return; } -if (!program.port) { - program.outputHelp(); - process.exit(1); +var createServer = function(options) { + serverMain(options, function(err, socket) { + vorpal + .mode('command') + .description('Enters the command-line mode.') + .delimiter(options.controllerType + '>') + .init(function(args, callback) { + this.log('You can now directly enter commands. To exit, type `exit`.'); + callback(); + }) + .action(function(command, callback) { + var line = command + '\n'; + socket.emit('write', options.port, line); + callback(); + }); + + console.log(''); + console.log('Type "help" to display supported options:'); + + vorpal + .delimiter('pendant$') + .show(); + }); +}; + +if (options.port) { + createServer(options); + return; } -serverMain({ - port: program.port, - baudrate: program.baudrate, - socketAddress: program.socketAddress, - socketPort: program.socketPort, - controllerType: program.controllerType +serialport.list(function(err, ports) { + if (err) { + console.error(err); + process.exit(1); + } + const choices = ports.map(function(port) { + return port.comName; + }); + + inquirer.prompt([{ + type: 'list', + name: 'port', + message: 'Specify which port you want to use?', + choices: choices + }]).then(function(answers) { + options.port = answers.port; + + createServer(options); + }); }); diff --git a/index.js b/index.js index 99e6310..031b911 100755 --- a/index.js +++ b/index.js @@ -1,12 +1,13 @@ #!/usr/bin/env node -var fs = require('fs'); -var path = require('path'); -var io = require('socket.io-client'); -var jwt = require('jsonwebtoken'); +const fs = require('fs'); +const path = require('path'); +const io = require('socket.io-client'); +const jwt = require('jsonwebtoken'); +const get = require('lodash.get'); -var generateAccessToken = function(payload, secret, expiration) { - var token = jwt.sign(payload, secret, { +const generateAccessToken = function(payload, secret, expiration) { + const token = jwt.sign(payload, secret, { expiresIn: expiration }); @@ -14,20 +15,39 @@ var generateAccessToken = function(payload, secret, expiration) { }; // Get secret key from the config file and generate an access token -var getUserHome = function () { +const getUserHome = function() { return process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME']; }; -module.exports = function(options) { - var cncrc = path.resolve(getUserHome(), '.cncrc'); - var config = JSON.parse(fs.readFileSync(cncrc, 'utf8')); - var token = generateAccessToken({ id: '', name: 'pendant' }, config.secret, '30d'); +module.exports = function(options, callback) { + options = options || {}; + options.secret = get(options, 'secret', process.env['CNCJS_SECRET']); + options.baudrate = get(options, 'baudrate', 115200); + options.socketAddress = get(options, 'socketAddress', 'localhost'); + options.socketPort = get(options, 'socketPort', 8000); + options.controllerType = get(options, 'controllerType', 'Grbl'); + options.accessTokenLifetime = get(options, 'accessTokenLifetime', '30d'); + + if (!options.secret) { + const cncrc = path.resolve(getUserHome(), '.cncrc'); + try { + const config = JSON.parse(fs.readFileSync(cncrc, 'utf8')); + options.secret = config.secret; + } catch (err) { + console.error(err); + process.exit(1); + } + } + + const token = generateAccessToken({ id: '', name: 'cncjs-pendant' }, options.secret, options.accessTokenLifetime); + const url = 'ws://' + options.socketAddress + ':' + options.socketPort + '?token=' + token; socket = io.connect('ws://' + options.socketAddress + ':' + options.socketPort, { 'query': 'token=' + token }); + socket.on('connect', () => { - console.log('[socket.io] Connected to ' + options.socketAddress + ':' + options.socketPort); + console.log('Connected to ' + url); // Open port socket.emit('open', options.port, { @@ -36,8 +56,8 @@ module.exports = function(options) { }); }); - socket.on('error', () => { - console.error('[socket.io] Error'); + socket.on('error', (err) => { + console.error('Connection error.'); if (socket) { socket.destroy(); socket = null; @@ -45,19 +65,28 @@ module.exports = function(options) { }); socket.on('close', () => { - console.log('[socket.io] Connection close'); + console.log('Connection closed.'); + }); + + socket.on('serialport:open', function(options) { + options = options || {}; + + console.log('Connected to port "' + options.port + '" (Baud rate: ' + options.baudrate + ')'); + + callback(null, socket); }); - socket.on('serialport:open', function (options) { - const { controllerType, port, baudrate, inuse } = options; - console.log('[pendant] Connected to port "' + options.port + '" (Baud rate: ' + options.baudrate + ')'); + socket.on('serialport:error', function(options) { + callback(new Error('Error opening serial port "' + options.port + '"')); }); socket.on('serialport:read', function(data) { - console.log(data); + console.log((data || '').trim()); }); + /* socket.on('serialport:write', function(data) { - console.log('> ' + data); + console.log((data || '').trim()); }); + */ }; diff --git a/package.json b/package.json index c28c743..41417c1 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,9 @@ "version": "0.1.0", "description": "A bare minimum example to develop a cncjs pendant.", "main": "./index.js", + "engines": { + "node": ">=4" + }, "bin": { "cncjs-pendant-boilerplate": "./bin/cncjs-pendant-boilerplate" }, @@ -27,8 +30,11 @@ "homepage": "https://github.com/cncjs/cncjs-pendant-boilerplate#readme", "dependencies": { "commander": "^2.9.0", + "inquirer": "^3.0.1", "jsonwebtoken": "^7.2.1", + "lodash.get": "^4.4.2", "serialport": "^4.0.7", - "socket.io-client": "^1.7.2" + "socket.io-client": "^1.7.2", + "vorpal": "^1.11.4" } }