Merge pull request #41 from maraoz/feature/stream-new-txs

new transactions shown on homepage via socket.io
This commit is contained in:
Manuel Aráoz 2014-01-14 12:53:46 -08:00
commit 111e3d12ef
12 changed files with 103 additions and 38 deletions

View File

@ -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 cb(err);
} }
return callback(); mongo_txs.push(new_tx);
return cb();
}); });
}, },
function(err) { function(err) {
return next(err); return next(err, mongo_txs);
} }
); );
}; };

View File

@ -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')

View File

@ -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')

View File

@ -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);
};

View File

@ -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"
} }
} }

View File

@ -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) {

View File

@ -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;
}

View File

@ -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', []);

View File

@ -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 = [];
}]);

View File

@ -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);
}
});
});
}
};
});

View File

@ -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>

View File

@ -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;