2018-03-07 22:01:04 +08:00
|
|
|
const cors = require('../middleware/cors');
|
|
|
|
const userMiddleware = require('../middleware/user');
|
|
|
|
const allowQueryParams = require('../middleware/allow-query-params');
|
|
|
|
const vectorError = require('../middleware/vector-error');
|
|
|
|
const DataviewBackend = require('../backends/dataview');
|
|
|
|
const AnalysisStatusBackend = require('../backends/analysis-status');
|
|
|
|
const MapStoreMapConfigProvider = require('../models/mapconfig/provider/map-store-provider');
|
|
|
|
const QueryTables = require('cartodb-query-tables');
|
2015-07-10 17:24:32 +08:00
|
|
|
|
|
|
|
/**
|
2018-03-07 21:54:09 +08:00
|
|
|
* @param {prepareContext} prepareContext
|
2015-09-16 22:18:26 +08:00
|
|
|
* @param {PgConnection} pgConnection
|
2015-07-10 17:24:32 +08:00
|
|
|
* @param {MapStore} mapStore
|
|
|
|
* @param {TileBackend} tileBackend
|
|
|
|
* @param {PreviewBackend} previewBackend
|
|
|
|
* @param {AttributesBackend} attributesBackend
|
2015-07-14 19:40:41 +08:00
|
|
|
* @param {SurrogateKeysCache} surrogateKeysCache
|
2015-07-14 17:55:49 +08:00
|
|
|
* @param {UserLimitsApi} userLimitsApi
|
2015-07-14 19:40:41 +08:00
|
|
|
* @param {LayergroupAffectedTables} layergroupAffectedTables
|
2016-04-14 23:09:07 +08:00
|
|
|
* @param {AnalysisBackend} analysisBackend
|
2015-07-10 17:24:32 +08:00
|
|
|
* @constructor
|
|
|
|
*/
|
2017-09-26 01:40:27 +08:00
|
|
|
function LayergroupController(prepareContext, pgConnection, mapStore, tileBackend, previewBackend, attributesBackend,
|
2016-05-27 01:32:58 +08:00
|
|
|
surrogateKeysCache, userLimitsApi, layergroupAffectedTables, analysisBackend) {
|
2016-02-22 18:40:25 +08:00
|
|
|
this.pgConnection = pgConnection;
|
2015-07-10 17:24:32 +08:00
|
|
|
this.mapStore = mapStore;
|
|
|
|
this.tileBackend = tileBackend;
|
|
|
|
this.previewBackend = previewBackend;
|
|
|
|
this.attributesBackend = attributesBackend;
|
2015-07-14 19:40:41 +08:00
|
|
|
this.surrogateKeysCache = surrogateKeysCache;
|
2015-07-11 01:10:55 +08:00
|
|
|
this.userLimitsApi = userLimitsApi;
|
2015-07-14 19:40:41 +08:00
|
|
|
this.layergroupAffectedTables = layergroupAffectedTables;
|
2016-03-19 00:22:02 +08:00
|
|
|
|
2016-04-14 23:09:07 +08:00
|
|
|
this.dataviewBackend = new DataviewBackend(analysisBackend);
|
2016-04-14 19:25:56 +08:00
|
|
|
this.analysisStatusBackend = new AnalysisStatusBackend();
|
2017-09-21 19:37:32 +08:00
|
|
|
|
2017-09-26 01:40:27 +08:00
|
|
|
this.prepareContext = prepareContext;
|
2015-07-10 17:24:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = LayergroupController;
|
|
|
|
|
2017-10-05 18:12:21 +08:00
|
|
|
LayergroupController.prototype.register = function(app) {
|
2018-03-07 19:05:53 +08:00
|
|
|
const { base_url_mapconfig: basePath } = app;
|
|
|
|
|
2017-10-05 18:12:21 +08:00
|
|
|
app.get(
|
2018-03-07 19:05:53 +08:00
|
|
|
`${basePath}/:token/:z/:x/:y@:scale_factor?x.:format`,
|
2017-09-22 04:53:31 +08:00
|
|
|
cors(),
|
2017-10-05 18:12:21 +08:00
|
|
|
userMiddleware,
|
2017-09-22 23:56:47 +08:00
|
|
|
this.prepareContext,
|
2018-03-06 23:19:53 +08:00
|
|
|
this.getMapStoreMapConfigProvider(this.mapStore, this.userLimitsApi),
|
|
|
|
this.tile(this.tileBackend),
|
2018-03-07 01:28:40 +08:00
|
|
|
this.setCacheControlHeader(),
|
|
|
|
this.setLastModifiedHeader(),
|
2018-03-07 03:01:43 +08:00
|
|
|
this.getAffectedTables(this.layergroupAffectedTables, this.pgConnection),
|
|
|
|
this.setCacheChannelHeader(),
|
|
|
|
this.setSurrogateKeyHeader(this.surrogateKeysCache),
|
2018-03-07 21:42:21 +08:00
|
|
|
this.incrementSuccessMetrics(global.statsClient),
|
2018-03-07 01:28:40 +08:00
|
|
|
this.sendResponse(),
|
2018-03-07 21:42:21 +08:00
|
|
|
this.incrementErrorMetrics(global.statsClient),
|
2018-03-06 23:44:37 +08:00
|
|
|
this.tileError(),
|
2017-11-07 18:07:38 +08:00
|
|
|
vectorError()
|
2017-09-22 04:53:31 +08:00
|
|
|
);
|
2015-09-30 23:17:01 +08:00
|
|
|
|
2017-10-05 18:12:21 +08:00
|
|
|
app.get(
|
2018-03-07 19:05:53 +08:00
|
|
|
`${basePath}/:token/:z/:x/:y.:format`,
|
2017-10-05 18:12:21 +08:00
|
|
|
cors(),
|
|
|
|
userMiddleware,
|
2017-09-22 23:56:47 +08:00
|
|
|
this.prepareContext,
|
2018-03-06 23:19:53 +08:00
|
|
|
this.getMapStoreMapConfigProvider(this.mapStore, this.userLimitsApi),
|
|
|
|
this.tile(this.tileBackend),
|
2018-03-07 01:28:40 +08:00
|
|
|
this.setCacheControlHeader(),
|
|
|
|
this.setLastModifiedHeader(),
|
2018-03-07 03:01:43 +08:00
|
|
|
this.getAffectedTables(this.layergroupAffectedTables, this.pgConnection),
|
|
|
|
this.setCacheChannelHeader(),
|
|
|
|
this.setSurrogateKeyHeader(this.surrogateKeysCache),
|
2018-03-07 21:42:21 +08:00
|
|
|
this.incrementSuccessMetrics(global.statsClient),
|
2018-03-07 01:28:40 +08:00
|
|
|
this.sendResponse(),
|
2018-03-07 21:42:21 +08:00
|
|
|
this.incrementErrorMetrics(global.statsClient),
|
2018-03-06 23:44:37 +08:00
|
|
|
this.tileError(),
|
2017-11-07 18:07:38 +08:00
|
|
|
vectorError()
|
2017-09-22 04:53:31 +08:00
|
|
|
);
|
2015-09-30 23:17:01 +08:00
|
|
|
|
2017-10-05 18:12:21 +08:00
|
|
|
app.get(
|
2018-03-07 19:05:53 +08:00
|
|
|
`${basePath}/:token/:layer/:z/:x/:y.(:format)`,
|
2017-10-05 18:12:21 +08:00
|
|
|
cors(),
|
|
|
|
userMiddleware,
|
2018-03-07 21:48:21 +08:00
|
|
|
validateLayerRoute(),
|
2017-09-22 23:56:47 +08:00
|
|
|
this.prepareContext,
|
2018-03-06 23:19:53 +08:00
|
|
|
this.getMapStoreMapConfigProvider(this.mapStore, this.userLimitsApi),
|
|
|
|
this.layer(this.tileBackend),
|
2018-03-07 01:28:40 +08:00
|
|
|
this.setCacheControlHeader(),
|
|
|
|
this.setLastModifiedHeader(),
|
2018-03-07 03:01:43 +08:00
|
|
|
this.getAffectedTables(this.layergroupAffectedTables, this.pgConnection),
|
|
|
|
this.setCacheChannelHeader(),
|
|
|
|
this.setSurrogateKeyHeader(this.surrogateKeysCache),
|
2018-03-07 21:42:21 +08:00
|
|
|
this.incrementSuccessMetrics(global.statsClient),
|
2018-03-07 01:28:40 +08:00
|
|
|
this.sendResponse(),
|
2018-03-07 21:42:21 +08:00
|
|
|
this.incrementErrorMetrics(global.statsClient),
|
2018-03-06 23:44:37 +08:00
|
|
|
this.tileError(),
|
2017-11-07 18:07:38 +08:00
|
|
|
vectorError()
|
2017-09-22 04:53:31 +08:00
|
|
|
);
|
2015-09-30 23:17:01 +08:00
|
|
|
|
2017-10-05 18:12:21 +08:00
|
|
|
app.get(
|
2018-03-07 19:05:53 +08:00
|
|
|
`${basePath}/:token/:layer/attributes/:fid`,
|
2017-10-05 18:12:21 +08:00
|
|
|
cors(),
|
|
|
|
userMiddleware,
|
2017-09-22 23:56:47 +08:00
|
|
|
this.prepareContext,
|
2018-03-06 01:28:52 +08:00
|
|
|
this.getMapStoreMapConfigProvider(this.mapStore, this.userLimitsApi),
|
2018-03-07 01:28:40 +08:00
|
|
|
this.attributes(this.attributesBackend),
|
|
|
|
this.setCacheControlHeader(),
|
|
|
|
this.setLastModifiedHeader(),
|
2018-03-07 03:01:43 +08:00
|
|
|
this.getAffectedTables(this.layergroupAffectedTables, this.pgConnection),
|
|
|
|
this.setCacheChannelHeader(),
|
|
|
|
this.setSurrogateKeyHeader(this.surrogateKeysCache),
|
2018-03-07 01:28:40 +08:00
|
|
|
this.sendResponse()
|
2017-09-22 04:47:08 +08:00
|
|
|
);
|
2015-09-30 23:17:01 +08:00
|
|
|
|
2018-03-06 19:44:17 +08:00
|
|
|
const forcedFormat = 'png';
|
|
|
|
|
2017-10-05 18:12:21 +08:00
|
|
|
app.get(
|
2018-03-07 19:05:53 +08:00
|
|
|
`${basePath}/static/center/:token/:z/:lat/:lng/:width/:height.:format`,
|
2017-10-05 18:12:21 +08:00
|
|
|
cors(),
|
|
|
|
userMiddleware,
|
2017-09-22 04:43:59 +08:00
|
|
|
allowQueryParams(['layer']),
|
2017-09-22 23:56:47 +08:00
|
|
|
this.prepareContext,
|
2018-03-06 19:44:17 +08:00
|
|
|
this.getMapStoreMapConfigProvider(this.mapStore, this.userLimitsApi, forcedFormat),
|
2018-03-07 01:28:40 +08:00
|
|
|
this.center(this.previewBackend),
|
|
|
|
this.setCacheControlHeader(),
|
|
|
|
this.setLastModifiedHeader(),
|
2018-03-07 03:01:43 +08:00
|
|
|
this.getAffectedTables(this.layergroupAffectedTables, this.pgConnection),
|
|
|
|
this.setCacheChannelHeader(),
|
|
|
|
this.setSurrogateKeyHeader(this.surrogateKeysCache),
|
2018-03-07 01:28:40 +08:00
|
|
|
this.sendResponse()
|
2017-09-22 04:43:59 +08:00
|
|
|
);
|
2015-09-30 23:17:01 +08:00
|
|
|
|
2017-10-05 18:12:21 +08:00
|
|
|
app.get(
|
2018-03-07 19:05:53 +08:00
|
|
|
`${basePath}/static/bbox/:token/:west,:south,:east,:north/:width/:height.:format`,
|
2017-10-05 18:12:21 +08:00
|
|
|
cors(),
|
|
|
|
userMiddleware,
|
2017-09-22 04:43:59 +08:00
|
|
|
allowQueryParams(['layer']),
|
2017-09-22 23:56:47 +08:00
|
|
|
this.prepareContext,
|
2018-03-06 19:44:17 +08:00
|
|
|
this.getMapStoreMapConfigProvider(this.mapStore, this.userLimitsApi, forcedFormat),
|
2018-03-07 01:28:40 +08:00
|
|
|
this.bbox(this.previewBackend),
|
|
|
|
this.setCacheControlHeader(),
|
|
|
|
this.setLastModifiedHeader(),
|
2018-03-07 03:01:43 +08:00
|
|
|
this.getAffectedTables(this.layergroupAffectedTables, this.pgConnection),
|
|
|
|
this.setCacheChannelHeader(),
|
|
|
|
this.setSurrogateKeyHeader(this.surrogateKeysCache),
|
2018-03-07 01:28:40 +08:00
|
|
|
this.sendResponse()
|
2017-09-22 04:43:59 +08:00
|
|
|
);
|
2015-10-07 01:47:44 +08:00
|
|
|
|
2016-01-16 00:02:09 +08:00
|
|
|
// Undocumented/non-supported API endpoint methods.
|
|
|
|
// Use at your own peril.
|
2016-03-23 19:14:17 +08:00
|
|
|
|
2018-03-07 19:09:41 +08:00
|
|
|
const allowedDataviewQueryParams = [
|
2017-06-09 01:22:33 +08:00
|
|
|
'filters', // json
|
|
|
|
'own_filter', // 0, 1
|
2017-12-12 18:54:09 +08:00
|
|
|
'no_filters', // 0, 1
|
2017-06-09 01:22:33 +08:00
|
|
|
'bbox', // w,s,e,n
|
|
|
|
'start', // number
|
|
|
|
'end', // number
|
|
|
|
'column_type', // string
|
|
|
|
'bins', // number
|
|
|
|
'aggregation', //string
|
2017-07-15 00:30:36 +08:00
|
|
|
'offset', // number
|
2017-11-07 23:14:47 +08:00
|
|
|
'q', // widgets search
|
|
|
|
'categories', // number
|
2017-06-09 01:22:33 +08:00
|
|
|
];
|
|
|
|
|
2017-10-05 18:12:21 +08:00
|
|
|
app.get(
|
2018-03-07 19:05:53 +08:00
|
|
|
`${basePath}/:token/dataview/:dataviewName`,
|
2017-10-05 18:12:21 +08:00
|
|
|
cors(),
|
|
|
|
userMiddleware,
|
2017-06-09 01:22:33 +08:00
|
|
|
allowQueryParams(allowedDataviewQueryParams),
|
2017-09-22 23:56:47 +08:00
|
|
|
this.prepareContext,
|
2018-03-06 00:44:04 +08:00
|
|
|
this.getMapStoreMapConfigProvider(this.mapStore, this.userLimitsApi),
|
2018-03-07 01:28:40 +08:00
|
|
|
this.getDataview(this.dataviewBackend),
|
|
|
|
this.setCacheControlHeader(),
|
|
|
|
this.setLastModifiedHeader(),
|
2018-03-07 03:01:43 +08:00
|
|
|
this.getAffectedTables(this.layergroupAffectedTables, this.pgConnection),
|
|
|
|
this.setCacheChannelHeader(),
|
|
|
|
this.setSurrogateKeyHeader(this.surrogateKeysCache),
|
2018-03-07 01:28:40 +08:00
|
|
|
this.sendResponse()
|
2017-06-09 01:22:33 +08:00
|
|
|
);
|
|
|
|
|
2017-10-05 18:12:21 +08:00
|
|
|
app.get(
|
2018-03-07 19:05:53 +08:00
|
|
|
`${basePath}/:token/:layer/widget/:dataviewName`,
|
2017-10-05 18:12:21 +08:00
|
|
|
cors(),
|
|
|
|
userMiddleware,
|
2017-06-09 01:22:33 +08:00
|
|
|
allowQueryParams(allowedDataviewQueryParams),
|
2017-09-22 23:56:47 +08:00
|
|
|
this.prepareContext,
|
2018-03-06 00:44:04 +08:00
|
|
|
this.getMapStoreMapConfigProvider(this.mapStore, this.userLimitsApi),
|
2018-03-07 01:28:40 +08:00
|
|
|
this.getDataview(this.dataviewBackend),
|
|
|
|
this.setCacheControlHeader(),
|
|
|
|
this.setLastModifiedHeader(),
|
2018-03-07 03:01:43 +08:00
|
|
|
this.getAffectedTables(this.layergroupAffectedTables, this.pgConnection),
|
|
|
|
this.setCacheChannelHeader(),
|
|
|
|
this.setSurrogateKeyHeader(this.surrogateKeysCache),
|
2018-03-07 01:28:40 +08:00
|
|
|
this.sendResponse()
|
2017-06-09 01:22:33 +08:00
|
|
|
);
|
|
|
|
|
2017-10-05 18:12:21 +08:00
|
|
|
app.get(
|
2018-03-07 19:05:53 +08:00
|
|
|
`${basePath}/:token/dataview/:dataviewName/search`,
|
2017-10-05 18:12:21 +08:00
|
|
|
cors(),
|
|
|
|
userMiddleware,
|
2017-06-09 01:22:33 +08:00
|
|
|
allowQueryParams(allowedDataviewQueryParams),
|
2017-09-22 23:56:47 +08:00
|
|
|
this.prepareContext,
|
2018-03-06 01:05:42 +08:00
|
|
|
this.getMapStoreMapConfigProvider(this.mapStore, this.userLimitsApi),
|
2018-03-07 01:28:40 +08:00
|
|
|
this.dataviewSearch(this.dataviewBackend),
|
|
|
|
this.setCacheControlHeader(),
|
|
|
|
this.setLastModifiedHeader(),
|
2018-03-07 03:01:43 +08:00
|
|
|
this.getAffectedTables(this.layergroupAffectedTables, this.pgConnection),
|
|
|
|
this.setCacheChannelHeader(),
|
|
|
|
this.setSurrogateKeyHeader(this.surrogateKeysCache),
|
2018-03-07 01:28:40 +08:00
|
|
|
this.sendResponse()
|
2017-06-09 01:22:33 +08:00
|
|
|
);
|
|
|
|
|
2017-10-05 18:12:21 +08:00
|
|
|
app.get(
|
2018-03-07 19:05:53 +08:00
|
|
|
`${basePath}/:token/:layer/widget/:dataviewName/search`,
|
2017-10-05 18:12:21 +08:00
|
|
|
cors(),
|
|
|
|
userMiddleware,
|
2017-06-09 01:22:33 +08:00
|
|
|
allowQueryParams(allowedDataviewQueryParams),
|
2017-09-22 23:56:47 +08:00
|
|
|
this.prepareContext,
|
2018-03-06 01:05:42 +08:00
|
|
|
this.getMapStoreMapConfigProvider(this.mapStore, this.userLimitsApi),
|
2018-03-07 01:28:40 +08:00
|
|
|
this.dataviewSearch(this.dataviewBackend),
|
|
|
|
this.setCacheControlHeader(),
|
|
|
|
this.setLastModifiedHeader(),
|
2018-03-07 03:01:43 +08:00
|
|
|
this.getAffectedTables(this.layergroupAffectedTables, this.pgConnection),
|
|
|
|
this.setCacheChannelHeader(),
|
|
|
|
this.setSurrogateKeyHeader(this.surrogateKeysCache),
|
2018-03-07 01:28:40 +08:00
|
|
|
this.sendResponse()
|
2017-06-09 01:22:33 +08:00
|
|
|
);
|
2016-04-12 00:49:56 +08:00
|
|
|
|
2017-10-05 18:12:21 +08:00
|
|
|
app.get(
|
2018-03-07 19:05:53 +08:00
|
|
|
`${basePath}/:token/analysis/node/:nodeId`,
|
2017-10-05 18:12:21 +08:00
|
|
|
cors(),
|
|
|
|
userMiddleware,
|
2017-09-22 23:56:47 +08:00
|
|
|
this.prepareContext,
|
2018-03-07 01:28:40 +08:00
|
|
|
this.analysisNodeStatus(this.analysisStatusBackend),
|
|
|
|
this.sendResponse()
|
2017-09-21 19:37:32 +08:00
|
|
|
);
|
2016-04-12 00:49:56 +08:00
|
|
|
};
|
|
|
|
|
2018-03-07 21:48:21 +08:00
|
|
|
function validateLayerRoute () {
|
|
|
|
return function validateLayerRouteMiddleware(req, res, next) {
|
|
|
|
if (req.params.token === 'static') {
|
|
|
|
return next('route');
|
|
|
|
}
|
2018-03-06 23:21:46 +08:00
|
|
|
|
2018-03-07 21:48:21 +08:00
|
|
|
next();
|
|
|
|
};
|
2018-03-06 23:21:46 +08:00
|
|
|
}
|
|
|
|
|
2018-03-06 01:13:19 +08:00
|
|
|
LayergroupController.prototype.analysisNodeStatus = function (analysisStatusBackend) {
|
|
|
|
return function analysisNodeStatusMiddleware(req, res, next) {
|
2018-03-07 19:46:18 +08:00
|
|
|
analysisStatusBackend.getNodeStatus(res.locals, (err, nodeStatus, stats = {}) => {
|
|
|
|
req.profiler.add(stats);
|
2016-04-14 16:59:51 +08:00
|
|
|
|
|
|
|
if (err) {
|
2017-09-21 17:46:31 +08:00
|
|
|
err.label = 'GET NODE STATUS';
|
2018-03-06 01:13:19 +08:00
|
|
|
return next(err);
|
2016-04-14 16:59:51 +08:00
|
|
|
}
|
2018-03-06 01:13:19 +08:00
|
|
|
|
2018-03-07 01:28:40 +08:00
|
|
|
res.set({
|
2018-03-06 01:13:19 +08:00
|
|
|
'Cache-Control': 'public,max-age=5',
|
|
|
|
'Last-Modified': new Date().toUTCString()
|
|
|
|
});
|
2018-03-07 01:28:40 +08:00
|
|
|
|
|
|
|
res.body = nodeStatus;
|
|
|
|
|
|
|
|
next();
|
2018-03-06 01:13:19 +08:00
|
|
|
});
|
2018-03-07 03:05:55 +08:00
|
|
|
};
|
2016-03-19 00:22:02 +08:00
|
|
|
};
|
|
|
|
|
2018-03-06 19:44:17 +08:00
|
|
|
function getRequestParams(locals) {
|
|
|
|
const params = Object.assign({}, locals);
|
|
|
|
|
|
|
|
delete params.mapConfigProvider;
|
|
|
|
delete params.allowedQueryParams;
|
|
|
|
|
|
|
|
return params;
|
|
|
|
}
|
|
|
|
|
|
|
|
LayergroupController.prototype.getMapStoreMapConfigProvider = function (mapStore, userLimitsApi, forcedFormat = null) {
|
2018-03-06 00:44:04 +08:00
|
|
|
return function getMapStoreMapConfigProviderMiddleware (req, res, next) {
|
|
|
|
const { user } = res.locals;
|
2016-03-19 00:22:02 +08:00
|
|
|
|
2018-03-06 19:44:17 +08:00
|
|
|
const params = getRequestParams(res.locals);
|
|
|
|
|
|
|
|
if (forcedFormat) {
|
|
|
|
params.format = forcedFormat;
|
|
|
|
params.layer = params.layer || 'all';
|
|
|
|
}
|
|
|
|
|
2018-03-07 03:01:43 +08:00
|
|
|
const mapConfigProvider = new MapStoreMapConfigProvider(mapStore, user, userLimitsApi, params);
|
2018-03-06 00:44:04 +08:00
|
|
|
|
2018-03-07 03:01:43 +08:00
|
|
|
mapConfigProvider.getMapConfig((err, mapconfig) => {
|
|
|
|
if (err) {
|
|
|
|
return next(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
res.locals.mapConfigProvider = mapConfigProvider;
|
|
|
|
res.locals.mapconfig = mapconfig;
|
|
|
|
|
|
|
|
next();
|
|
|
|
});
|
2018-03-06 00:44:04 +08:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2018-03-06 01:04:50 +08:00
|
|
|
LayergroupController.prototype.getDataview = function (dataviewBackend) {
|
2018-03-06 00:44:04 +08:00
|
|
|
return function getDataviewMiddleware (req, res, next) {
|
|
|
|
const { user, mapConfigProvider } = res.locals;
|
2018-03-07 19:52:44 +08:00
|
|
|
const params = getRequestParams(res.locals);
|
2018-03-06 00:44:04 +08:00
|
|
|
|
2018-03-07 19:52:44 +08:00
|
|
|
dataviewBackend.getDataview(mapConfigProvider, user, params, (err, dataview, stats = {}) => {
|
2018-03-07 19:46:18 +08:00
|
|
|
req.profiler.add(stats);
|
2016-03-19 00:22:02 +08:00
|
|
|
|
|
|
|
if (err) {
|
2017-09-21 17:46:31 +08:00
|
|
|
err.label = 'GET DATAVIEW';
|
2018-03-06 00:44:04 +08:00
|
|
|
return next(err);
|
2016-03-23 19:14:17 +08:00
|
|
|
}
|
2018-03-06 00:44:04 +08:00
|
|
|
|
2018-03-07 01:28:40 +08:00
|
|
|
res.body = dataview;
|
|
|
|
|
|
|
|
next();
|
2018-03-06 00:44:04 +08:00
|
|
|
});
|
2018-03-07 03:05:55 +08:00
|
|
|
};
|
2016-03-23 19:14:17 +08:00
|
|
|
};
|
|
|
|
|
2018-03-06 01:05:42 +08:00
|
|
|
LayergroupController.prototype.dataviewSearch = function (dataviewBackend) {
|
2018-03-07 22:05:36 +08:00
|
|
|
return function dataviewSearchMiddleware (req, res, next) {
|
2018-03-06 01:05:42 +08:00
|
|
|
const { user, dataviewName, mapConfigProvider } = res.locals;
|
2018-03-07 19:52:44 +08:00
|
|
|
const params = getRequestParams(res.locals);
|
2016-03-23 19:14:17 +08:00
|
|
|
|
2018-03-07 19:52:44 +08:00
|
|
|
dataviewBackend.search(mapConfigProvider, user, dataviewName, params, (err, searchResult, stats = {}) => {
|
2018-03-07 19:46:18 +08:00
|
|
|
req.profiler.add(stats);
|
2016-03-23 19:14:17 +08:00
|
|
|
|
|
|
|
if (err) {
|
2017-09-21 17:46:31 +08:00
|
|
|
err.label = 'GET DATAVIEW SEARCH';
|
2018-03-06 01:05:42 +08:00
|
|
|
return next(err);
|
2016-03-19 00:22:02 +08:00
|
|
|
}
|
|
|
|
|
2018-03-07 01:28:40 +08:00
|
|
|
res.body = searchResult;
|
|
|
|
|
|
|
|
next();
|
2018-03-06 01:05:42 +08:00
|
|
|
});
|
2018-03-07 03:05:55 +08:00
|
|
|
};
|
2015-07-10 17:24:32 +08:00
|
|
|
};
|
|
|
|
|
2018-03-06 01:28:52 +08:00
|
|
|
LayergroupController.prototype.attributes = function (attributesBackend) {
|
|
|
|
return function attributesMiddleware (req, res, next) {
|
|
|
|
req.profiler.start('windshaft.maplayer_attribute');
|
2015-07-10 17:24:32 +08:00
|
|
|
|
2018-03-06 01:28:52 +08:00
|
|
|
const { mapConfigProvider } = res.locals;
|
2018-03-07 19:52:44 +08:00
|
|
|
const params = getRequestParams(res.locals);
|
2015-07-10 17:24:32 +08:00
|
|
|
|
2018-03-07 19:52:44 +08:00
|
|
|
attributesBackend.getFeatureAttributes(mapConfigProvider, params, false, (err, tile, stats = {}) => {
|
2018-03-07 19:46:18 +08:00
|
|
|
req.profiler.add(stats);
|
2015-07-10 17:24:32 +08:00
|
|
|
|
|
|
|
if (err) {
|
2017-09-21 17:46:31 +08:00
|
|
|
err.label = 'GET ATTRIBUTES';
|
2018-03-06 01:28:52 +08:00
|
|
|
return next(err);
|
2015-07-10 17:24:32 +08:00
|
|
|
}
|
|
|
|
|
2018-03-07 01:28:40 +08:00
|
|
|
res.body = tile;
|
|
|
|
|
|
|
|
next();
|
2018-03-06 01:28:52 +08:00
|
|
|
});
|
2018-03-07 03:05:55 +08:00
|
|
|
};
|
2015-07-10 17:24:32 +08:00
|
|
|
};
|
|
|
|
|
2018-03-06 23:19:53 +08:00
|
|
|
function getStatusCode(tile, format){
|
2018-03-07 01:28:40 +08:00
|
|
|
return tile.length === 0 && format === 'mvt'? 204 : 200;
|
2018-03-06 23:19:53 +08:00
|
|
|
}
|
2015-07-10 17:24:32 +08:00
|
|
|
|
2018-03-06 23:19:53 +08:00
|
|
|
const supportedFormats = {
|
|
|
|
grid_json: true,
|
|
|
|
json_torque: true,
|
|
|
|
torque_json: true,
|
|
|
|
png: true,
|
|
|
|
png32: true,
|
|
|
|
mvt: true
|
2015-07-10 17:24:32 +08:00
|
|
|
};
|
|
|
|
|
2018-03-07 18:56:57 +08:00
|
|
|
function parseFormat (format = '') {
|
2018-03-06 23:19:53 +08:00
|
|
|
const prettyFormat = format.replace('.', '_');
|
|
|
|
let formatStat = 'invalid';
|
2015-07-10 17:24:32 +08:00
|
|
|
|
2018-03-06 23:19:53 +08:00
|
|
|
if (supportedFormats[prettyFormat]) {
|
|
|
|
formatStat = prettyFormat;
|
|
|
|
}
|
|
|
|
|
|
|
|
return formatStat;
|
2017-10-06 22:19:00 +08:00
|
|
|
}
|
|
|
|
|
2018-03-06 23:19:53 +08:00
|
|
|
LayergroupController.prototype.tile = function (tileBackend) {
|
|
|
|
return function tileMiddleware (req, res, next) {
|
|
|
|
req.profiler.start('windshaft.map_tile');
|
2017-09-21 17:46:31 +08:00
|
|
|
|
2018-03-06 23:19:53 +08:00
|
|
|
const { mapConfigProvider } = res.locals;
|
|
|
|
const params = getRequestParams(res.locals);
|
|
|
|
|
2018-03-07 19:46:18 +08:00
|
|
|
tileBackend.getTile(mapConfigProvider, params, (err, tile, headers, stats = {}) => {
|
2018-03-06 23:19:53 +08:00
|
|
|
req.profiler.add(stats);
|
|
|
|
|
|
|
|
if (err) {
|
2018-03-07 18:56:57 +08:00
|
|
|
return next(err);
|
2018-03-06 23:19:53 +08:00
|
|
|
}
|
|
|
|
|
2018-03-07 01:28:40 +08:00
|
|
|
if (headers) {
|
|
|
|
res.set(headers);
|
|
|
|
}
|
|
|
|
|
2018-03-07 18:56:57 +08:00
|
|
|
const formatStat = parseFormat(req.params.format);
|
|
|
|
|
2018-03-07 01:28:40 +08:00
|
|
|
res.statusCode = getStatusCode(tile, formatStat);
|
|
|
|
res.body = tile;
|
|
|
|
|
|
|
|
next();
|
2018-03-06 23:19:53 +08:00
|
|
|
});
|
2018-03-07 03:05:55 +08:00
|
|
|
};
|
2018-03-06 23:19:53 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
LayergroupController.prototype.layer = function (tileBackend) {
|
|
|
|
return function layerMiddleware (req, res, next) {
|
|
|
|
req.profiler.start('windshaft.maplayer_tile');
|
|
|
|
|
|
|
|
const { mapConfigProvider } = res.locals;
|
|
|
|
const params = getRequestParams(res.locals);
|
|
|
|
|
2018-03-07 19:46:18 +08:00
|
|
|
tileBackend.getTile(mapConfigProvider, params, (err, tile, headers, stats = {}) => {
|
2018-03-06 23:19:53 +08:00
|
|
|
req.profiler.add(stats);
|
|
|
|
|
|
|
|
if (err) {
|
2018-03-07 18:56:57 +08:00
|
|
|
return next(err);
|
2018-03-06 23:19:53 +08:00
|
|
|
}
|
|
|
|
|
2018-03-07 01:28:40 +08:00
|
|
|
if (headers) {
|
|
|
|
res.set(headers);
|
|
|
|
}
|
|
|
|
|
2018-03-07 18:56:57 +08:00
|
|
|
const formatStat = parseFormat(req.params.format);
|
|
|
|
|
2018-03-07 01:28:40 +08:00
|
|
|
res.statusCode = getStatusCode(tile, formatStat);
|
|
|
|
res.body = tile;
|
|
|
|
|
|
|
|
next();
|
2018-03-06 23:19:53 +08:00
|
|
|
});
|
2018-03-07 03:05:55 +08:00
|
|
|
};
|
2015-07-10 17:24:32 +08:00
|
|
|
};
|
|
|
|
|
2018-03-06 02:26:26 +08:00
|
|
|
LayergroupController.prototype.center = function (previewBackend) {
|
|
|
|
return function centerMiddleware (req, res, next) {
|
|
|
|
const width = +req.params.width;
|
|
|
|
const height = +req.params.height;
|
|
|
|
const zoom = +req.params.z;
|
|
|
|
const center = {
|
|
|
|
lng: +req.params.lng,
|
|
|
|
lat: +req.params.lat
|
|
|
|
};
|
2015-07-10 17:24:32 +08:00
|
|
|
|
2018-03-06 02:26:26 +08:00
|
|
|
const format = req.params.format === 'jpg' ? 'jpeg' : 'png';
|
2018-03-07 19:46:18 +08:00
|
|
|
const { mapConfigProvider: provider } = res.locals;
|
2015-07-10 17:24:32 +08:00
|
|
|
|
2018-03-07 19:46:18 +08:00
|
|
|
previewBackend.getImage(provider, format, width, height, zoom, center, (err, image, headers, stats = {}) => {
|
2018-03-06 02:26:26 +08:00
|
|
|
req.profiler.done('render-' + format);
|
2018-03-07 19:46:18 +08:00
|
|
|
req.profiler.add(stats);
|
2018-03-06 02:26:26 +08:00
|
|
|
|
|
|
|
if (err) {
|
|
|
|
err.label = 'STATIC_MAP';
|
|
|
|
return next(err);
|
2015-07-10 17:24:32 +08:00
|
|
|
}
|
2018-03-06 02:26:26 +08:00
|
|
|
|
2018-03-07 01:28:40 +08:00
|
|
|
if (headers) {
|
|
|
|
res.set(headers);
|
|
|
|
}
|
|
|
|
|
2018-03-06 02:26:26 +08:00
|
|
|
res.set('Content-Type', headers['Content-Type'] || 'image/' + format);
|
2018-03-07 01:28:40 +08:00
|
|
|
|
|
|
|
res.body = image;
|
|
|
|
|
|
|
|
next();
|
2018-03-06 02:26:26 +08:00
|
|
|
});
|
2018-03-07 03:05:55 +08:00
|
|
|
};
|
2018-03-06 02:26:26 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
LayergroupController.prototype.bbox = function (previewBackend) {
|
|
|
|
return function bboxMiddleware (req, res, next) {
|
|
|
|
const width = +req.params.width;
|
|
|
|
const height = +req.params.height;
|
|
|
|
const bounds = {
|
|
|
|
west: +req.params.west,
|
|
|
|
north: +req.params.north,
|
|
|
|
east: +req.params.east,
|
|
|
|
south: +req.params.south
|
|
|
|
};
|
|
|
|
const format = req.params.format === 'jpg' ? 'jpeg' : 'png';
|
2018-03-07 19:46:18 +08:00
|
|
|
const { mapConfigProvider: provider } = res.locals;
|
2018-03-06 02:26:26 +08:00
|
|
|
|
2018-03-07 19:46:18 +08:00
|
|
|
previewBackend.getImage(provider, format, width, height, bounds, (err, image, headers, stats = {}) => {
|
2015-07-10 17:24:32 +08:00
|
|
|
req.profiler.done('render-' + format);
|
2018-03-07 19:46:18 +08:00
|
|
|
req.profiler.add(stats);
|
2015-07-10 17:24:32 +08:00
|
|
|
|
|
|
|
if (err) {
|
2017-09-21 17:46:31 +08:00
|
|
|
err.label = 'STATIC_MAP';
|
2018-03-06 02:26:26 +08:00
|
|
|
return next(err);
|
2015-07-14 17:55:49 +08:00
|
|
|
}
|
2018-03-06 02:26:26 +08:00
|
|
|
|
2018-03-07 01:28:40 +08:00
|
|
|
if (headers) {
|
|
|
|
res.set(headers);
|
|
|
|
}
|
|
|
|
|
2018-03-06 02:26:26 +08:00
|
|
|
res.set('Content-Type', headers['Content-Type'] || 'image/' + format);
|
|
|
|
|
2018-03-07 01:28:40 +08:00
|
|
|
res.body = image;
|
|
|
|
|
|
|
|
next();
|
2018-03-06 02:26:26 +08:00
|
|
|
});
|
2018-03-07 03:05:55 +08:00
|
|
|
};
|
2015-07-14 17:55:49 +08:00
|
|
|
};
|
|
|
|
|
2018-03-07 01:28:40 +08:00
|
|
|
LayergroupController.prototype.setLastModifiedHeader = function () {
|
|
|
|
return function setLastModifiedHeaderMiddleware (req, res, next) {
|
|
|
|
let { cache_buster: cacheBuster } = res.locals;
|
2017-02-23 01:38:25 +08:00
|
|
|
|
2018-03-07 01:28:40 +08:00
|
|
|
cacheBuster = parseInt(cacheBuster);
|
2015-07-14 17:55:49 +08:00
|
|
|
|
2018-03-07 01:28:40 +08:00
|
|
|
const lastUpdated = res.locals.cache_buster ? new Date(cacheBuster) : new Date();
|
2015-07-14 17:55:49 +08:00
|
|
|
|
2018-03-07 01:28:40 +08:00
|
|
|
res.set('Last-Modified', lastUpdated.toUTCString());
|
2017-10-31 02:28:40 +08:00
|
|
|
|
2018-03-07 01:28:40 +08:00
|
|
|
next();
|
|
|
|
};
|
|
|
|
};
|
2017-10-31 02:28:40 +08:00
|
|
|
|
2018-03-07 01:28:40 +08:00
|
|
|
LayergroupController.prototype.setCacheControlHeader = function () {
|
|
|
|
return function setCacheControlHeaderMiddleware (req, res, next) {
|
2018-03-07 19:30:59 +08:00
|
|
|
res.set('Cache-Control', 'public,max-age=31536000');
|
2018-03-06 23:55:27 +08:00
|
|
|
|
2018-03-07 01:28:40 +08:00
|
|
|
next();
|
|
|
|
};
|
|
|
|
};
|
2018-03-06 23:55:27 +08:00
|
|
|
|
2018-03-07 03:01:43 +08:00
|
|
|
LayergroupController.prototype.getAffectedTables = function (layergroupAffectedTables, pgConnection) {
|
|
|
|
return function getAffectedTablesMiddleware (req, res, next) {
|
|
|
|
const { user, dbname, token, mapconfig } = res.locals;
|
2017-10-31 02:28:40 +08:00
|
|
|
|
2018-03-07 03:01:43 +08:00
|
|
|
if (layergroupAffectedTables.hasAffectedTables(dbname, token)) {
|
|
|
|
res.locals.affectedTables = layergroupAffectedTables.get(dbname, token);
|
|
|
|
return next();
|
|
|
|
}
|
2018-03-07 01:28:40 +08:00
|
|
|
|
2018-03-07 03:01:43 +08:00
|
|
|
pgConnection.getConnection(user, (err, connection) => {
|
2018-03-07 01:28:40 +08:00
|
|
|
if (err) {
|
|
|
|
global.logger.warn('ERROR generating cache channel: ' + err);
|
2018-03-07 03:01:43 +08:00
|
|
|
return next();
|
2017-10-31 02:28:40 +08:00
|
|
|
}
|
2018-03-07 01:28:40 +08:00
|
|
|
|
2018-03-07 03:01:43 +08:00
|
|
|
const sql = [];
|
|
|
|
mapconfig.getLayers().forEach(function(layer) {
|
|
|
|
sql.push(layer.options.sql);
|
|
|
|
if (layer.options.affected_tables) {
|
|
|
|
layer.options.affected_tables.map(function(table) {
|
|
|
|
sql.push('SELECT * FROM ' + table + ' LIMIT 0');
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
2018-03-07 01:28:40 +08:00
|
|
|
|
2018-03-07 03:01:43 +08:00
|
|
|
QueryTables.getAffectedTablesFromQuery(connection, sql.join(';'), (err, affectedTables) => {
|
|
|
|
req.profiler.done('getAffectedTablesFromQuery');
|
|
|
|
if (err) {
|
|
|
|
global.logger.warn('ERROR generating cache channel: ' + err);
|
|
|
|
return next();
|
|
|
|
}
|
2015-07-14 17:55:49 +08:00
|
|
|
|
2018-03-07 03:01:43 +08:00
|
|
|
// feed affected tables cache so it can be reused from, for instance, map controller
|
|
|
|
layergroupAffectedTables.set(dbname, token, affectedTables);
|
2015-07-14 17:55:49 +08:00
|
|
|
|
2018-03-07 03:01:43 +08:00
|
|
|
res.locals.affectedTables = affectedTables;
|
2015-07-14 17:55:49 +08:00
|
|
|
|
2018-03-07 03:01:43 +08:00
|
|
|
next();
|
|
|
|
});
|
2018-03-07 01:43:23 +08:00
|
|
|
});
|
2018-03-07 03:01:43 +08:00
|
|
|
};
|
|
|
|
};
|
2018-03-07 01:43:23 +08:00
|
|
|
|
2018-03-07 03:01:43 +08:00
|
|
|
LayergroupController.prototype.setCacheChannelHeader = function () {
|
|
|
|
return function setCacheChannelHeaderMiddleware (req, res, next) {
|
|
|
|
const { affectedTables } = res.locals;
|
2015-07-14 17:55:49 +08:00
|
|
|
|
2018-03-07 03:01:43 +08:00
|
|
|
if (affectedTables) {
|
|
|
|
res.set('X-Cache-Channel', affectedTables.getCacheChannel());
|
2018-03-07 01:43:23 +08:00
|
|
|
}
|
|
|
|
|
2018-03-07 03:01:43 +08:00
|
|
|
next();
|
|
|
|
};
|
|
|
|
};
|
2018-03-07 00:08:39 +08:00
|
|
|
|
2018-03-07 03:01:43 +08:00
|
|
|
LayergroupController.prototype.setSurrogateKeyHeader = function (surrogateKeysCache) {
|
|
|
|
return function setSurrogateKeyHeaderMiddleware (req, res, next) {
|
|
|
|
const { affectedTables } = res.locals;
|
2018-03-07 00:08:39 +08:00
|
|
|
|
2018-03-07 03:01:43 +08:00
|
|
|
if (affectedTables) {
|
|
|
|
surrogateKeysCache.tag(res, affectedTables);
|
|
|
|
}
|
2018-03-07 01:43:23 +08:00
|
|
|
|
2018-03-07 03:01:43 +08:00
|
|
|
next();
|
|
|
|
};
|
2015-07-10 17:24:32 +08:00
|
|
|
};
|
2018-03-07 01:28:40 +08:00
|
|
|
|
2018-03-07 21:53:13 +08:00
|
|
|
LayergroupController.prototype.incrementSuccessMetrics = function (statsClient) {
|
|
|
|
return function incrementSuccessMetricsMiddleware (req, res, next) {
|
|
|
|
const formatStat = parseFormat(req.params.format);
|
|
|
|
|
|
|
|
statsClient.increment('windshaft.tiles.success');
|
|
|
|
statsClient.increment(`windshaft.tiles.${formatStat}.success`);
|
|
|
|
|
|
|
|
next();
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2018-03-07 01:28:40 +08:00
|
|
|
LayergroupController.prototype.sendResponse = function () {
|
|
|
|
return function sendResponseMiddleware (req, res) {
|
|
|
|
req.profiler.done('res');
|
|
|
|
|
|
|
|
res.status(res.statusCode || 200);
|
|
|
|
|
|
|
|
if (!Buffer.isBuffer(res.body) && typeof res.body === 'object') {
|
|
|
|
if (req.query && req.query.callback) {
|
|
|
|
res.jsonp(res.body);
|
|
|
|
} else {
|
|
|
|
res.json(res.body);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
res.send(res.body);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
2018-03-07 21:53:13 +08:00
|
|
|
|
|
|
|
LayergroupController.prototype.incrementErrorMetrics = function (statsClient) {
|
|
|
|
return function incrementErrorMetricsMiddleware (err, req, res, next) {
|
|
|
|
const formatStat = parseFormat(req.params.format);
|
|
|
|
|
|
|
|
statsClient.increment('windshaft.tiles.error');
|
|
|
|
statsClient.increment(`windshaft.tiles.${formatStat}.error`);
|
|
|
|
|
|
|
|
next(err);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
LayergroupController.prototype.tileError = function () {
|
|
|
|
return function tileErrorMiddleware (err, req, res, next) {
|
|
|
|
// See https://github.com/Vizzuality/Windshaft-cartodb/issues/68
|
|
|
|
let errMsg = err.message ? ( '' + err.message ) : ( '' + err );
|
|
|
|
|
|
|
|
// Rewrite mapnik parsing errors to start with layer number
|
|
|
|
const matches = errMsg.match("(.*) in style 'layer([0-9]+)'");
|
|
|
|
|
|
|
|
if (matches) {
|
|
|
|
errMsg = 'style' + matches[2] + ': ' + matches[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
err.message = errMsg;
|
|
|
|
err.label = 'TILE RENDER';
|
|
|
|
|
|
|
|
next(err);
|
|
|
|
};
|
|
|
|
};
|