├── .gitignore ├── .travis.yml ├── README.md ├── docs └── EXAMPLES.md ├── index.js ├── package.json ├── src ├── Client.js ├── Server.js └── defaults.js └── tests ├── benchmark.js ├── index.js └── libs ├── async.js └── spinner.js /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /_old/ 3 | /npm-debug.log 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "5.0" 4 | script: "npm run-script test-travis" 5 | # Send coverage data to Coveralls 6 | after_script: "cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js" 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ipc-light 2 | 3 | [![ipc-light](https://img.shields.io/npm/v/ipc-light.svg)](https://www.npmjs.com/package/ipc-light) 4 | [![Build Status](https://travis-ci.org/fed135/ipc-light.svg?branch=master)](https://travis-ci.org/fed135/ipc-light) 5 | [![Coverage Status](https://coveralls.io/repos/fed135/ipc-light/badge.svg)](https://coveralls.io/r/fed135/ipc-light) 6 | [![Dependencies](https://david-dm.org/fed135/ipc-light.svg)](https://www.npmjs.com/package/ipc-light) 7 | 8 | ## What is ipc-light? 9 | 10 | **ipc-light** is a lightweight inter-process-communication library 11 | that leverages UNIX domain sockets to avoid latency, unreliability and overhead of 12 | going through the network card, like most socket types. 13 | 14 | Unfortunatly, it is only available on Mac and Linux yet. Windows support is on the way. 15 | 16 | The goal behind this implementation design is to further mimick the 17 | node classic server setup pattern. It's designed to be simple. Very, very simple. 18 | 19 | COMPATIBLE WITH ALL VERSIONS OF NODE. 20 | 21 | ## Releases 22 | 23 | [Latest release](https://github.com/fed135/ipc-light/releases/latest) 24 | 25 | [All releases](https://github.com/fed135/ipc-light/releases) 26 | 27 | 28 | ## Installation 29 | 30 | $ npm install ipc-light --save 31 | 32 | 33 | ## Tests 34 | 35 | $ npm test 36 | 37 | 38 | ## Debugging 39 | 40 | ipc-light uses the debug module, to include ipc-light logs in your app 41 | use the debug syntax. Ex: 42 | 43 | $ DEBUG=ipc npm start 44 | 45 | 46 | ## Usage 47 | 48 | See examples in the docs folder. [Here](https://github.com/fed135/ipc-light/blob/master/docs/EXAMPLES.md) 49 | 50 | 51 | ## Benchmarks 52 | 53 | $ node tests/benchmark.js 54 | 55 | ## Roadmap 56 | 57 | [Milestones](https://github.com/fed135/ipc-light/milestones) -------------------------------------------------------------------------------- /docs/EXAMPLES.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | ## Setting up a server 4 | 5 | var ipc = require('ipc-light'); 6 | 7 | var server = ipc.createServer(function(request, reply) { 8 | reply('Hello there!'); 9 | }).listen(); 10 | 11 | 12 | ## Connecting to a server 13 | 14 | var ipc = require('ipc-light'); 15 | 16 | var socket = ipc.connect({}, function() { 17 | socket.emit('Hello, neighbour!'); 18 | }); 19 | 20 | socket.ondata.add(function(request, reply) { 21 | //Check request.payload for data 22 | reply('Sounds nice!'); 23 | }); 24 | 25 | 26 | ## Broadcasting 27 | 28 | server.broadcast({ 29 | message: 'I\'m holding a barbecue this weekend.', 30 | time: '4PM', 31 | address: 'Mt doom.' 32 | }); 33 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Main 3 | */ 4 | 5 | 'use strict'; 6 | 7 | /* Requires ------------------------------------------------------------------*/ 8 | 9 | var Client = require('./src/Client'); 10 | var Server = require('./src/Server'); 11 | var defaults = require('./src/defaults'); 12 | 13 | /* Exports -------------------------------------------------------------------*/ 14 | 15 | module.exports = { 16 | /** 17 | * Helper function to create an IPC server 18 | */ 19 | createServer: function(requestHandler) { 20 | var server = new Server(); 21 | server.handler = requestHandler; 22 | return server; 23 | }, 24 | /** 25 | * Helper function to create a client and listen to a server 26 | */ 27 | connect: function(config, callback) { 28 | var client = new Client(config); 29 | client.connect(callback); 30 | return client; 31 | }, 32 | Client: Client, 33 | Server: Server, 34 | defaults: defaults 35 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ipc-light", 3 | "version": "1.1.3", 4 | "description": "A lightweight IPC server library", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha ./tests/index.js", 8 | "test-travis": "./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha -- -R spec ./tests/index.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/fed135/ipc-light.git" 13 | }, 14 | "keywords": [ 15 | "ipc", 16 | "socket", 17 | "unix", 18 | "process", 19 | "network", 20 | "micro-service", 21 | "communication", 22 | "light" 23 | ], 24 | "author": "frederic charette", 25 | "license": "GPL-3.0", 26 | "bugs": { 27 | "url": "https://github.com/fed135/ipc-light/issues" 28 | }, 29 | "homepage": "https://github.com/fed135/ipc-light#readme", 30 | "devDependencies": { 31 | "coveralls": "2.11.x", 32 | "chai": "3.4.x", 33 | "mocha": "2.4.x", 34 | "istanbul": "0.4.x" 35 | }, 36 | "dependencies": { 37 | "debug": "2.2.x", 38 | "signals": "1.0.x" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Client.js: -------------------------------------------------------------------------------- 1 | /** 2 | * IPC Client class 3 | * @class Client 4 | */ 5 | 6 | 'use strict'; 7 | 8 | /* Requires ------------------------------------------------------------------*/ 9 | 10 | var defaults = require('./defaults'); 11 | 12 | var net = require('net'); 13 | var Signal = require('signals'); 14 | var debug = require('debug')('ipc'); 15 | 16 | /* Methods -------------------------------------------------------------------*/ 17 | 18 | /** 19 | * Client class constructor 20 | * @constructor 21 | * @param {object} config The configuration object for the client 22 | */ 23 | function Client(config) { 24 | config = config || {}; 25 | this.path = config.path || defaults.path; 26 | this.socket = null; 27 | 28 | this.onconnect = new Signal(); 29 | this.ondisconnect = new Signal(); 30 | this.ondata = new Signal(); 31 | this.onerror = new Signal(); 32 | } 33 | 34 | /** 35 | * Emits a socket to an ipc server 36 | * @method emit 37 | * @memberof Client 38 | * param {?} payload The payload to send to the server 39 | * returns {Client} Self reference, for chaining 40 | */ 41 | Client.prototype.emit = function(payload, callback) { 42 | if (!this.socket) { 43 | debug('error: client is not connected'); 44 | return this; 45 | } 46 | 47 | // Can now send a Buffer or a plain string, no added steps 48 | if (!(payload instanceof Buffer) && !(payload instanceof String)) { 49 | payload = JSON.stringify(payload); 50 | } 51 | 52 | this.socket.write(payload, callback); 53 | 54 | return this; 55 | }; 56 | 57 | /** 58 | * Connects the client to an IPC server 59 | * @method connect 60 | * @memberof Client 61 | * @param {function} callback The callback method 62 | * @returns {Client} Self reference, for chaining 63 | */ 64 | Client.prototype.connect = function(callback) { 65 | debug('log: trying to connect to ' + this.path); 66 | 67 | this.socket = net.connect({ 68 | path: this.path 69 | }); 70 | 71 | this.socket.on('close', this._handleDisconnect.bind(this)); 72 | 73 | this.socket.on('error', this._handleError.bind(this)); 74 | 75 | this.socket.on(defaults.evt, this._handleData.bind(this)); 76 | 77 | debug('log: client connected'); 78 | this.onconnect.dispatch(this); 79 | if (callback) callback(this); 80 | 81 | return this; 82 | }; 83 | 84 | /** 85 | * Parses received buffer to transform it back into an object 86 | * @private 87 | * @method _handleData 88 | * @memberof Client 89 | * @param {Buffer} data The received data 90 | */ 91 | Client.prototype._handleData = function(data) { 92 | this.ondata.dispatch(data); 93 | }; 94 | 95 | /** 96 | * Disconnects the client to an IPC server 97 | * @method disconnect 98 | * @memberof Client 99 | * @returns {Client} Self reference, for chaining 100 | */ 101 | Client.prototype.disconnect = function() { 102 | if (this.socket) { 103 | debug('warning: disconnecting client'); 104 | this.socket.destroy(); 105 | this.socket = null; 106 | this.ondisconnect.dispatch(this); 107 | } 108 | }; 109 | 110 | /** 111 | * Handles socket disconnection 112 | * @private 113 | * @method _handleDisconnect 114 | * @memberof Client 115 | */ 116 | Client.prototype._handleDisconnect = function() { 117 | if (this.socket) { 118 | debug('warning: client has been disconnected'); 119 | this.socket.destroy(); 120 | this.socket = null; 121 | this.ondisconnect.dispatch(this); 122 | } 123 | }; 124 | 125 | /** 126 | * Handles socket errors 127 | * @private 128 | * @method _handleError 129 | * @memberof Client 130 | * @param {Error} error The error object 131 | */ 132 | Client.prototype._handleError = function(error) { 133 | debug('error: socket error [' + error + ']'); 134 | 135 | this.socket.destroy(); 136 | this.socket = null; 137 | this.onerror.dispatch(this); 138 | }; 139 | 140 | /* Exports -------------------------------------------------------------------*/ 141 | 142 | module.exports = Client; -------------------------------------------------------------------------------- /src/Server.js: -------------------------------------------------------------------------------- 1 | /** 2 | * IPC Server class 3 | * @class Server 4 | */ 5 | 6 | 'use strict'; 7 | 8 | /* Requires ------------------------------------------------------------------*/ 9 | 10 | var defaults = require('./defaults'); 11 | 12 | var fs = require('fs'); 13 | var net = require('net'); 14 | var Signal = require('signals'); 15 | var debug = require('debug')('ipc'); 16 | 17 | /* Methods -------------------------------------------------------------------*/ 18 | 19 | /** 20 | * Server class constructor 21 | * @constructor 22 | * @param {object} config The configuration object for the server 23 | */ 24 | function Server() { 25 | this.path = null; 26 | this.handler = null; 27 | this.sockets = []; 28 | this.server = null; 29 | 30 | //Events 31 | this.onconnect = new Signal(); 32 | this.ondisconnect = new Signal(); 33 | this.onerror = new Signal(); 34 | } 35 | 36 | /** 37 | * Tells the server to start listening. 38 | * @method listen 39 | * @memberof Server 40 | * @param {string} path The system path to connect to 41 | * @returns {Server} Self reference, for chaining 42 | */ 43 | Server.prototype.listen = function(path, callback) { 44 | var _self = this; 45 | 46 | if (this.server) { 47 | debug('warning: server already listening on path: ' + this.path); 48 | 49 | return this.close.call(this, function reconnect() { 50 | _self.listen.call(_self, path, callback); 51 | }); 52 | } 53 | 54 | this.path = path || defaults.path; 55 | if (!path) { 56 | debug('log: no path provided, default path used: ' + defaults.path); 57 | } 58 | 59 | debug('log: unlinking server path...'); 60 | fs.unlink(this.path, function bindSocket() { 61 | 62 | _self.server = net.createServer(_self._handleConnections.bind(_self)); 63 | 64 | debug('log: starting server ' + _self.path); 65 | _self.server.listen(_self.path, callback); 66 | }); 67 | 68 | return this; 69 | }; 70 | 71 | /** 72 | * Makes the server broadcast a message to all connected sockets 73 | * @method broadcast 74 | * @memberof Server 75 | * @param {?} payload The payload to send to all connected sockets 76 | * @returns {Server} Self reference, for chaining 77 | */ 78 | Server.prototype.broadcast = function(payload) { 79 | // Can now send a Buffer or a plain string, no added steps 80 | if (!(payload instanceof Buffer) && !(payload instanceof String)) { 81 | payload = JSON.stringify(payload); 82 | } 83 | 84 | this.sockets.forEach(function writeToAll(e) { 85 | this.write(e, payload); 86 | }, this); 87 | 88 | return this; 89 | }; 90 | 91 | /** 92 | * Makes the server broadcast a message to all connected sockets 93 | * @method broadcast 94 | * @memberof Server 95 | * @param {Socket} socket The socket to write to 96 | * @param {?} payload The payload to send to the socket 97 | * @returns {Server} Self reference, for chaining 98 | */ 99 | Server.prototype.write = function(socket, payload) { 100 | // Can now send a Buffer or a plain string, no added steps 101 | if (!(payload instanceof Buffer) && !(payload instanceof String)) { 102 | payload = JSON.stringify(payload); 103 | } 104 | 105 | if (socket && socket.write) socket.write(payload); 106 | }; 107 | 108 | /** 109 | * Shuts down the server explicitly 110 | * @method close 111 | * @memberof Server 112 | * @param {function} callback The callback method 113 | * @returns {Server} Self reference, for chaining 114 | */ 115 | Server.prototype.close = function(callback) { 116 | debug('warning: closing current server'); 117 | this.server.close(); 118 | this.server = null; 119 | fs.unlink(this.path, function unlink() { 120 | //Regardless of the outcome 121 | if (callback) callback(); 122 | }); 123 | return this; 124 | }; 125 | 126 | /** 127 | * Handles a socket disconnection 128 | * @private 129 | * @method _handleDisconnect 130 | * @memberof Server 131 | * @param {object} socket The socket that just disconnected 132 | */ 133 | Server.prototype._handleDisconnect = function(socket) { 134 | debug('log: socket disconnected'); 135 | 136 | //Remove socket from list 137 | this.sockets = this.sockets.filter(function(e) { 138 | return e !== socket; 139 | }); 140 | 141 | this.ondisconnect.dispatch(socket); 142 | }; 143 | 144 | /** 145 | * Handles socket errors 146 | * @private 147 | * @method _handleError 148 | * @memberof Server 149 | * @param {object} socket The socket that just had an error 150 | * @param {Error} error The error object 151 | */ 152 | Server.prototype._handleError = function(socket, error) { 153 | debug('error: socket error [' + error + ']'); 154 | 155 | this.onerror.dispatch({ 156 | error: error, 157 | socket: socket 158 | }); 159 | }; 160 | 161 | /** 162 | * Handles new socket connections 163 | * @private 164 | * @method _handleConnections 165 | * @memberof Server 166 | * @param {object} socket The socket that just connected 167 | */ 168 | Server.prototype._handleConnections = function(socket) { 169 | var _self = this; 170 | 171 | debug('log: connection received'); 172 | 173 | this.sockets.push(socket); 174 | 175 | socket.on('close', function _socketClose() { 176 | _self._handleDisconnect.call(_self, socket); 177 | }); 178 | 179 | socket.on('error', function _socketError(err) { 180 | _self._handleError.call(_self, socket, err); 181 | }); 182 | 183 | socket.on(defaults.evt, function _socketData(payload) { 184 | _self.handler(payload, function _socketHandler(msg) { 185 | _self.write.call(_self, socket, msg); 186 | }); 187 | }); 188 | 189 | _self.onconnect.dispatch(socket); 190 | }; 191 | 192 | /* Exports -------------------------------------------------------------------*/ 193 | 194 | module.exports = Server; -------------------------------------------------------------------------------- /src/defaults.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Module configuration 3 | */ 4 | 5 | module.exports = { 6 | path: '/tmp/app.socket', 7 | evt: 'data' 8 | }; -------------------------------------------------------------------------------- /tests/benchmark.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Benchmarks to compare the speeds of http server, vs tcp socket vs udp socket 3 | * vs ipc socket. 4 | */ 5 | 6 | /* Requires ------------------------------------------------------------------*/ 7 | 8 | var ipc = require('../index'); 9 | var http = require('http'); 10 | var dgram = require('dgram'); 11 | var net = require('net'); 12 | 13 | var async = require('./libs/async'); 14 | var spinner = require('./libs/spinner'); 15 | 16 | /* Local variables -----------------------------------------------------------*/ 17 | 18 | var times = {}; 19 | var servers = {}; 20 | 21 | /* Methods -------------------------------------------------------------------*/ 22 | 23 | function _startServers(resolve) { 24 | spinner.setText('setup'); 25 | servers.http = http.createServer(function(request, response) { 26 | //console.log('hi there !'); 27 | response.writeHead(200, {'Content-Type': 'text/plain'}); 28 | response.end('test'); 29 | }); 30 | servers.http.listen(6080); 31 | 32 | servers.ipc = ipc.createServer(function(request, reply) { 33 | reply('test'); 34 | }).listen(); 35 | 36 | servers.udp = dgram.createSocket('udp4'); 37 | servers.udp.on('message', function (message, remote) { 38 | //reply 39 | //console.log(remote); 40 | _udp(function(){}, remote.port); 41 | }); 42 | servers.udp.bind(33333, '127.0.0.1'); 43 | 44 | servers.tcp = net.createServer(function(socket){ 45 | socket.end('test'); 46 | }); 47 | servers.tcp.listen(3080); 48 | 49 | setTimeout(resolve, 2000); 50 | } 51 | 52 | function _runTest(type, callback) { 53 | var _currTime = _microTime(); 54 | type.method(function(){ 55 | var result = Math.round(_microTime() - _currTime); 56 | if (!times[type.name]) times[type.name] = { 57 | min: null, 58 | max: null, 59 | _total: 0, 60 | calls: 0 61 | }; 62 | times[type.name].calls++; 63 | times[type.name]._total += result; 64 | if (times[type.name].min == null || 65 | times[type.name].min > result) times[type.name].min = result; 66 | if (times[type.name].max == null || 67 | times[type.name].max < result) times[type.name].max = result; 68 | 69 | if (callback) callback(); 70 | }); 71 | } 72 | 73 | function _microTime() { 74 | var time = process.hrtime(); 75 | return time[0] * 1000000 + time[1]*0.001; 76 | } 77 | 78 | function _ipc(callback) { 79 | if (!servers.ipc) return; 80 | var client = ipc.connect(); 81 | client.ondata.add(function() { 82 | client.disconnect(); 83 | callback() 84 | }); 85 | client.emit('test'); 86 | } 87 | 88 | function _http(callback){ 89 | if (!servers.http) return; 90 | var req = http.request('http://localhost:6080', callback); 91 | req.write('test'); 92 | req.end(); 93 | } 94 | 95 | function _udp(callback, port){ 96 | if (!servers.udp) return; 97 | var client = dgram.createSocket('udp4'); 98 | var message = new Buffer('test'); 99 | client.send(message, 0, message.length, port || 33333, '127.0.0.1', function(err, bytes) { 100 | if (err) { 101 | client.close(); 102 | //throw err; 103 | } 104 | }); 105 | 106 | client.on('message', function(){ 107 | callback(); 108 | client.close(); 109 | }); 110 | } 111 | 112 | function _tcp(callback) { 113 | if (!servers.tcp) return; 114 | var client = net.connect(3080); 115 | client.on('error', function(){}); 116 | client.write('test'); 117 | client.on('data', function(){ 118 | client.end(); 119 | callback(); 120 | }); 121 | } 122 | 123 | function _teardown(err) { 124 | if (err) { 125 | console.log('Error!'); 126 | console.log(err); 127 | } 128 | 129 | spinner.setText('finishing'); 130 | Object.keys(servers).forEach(function(e) { 131 | if (servers[e].destroy) servers[e].destroy(); 132 | 133 | if (servers[e].close) servers[e].close(); 134 | else console.log('server ' + e + ' has no close method.'); 135 | delete servers[e]; 136 | }); 137 | spinner.stop(); 138 | 139 | Object.keys(times).forEach(function(e, i, arr) { 140 | times[e].avg = Math.round(times[e]._total/times[e].calls); 141 | delete times[e]._total; 142 | }); 143 | console.log(times); 144 | } 145 | 146 | function main() { 147 | var tests = [ 148 | _startServers, 149 | _batchTest.bind({ 150 | name: 'ipc', 151 | method: _ipc 152 | }), 153 | _batchTest.bind({ 154 | name: 'http', 155 | method: _http 156 | }), 157 | _batchTest.bind({ 158 | name: 'udp', 159 | method: _udp 160 | }), 161 | _batchTest.bind({ 162 | name: 'tcp', 163 | method: _tcp 164 | }) 165 | ]; 166 | 167 | spinner.start(); 168 | 169 | async.queue(tests, _teardown); 170 | } 171 | 172 | function _batchTest(resolve) { 173 | spinner.setText(this.name); 174 | var handbreak = false; 175 | 176 | function _runInContext() { 177 | if (!handbreak) { 178 | _runTest(this, _runInContext.bind(this)); 179 | } 180 | } 181 | 182 | _runInContext.call(this); 183 | 184 | setTimeout(function() { 185 | handbreak = true; 186 | spinner.setText('preparing'); 187 | setTimeout(function() { 188 | if (resolve) resolve(); 189 | }, 1000); 190 | },10000); 191 | } 192 | 193 | /* Entry point ---------------------------------------------------------------*/ 194 | 195 | main(); -------------------------------------------------------------------------------- /tests/index.js: -------------------------------------------------------------------------------- 1 | var ipc = require('../index'); 2 | 3 | //Values 4 | var server_a; 5 | var server_b; 6 | 7 | var client_a; 8 | var client_b; 9 | 10 | //Server 11 | describe('Starting:', function() { 12 | 13 | //Creation - no args 14 | it('a) #createServer()', function() { 15 | server_a = ipc.createServer(function(request, reply) { 16 | //console.log('a) handler'); 17 | //console.log(request); 18 | reply('server_a'); 19 | }).listen(); 20 | }); 21 | 22 | //Creation - with args 23 | it('b) #createServer(args)', function() { 24 | server_b = ipc.createServer(function(request, reply) { 25 | //console.log('b) handler'); 26 | //console.log(request); 27 | reply('server_b'); 28 | }).listen('/var/tmp/test_test.socket'); 29 | }); 30 | }); 31 | 32 | //Client 33 | describe('Connecting:', function() { 34 | 35 | //Creation - no args 36 | it('a) #connect()', function() { 37 | client_a = ipc.connect(); 38 | }); 39 | 40 | //Creation - with args 41 | it('b) #connect(args)', function() { 42 | client_b = ipc.connect({ 43 | path: '/var/tmp/test_test.socket' 44 | }); 45 | }); 46 | }); 47 | 48 | describe('Client:', function() { 49 | it('a) #emit()', function() { 50 | client_a.ondata.add(function(data) { 51 | //console.log('a) emit response:'); 52 | //console.log(data); 53 | }); 54 | client_a.emit('some payload'); 55 | }); 56 | 57 | it('b) #emit()', function() { 58 | client_b.ondata.add(function(data) { 59 | //console.log('b) emit response:'); 60 | //console.log(data); 61 | }); 62 | client_b.emit({foo:'bar'}); 63 | }); 64 | }); 65 | 66 | describe('Server:', function() { 67 | it('a) #broadcast()', function() { 68 | server_a.broadcast('some broadcast'); 69 | }); 70 | 71 | it('b) #broadcast()', function() { 72 | server_b.broadcast({bar:'foo'}); 73 | }); 74 | }); 75 | 76 | describe('Teardown:', function() { 77 | it('a) #disconnect()', function() { 78 | client_a.disconnect(); 79 | }); 80 | 81 | it('b) #disconnect()', function() { 82 | client_b.disconnect(); 83 | }); 84 | 85 | it('a) #close()', function() { 86 | server_a.close(); 87 | }); 88 | 89 | it('b) #close()', function() { 90 | server_b.close(); 91 | }); 92 | }); -------------------------------------------------------------------------------- /tests/libs/async.js: -------------------------------------------------------------------------------- 1 | // Imported from Kalm 2 | 3 | function _promisify(method) { 4 | return new Promise(method); 5 | } 6 | 7 | function all(list, callback) { 8 | Promise.all(list.map(_promisify)).then(function() { 9 | callback(); 10 | }, 11 | function(err) { 12 | callback(err || 'unhandled_error'); 13 | cl.error('Boot failure: '); 14 | cl.error(err); 15 | }); 16 | } 17 | 18 | //For some reason, it's not doing the tasks in a 19 | //synchronous manner... had to go full dirty 20 | function queue(list, callback) { 21 | if (list.length === 0) callback(); 22 | 23 | for(var i = 0; i < list.length; i++) { 24 | list[i](list[i+1] || callback); 25 | } 26 | } 27 | 28 | module.exports = { 29 | all: all, 30 | queue: queue 31 | }; -------------------------------------------------------------------------------- /tests/libs/spinner.js: -------------------------------------------------------------------------------- 1 | var _spinnerSymbols = ['/','-','\\','|']; 2 | var _spinnerTimer; 3 | var text = ''; 4 | 5 | function _startSpinner() { 6 | _stopSpinner(); 7 | _spinnerTimer = setInterval(_stepSpinner, 90); 8 | } 9 | 10 | function _stepSpinner() { 11 | _spinnerSymbols.push(_spinnerSymbols.shift()); 12 | process.stdout.write('\r ' + text + ' ' + _spinnerSymbols[0]); 13 | } 14 | 15 | function _stopSpinner() { 16 | if (_spinnerTimer) clearInterval(_spinnerTimer); 17 | process.stdout.write('\r \n'); 18 | } 19 | 20 | module.exports = { 21 | start: _startSpinner, 22 | stop: _stopSpinner, 23 | setText: function(txt) { 24 | text = txt; 25 | } 26 | }; --------------------------------------------------------------------------------