diff --git a/app/models/Transaction.js b/app/models/Transaction.js index 57d2fc29..5bd351e7 100644 --- a/app/models/Transaction.js +++ b/app/models/Transaction.js @@ -91,18 +91,22 @@ TransactionSchema.statics.fromIdWithInfo = function(txid, cb) { TransactionSchema.statics.createFromArray = function(txs, next) { var that = this; if (!txs) return next(); - + var mongo_txs = []; async.forEach( txs, - function(tx, callback) { - that.create({ txid: tx }, function(err) { - if (err && ! err.toString().match(/E11000/)) { - return callback(err); + function(tx, cb) { + that.create({ txid: tx }, function(err, new_tx) { + if (err) { + if (err.toString().match(/E11000/)) { + return cb(); + } + return cb(err); } - return callback(); + mongo_txs.push(new_tx); + return cb(); }); }, function(err) { - return next(err); + return next(err, mongo_txs); } ); }; diff --git a/app/views/includes/foot.jade b/app/views/includes/foot.jade index 52b6e0f1..0569542d 100755 --- a/app/views/includes/foot.jade +++ b/app/views/includes/foot.jade @@ -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/qrcode-generator/js/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 script(type='text/javascript', src='/lib/angular-bootstrap/ui-bootstrap.js') diff --git a/app/views/includes/head.jade b/app/views/includes/head.jade index cdec0aee..b33ff2be 100755 --- a/app/views/includes/head.jade +++ b/app/views/includes/head.jade @@ -14,5 +14,4 @@ head link(rel='stylesheet', href='/css/common.css') script(src='/socket.io/socket.io.js') - script(src='/lib/jquery/jquery.js') diff --git a/app/views/sockets/main.js b/app/views/sockets/main.js index b6d9db41..d4b0452b 100644 --- a/app/views/sockets/main.js +++ b/app/views/sockets/main.js @@ -2,12 +2,19 @@ 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.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); +}; diff --git a/bower.json b/bower.json index 60f6edbd..5b4d4998 100644 --- a/bower.json +++ b/bower.json @@ -10,6 +10,8 @@ "bootstrap": "3.0.3", "angular-bootstrap": "0.9.0", "angular-ui-utils": "0.1.0", - "angular-qrcode": "latest" + "angular-qrcode": "latest", + "angular-animate": "latest" + } } diff --git a/lib/Sync.js b/lib/Sync.js index 3e345b5a..a25fab2c 100644 --- a/lib/Sync.js +++ b/lib/Sync.js @@ -13,6 +13,7 @@ function spec() { var Block = require('../app/models/Block'); var Transaction = require('../app/models/Transaction'); var TransactionItem = require('../app/models/TransactionItem'); + var sockets = require('../app/views/sockets/main.js'); function Sync(config) { this.tx_count =0; @@ -61,11 +62,14 @@ function spec() { Sync.prototype.storeTxs = function(txids, cb) { var that=this; - Transaction.createFromArray(txids, function(err) { + Transaction.createFromArray(txids, function(err, inserted_txs) { 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 Transaction.explodeTransactionItems( txid, function(err) { that.tx_count++; @@ -205,7 +209,7 @@ function spec() { if (!(opts && opts.skip_db_connection)) { mongoose.connect(config.db, {server: {auto_reconnect: true}} ); } - + this.opts = opts; this.db = mongoose.connection; this.db.on('error', function(err) { diff --git a/public/css/common.css b/public/css/common.css index 73068675..80a60283 100644 --- a/public/css/common.css +++ b/public/css/common.css @@ -49,3 +49,15 @@ body { } #search { width: 400px; } + + + +/*Animations*/ +.fader.ng-enter { + transition: opacity 1s; + opacity: 0; +} + +.fader.ng-enter-active { + opacity: 1; +} diff --git a/public/js/app.js b/public/js/app.js index cea93635..c11c807e 100755 --- a/public/js/app.js +++ b/public/js/app.js @@ -1,6 +1,20 @@ '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.index', []); diff --git a/public/js/controllers/index.js b/public/js/controllers/index.js index 36811010..06d4b7d7 100755 --- a/public/js/controllers/index.js +++ b/public/js/controllers/index.js @@ -1,16 +1,14 @@ '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.index = Index; -}]); - -$(document).ready(function() { - var socket = io.connect('http://localhost'); socket.on('tx', function(data) { var tx = data; - console.log('Transaction received! '+tx.txid); + console.log('Transaction received! ' + tx.txid); + $scope.txs.unshift(tx.txid); }); -}); + $scope.txs = []; + +}]); diff --git a/public/js/services/index.js b/public/js/services/index.js index 08cb3ffa..bcea15c4 100644 --- a/public/js/services/index.js +++ b/public/js/services/index.js @@ -1,5 +1,26 @@ 'use strict'; -angular.module('mystery.index').factory('Index', ['$resource', function($resource) { - return $resource; -}]); +app.factory('socket', function($rootScope) { + 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); + } + }); + }); + } + }; +}); + diff --git a/public/views/index.html b/public/views/index.html index 469172a2..09d5d072 100644 --- a/public/views/index.html +++ b/public/views/index.html @@ -1,8 +1,9 @@ -
-
-

Hello, BitPay!

-

Start here for blocks information

-

List all blocks

+
+
+

New transactions

+
+ {{tx}} +
diff --git a/server.js b/server.js index ba879b4b..b7ded02d 100644 --- a/server.js +++ b/server.js @@ -43,7 +43,8 @@ walk(models_path); // p2p_sync process var ps = new PeerSync(); ps.init({ - skip_db_connection: true + skip_db_connection: true, + broadcast_txs: true }); ps.run(); @@ -59,12 +60,13 @@ require('./config/routes')(app); // socket.io var server = require('http').createServer(app); 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 var port = process.env.PORT || config.port; -server.listen(port); -console.log('Express app started on port ' + port); +server.listen(port, function(){ + console.log('Express server listening on port %d in %s mode', server.address().port, process.env.NODE_ENV); +}); //expose app exports = module.exports = app;