From 665e0f87318015dee714a80afb9909e519fb278f Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Fri, 13 Mar 2015 10:47:10 -0300 Subject: [PATCH 1/7] add socket.io dep --- package.json | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 3581cf5..12527c1 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "read": "^1.0.5", "request": "^2.53.0", "sjcl": "^1.0.2", + "socket.io": "^1.3.5", "uuid": "*" }, "devDependencies": { @@ -53,13 +54,10 @@ "coveralls": "./node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage" }, "contributors": [{ - "name": "Ivan Socolsky", - "email": "ivan@bitpay.com" - }, - - { - "name": "Matias Alejo Garcia", - "email": "ematiu@gmail.com" - } - ] + "name": "Ivan Socolsky", + "email": "ivan@bitpay.com" + }, { + "name": "Matias Alejo Garcia", + "email": "ematiu@gmail.com" + }] } From deaca91a3d0f3de66740bfde534ff21b47c565aa Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Mon, 23 Mar 2015 12:50:00 -0300 Subject: [PATCH 2/7] delegate event broadcasting --- app.js | 13 ++++++++++++- lib/server.js | 25 +++++++++++++++++++++---- test/integration/server.js | 8 ++++---- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/app.js b/app.js index 1a0ee5f..a8ea379 100644 --- a/app.js +++ b/app.js @@ -8,6 +8,17 @@ var port = process.env.BWS_PORT || 3001; var app = ExpressApp.start({ basePath: basePath, }); -app.listen(port); +//app.listen(port); + +var server = require('http').Server(app); +var io = require('socket.io')(server); + +server.listen(port); + +io.sockets.on('connection', function(socket) { + socket.emit('message', { + 'message': 'hello world' + }); +}); console.log('Bitcore Wallet Service running on port ' + port); diff --git a/lib/server.js b/lib/server.js index 8864375..5f26fc9 100644 --- a/lib/server.js +++ b/lib/server.js @@ -28,6 +28,23 @@ var Notification = require('./model/notification'); var initialized = false; var storage, blockExplorer; + +function EventBroadcaster() {}; + +nodeutil.inherits(EventBroadcaster, events.EventEmitter); + +EventBroadcaster.prototype.broadcast = function(service, args) { + this.emit(service, args); +}; + +var _eventBroadcasterInstance; +EventBroadcaster.singleton = function() { + if (!_eventBroadcasterInstance) { + _eventBroadcasterInstance = new EventBroadcaster(); + } + return _eventBroadcasterInstance; +}; + /** * Creates an instance of the Bitcore Wallet Service. * @constructor @@ -41,9 +58,6 @@ function WalletService() { this.notifyTicker = 0; }; -nodeutil.inherits(WalletService, events.EventEmitter); - - /** * Initializes global settings for all instances. * @param {Object} opts @@ -161,6 +175,9 @@ WalletService.prototype._verifySignature = function(text, signature, pubKey) { return WalletUtils.verifyMessage(text, signature, pubKey); }; +WalletService.prototype._emit = function(args) { + EventBroadcaster.singleton().broadcast(this, args); +}; /** * _notify @@ -182,7 +199,7 @@ WalletService.prototype._notify = function(type, data) { ticker: this.notifyTicker++, }); this.storage.storeNotification(walletId, n, function() { - self.emit(n); + self._emit(n); }); }; diff --git a/test/integration/server.js b/test/integration/server.js index f726385..877f0dd 100644 --- a/test/integration/server.js +++ b/test/integration/server.js @@ -1945,7 +1945,7 @@ describe('Copay server', function() { server.getPendingTxs({}, function(err, txs) { var tx = txs[2]; var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey); - sinon.spy(server, 'emit'); + sinon.spy(server, '_emit'); server.signTx({ txProposalId: tx.id, signatures: signatures, @@ -1964,9 +1964,9 @@ describe('Copay server', function() { var types = _.pluck(notifications, 'type'); types.should.deep.equal(['NewOutgoingTx', 'TxProposalFinallyAccepted', 'TxProposalAcceptedBy']); // Check also events - server.emit.getCall(0).args[0].type.should.equal('TxProposalAcceptedBy'); - server.emit.getCall(1).args[0].type.should.equal('TxProposalFinallyAccepted');; - server.emit.getCall(2).args[0].type.should.equal('NewOutgoingTx'); + server._emit.getCall(0).args[0].type.should.equal('TxProposalAcceptedBy'); + server._emit.getCall(1).args[0].type.should.equal('TxProposalFinallyAccepted');; + server._emit.getCall(2).args[0].type.should.equal('NewOutgoingTx'); done(); }); From 30e126c3835ee123c606a29bb0bcd0b30101b12f Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Mon, 23 Mar 2015 13:23:51 -0300 Subject: [PATCH 3/7] separate event broadcaster from wallet service --- lib/eventbroadcaster.js | 23 +++++++++++++++++++++++ lib/server.js | 31 +++++++++++-------------------- 2 files changed, 34 insertions(+), 20 deletions(-) create mode 100644 lib/eventbroadcaster.js diff --git a/lib/eventbroadcaster.js b/lib/eventbroadcaster.js new file mode 100644 index 0000000..db1d273 --- /dev/null +++ b/lib/eventbroadcaster.js @@ -0,0 +1,23 @@ +var log = require('npmlog'); +log.debug = log.verbose; +var inherits = require('inherits'); +var events = require('events'); +var nodeutil = require('util'); + +function EventBroadcaster() {}; + +nodeutil.inherits(EventBroadcaster, events.EventEmitter); + +EventBroadcaster.prototype.broadcast = function(service, args) { + this.emit(service, args); +}; + +var _eventBroadcasterInstance; +EventBroadcaster.singleton = function() { + if (!_eventBroadcasterInstance) { + _eventBroadcasterInstance = new EventBroadcaster(); + } + return _eventBroadcasterInstance; +}; + +module.exports = EventBroadcaster.singleton(); diff --git a/lib/server.js b/lib/server.js index 5f26fc9..4b07e60 100644 --- a/lib/server.js +++ b/lib/server.js @@ -4,9 +4,6 @@ var $ = require('preconditions').singleton(); var async = require('async'); var log = require('npmlog'); log.debug = log.verbose; -var inherits = require('inherits'); -var events = require('events'); -var nodeutil = require('util'); var WalletUtils = require('bitcore-wallet-utils'); var Bitcore = WalletUtils.Bitcore; @@ -18,6 +15,7 @@ var Explorers = require('bitcore-explorers'); var ClientError = require('./clienterror'); var Utils = require('./utils'); var Storage = require('./storage'); +var EventBroadcaster = require('./eventbroadcaster'); var Wallet = require('./model/wallet'); var Copayer = require('./model/copayer'); @@ -29,22 +27,6 @@ var initialized = false; var storage, blockExplorer; -function EventBroadcaster() {}; - -nodeutil.inherits(EventBroadcaster, events.EventEmitter); - -EventBroadcaster.prototype.broadcast = function(service, args) { - this.emit(service, args); -}; - -var _eventBroadcasterInstance; -EventBroadcaster.singleton = function() { - if (!_eventBroadcasterInstance) { - _eventBroadcasterInstance = new EventBroadcaster(); - } - return _eventBroadcasterInstance; -}; - /** * Creates an instance of the Bitcore Wallet Service. * @constructor @@ -58,6 +40,10 @@ function WalletService() { this.notifyTicker = 0; }; +WalletService.onNotification = function(func) { + EventBroadcaster.on('notification', func); +}; + /** * Initializes global settings for all instances. * @param {Object} opts @@ -175,8 +161,13 @@ WalletService.prototype._verifySignature = function(text, signature, pubKey) { return WalletUtils.verifyMessage(text, signature, pubKey); }; +/** + * _emit + * + * @param {Object} args + */ WalletService.prototype._emit = function(args) { - EventBroadcaster.singleton().broadcast(this, args); + EventBroadcaster.broadcast(this, args); }; /** From 221431d6cb2ca1a2fdafec2a58784769b5d47f3c Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Mon, 23 Mar 2015 18:26:47 -0300 Subject: [PATCH 4/7] implement ws handshake --- app.js | 10 +++---- lib/eventbroadcaster.js | 6 +++-- lib/server.js | 6 ++--- lib/wsapp.js | 58 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 12 deletions(-) create mode 100644 lib/wsapp.js diff --git a/app.js b/app.js index a8ea379..c13a39e 100644 --- a/app.js +++ b/app.js @@ -1,6 +1,7 @@ #!/usr/bin/env node var ExpressApp = require('./lib/expressapp'); +var WsApp = require('./lib/wsapp'); var basePath = process.env.BWS_BASE_PATH || '/bws/api'; var port = process.env.BWS_PORT || 3001; @@ -11,14 +12,9 @@ var app = ExpressApp.start({ //app.listen(port); var server = require('http').Server(app); -var io = require('socket.io')(server); + +var ws = WsApp.start(server); server.listen(port); -io.sockets.on('connection', function(socket) { - socket.emit('message', { - 'message': 'hello world' - }); -}); - console.log('Bitcore Wallet Service running on port ' + port); diff --git a/lib/eventbroadcaster.js b/lib/eventbroadcaster.js index db1d273..e8ab506 100644 --- a/lib/eventbroadcaster.js +++ b/lib/eventbroadcaster.js @@ -1,3 +1,5 @@ +'use strict'; + var log = require('npmlog'); log.debug = log.verbose; var inherits = require('inherits'); @@ -8,8 +10,8 @@ function EventBroadcaster() {}; nodeutil.inherits(EventBroadcaster, events.EventEmitter); -EventBroadcaster.prototype.broadcast = function(service, args) { - this.emit(service, args); +EventBroadcaster.prototype.broadcast = function(eventName, serviceInstance, args) { + this.emit(eventName, serviceInstance, args); }; var _eventBroadcasterInstance; diff --git a/lib/server.js b/lib/server.js index 4b07e60..d005808 100644 --- a/lib/server.js +++ b/lib/server.js @@ -166,8 +166,8 @@ WalletService.prototype._verifySignature = function(text, signature, pubKey) { * * @param {Object} args */ -WalletService.prototype._emit = function(args) { - EventBroadcaster.broadcast(this, args); +WalletService.prototype._emit = function(eventName, args) { + EventBroadcaster.broadcast(eventName, this, args); }; /** @@ -190,7 +190,7 @@ WalletService.prototype._notify = function(type, data) { ticker: this.notifyTicker++, }); this.storage.storeNotification(walletId, n, function() { - self._emit(n); + self._emit('notification', n); }); }; diff --git a/lib/wsapp.js b/lib/wsapp.js new file mode 100644 index 0000000..b4fe03b --- /dev/null +++ b/lib/wsapp.js @@ -0,0 +1,58 @@ +'use strict'; + +var $ = require('preconditions').singleton(); +var _ = require('lodash'); +var async = require('async'); +var log = require('npmlog'); +var express = require('express'); +var querystring = require('querystring'); +var bodyParser = require('body-parser') +var Uuid = require('uuid'); + +var WalletService = require('./server'); + +log.debug = log.verbose; +log.level = 'debug'; + +var subscriptions = {}; + +var WsApp = function() {}; + +WsApp.start = function(server) { + var self = this; + + var io = require('socket.io')(server); + + WalletService.onNotification(function(serviceInstance, args) { + var walletId = serviceInstance.walletId; + var copayerId = serviceInstance.copayerId; + + io.to(walletId).emit('notification', args); + }); + + + io.on('connection', function(socket) { + socket.nonce = Uuid.v4(); + socket.emit('challenge', socket.nonce); + + socket.on('authorize', function(data) { + if (data.message != socket.nonce) { + socket.emit('unauthorized'); + socket.disconnect(); + return; + } + WalletService.getInstanceWithAuth(data, function(err, res) { + var room = res.walletId; + if (err) { + socket.emit('unauthorized'); + socket.disconnect(); + return; + } + socket.join(room); + socket.emit('authorized'); + }); + }); + }); +}; + +module.exports = WsApp; From 8272232d0c88e08f39d15f170e9cf3aded34471a Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Mon, 23 Mar 2015 19:07:06 -0300 Subject: [PATCH 5/7] remove redundancy --- lib/wsapp.js | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/lib/wsapp.js b/lib/wsapp.js index b4fe03b..af7698f 100644 --- a/lib/wsapp.js +++ b/lib/wsapp.js @@ -18,37 +18,31 @@ var subscriptions = {}; var WsApp = function() {}; +WsApp._unauthorized = function() { + socket.emit('unauthorized'); + socket.disconnect(); +}; + WsApp.start = function(server) { var self = this; var io = require('socket.io')(server); WalletService.onNotification(function(serviceInstance, args) { - var walletId = serviceInstance.walletId; - var copayerId = serviceInstance.copayerId; - - io.to(walletId).emit('notification', args); + io.to(serviceInstance.walletId).emit('notification', args); }); - io.on('connection', function(socket) { socket.nonce = Uuid.v4(); socket.emit('challenge', socket.nonce); socket.on('authorize', function(data) { - if (data.message != socket.nonce) { - socket.emit('unauthorized'); - socket.disconnect(); - return; - } + if (data.message != socket.nonce) return WsApp.unauthorized(); + WalletService.getInstanceWithAuth(data, function(err, res) { - var room = res.walletId; - if (err) { - socket.emit('unauthorized'); - socket.disconnect(); - return; - } - socket.join(room); + if (err) return WsApp.unauthorized(); + + socket.join(res.walletId); socket.emit('authorized'); }); }); From 43de1e458c157fb3cfe229ef13b5d39e53467a1e Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Tue, 24 Mar 2015 12:46:54 -0300 Subject: [PATCH 6/7] add creator to notifications --- lib/model/notification.js | 2 ++ lib/server.js | 1 + test/integration/server.js | 10 +++++++--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/model/notification.js b/lib/model/notification.js index 18f94ec..2cffa09 100644 --- a/lib/model/notification.js +++ b/lib/model/notification.js @@ -37,6 +37,7 @@ Notification.create = function(opts) { x.id = _.padLeft(now, 14, '0') + _.padLeft(opts.ticker || 0, 4, '0'); x.type = opts.type || 'general'; x.data = opts.data; + x.creatorId = opts.creatorId; return x; }; @@ -48,6 +49,7 @@ Notification.fromObj = function(obj) { x.id = obj.id; x.type = obj.type, x.data = obj.data; + x.creatorId = obj.creatorId; return x; }; diff --git a/lib/server.js b/lib/server.js index d005808..40d7a0b 100644 --- a/lib/server.js +++ b/lib/server.js @@ -188,6 +188,7 @@ WalletService.prototype._notify = function(type, data) { type: type, data: data, ticker: this.notifyTicker++, + creatorId: self.copayerId, }); this.storage.storeNotification(walletId, n, function() { self._emit('notification', n); diff --git a/test/integration/server.js b/test/integration/server.js index 877f0dd..c57b926 100644 --- a/test/integration/server.js +++ b/test/integration/server.js @@ -1611,6 +1611,7 @@ describe('Copay server', function() { should.not.exist(err); var last = _.last(notifications); last.type.should.equal('TxProposalFinallyAccepted'); + last.creatorId.should.equal(wallet.copayers[1].id); last.data.txProposalId.should.equal(txp.id); done(); }); @@ -1868,6 +1869,9 @@ describe('Copay server', function() { should.not.exist(err); var types = _.pluck(notifications, 'type'); types.should.deep.equal(['NewTxProposal', 'NewTxProposal', 'NewTxProposal', 'NewAddress']); + var creators = _.uniq(_.pluck(notifications, 'creatorId')); + creators.length.should.equal(1); + creators[0].should.equal(wallet.copayers[0].id); done(); }); }); @@ -1964,9 +1968,9 @@ describe('Copay server', function() { var types = _.pluck(notifications, 'type'); types.should.deep.equal(['NewOutgoingTx', 'TxProposalFinallyAccepted', 'TxProposalAcceptedBy']); // Check also events - server._emit.getCall(0).args[0].type.should.equal('TxProposalAcceptedBy'); - server._emit.getCall(1).args[0].type.should.equal('TxProposalFinallyAccepted');; - server._emit.getCall(2).args[0].type.should.equal('NewOutgoingTx'); + server._emit.getCall(0).args[1].type.should.equal('TxProposalAcceptedBy'); + server._emit.getCall(1).args[1].type.should.equal('TxProposalFinallyAccepted');; + server._emit.getCall(2).args[1].type.should.equal('NewOutgoingTx'); done(); }); From d57034cc8c3d4bf1dddc81bb7dab3bf0c6b612d9 Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Thu, 26 Mar 2015 13:52:29 -0300 Subject: [PATCH 7/7] v0.0.14 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 12527c1..db3ff0a 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "bitcore-wallet-service", "description": "A service for Mutisig HD Bitcoin Wallets", "author": "BitPay Inc", - "version": "0.0.13", + "version": "0.0.14", "keywords": [ "bitcoin", "copay",