From 74c999abe3ef3d9f25fb0929aa8e274355f6b213 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Thu, 14 Jul 2016 16:53:13 -0700 Subject: [PATCH] refactor websocket api. --- lib/bcoin/http/client.js | 28 ++++++---- lib/bcoin/http/server.js | 115 +++++++++++++++++++++++++++++++-------- lib/bcoin/http/wallet.js | 7 ++- 3 files changed, 112 insertions(+), 38 deletions(-) diff --git a/lib/bcoin/http/client.js b/lib/bcoin/http/client.js index 27830f8e..5b10e9be 100644 --- a/lib/bcoin/http/client.js +++ b/lib/bcoin/http/client.js @@ -89,7 +89,7 @@ HTTPClient.prototype._open = function _open(callback) { self.emit('error', new Error('Wrong network.')); }); - this.socket.on('tx', function(tx, map) { + this.socket.on('wallet tx', function(tx, map) { try { tx = bcoin.tx.fromJSON(tx); } catch (e) { @@ -98,7 +98,7 @@ HTTPClient.prototype._open = function _open(callback) { self.emit('tx', tx, map); }); - this.socket.on('confirmed', function(tx, map) { + this.socket.on('wallet confirmed', function(tx, map) { try { tx = bcoin.tx.fromJSON(tx); } catch (e) { @@ -107,7 +107,7 @@ HTTPClient.prototype._open = function _open(callback) { self.emit('confirmed', tx, map); }); - this.socket.on('updated', function(tx, map) { + this.socket.on('wallet updated', function(tx, map) { try { tx = bcoin.tx.fromJSON(tx); } catch (e) { @@ -116,7 +116,7 @@ HTTPClient.prototype._open = function _open(callback) { self.emit('updated', tx, map); }); - this.socket.on('address', function(receive, change, map) { + this.socket.on('wallet address', function(receive, change, map) { receive = receive.map(function(address) { return bcoin.keyring.fromJSON(address); }); @@ -126,7 +126,7 @@ HTTPClient.prototype._open = function _open(callback) { self.emit('address', receive, change, map); }); - this.socket.on('balance', function(balance, id) { + this.socket.on('wallet balance', function(balance, id) { self.emit('balance', { confirmed: utils.satoshi(balance.confirmed), unconfirmed: utils.satoshi(balance.unconfirmed), @@ -134,7 +134,7 @@ HTTPClient.prototype._open = function _open(callback) { }, id); }); - this.socket.on('balances', function(json) { + this.socket.on('wallet balances', function(json) { var balances = {}; Object.keys(json).forEach(function(id) { balances[id] = { @@ -147,7 +147,11 @@ HTTPClient.prototype._open = function _open(callback) { }); this.socket.on('connect', function() { - callback(); + self.socket.emit('auth', self.apiKey.toString('hex'), function(err) { + if (err) + return callback(new Error(err.error)); + callback(); + }); }); }; @@ -172,11 +176,11 @@ HTTPClient.prototype._close = function close(callback) { * @param {WalletID} id */ -HTTPClient.prototype.join = function join(id, token) { +HTTPClient.prototype.join = function join(id, token, callback) { if (!this.socket) - return; + return callback(); - this.socket.emit('join', id, token); + this.socket.emit('wallet join', id, token, callback); }; /** @@ -184,11 +188,11 @@ HTTPClient.prototype.join = function join(id, token) { * @param {WalletID} id */ -HTTPClient.prototype.leave = function leave(id) { +HTTPClient.prototype.leave = function leave(id, callback) { if (!this.socket) return; - this.socket.emit('leave', id); + this.socket.emit('wallet leave', id, callback); }; /** diff --git a/lib/bcoin/http/server.js b/lib/bcoin/http/server.js index cf872ef7..b9ed1a4e 100644 --- a/lib/bcoin/http/server.js +++ b/lib/bcoin/http/server.js @@ -830,34 +830,69 @@ HTTPServer.prototype._initIO = function _initIO() { return; this.server.on('websocket', function(socket) { + socket.bcoin = new ClientSocket(self, socket); + socket.bcoin.startTimeout(); + socket.on('error', function(err) { self.emit('error', err); }); - socket.on('join', function(id, token) { + socket.on('auth', function(apiKey, callback) { + callback = utils.ensure(callback); + + if (!self.apiKey) { + self.logger.info('Successful auth.'); + socket.bcoin.stopTimeout(); + self.emit('websocket', socket); + return callback(); + } + + if (!utils.isHex(apiKey)) + return callback({ error: 'Bad key.' }); + + apiKey = new Buffer(apiKey, 'hex'); + + if (!utils.ccmp(apiKey, self.apiKey)) + return callback({ error: 'Bad key.' }); + + self.logger.info('Successful auth.'); + socket.bcoin.stopTimeout(); + self.emit('websocket', socket); + + return callback(); + }); + + socket.emit('version', { + version: constants.USER_VERSION, + agent: constants.USER_AGENT, + network: self.network.type + }); + }); + + this.on('websocket', function(socket) { + socket.on('wallet join', function(id, token, callback) { + callback = utils.ensure(callback); + if (!self.options.walletAuth) { socket.join(id); - return; + return callback(); } + self.walletdb.auth(id, token, function(err) { if (err) { - self.logger.info('Auth failure for %s: %s.', id, err.message); - return; + self.logger.info('Wallet auth failure for %s: %s.', id, err.message); + return callback({ error: 'Bad token.' }); } - self.logger.info('Successful auth for %s.', id); + self.logger.info('Successful wallet auth for %s.', id); socket.join(id); + return callback(); }); }); - socket.on('leave', function(id) { + socket.on('wallet leave', function(id, callback) { + callback = utils.ensure(callback); socket.leave(id); - }); - - self.emit('websocket', socket); - - socket.emit('version', { - version: constants.USER_AGENT, - network: self.network.type + return callback(); }); }); @@ -865,27 +900,27 @@ HTTPServer.prototype._initIO = function _initIO() { var summary = map.toJSON(); tx = tx.toJSON(); map.getWallets().forEach(function(id) { - self.server.io.to(id).emit('tx', tx, summary); + self.server.io.to(id).emit('wallet tx', tx, summary); }); - self.server.io.to('!all').emit('tx', tx, summary); + self.server.io.to('!all').emit('wallet tx', tx, summary); }); this.walletdb.on('confirmed', function(tx, map) { var summary = map.toJSON(); tx = tx.toJSON(); map.getWallets().forEach(function(id) { - self.server.io.to(id).emit('confirmed', tx, summary); + self.server.io.to(id).emit('wallet confirmed', tx, summary); }); - self.server.io.to('!all').emit('confirmed', tx, summary); + self.server.io.to('!all').emit('wallet confirmed', tx, summary); }); this.walletdb.on('updated', function(tx, map) { var summary = map.toJSON(); tx = tx.toJSON(); map.getWallets().forEach(function(id) { - self.server.io.to(id).emit('updated', tx, summary); + self.server.io.to(id).emit('wallet updated', tx, summary); }); - self.server.io.to('!all').emit('updated', tx, summary); + self.server.io.to('!all').emit('wallet updated', tx, summary); }); this.walletdb.on('balances', function(balances) { @@ -896,10 +931,10 @@ HTTPServer.prototype._initIO = function _initIO() { unconfirmed: utils.btc(balances[id].unconfirmed), total: utils.btc(balances[id].total) }; - self.server.io.to(id).emit('balance', json[id], id); - self.server.io.to('!all').emit('balance', json[id], id); + self.server.io.to(id).emit('wallet balance', json[id], id); + self.server.io.to('!all').emit('wallet balance', json[id], id); }); - self.server.io.to('!all').emit('balances', json); + self.server.io.to('!all').emit('wallet balances', json); }); this.walletdb.on('address', function(receive, change, map) { @@ -914,10 +949,10 @@ HTTPServer.prototype._initIO = function _initIO() { }); map.getWallets().forEach(function(id) { - self.server.io.to(id).emit('address', receive, change, summary); + self.server.io.to(id).emit('wallet address', receive, change, summary); }); - self.server.io.to('!all').emit('address', receive, change, summary); + self.server.io.to('!all').emit('wallet address', receive, change, summary); }); }; @@ -1003,6 +1038,38 @@ HTTPServer.prototype.listen = function listen(port, host, callback) { }); }; +/** + * ClientSocket + * @constructor + * @param {HTTPServer} server + * @param {SocketIO.Socket} + */ + +function ClientSocket(server, socket) { + this.server = server; + this.socket = socket; + this.timeout = null; +} + +ClientSocket.prototype.startTimeout = function startTimeout() { + var self = this; + this.stopTimeout(); + this.timeout = setTimeout(function() { + self.destroy(); + }, 60000); +}; + +ClientSocket.prototype.stopTimeout = function stopTimeout() { + if (this.timeout != null) { + clearTimeout(this.timeout); + this.timeout = null; + } +}; + +ClientSocket.prototype.destroy = function() { + this.socket.disconnect(); +}; + /* * Expose */ diff --git a/lib/bcoin/http/wallet.js b/lib/bcoin/http/wallet.js index 472d17df..4f92daa1 100644 --- a/lib/bcoin/http/wallet.js +++ b/lib/bcoin/http/wallet.js @@ -114,8 +114,11 @@ HTTPWallet.prototype.open = function open(options, callback) { self.id = wallet.id; self.client.auth = { username: 'x', password: wallet.token }; self.token = new Buffer(wallet.token, 'hex'); - self.client.join(self.id, wallet.token); - callback(null, wallet); + self.client.join(self.id, wallet.token, function(err) { + if (err) + return callback(new Error(err.error)); + callback(null, wallet); + }); }); }); };