Route caching bug fix, simplify routing (#763)

* move window.apiPrefix into Angular service

* avoid routing by accept headers, integrate api service

* Revert "Fixed over-matching of index route."

This reverts commit 62e1225dd3.

* better name for index template file
This commit is contained in:
Jason Dreyzehner 2017-05-04 12:42:17 -04:00 committed by GitHub
parent cc7c6f81d4
commit 340decd978
19 changed files with 144 additions and 104 deletions

View File

@ -1,5 +1,7 @@
'use strict'; 'use strict';
// var config = require('insight-config.json');
module.exports = function(grunt) { module.exports = function(grunt) {
//Load NPM tasks //Load NPM tasks
@ -10,10 +12,27 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-markdown'); grunt.loadNpmTasks('grunt-markdown');
grunt.loadNpmTasks('grunt-macreload'); grunt.loadNpmTasks('grunt-macreload');
grunt.loadNpmTasks('grunt-angular-gettext'); grunt.loadNpmTasks('grunt-angular-gettext');
grunt.loadNpmTasks('grunt-replace');
// Project Configuration // Project Configuration
grunt.initConfig({ grunt.initConfig({
pkg: grunt.file.readJSON('package.json'), pkg: grunt.file.readJSON('package.json'),
replace: {
dist: {
options: {
patterns: [
{
match: 'INSIGHT_API_PREFIX',
replacement: '<%= pkg.insightConfig.apiPrefix %>'
}
],
usePrefix: false
},
files: [
{src: ['public/src/templates/api.js'], dest: 'public/src/js/services/api.js'}
]
}
},
concat: { concat: {
options: { options: {
process: function(src, filepath) { process: function(src, filepath) {
@ -117,13 +136,13 @@ module.exports = function(grunt) {
grunt.option('force', true); grunt.option('force', true);
//Default task(s). //Default task(s).
grunt.registerTask('default', ['watch']); grunt.registerTask('default', ['replace', 'watch']);
//Update .pot file //Update .pot file
grunt.registerTask('translate', ['nggettext_extract']); grunt.registerTask('translate', ['nggettext_extract']);
//Compile task (concat + minify) //Compile task (concat + minify)
grunt.registerTask('compile', ['nggettext_compile', 'concat', 'uglify', 'cssmin']); grunt.registerTask('compile', ['replace', 'nggettext_compile', 'concat', 'uglify', 'cssmin']);
}; };

View File

@ -23,24 +23,42 @@ Open a web browser to `http://localhost:3001/insight/`
## Development ## Development
To run Insight UI locally in development mode: To build Insight UI locally:
Install bower dependencies:
``` ```
$ bower install $ npm run build
``` ```
To compile and minify the web application's assets: A watch task is also available:
``` ```
$ grunt compile $ npm run watch
``` ```
There is a convenient Gruntfile.js for automation during editing the code ## Changing routePrefix and apiPrefix
By default, the `insightConfig` in `package.json` is:
```json
"insightConfig": {
"apiPrefix": "insight-api",
"routePrefix": "insight"
}
```
To change these routes, first make your changes to `package.json`, for example:
```json
"insightConfig": {
"apiPrefix": "api",
"routePrefix": ""
}
```
Then rebuild the `insight-ui` service:
``` ```
$ grunt $ npm run build
``` ```
## Multilanguage support ## Multilanguage support

View File

@ -3,19 +3,15 @@
var BaseService = require('./service'); var BaseService = require('./service');
var inherits = require('util').inherits; var inherits = require('util').inherits;
var fs = require('fs'); var fs = require('fs');
var pkg = require('../package');
var InsightUI = function(options) { var InsightUI = function(options) {
BaseService.call(this, options); BaseService.call(this, options);
if (typeof options.apiPrefix !== 'undefined') { // we don't use the options object for routePrefix and apiPrefix, since the
this.apiPrefix = options.apiPrefix; // client must be rebuilt with the proper options. A future version of
} else { // Bitcore should allow for a service "build" step to make this better.
this.apiPrefix = 'insight-api'; this.apiPrefix = pkg.insightConfig.apiPrefix;
} this.routePrefix = pkg.insightConfig.routePrefix;
if (typeof options.routePrefix !== 'undefined') {
this.routePrefix = options.routePrefix;
} else {
this.routePrefix = 'insight';
}
}; };
InsightUI.dependencies = ['insight-api']; InsightUI.dependencies = ['insight-api'];
@ -23,20 +19,8 @@ InsightUI.dependencies = ['insight-api'];
inherits(InsightUI, BaseService); inherits(InsightUI, BaseService);
InsightUI.prototype.start = function(callback) { InsightUI.prototype.start = function(callback) {
this.indexFile = this.filterIndexHTML(fs.readFileSync(__dirname + '/../public/index-template.html', {encoding: 'utf8'}));
var self = this; setImmediate(callback);
var indexFile = __dirname + '/../public/index.html';
fs.readFile(indexFile, { encoding: 'utf8' }, function(err, data) {
if(err) {
return callback(err);
}
self.indexFile = self.filterIndexHTML(data);
callback();
});
}; };
InsightUI.prototype.getRoutePrefix = function() { InsightUI.prototype.getRoutePrefix = function() {
@ -45,26 +29,19 @@ InsightUI.prototype.getRoutePrefix = function() {
InsightUI.prototype.setupRoutes = function(app, express) { InsightUI.prototype.setupRoutes = function(app, express) {
var self = this; var self = this;
app.use(express.static(__dirname + '/../public'));
app.use('/', function(req, res, next){ // if not in found, fall back to indexFile (404 is handled client-side)
app.use(function(req, res, next) {
if (req.url === '/') { res.setHeader('Content-Type', 'text/html');
res.send(self.indexFile); res.send(self.indexFile);
} else {
express.static(__dirname + '/../public')(req, res, next);
}
}); });
}; };
InsightUI.prototype.filterIndexHTML = function(data) { InsightUI.prototype.filterIndexHTML = function(data) {
var transformed = data var transformed = data;
.replace(/apiPrefix = '\/api'/, "apiPrefix = '/" + this.apiPrefix + "'"); if (this.routePrefix !== '') {
transformed = transformed.replace('<base href="/"', '<base href="/' + this.routePrefix + '/"');
if (this.routePrefix) {
transformed = transformed.replace(/<base href=\"\/\"/, '<base href="/' + this.routePrefix + '/"');
} }
return transformed; return transformed;
}; };

View File

@ -39,19 +39,27 @@
"front-end" "front-end"
], ],
"bitcoreNode": "bitcore-node", "bitcoreNode": "bitcore-node",
"dependencies": { "insightConfig": {
"apiPrefix": "insight-api",
"routePrefix": "insight"
}, },
"scripts": {
"build": "bower install && grunt compile",
"watch": "grunt"
},
"dependencies": {},
"devDependencies": { "devDependencies": {
"bower": "~1.2.8", "bower": "~1.8.0",
"grunt": "~0.4.2", "grunt": "~0.4.2",
"grunt-angular-gettext": "^0.2.15",
"grunt-cli": "~0.1.11", "grunt-cli": "~0.1.11",
"grunt-contrib-jshint": "~0.8.0",
"grunt-contrib-concat": "~0.3.0", "grunt-contrib-concat": "~0.3.0",
"grunt-contrib-jshint": "~0.8.0",
"grunt-contrib-uglify": "~0.3.2", "grunt-contrib-uglify": "~0.3.2",
"grunt-contrib-watch": "*", "grunt-contrib-watch": "*",
"grunt-macreload": "*",
"grunt-css": "~0.5.4", "grunt-css": "~0.5.4",
"grunt-macreload": "*",
"grunt-markdown": "~0.5.0", "grunt-markdown": "~0.5.0",
"grunt-angular-gettext": "^0.2.15" "grunt-replace": "^1.0.1"
} }
} }

View File

@ -8,7 +8,7 @@
<meta name="fragment" content="!"> <meta name="fragment" content="!">
<title data-ng-bind="$root.title + $root.titleDetail + ' | Insight'">Insight</title> <title data-ng-bind="$root.title + $root.titleDetail + ' | Insight'">Insight</title>
<meta name="keywords" content="bitcoins, transactions, blocks, address, block chain, best block, mining difficulty, hash serialized"> <meta name="keywords" content="bitcoins, transactions, blocks, address, block chain, best block, mining difficulty, hash serialized">
<meta name="description" content="Bitcoin Insight. View detailed information on all bitcoin transactions and block. {{ $root.title + $root.titleDetail }}"> <meta name="description" content="Bitcoin Insight. View detailed information on all bitcoin transactions and blocks.">
<link rel="shortcut icon" href="img/icons/favicon.ico" type="image/x-icon"> <link rel="shortcut icon" href="img/icons/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700,400italic"> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700,400italic">
<link rel="stylesheet" href="css/main.min.css"> <link rel="stylesheet" href="css/main.min.css">
@ -66,7 +66,6 @@
<a class="insight m10v pull-right" target="_blank" href="http://insight.is">insight <small>API v{{version}}</small></a> <a class="insight m10v pull-right" target="_blank" href="http://insight.is">insight <small>API v{{version}}</small></a>
</div> </div>
</div> </div>
<script language="javascript">window.apiPrefix = '/api';</script>
<script src="/socket.io/socket.io.js"></script> <script src="/socket.io/socket.io.js"></script>
<script src="js/vendors.min.js"></script> <script src="js/vendors.min.js"></script>
<script src="js/angularjs-all.min.js"></script> <script src="js/angularjs-all.min.js"></script>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -15,6 +15,7 @@ angular.module('insight',[
'angularMoment', 'angularMoment',
'insight.system', 'insight.system',
'insight.socket', 'insight.socket',
'insight.api',
'insight.blocks', 'insight.blocks',
'insight.transactions', 'insight.transactions',
'insight.address', 'insight.address',
@ -27,6 +28,7 @@ angular.module('insight',[
angular.module('insight.system', []); angular.module('insight.system', []);
angular.module('insight.socket', []); angular.module('insight.socket', []);
angular.module('insight.api', []);
angular.module('insight.blocks', []); angular.module('insight.blocks', []);
angular.module('insight.transactions', []); angular.module('insight.transactions', []);
angular.module('insight.address', []); angular.module('insight.address', []);

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
angular.module('insight.messages').controller('VerifyMessageController', angular.module('insight.messages').controller('VerifyMessageController',
function($scope, $http) { function($scope, $http, Api) {
$scope.message = { $scope.message = {
address: '', address: '',
signature: '', signature: '',
@ -22,7 +22,7 @@ angular.module('insight.messages').controller('VerifyMessageController',
$scope.verify = function() { $scope.verify = function() {
$scope.verification.status = 'loading'; $scope.verification.status = 'loading';
$scope.verification.address = $scope.message.address; $scope.verification.address = $scope.message.address;
$http.post(window.apiPrefix + '/messages/verify', $scope.message) $http.post(Api.apiPrefix + '/messages/verify', $scope.message)
.success(function(data, status, headers, config) { .success(function(data, status, headers, config) {
if(typeof(data.result) != 'boolean') { if(typeof(data.result) != 'boolean') {
// API returned 200 but result was not true or false // API returned 200 but result was not true or false

View File

@ -175,7 +175,7 @@ function($scope, $rootScope, $routeParams, $location, Global, Transaction, Trans
}); });
angular.module('insight.transactions').controller('SendRawTransactionController', angular.module('insight.transactions').controller('SendRawTransactionController',
function($scope, $http) { function($scope, $http, Api) {
$scope.transaction = ''; $scope.transaction = '';
$scope.status = 'ready'; // ready|loading|sent|error $scope.status = 'ready'; // ready|loading|sent|error
$scope.txid = ''; $scope.txid = '';
@ -189,7 +189,7 @@ angular.module('insight.transactions').controller('SendRawTransactionController'
rawtx: $scope.transaction rawtx: $scope.transaction
}; };
$scope.status = 'loading'; $scope.status = 'loading';
$http.post(window.apiPrefix + '/tx/send', postData) $http.post(Api.apiPrefix + '/tx/send', postData)
.success(function(data, status, headers, config) { .success(function(data, status, headers, config) {
if(typeof(data.txid) != 'string') { if(typeof(data.txid) != 'string') {
// API returned 200 but the format is not known // API returned 200 but the format is not known

View File

@ -1,8 +1,8 @@
'use strict'; 'use strict';
angular.module('insight.address').factory('Address', angular.module('insight.address').factory('Address',
function($resource) { function($resource, Api) {
return $resource(window.apiPrefix + '/addr/:addrStr/?noTxList=1', { return $resource(Api.apiPrefix + '/addr/:addrStr/?noTxList=1', {
addrStr: '@addStr' addrStr: '@addStr'
}, { }, {
get: { get: {

View File

@ -0,0 +1,9 @@
'use strict';
angular.module('insight.api')
.factory('Api',
function() {
return {
apiPrefix: '/insight-api'
}
});

View File

@ -2,8 +2,8 @@
angular.module('insight.blocks') angular.module('insight.blocks')
.factory('Block', .factory('Block',
function($resource) { function($resource, Api) {
return $resource(window.apiPrefix + '/block/:blockHash', { return $resource(Api.apiPrefix + '/block/:blockHash', {
blockHash: '@blockHash' blockHash: '@blockHash'
}, { }, {
get: { get: {
@ -22,10 +22,10 @@ angular.module('insight.blocks')
}); });
}) })
.factory('Blocks', .factory('Blocks',
function($resource) { function($resource, Api) {
return $resource(window.apiPrefix + '/blocks'); return $resource(Api.apiPrefix + '/blocks');
}) })
.factory('BlockByHeight', .factory('BlockByHeight',
function($resource) { function($resource, Api) {
return $resource(window.apiPrefix + '/block-index/:blockHeight'); return $resource(Api.apiPrefix + '/block-index/:blockHeight');
}); });

View File

@ -1,6 +1,6 @@
'use strict'; 'use strict';
angular.module('insight.currency').factory('Currency', angular.module('insight.currency').factory('Currency',
function($resource) { function($resource, Api) {
return $resource(window.apiPrefix + '/currency'); return $resource(Api.apiPrefix + '/currency');
}); });

View File

@ -7,6 +7,6 @@ angular.module('insight.system')
} }
]) ])
.factory('Version', .factory('Version',
function($resource) { function($resource, Api) {
return $resource(window.apiPrefix + '/version'); return $resource(Api.apiPrefix + '/version');
}); });

View File

@ -2,16 +2,16 @@
angular.module('insight.status') angular.module('insight.status')
.factory('Status', .factory('Status',
function($resource) { function($resource, Api) {
return $resource(window.apiPrefix + '/status', { return $resource(Api.apiPrefix + '/status', {
q: '@q' q: '@q'
}); });
}) })
.factory('Sync', .factory('Sync',
function($resource) { function($resource, Api) {
return $resource(window.apiPrefix + '/sync'); return $resource(Api.apiPrefix + '/sync');
}) })
.factory('PeerSync', .factory('PeerSync',
function($resource) { function($resource, Api) {
return $resource(window.apiPrefix + '/peer'); return $resource(Api.apiPrefix + '/peer');
}); });

View File

@ -2,8 +2,8 @@
angular.module('insight.transactions') angular.module('insight.transactions')
.factory('Transaction', .factory('Transaction',
function($resource) { function($resource, Api) {
return $resource(window.apiPrefix + '/tx/:txId', { return $resource(Api.apiPrefix + '/tx/:txId', {
txId: '@txId' txId: '@txId'
}, { }, {
get: { get: {
@ -22,18 +22,18 @@ angular.module('insight.transactions')
}); });
}) })
.factory('TransactionsByBlock', .factory('TransactionsByBlock',
function($resource) { function($resource, Api) {
return $resource(window.apiPrefix + '/txs', { return $resource(Api.apiPrefix + '/txs', {
block: '@block' block: '@block'
}); });
}) })
.factory('TransactionsByAddress', .factory('TransactionsByAddress',
function($resource) { function($resource, Api) {
return $resource(window.apiPrefix + '/txs', { return $resource(Api.apiPrefix + '/txs', {
address: '@address' address: '@address'
}); });
}) })
.factory('Transactions', .factory('Transactions',
function($resource) { function($resource, Api) {
return $resource(window.apiPrefix + '/txs'); return $resource(Api.apiPrefix + '/txs');
}); });

View File

@ -0,0 +1,9 @@
'use strict';
angular.module('insight.api')
.factory('Api',
function() {
return {
apiPrefix: '/INSIGHT_API_PREFIX'
}
});