Merge pull request #150 from isocolsky/feat/ws
Implement notifications via web sockets
This commit is contained in:
commit
b57a6ad88e
9
app.js
9
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;
|
||||
|
@ -8,6 +9,12 @@ 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 ws = WsApp.start(server);
|
||||
|
||||
server.listen(port);
|
||||
|
||||
console.log('Bitcore Wallet Service running on port ' + port);
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
'use strict';
|
||||
|
||||
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(eventName, serviceInstance, args) {
|
||||
this.emit(eventName, serviceInstance, args);
|
||||
};
|
||||
|
||||
var _eventBroadcasterInstance;
|
||||
EventBroadcaster.singleton = function() {
|
||||
if (!_eventBroadcasterInstance) {
|
||||
_eventBroadcasterInstance = new EventBroadcaster();
|
||||
}
|
||||
return _eventBroadcasterInstance;
|
||||
};
|
||||
|
||||
module.exports = EventBroadcaster.singleton();
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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');
|
||||
|
@ -28,6 +26,7 @@ var Notification = require('./model/notification');
|
|||
var initialized = false;
|
||||
var storage, blockExplorer;
|
||||
|
||||
|
||||
/**
|
||||
* Creates an instance of the Bitcore Wallet Service.
|
||||
* @constructor
|
||||
|
@ -41,8 +40,9 @@ function WalletService() {
|
|||
this.notifyTicker = 0;
|
||||
};
|
||||
|
||||
nodeutil.inherits(WalletService, events.EventEmitter);
|
||||
|
||||
WalletService.onNotification = function(func) {
|
||||
EventBroadcaster.on('notification', func);
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes global settings for all instances.
|
||||
|
@ -161,6 +161,14 @@ WalletService.prototype._verifySignature = function(text, signature, pubKey) {
|
|||
return WalletUtils.verifyMessage(text, signature, pubKey);
|
||||
};
|
||||
|
||||
/**
|
||||
* _emit
|
||||
*
|
||||
* @param {Object} args
|
||||
*/
|
||||
WalletService.prototype._emit = function(eventName, args) {
|
||||
EventBroadcaster.broadcast(eventName, this, args);
|
||||
};
|
||||
|
||||
/**
|
||||
* _notify
|
||||
|
@ -180,9 +188,10 @@ WalletService.prototype._notify = function(type, data) {
|
|||
type: type,
|
||||
data: data,
|
||||
ticker: this.notifyTicker++,
|
||||
creatorId: self.copayerId,
|
||||
});
|
||||
this.storage.storeNotification(walletId, n, function() {
|
||||
self.emit(n);
|
||||
self._emit('notification', n);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
'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._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) {
|
||||
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) return WsApp.unauthorized();
|
||||
|
||||
WalletService.getInstanceWithAuth(data, function(err, res) {
|
||||
if (err) return WsApp.unauthorized();
|
||||
|
||||
socket.join(res.walletId);
|
||||
socket.emit('authorized');
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = WsApp;
|
10
package.json
10
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",
|
||||
|
@ -35,6 +35,7 @@
|
|||
"read": "^1.0.5",
|
||||
"request": "^2.53.0",
|
||||
"sjcl": "^1.0.2",
|
||||
"socket.io": "^1.3.5",
|
||||
"uuid": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -55,11 +56,8 @@
|
|||
"contributors": [{
|
||||
"name": "Ivan Socolsky",
|
||||
"email": "ivan@bitpay.com"
|
||||
},
|
||||
|
||||
{
|
||||
}, {
|
||||
"name": "Matias Alejo Garcia",
|
||||
"email": "ematiu@gmail.com"
|
||||
}
|
||||
]
|
||||
}]
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
@ -1945,7 +1949,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 +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();
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue