From dbf8832aa988eed0d0c77f83104bc2a46d0c7347 Mon Sep 17 00:00:00 2001 From: tigerbot Date: Thu, 27 Apr 2017 19:29:16 -0600 Subject: [PATCH] added ability to add/clear tokens on active websocket --- package.json | 5 ++-- wsclient.js | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 42ae3bc..6e7cc92 100644 --- a/package.json +++ b/package.json @@ -46,11 +46,12 @@ }, "homepage": "https://git.daplie.com/Daplie/node-tunnel-client#readme", "dependencies": { + "bluebird": "^3.5.0", "commander": "^2.9.0", - "oauth3.js": "git+https://git.daplie.com/OAuth3/oauth3.js.git#v1", "jsonwebtoken": "^7.1.9", + "oauth3.js": "git+https://git.daplie.com/OAuth3/oauth3.js.git#v1", "sni": "^1.0.0", - "tunnel-packer": "^1.1.0", + "tunnel-packer": "^1.2.0", "ws": "^2.2.3" } } diff --git a/wsclient.js b/wsclient.js index bebcf46..231abff 100644 --- a/wsclient.js +++ b/wsclient.js @@ -2,6 +2,7 @@ 'use strict'; var WebSocket = require('ws'); +var PromiseA = require('bluebird'); var sni = require('sni'); var Packer = require('tunnel-packer'); @@ -69,8 +70,61 @@ function run(copts) { } }; + var pendingCommands = {}; + function sendCommand(name) { + var id = Math.ceil(1e9 * Math.random()); + var cmd = [id, name].concat(Array.prototype.slice.call(arguments, 1)); + + wsHandlers.sendMessage(Packer.pack(null, cmd, 'control')); + setTimeout(function () { + if (pendingCommands[id]) { + console.warn('command', id, 'timed out'); + pendingCommands[id]({ + message: 'response not received in time' + , code: 'E_TIMEOUT' + }); + } + }, pongTimeout); + + return new PromiseA(function (resolve, reject) { + pendingCommands[id] = function (err, result) { + delete pendingCommands[id]; + if (err) { + reject(err); + } else { + resolve(result); + } + }; + }); + } + var packerHandlers = { - onmessage: function (opts) { + oncontrol: function (opts) { + var cmd, err; + try { + cmd = JSON.parse(opts.data.toString()); + } catch (err) {} + if (!Array.isArray(cmd) || typeof cmd[0] !== 'number') { + console.warn('received bad command "' + opts.data.toString() + '"'); + return; + } + + if (cmd[0] < 0) { + var cb = pendingCommands[-cmd[0]]; + if (!cb) { + console.warn('received response for unknown request:', cmd); + } else { + cb.apply(null, cmd.slice(1)); + } + return; + } + + // TODO: handle a "hello" message that let's us know we're authenticated. + err = { message: 'unknown command '+cmd[1], code: 'E_UNKNOWN_COMMAND' }; + + wsHandlers.sendMessage(Packer.pack(null, [-cmd[0], err], 'control')); + } + , onmessage: function (opts) { var net = copts.net || require('net'); var cid = Packer.addrToId(opts); var service = opts.service.toLowerCase(); @@ -222,6 +276,12 @@ function run(copts) { clearTimeout(timeoutId); wstunneler = null; clientHandlers.closeAll(); + Object.keys(pendingCommands).forEach(function (id) { + pendingCommands[id]({ + message: 'websocket connection closed before response' + , code: 'E_CONN_CLOSED' + }); + }); if (!authenticated) { console.info('[close] failed on first attempt... check authentication.'); @@ -297,6 +357,12 @@ function run(copts) { } } } + , append: function (token) { + return sendCommand('add_token', token); + } + , clear: function (token) { + return sendCommand('delete_token', token || '*'); + } }; }