lazy connect
This commit is contained in:
parent
0917fcd7da
commit
c45495eeff
4 changed files with 91 additions and 58 deletions
|
|
@ -27,15 +27,15 @@ var preconditions = require('preconditions').singleton();
|
||||||
- disconnect: the connection with the blochckain is unavailable.
|
- disconnect: the connection with the blochckain is unavailable.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Insight = function (opts) {
|
var Insight = function(opts) {
|
||||||
this.status = this.STATUS.DISCONNECTED;
|
this.status = this.STATUS.DISCONNECTED;
|
||||||
this.subscribed = {};
|
this.subscribed = {};
|
||||||
this.listeningBlocks = false;
|
this.listeningBlocks = false;
|
||||||
|
|
||||||
preconditions.checkArgument(opts).shouldBeObject(opts)
|
preconditions.checkArgument(opts).shouldBeObject(opts)
|
||||||
.checkArgument(opts.host)
|
.checkArgument(opts.host)
|
||||||
.checkArgument(opts.port)
|
.checkArgument(opts.port)
|
||||||
.checkArgument(opts.schema);
|
.checkArgument(opts.schema);
|
||||||
|
|
||||||
this.url = opts.schema + '://' + opts.host + ':' + opts.port;
|
this.url = opts.schema + '://' + opts.host + ':' + opts.port;
|
||||||
this.opts = {
|
this.opts = {
|
||||||
|
|
@ -44,33 +44,6 @@ var Insight = function (opts) {
|
||||||
'secure': opts.schema === 'https'
|
'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);
|
util.inherits(Insight, EventEmitter);
|
||||||
|
|
@ -83,19 +56,55 @@ Insight.prototype.STATUS = {
|
||||||
|
|
||||||
/** @private */
|
/** @private */
|
||||||
Insight.prototype.subscribeToBlocks = function() {
|
Insight.prototype.subscribeToBlocks = function() {
|
||||||
if (this.listeningBlocks || !this.socket.connected) return;
|
var socket = this.getSocket();
|
||||||
|
if (this.listeningBlocks || ! socket.connected) return;
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
this.socket.emit('subscribe', 'inv');
|
socket.emit('subscribe', 'inv');
|
||||||
this.socket.on('block', function(blockHash) {
|
socket.on('block', function(blockHash) {
|
||||||
self.emit('block', blockHash);
|
self.emit('block', blockHash);
|
||||||
});
|
});
|
||||||
this.listeningBlocks = true;
|
this.listeningBlocks = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @private */
|
||||||
|
Insight.prototype._getSocketIO = function(url, opts) {
|
||||||
|
return io(this.url, this.opts);
|
||||||
|
};
|
||||||
|
|
||||||
/** @private */
|
/** @private */
|
||||||
Insight.prototype.getSocket = function(url, opts) {
|
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 */
|
/** @private */
|
||||||
|
|
@ -107,11 +116,15 @@ Insight.prototype.request = function(path, cb) {
|
||||||
/** @private */
|
/** @private */
|
||||||
Insight.prototype.requestPost = function(path, data, cb) {
|
Insight.prototype.requestPost = function(path, data, cb) {
|
||||||
preconditions.checkArgument(path).checkArgument(data).shouldBeFunction(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() {
|
Insight.prototype.destroy = function() {
|
||||||
this.socket.destroy();
|
this.getSocket().destroy();
|
||||||
this.subscribed = {};
|
this.subscribed = {};
|
||||||
this.status = this.STATUS.DESTROYED;
|
this.status = this.STATUS.DESTROYED;
|
||||||
this.removeAllListeners();
|
this.removeAllListeners();
|
||||||
|
|
@ -122,10 +135,13 @@ Insight.prototype.subscribe = function(addresses) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
function handlerFor(self, address) {
|
function handlerFor(self, address) {
|
||||||
return function (txid) {
|
return function(txid) {
|
||||||
// verify the address is still subscribed
|
// verify the address is still subscribed
|
||||||
if (!self.subscribed[address]) return;
|
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
|
// skip already subscibed
|
||||||
if (!self.subscribed[address]) {
|
if (!self.subscribed[address]) {
|
||||||
self.subscribed[address] = true;
|
self.subscribed[address] = true;
|
||||||
self.socket.emit('subscribe', address);
|
self.getSocket().emit('subscribe', address);
|
||||||
self.socket.on(address, handlerFor(self, address));
|
self.getSocket().on(address, handlerFor(self, address));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
@ -151,7 +167,7 @@ Insight.prototype.unsubscribe = function(addresses) {
|
||||||
|
|
||||||
addresses.forEach(function(address) {
|
addresses.forEach(function(address) {
|
||||||
preconditions.checkArgument(new bitcore.Address(address).isValid());
|
preconditions.checkArgument(new bitcore.Address(address).isValid());
|
||||||
self.socket.removeEventListener(address);
|
self.getSocket().removeEventListener(address);
|
||||||
delete self.subscribed[address];
|
delete self.subscribed[address];
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
@ -164,7 +180,9 @@ Insight.prototype.broadcast = function(rawtx, cb) {
|
||||||
preconditions.checkArgument(rawtx);
|
preconditions.checkArgument(rawtx);
|
||||||
preconditions.shouldBeFunction(cb);
|
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);
|
if (err || res.statusCode != 200) cb(err || res);
|
||||||
cb(null, body.txid);
|
cb(null, body.txid);
|
||||||
});
|
});
|
||||||
|
|
@ -218,7 +236,9 @@ Insight.prototype.getUnspent = function(addresses, cb) {
|
||||||
preconditions.shouldBeArray(addresses);
|
preconditions.shouldBeArray(addresses);
|
||||||
preconditions.shouldBeFunction(cb);
|
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);
|
if (err || res.statusCode != 200) return cb(err || res);
|
||||||
cb(null, body);
|
cb(null, body);
|
||||||
});
|
});
|
||||||
|
|
@ -243,8 +263,8 @@ Insight.prototype.getActivity = function(addresses, cb) {
|
||||||
var getOutputs = function(t) {
|
var getOutputs = function(t) {
|
||||||
return flatArray(
|
return flatArray(
|
||||||
t.vout.map(function(vout) {
|
t.vout.map(function(vout) {
|
||||||
return vout.scriptPubKey.addresses;
|
return vout.scriptPubKey.addresses;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -312,7 +312,7 @@ angular.module('copayApp.services')
|
||||||
var allAddrs = $rootScope.addrInfos;
|
var allAddrs = $rootScope.addrInfos;
|
||||||
|
|
||||||
var newAddrs = [];
|
var newAddrs = [];
|
||||||
for (var i in allAddrs) {
|
for:(var i in allAddrs) {
|
||||||
var a = allAddrs[i];
|
var a = allAddrs[i];
|
||||||
if (!currentAddrs[a.addressStr] && !a.isChange)
|
if (!currentAddrs[a.addressStr] && !a.isChange)
|
||||||
newAddrs.push(a.addressStr);
|
newAddrs.push(a.addressStr);
|
||||||
|
|
|
||||||
|
|
@ -48,13 +48,13 @@ var FAKE_OPTS = {
|
||||||
describe('Insight model', function() {
|
describe('Insight model', function() {
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
sinon.stub(Insight.prototype, "getSocket", function() {
|
sinon.stub(Insight.prototype, "_getSocketIO", function() {
|
||||||
return new FakeSocket();
|
return new FakeSocket();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
after(function() {
|
after(function() {
|
||||||
Insight.prototype.getSocket.restore();
|
Insight.prototype._getSocketIO.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create an instance', function() {
|
it('should create an instance', function() {
|
||||||
|
|
@ -65,7 +65,8 @@ describe('Insight model', function() {
|
||||||
|
|
||||||
it('should subscribe to inventory', function(done) {
|
it('should subscribe to inventory', function(done) {
|
||||||
var blockchain = new Insight(FAKE_OPTS);
|
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() {
|
blockchain.on('connect', function() {
|
||||||
emitSpy.calledWith('subscribe', 'inv');
|
emitSpy.calledWith('subscribe', 'inv');
|
||||||
done();
|
done();
|
||||||
|
|
@ -75,6 +76,7 @@ describe('Insight model', function() {
|
||||||
it('should be able to destroy the instance', function(done) {
|
it('should be able to destroy the instance', function(done) {
|
||||||
var blockchain = new Insight(FAKE_OPTS);
|
var blockchain = new Insight(FAKE_OPTS);
|
||||||
blockchain.status.should.be.equal('disconnected');
|
blockchain.status.should.be.equal('disconnected');
|
||||||
|
var socket = blockchain.getSocket();
|
||||||
blockchain.on('connect', function() {
|
blockchain.on('connect', function() {
|
||||||
blockchain.subscribe('mg7UbtKgMvWAixTNMbC8soyUnwFk1qxEuM');
|
blockchain.subscribe('mg7UbtKgMvWAixTNMbC8soyUnwFk1qxEuM');
|
||||||
blockchain.getSubscriptions().length.should.equal(1);
|
blockchain.getSubscriptions().length.should.equal(1);
|
||||||
|
|
@ -87,7 +89,8 @@ describe('Insight model', function() {
|
||||||
|
|
||||||
it('should subscribe to an address', function() {
|
it('should subscribe to an address', function() {
|
||||||
var blockchain = new Insight(FAKE_OPTS);
|
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.subscribe('mg7UbtKgMvWAixTNMbC8soyUnwFk1qxEuM');
|
||||||
blockchain.getSubscriptions().length.should.equal(1);
|
blockchain.getSubscriptions().length.should.equal(1);
|
||||||
|
|
@ -104,7 +107,8 @@ describe('Insight model', function() {
|
||||||
|
|
||||||
it('should subscribe to a list of addresses', function() {
|
it('should subscribe to a list of addresses', function() {
|
||||||
var blockchain = new Insight(FAKE_OPTS);
|
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([
|
blockchain.subscribe([
|
||||||
'mg7UbtKgMvWAixTNMbC8soyUnwFk1qxEuM',
|
'mg7UbtKgMvWAixTNMbC8soyUnwFk1qxEuM',
|
||||||
|
|
@ -354,8 +358,10 @@ describe('Insight model', function() {
|
||||||
describe('Events', function() {
|
describe('Events', function() {
|
||||||
it('should emmit event on a new block', function(done) {
|
it('should emmit event on a new block', function(done) {
|
||||||
var blockchain = new Insight(FAKE_OPTS);
|
var blockchain = new Insight(FAKE_OPTS);
|
||||||
|
var socket = blockchain.getSocket();
|
||||||
blockchain.on('connect', function() {
|
blockchain.on('connect', function() {
|
||||||
blockchain.socket.emit('block', '12312312');
|
var socket = blockchain.getSocket();
|
||||||
|
socket.emit('block', '12312312');
|
||||||
});
|
});
|
||||||
|
|
||||||
blockchain.on('block', function(blockid) {
|
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 blockchain = new Insight(FAKE_OPTS);
|
||||||
|
var socket = blockchain.getSocket();
|
||||||
blockchain.subscribe('2NFjCBFZSsxiwWAD7CKQ3hzWFtf9DcqTucY');
|
blockchain.subscribe('2NFjCBFZSsxiwWAD7CKQ3hzWFtf9DcqTucY');
|
||||||
blockchain.on('connect', function() {
|
blockchain.on('connect', function() {
|
||||||
blockchain.socket.emit('2NFjCBFZSsxiwWAD7CKQ3hzWFtf9DcqTucY', '1123');
|
var socket = blockchain.getSocket();
|
||||||
|
socket.emit('2NFjCBFZSsxiwWAD7CKQ3hzWFtf9DcqTucY', '1123');
|
||||||
});
|
});
|
||||||
|
|
||||||
blockchain.on('tx', function(ev) {
|
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) {
|
it('should\'t emmit event on a transaction for non subscribed addresses', function(done) {
|
||||||
var blockchain = new Insight(FAKE_OPTS);
|
var blockchain = new Insight(FAKE_OPTS);
|
||||||
|
var socket = blockchain.getSocket();
|
||||||
blockchain.on('connect', function() {
|
blockchain.on('connect', function() {
|
||||||
blockchain.socket.emit('2NFjCBFZSsxiwWAD7CKQ3hzWFtf9DcqTucY', '1123');
|
var socket = blockchain.getSocket();
|
||||||
|
socket.emit('2NFjCBFZSsxiwWAD7CKQ3hzWFtf9DcqTucY', '1123');
|
||||||
setTimeout(function() { done(); }, 20);
|
setTimeout(function() { done(); }, 20);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -392,6 +402,7 @@ describe('Insight model', function() {
|
||||||
|
|
||||||
it('should emmit event on connection', function(done) {
|
it('should emmit event on connection', function(done) {
|
||||||
var blockchain = new Insight(FAKE_OPTS);
|
var blockchain = new Insight(FAKE_OPTS);
|
||||||
|
var socket = blockchain.getSocket();
|
||||||
blockchain.on('connect', function() {
|
blockchain.on('connect', function() {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
@ -399,8 +410,10 @@ describe('Insight model', function() {
|
||||||
|
|
||||||
it('should emmit event on disconnection', function(done) {
|
it('should emmit event on disconnection', function(done) {
|
||||||
var blockchain = new Insight(FAKE_OPTS);
|
var blockchain = new Insight(FAKE_OPTS);
|
||||||
|
var socket = blockchain.getSocket();
|
||||||
blockchain.on('connect', function() {
|
blockchain.on('connect', function() {
|
||||||
blockchain.socket.emit('connect_error');
|
var socket = blockchain.getSocket();
|
||||||
|
socket.emit('connect_error');
|
||||||
});
|
});
|
||||||
blockchain.on('disconnect', function() {
|
blockchain.on('disconnect', function() {
|
||||||
done();
|
done();
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<div class="open" ng-controller="OpenController">
|
<div class="open" ng-controller="OpenController">
|
||||||
<div data-alert class="loading-screen" ng-show="loading && !failure">
|
<div data-alert class="loading-screen" ng-show="loading && !failure">
|
||||||
<i class="size-60 fi-bitcoin-circle icon-rotate spinner"></i>
|
<i class="size-60 fi-bitcoin-circle icon-rotate spinner"></i>
|
||||||
<span translate>Authenticating and looking for peers...</span>
|
<span translate>Connecting...</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="row" ng-show="!loading">
|
<div class="row" ng-show="!loading">
|
||||||
<div class="large-4 columns logo-setup">
|
<div class="large-4 columns logo-setup">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue