From c45495eeffc526f04808806be7529b42bffe69d6 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Tue, 9 Sep 2014 13:45:50 -0300 Subject: [PATCH] lazy connect --- js/models/blockchain/Insight.js | 112 +++++++++++++++++++------------- js/services/controllerUtils.js | 2 +- test/test.blockchain.Insight.js | 33 +++++++--- views/open.html | 2 +- 4 files changed, 91 insertions(+), 58 deletions(-) diff --git a/js/models/blockchain/Insight.js b/js/models/blockchain/Insight.js index e26651787..67b95fd7c 100644 --- a/js/models/blockchain/Insight.js +++ b/js/models/blockchain/Insight.js @@ -27,15 +27,15 @@ var preconditions = require('preconditions').singleton(); - disconnect: the connection with the blochckain is unavailable. */ -var Insight = function (opts) { +var Insight = function(opts) { this.status = this.STATUS.DISCONNECTED; this.subscribed = {}; this.listeningBlocks = false; preconditions.checkArgument(opts).shouldBeObject(opts) - .checkArgument(opts.host) - .checkArgument(opts.port) - .checkArgument(opts.schema); + .checkArgument(opts.host) + .checkArgument(opts.port) + .checkArgument(opts.schema); this.url = opts.schema + '://' + opts.host + ':' + opts.port; this.opts = { @@ -44,33 +44,6 @@ var Insight = function (opts) { 'secure': opts.schema === 'https' }; - this.socket = this.getSocket(this.url, this.opts); - - // Emmit connection events - var self = this; - this.socket.on('connect', function() { - self.status = self.STATUS.CONNECTED; - self.subscribeToBlocks(); - self.emit('connect', 0); - }); - - this.socket.on('connect_error', function() { - if (self.status != self.STATUS.CONNECTED) return; - self.status = self.STATUS.DISCONNECTED; - self.emit('disconnect'); - }); - - this.socket.on('connect_timeout', function() { - if (self.status != self.STATUS.CONNECTED) return; - self.status = self.STATUS.DISCONNECTED; - self.emit('disconnect'); - }); - - this.socket.on('reconnect', function(attempt) { - if (self.status != self.STATUS.DISCONNECTED) return; - self.status = self.STATUS.CONNECTED; - self.emit('connect', attempt); - }); } util.inherits(Insight, EventEmitter); @@ -83,19 +56,55 @@ Insight.prototype.STATUS = { /** @private */ Insight.prototype.subscribeToBlocks = function() { - if (this.listeningBlocks || !this.socket.connected) return; + var socket = this.getSocket(); + if (this.listeningBlocks || ! socket.connected) return; var self = this; - this.socket.emit('subscribe', 'inv'); - this.socket.on('block', function(blockHash) { + socket.emit('subscribe', 'inv'); + socket.on('block', function(blockHash) { self.emit('block', blockHash); }); this.listeningBlocks = true; } +/** @private */ +Insight.prototype._getSocketIO = function(url, opts) { + return io(this.url, this.opts); +}; + /** @private */ Insight.prototype.getSocket = function(url, opts) { - return io(this.url, this.opts); + + if (!this.socket) { + this.socket = this._getSocketIO(this.url, this.opts); + + // Emmit connection events + var self = this; + this.socket.on('connect', function() { + self.status = self.STATUS.CONNECTED; + self.subscribeToBlocks(); + self.emit('connect', 0); + }); + + this.socket.on('connect_error', function() { + if (self.status != self.STATUS.CONNECTED) return; + self.status = self.STATUS.DISCONNECTED; + self.emit('disconnect'); + }); + + this.socket.on('connect_timeout', function() { + if (self.status != self.STATUS.CONNECTED) return; + self.status = self.STATUS.DISCONNECTED; + self.emit('disconnect'); + }); + + this.socket.on('reconnect', function(attempt) { + if (self.status != self.STATUS.DISCONNECTED) return; + self.status = self.STATUS.CONNECTED; + self.emit('connect', attempt); + }); + } + return this.socket; } /** @private */ @@ -107,11 +116,15 @@ Insight.prototype.request = function(path, cb) { /** @private */ Insight.prototype.requestPost = function(path, data, cb) { preconditions.checkArgument(path).checkArgument(data).shouldBeFunction(cb); - request({method: "POST", url: this.url + path, json: data}, cb); + request({ + method: "POST", + url: this.url + path, + json: data + }, cb); } Insight.prototype.destroy = function() { - this.socket.destroy(); + this.getSocket().destroy(); this.subscribed = {}; this.status = this.STATUS.DESTROYED; this.removeAllListeners(); @@ -122,10 +135,13 @@ Insight.prototype.subscribe = function(addresses) { var self = this; function handlerFor(self, address) { - return function (txid) { + return function(txid) { // verify the address is still subscribed if (!self.subscribed[address]) return; - self.emit('tx', {address: address, txid: txid}); + self.emit('tx', { + address: address, + txid: txid + }); } } @@ -135,8 +151,8 @@ Insight.prototype.subscribe = function(addresses) { // skip already subscibed if (!self.subscribed[address]) { self.subscribed[address] = true; - self.socket.emit('subscribe', address); - self.socket.on(address, handlerFor(self, address)); + self.getSocket().emit('subscribe', address); + self.getSocket().on(address, handlerFor(self, address)); } }); }; @@ -151,7 +167,7 @@ Insight.prototype.unsubscribe = function(addresses) { addresses.forEach(function(address) { preconditions.checkArgument(new bitcore.Address(address).isValid()); - self.socket.removeEventListener(address); + self.getSocket().removeEventListener(address); delete self.subscribed[address]; }); }; @@ -164,7 +180,9 @@ Insight.prototype.broadcast = function(rawtx, cb) { preconditions.checkArgument(rawtx); preconditions.shouldBeFunction(cb); - this.requestPost('/api/tx/send', {rawtx: rawtx}, function(err, res, body) { + this.requestPost('/api/tx/send', { + rawtx: rawtx + }, function(err, res, body) { if (err || res.statusCode != 200) cb(err || res); cb(null, body.txid); }); @@ -218,7 +236,9 @@ Insight.prototype.getUnspent = function(addresses, cb) { preconditions.shouldBeArray(addresses); preconditions.shouldBeFunction(cb); - this.requestPost('/api/addrs/utxo', {addrs: addresses.join(',')}, function(err, res, body) { + this.requestPost('/api/addrs/utxo', { + addrs: addresses.join(',') + }, function(err, res, body) { if (err || res.statusCode != 200) return cb(err || res); cb(null, body); }); @@ -243,8 +263,8 @@ Insight.prototype.getActivity = function(addresses, cb) { var getOutputs = function(t) { return flatArray( t.vout.map(function(vout) { - return vout.scriptPubKey.addresses; - }) + return vout.scriptPubKey.addresses; + }) ); }; diff --git a/js/services/controllerUtils.js b/js/services/controllerUtils.js index a5ecf83d2..5a339a165 100644 --- a/js/services/controllerUtils.js +++ b/js/services/controllerUtils.js @@ -312,7 +312,7 @@ angular.module('copayApp.services') var allAddrs = $rootScope.addrInfos; var newAddrs = []; - for (var i in allAddrs) { + for:(var i in allAddrs) { var a = allAddrs[i]; if (!currentAddrs[a.addressStr] && !a.isChange) newAddrs.push(a.addressStr); diff --git a/test/test.blockchain.Insight.js b/test/test.blockchain.Insight.js index 7546ff315..46eecdc0e 100644 --- a/test/test.blockchain.Insight.js +++ b/test/test.blockchain.Insight.js @@ -48,13 +48,13 @@ var FAKE_OPTS = { describe('Insight model', function() { before(function() { - sinon.stub(Insight.prototype, "getSocket", function() { + sinon.stub(Insight.prototype, "_getSocketIO", function() { return new FakeSocket(); }); }); after(function() { - Insight.prototype.getSocket.restore(); + Insight.prototype._getSocketIO.restore(); }); it('should create an instance', function() { @@ -65,7 +65,8 @@ describe('Insight model', function() { it('should subscribe to inventory', function(done) { var blockchain = new Insight(FAKE_OPTS); - var emitSpy = sinon.spy(blockchain.socket, 'emit'); + var socket = blockchain.getSocket(); + var emitSpy = sinon.spy(socket, 'emit'); blockchain.on('connect', function() { emitSpy.calledWith('subscribe', 'inv'); done(); @@ -75,6 +76,7 @@ describe('Insight model', function() { it('should be able to destroy the instance', function(done) { var blockchain = new Insight(FAKE_OPTS); blockchain.status.should.be.equal('disconnected'); + var socket = blockchain.getSocket(); blockchain.on('connect', function() { blockchain.subscribe('mg7UbtKgMvWAixTNMbC8soyUnwFk1qxEuM'); blockchain.getSubscriptions().length.should.equal(1); @@ -87,7 +89,8 @@ describe('Insight model', function() { it('should subscribe to an address', function() { var blockchain = new Insight(FAKE_OPTS); - var emitSpy = sinon.spy(blockchain.socket, 'emit'); + var socket = blockchain.getSocket(); + var emitSpy = sinon.spy(socket, 'emit'); blockchain.subscribe('mg7UbtKgMvWAixTNMbC8soyUnwFk1qxEuM'); blockchain.getSubscriptions().length.should.equal(1); @@ -104,7 +107,8 @@ describe('Insight model', function() { it('should subscribe to a list of addresses', function() { var blockchain = new Insight(FAKE_OPTS); - var emitSpy = sinon.spy(blockchain.socket, 'emit'); + var socket = blockchain.getSocket(); + var emitSpy = sinon.spy(socket, 'emit'); blockchain.subscribe([ 'mg7UbtKgMvWAixTNMbC8soyUnwFk1qxEuM', @@ -354,8 +358,10 @@ describe('Insight model', function() { describe('Events', function() { it('should emmit event on a new block', function(done) { var blockchain = new Insight(FAKE_OPTS); + var socket = blockchain.getSocket(); blockchain.on('connect', function() { - blockchain.socket.emit('block', '12312312'); + var socket = blockchain.getSocket(); + socket.emit('block', '12312312'); }); blockchain.on('block', function(blockid) { @@ -364,11 +370,13 @@ describe('Insight model', function() { }); }); - it('should emmit event on a transaction for subscried addresses', function(done) { + it('should emmit event on a transaction for subscribed addresses', function(done) { var blockchain = new Insight(FAKE_OPTS); + var socket = blockchain.getSocket(); blockchain.subscribe('2NFjCBFZSsxiwWAD7CKQ3hzWFtf9DcqTucY'); blockchain.on('connect', function() { - blockchain.socket.emit('2NFjCBFZSsxiwWAD7CKQ3hzWFtf9DcqTucY', '1123'); + var socket = blockchain.getSocket(); + socket.emit('2NFjCBFZSsxiwWAD7CKQ3hzWFtf9DcqTucY', '1123'); }); blockchain.on('tx', function(ev) { @@ -380,8 +388,10 @@ describe('Insight model', function() { it('should\'t emmit event on a transaction for non subscribed addresses', function(done) { var blockchain = new Insight(FAKE_OPTS); + var socket = blockchain.getSocket(); blockchain.on('connect', function() { - blockchain.socket.emit('2NFjCBFZSsxiwWAD7CKQ3hzWFtf9DcqTucY', '1123'); + var socket = blockchain.getSocket(); + socket.emit('2NFjCBFZSsxiwWAD7CKQ3hzWFtf9DcqTucY', '1123'); setTimeout(function() { done(); }, 20); }); @@ -392,6 +402,7 @@ describe('Insight model', function() { it('should emmit event on connection', function(done) { var blockchain = new Insight(FAKE_OPTS); + var socket = blockchain.getSocket(); blockchain.on('connect', function() { done(); }); @@ -399,8 +410,10 @@ describe('Insight model', function() { it('should emmit event on disconnection', function(done) { var blockchain = new Insight(FAKE_OPTS); + var socket = blockchain.getSocket(); blockchain.on('connect', function() { - blockchain.socket.emit('connect_error'); + var socket = blockchain.getSocket(); + socket.emit('connect_error'); }); blockchain.on('disconnect', function() { done(); diff --git a/views/open.html b/views/open.html index f9222e99e..8cf125ff2 100644 --- a/views/open.html +++ b/views/open.html @@ -1,7 +1,7 @@
- Authenticating and looking for peers... + Connecting...