Merge pull request #41 from maraoz/feature/stream-new-txs
new transactions shown on homepage via socket.io
This commit is contained in:
commit
111e3d12ef
|
@ -91,18 +91,22 @@ TransactionSchema.statics.fromIdWithInfo = function(txid, cb) {
|
||||||
TransactionSchema.statics.createFromArray = function(txs, next) {
|
TransactionSchema.statics.createFromArray = function(txs, next) {
|
||||||
var that = this;
|
var that = this;
|
||||||
if (!txs) return next();
|
if (!txs) return next();
|
||||||
|
var mongo_txs = [];
|
||||||
async.forEach( txs,
|
async.forEach( txs,
|
||||||
function(tx, callback) {
|
function(tx, cb) {
|
||||||
that.create({ txid: tx }, function(err) {
|
that.create({ txid: tx }, function(err, new_tx) {
|
||||||
if (err && ! err.toString().match(/E11000/)) {
|
if (err) {
|
||||||
return callback(err);
|
if (err.toString().match(/E11000/)) {
|
||||||
|
return cb();
|
||||||
}
|
}
|
||||||
return callback();
|
return cb(err);
|
||||||
|
}
|
||||||
|
mongo_txs.push(new_tx);
|
||||||
|
return cb();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function(err) {
|
function(err) {
|
||||||
return next(err);
|
return next(err, mongo_txs);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,7 @@ script(type='text/javascript', src='/lib/angular-resource/angular-resource.js')
|
||||||
script(type='text/javascript', src='/lib/angular-route/angular-route.js')
|
script(type='text/javascript', src='/lib/angular-route/angular-route.js')
|
||||||
script(type='text/javascript', src='/lib/qrcode-generator/js/qrcode.js')
|
script(type='text/javascript', src='/lib/qrcode-generator/js/qrcode.js')
|
||||||
script(type='text/javascript', src='/lib/angular-qrcode/qrcode.js')
|
script(type='text/javascript', src='/lib/angular-qrcode/qrcode.js')
|
||||||
|
script(type='text/javascript', src='/lib/angular-animate/angular-animate.js')
|
||||||
|
|
||||||
//Angular UI
|
//Angular UI
|
||||||
script(type='text/javascript', src='/lib/angular-bootstrap/ui-bootstrap.js')
|
script(type='text/javascript', src='/lib/angular-bootstrap/ui-bootstrap.js')
|
||||||
|
|
|
@ -14,5 +14,4 @@ head
|
||||||
link(rel='stylesheet', href='/css/common.css')
|
link(rel='stylesheet', href='/css/common.css')
|
||||||
|
|
||||||
script(src='/socket.io/socket.io.js')
|
script(src='/socket.io/socket.io.js')
|
||||||
script(src='/lib/jquery/jquery.js')
|
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,19 @@
|
||||||
|
|
||||||
var Transaction = require('../../models/Transaction');
|
var Transaction = require('../../models/Transaction');
|
||||||
|
|
||||||
module.exports = function(app, io) {
|
// server-side socket behaviour
|
||||||
|
|
||||||
|
var io = null;
|
||||||
|
|
||||||
|
module.exports.init = function(app, io_ext) {
|
||||||
|
io = io_ext;
|
||||||
io.set('log level', 1); // reduce logging
|
io.set('log level', 1); // reduce logging
|
||||||
io.sockets.on('connection', function(socket) {
|
io.sockets.on('connection', function(socket) {
|
||||||
Transaction.findOne(function(err, tx) {
|
|
||||||
socket.emit('tx', tx);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.exports.broadcast_tx = function(tx) {
|
||||||
|
io.sockets.emit('tx', tx);
|
||||||
|
};
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
"bootstrap": "3.0.3",
|
"bootstrap": "3.0.3",
|
||||||
"angular-bootstrap": "0.9.0",
|
"angular-bootstrap": "0.9.0",
|
||||||
"angular-ui-utils": "0.1.0",
|
"angular-ui-utils": "0.1.0",
|
||||||
"angular-qrcode": "latest"
|
"angular-qrcode": "latest",
|
||||||
|
"angular-animate": "latest"
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
12
lib/Sync.js
12
lib/Sync.js
|
@ -13,6 +13,7 @@ function spec() {
|
||||||
var Block = require('../app/models/Block');
|
var Block = require('../app/models/Block');
|
||||||
var Transaction = require('../app/models/Transaction');
|
var Transaction = require('../app/models/Transaction');
|
||||||
var TransactionItem = require('../app/models/TransactionItem');
|
var TransactionItem = require('../app/models/TransactionItem');
|
||||||
|
var sockets = require('../app/views/sockets/main.js');
|
||||||
|
|
||||||
function Sync(config) {
|
function Sync(config) {
|
||||||
this.tx_count =0;
|
this.tx_count =0;
|
||||||
|
@ -61,11 +62,14 @@ function spec() {
|
||||||
|
|
||||||
Sync.prototype.storeTxs = function(txids, cb) {
|
Sync.prototype.storeTxs = function(txids, cb) {
|
||||||
var that=this;
|
var that=this;
|
||||||
Transaction.createFromArray(txids, function(err) {
|
Transaction.createFromArray(txids, function(err, inserted_txs) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
async.each(inserted_txs, function(new_tx, next) {
|
||||||
|
var txid = new_tx.txid;
|
||||||
|
|
||||||
async.each(txids, function(txid, next) {
|
if (that.opts.broadcast_txs) {
|
||||||
|
sockets.broadcast_tx(new_tx);
|
||||||
|
}
|
||||||
// This will trigger an RPC call
|
// This will trigger an RPC call
|
||||||
Transaction.explodeTransactionItems( txid, function(err) {
|
Transaction.explodeTransactionItems( txid, function(err) {
|
||||||
that.tx_count++;
|
that.tx_count++;
|
||||||
|
@ -205,7 +209,7 @@ function spec() {
|
||||||
if (!(opts && opts.skip_db_connection)) {
|
if (!(opts && opts.skip_db_connection)) {
|
||||||
mongoose.connect(config.db, {server: {auto_reconnect: true}} );
|
mongoose.connect(config.db, {server: {auto_reconnect: true}} );
|
||||||
}
|
}
|
||||||
|
this.opts = opts;
|
||||||
this.db = mongoose.connection;
|
this.db = mongoose.connection;
|
||||||
|
|
||||||
this.db.on('error', function(err) {
|
this.db.on('error', function(err) {
|
||||||
|
|
|
@ -49,3 +49,15 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
#search { width: 400px; }
|
#search { width: 400px; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*Animations*/
|
||||||
|
.fader.ng-enter {
|
||||||
|
transition: opacity 1s;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fader.ng-enter-active {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,20 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('mystery', ['ngCookies', 'ngResource', 'ngRoute', 'ui.bootstrap', 'ui.route', 'mystery.system', 'mystery.index', 'mystery.blocks', 'mystery.transactions', 'monospaced.qrcode', 'mystery.address', 'mystery.search']);
|
var app = angular.module('mystery',
|
||||||
|
['ngAnimate',
|
||||||
|
'ngCookies',
|
||||||
|
'ngResource',
|
||||||
|
'ngRoute',
|
||||||
|
'ui.bootstrap',
|
||||||
|
'ui.route',
|
||||||
|
'mystery.system',
|
||||||
|
'mystery.index',
|
||||||
|
'mystery.blocks',
|
||||||
|
'mystery.transactions',
|
||||||
|
'monospaced.qrcode',
|
||||||
|
'mystery.address',
|
||||||
|
'mystery.search'
|
||||||
|
]);
|
||||||
|
|
||||||
angular.module('mystery.system', []);
|
angular.module('mystery.system', []);
|
||||||
angular.module('mystery.index', []);
|
angular.module('mystery.index', []);
|
||||||
|
|
|
@ -1,16 +1,14 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('mystery.system').controller('IndexController', ['$scope', 'Global', 'Index', function($scope, Global, Index) {
|
angular.module('mystery.system').controller('IndexController', ['$scope', 'Global', 'socket', function($scope, Global, socket) {
|
||||||
$scope.global = Global;
|
$scope.global = Global;
|
||||||
$scope.index = Index;
|
|
||||||
}]);
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
|
||||||
var socket = io.connect('http://localhost');
|
|
||||||
socket.on('tx', function(data) {
|
socket.on('tx', function(data) {
|
||||||
var tx = data;
|
var tx = data;
|
||||||
console.log('Transaction received! ' + tx.txid);
|
console.log('Transaction received! ' + tx.txid);
|
||||||
|
$scope.txs.unshift(tx.txid);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
$scope.txs = [];
|
||||||
|
|
||||||
|
}]);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,26 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('mystery.index').factory('Index', ['$resource', function($resource) {
|
app.factory('socket', function($rootScope) {
|
||||||
return $resource;
|
var socket = io.connect();
|
||||||
}]);
|
return {
|
||||||
|
on: function(eventName, callback) {
|
||||||
|
socket.on(eventName, function() {
|
||||||
|
var args = arguments;
|
||||||
|
$rootScope.$apply(function() {
|
||||||
|
callback.apply(socket, args);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
emit: function(eventName, data, callback) {
|
||||||
|
socket.emit(eventName, data, function() {
|
||||||
|
var args = arguments;
|
||||||
|
$rootScope.$apply(function() {
|
||||||
|
if (callback) {
|
||||||
|
callback.apply(socket, args);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
<section data-ng-controller="IndexController" data-ng-init="last_blocks()">
|
<section data-ng-controller="IndexController" data-ng-init="">
|
||||||
<div class="jumbotron">
|
<div class="">
|
||||||
<h1>Hello, BitPay!</h1>
|
<h3>New transactions</h3>
|
||||||
<p>Start here for blocks information</p>
|
<div class="alert alert-info fader" ng-repeat='tx in txs'>
|
||||||
<p><a href="/#!/blocks" class="btn btn-primary btn-lg">List all blocks</a></p>
|
{{tx}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
10
server.js
10
server.js
|
@ -43,7 +43,8 @@ walk(models_path);
|
||||||
// p2p_sync process
|
// p2p_sync process
|
||||||
var ps = new PeerSync();
|
var ps = new PeerSync();
|
||||||
ps.init({
|
ps.init({
|
||||||
skip_db_connection: true
|
skip_db_connection: true,
|
||||||
|
broadcast_txs: true
|
||||||
});
|
});
|
||||||
ps.run();
|
ps.run();
|
||||||
|
|
||||||
|
@ -59,12 +60,13 @@ require('./config/routes')(app);
|
||||||
// socket.io
|
// socket.io
|
||||||
var server = require('http').createServer(app);
|
var server = require('http').createServer(app);
|
||||||
var io = require('socket.io').listen(server);
|
var io = require('socket.io').listen(server);
|
||||||
require('./app/views/sockets/main.js')(app,io);
|
require('./app/views/sockets/main.js').init(app,io);
|
||||||
|
|
||||||
//Start the app by listening on <port>
|
//Start the app by listening on <port>
|
||||||
var port = process.env.PORT || config.port;
|
var port = process.env.PORT || config.port;
|
||||||
server.listen(port);
|
server.listen(port, function(){
|
||||||
console.log('Express app started on port ' + port);
|
console.log('Express server listening on port %d in %s mode', server.address().port, process.env.NODE_ENV);
|
||||||
|
});
|
||||||
|
|
||||||
//expose app
|
//expose app
|
||||||
exports = module.exports = app;
|
exports = module.exports = app;
|
||||||
|
|
Loading…
Reference in New Issue