Merge pull request #915 from CartoDB/unify-headers-middlewared
Unify headers middlewares
This commit is contained in:
commit
f2a7953d9d
11
lib/cartodb/cache/named_map_provider_cache.js
vendored
11
lib/cartodb/cache/named_map_provider_cache.js
vendored
@ -6,12 +6,20 @@ var queue = require('queue-async');
|
|||||||
|
|
||||||
var LruCache = require("lru-cache");
|
var LruCache = require("lru-cache");
|
||||||
|
|
||||||
function NamedMapProviderCache(templateMaps, pgConnection, metadataBackend, userLimitsApi, mapConfigAdapter) {
|
function NamedMapProviderCache(
|
||||||
|
templateMaps,
|
||||||
|
pgConnection,
|
||||||
|
metadataBackend,
|
||||||
|
userLimitsApi,
|
||||||
|
mapConfigAdapter,
|
||||||
|
affectedTablesCache
|
||||||
|
) {
|
||||||
this.templateMaps = templateMaps;
|
this.templateMaps = templateMaps;
|
||||||
this.pgConnection = pgConnection;
|
this.pgConnection = pgConnection;
|
||||||
this.metadataBackend = metadataBackend;
|
this.metadataBackend = metadataBackend;
|
||||||
this.userLimitsApi = userLimitsApi;
|
this.userLimitsApi = userLimitsApi;
|
||||||
this.mapConfigAdapter = mapConfigAdapter;
|
this.mapConfigAdapter = mapConfigAdapter;
|
||||||
|
this.affectedTablesCache = affectedTablesCache;
|
||||||
|
|
||||||
this.providerCache = new LruCache({ max: 2000 });
|
this.providerCache = new LruCache({ max: 2000 });
|
||||||
}
|
}
|
||||||
@ -30,6 +38,7 @@ NamedMapProviderCache.prototype.get = function(user, templateId, config, authTok
|
|||||||
this.metadataBackend,
|
this.metadataBackend,
|
||||||
this.userLimitsApi,
|
this.userLimitsApi,
|
||||||
this.mapConfigAdapter,
|
this.mapConfigAdapter,
|
||||||
|
this.affectedTablesCache,
|
||||||
user,
|
user,
|
||||||
templateId,
|
templateId,
|
||||||
config,
|
config,
|
||||||
|
@ -9,6 +9,7 @@ const authorize = require('../middleware/authorize');
|
|||||||
const dbConnSetup = require('../middleware/db-conn-setup');
|
const dbConnSetup = require('../middleware/db-conn-setup');
|
||||||
const rateLimit = require('../middleware/rate-limit');
|
const rateLimit = require('../middleware/rate-limit');
|
||||||
const { RATE_LIMIT_ENDPOINTS_GROUPS } = rateLimit;
|
const { RATE_LIMIT_ENDPOINTS_GROUPS } = rateLimit;
|
||||||
|
const cacheControlHeader = require('../middleware/cache-control-header');
|
||||||
const sendResponse = require('../middleware/send-response');
|
const sendResponse = require('../middleware/send-response');
|
||||||
|
|
||||||
function AnalysesController(pgConnection, authApi, userLimitsApi) {
|
function AnalysesController(pgConnection, authApi, userLimitsApi) {
|
||||||
@ -37,7 +38,7 @@ AnalysesController.prototype.register = function (app) {
|
|||||||
getDataFromQuery({ queryTemplate: catalogQueryTpl, key: 'catalog' }),
|
getDataFromQuery({ queryTemplate: catalogQueryTpl, key: 'catalog' }),
|
||||||
getDataFromQuery({ queryTemplate: tablesQueryTpl, key: 'tables' }),
|
getDataFromQuery({ queryTemplate: tablesQueryTpl, key: 'tables' }),
|
||||||
prepareResponse(),
|
prepareResponse(),
|
||||||
setCacheControlHeader(),
|
cacheControlHeader({ ttl: 10, revalidate: true }),
|
||||||
sendResponse(),
|
sendResponse(),
|
||||||
unauthorizedError()
|
unauthorizedError()
|
||||||
);
|
);
|
||||||
@ -112,13 +113,6 @@ function prepareResponse () {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function setCacheControlHeader () {
|
|
||||||
return function setCacheControlHeaderMiddleware (req, res, next) {
|
|
||||||
res.set('Cache-Control', 'public,max-age=10,must-revalidate');
|
|
||||||
next();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function unauthorizedError () {
|
function unauthorizedError () {
|
||||||
return function unathorizedErrorMiddleware(err, req, res, next) {
|
return function unathorizedErrorMiddleware(err, req, res, next) {
|
||||||
if (err.message.match(/permission\sdenied/)) {
|
if (err.message.match(/permission\sdenied/)) {
|
||||||
|
@ -9,11 +9,14 @@ const dbConnSetup = require('../middleware/db-conn-setup');
|
|||||||
const authorize = require('../middleware/authorize');
|
const authorize = require('../middleware/authorize');
|
||||||
const rateLimit = require('../middleware/rate-limit');
|
const rateLimit = require('../middleware/rate-limit');
|
||||||
const { RATE_LIMIT_ENDPOINTS_GROUPS } = rateLimit;
|
const { RATE_LIMIT_ENDPOINTS_GROUPS } = rateLimit;
|
||||||
|
const cacheControlHeader = require('../middleware/cache-control-header');
|
||||||
|
const cacheChannelHeader = require('../middleware/cache-channel-header');
|
||||||
|
const surrogateKeyHeader = require('../middleware/surrogate-key-header');
|
||||||
|
const lastModifiedHeader = require('../middleware/last-modified-header');
|
||||||
const sendResponse = require('../middleware/send-response');
|
const sendResponse = require('../middleware/send-response');
|
||||||
const DataviewBackend = require('../backends/dataview');
|
const DataviewBackend = require('../backends/dataview');
|
||||||
const AnalysisStatusBackend = require('../backends/analysis-status');
|
const AnalysisStatusBackend = require('../backends/analysis-status');
|
||||||
const MapStoreMapConfigProvider = require('../models/mapconfig/provider/map-store-provider');
|
const MapStoreMapConfigProvider = require('../models/mapconfig/provider/map-store-provider');
|
||||||
const QueryTables = require('cartodb-query-tables');
|
|
||||||
const SUPPORTED_FORMATS = {
|
const SUPPORTED_FORMATS = {
|
||||||
grid_json: true,
|
grid_json: true,
|
||||||
json_torque: true,
|
json_torque: true,
|
||||||
@ -44,7 +47,7 @@ function LayergroupController(
|
|||||||
attributesBackend,
|
attributesBackend,
|
||||||
surrogateKeysCache,
|
surrogateKeysCache,
|
||||||
userLimitsApi,
|
userLimitsApi,
|
||||||
layergroupAffectedTables,
|
layergroupAffectedTablesCache,
|
||||||
analysisBackend,
|
analysisBackend,
|
||||||
authApi
|
authApi
|
||||||
) {
|
) {
|
||||||
@ -55,7 +58,7 @@ function LayergroupController(
|
|||||||
this.attributesBackend = attributesBackend;
|
this.attributesBackend = attributesBackend;
|
||||||
this.surrogateKeysCache = surrogateKeysCache;
|
this.surrogateKeysCache = surrogateKeysCache;
|
||||||
this.userLimitsApi = userLimitsApi;
|
this.userLimitsApi = userLimitsApi;
|
||||||
this.layergroupAffectedTables = layergroupAffectedTables;
|
this.layergroupAffectedTablesCache = layergroupAffectedTablesCache;
|
||||||
|
|
||||||
this.dataviewBackend = new DataviewBackend(analysisBackend);
|
this.dataviewBackend = new DataviewBackend(analysisBackend);
|
||||||
this.analysisStatusBackend = new AnalysisStatusBackend();
|
this.analysisStatusBackend = new AnalysisStatusBackend();
|
||||||
@ -65,10 +68,10 @@ function LayergroupController(
|
|||||||
module.exports = LayergroupController;
|
module.exports = LayergroupController;
|
||||||
|
|
||||||
LayergroupController.prototype.register = function(app) {
|
LayergroupController.prototype.register = function(app) {
|
||||||
const { base_url_mapconfig: mapconfigBasePath } = app;
|
const { base_url_mapconfig: mapConfigBasePath } = app;
|
||||||
|
|
||||||
app.get(
|
app.get(
|
||||||
`${mapconfigBasePath}/:token/:z/:x/:y@:scale_factor?x.:format`,
|
`${mapConfigBasePath}/:token/:z/:x/:y@:scale_factor?x.:format`,
|
||||||
cors(),
|
cors(),
|
||||||
cleanUpQueryParams(),
|
cleanUpQueryParams(),
|
||||||
locals(),
|
locals(),
|
||||||
@ -78,13 +81,17 @@ LayergroupController.prototype.register = function(app) {
|
|||||||
credentials(),
|
credentials(),
|
||||||
authorize(this.authApi),
|
authorize(this.authApi),
|
||||||
dbConnSetup(this.pgConnection),
|
dbConnSetup(this.pgConnection),
|
||||||
createMapStoreMapConfigProvider(this.mapStore, this.userLimitsApi),
|
createMapStoreMapConfigProvider(
|
||||||
|
this.mapStore,
|
||||||
|
this.userLimitsApi,
|
||||||
|
this.pgConnection,
|
||||||
|
this.layergroupAffectedTablesCache
|
||||||
|
),
|
||||||
getTile(this.tileBackend, 'map_tile'),
|
getTile(this.tileBackend, 'map_tile'),
|
||||||
setCacheControlHeader(),
|
cacheControlHeader(),
|
||||||
setLastModifiedHeader(),
|
cacheChannelHeader(),
|
||||||
getAffectedTables(this.layergroupAffectedTables, this.pgConnection, this.mapStore),
|
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
|
||||||
setCacheChannelHeader(),
|
lastModifiedHeader(),
|
||||||
setSurrogateKeyHeader(this.surrogateKeysCache),
|
|
||||||
incrementSuccessMetrics(global.statsClient),
|
incrementSuccessMetrics(global.statsClient),
|
||||||
sendResponse(),
|
sendResponse(),
|
||||||
incrementErrorMetrics(global.statsClient),
|
incrementErrorMetrics(global.statsClient),
|
||||||
@ -93,7 +100,7 @@ LayergroupController.prototype.register = function(app) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
app.get(
|
app.get(
|
||||||
`${mapconfigBasePath}/:token/:z/:x/:y.:format`,
|
`${mapConfigBasePath}/:token/:z/:x/:y.:format`,
|
||||||
cors(),
|
cors(),
|
||||||
cleanUpQueryParams(),
|
cleanUpQueryParams(),
|
||||||
locals(),
|
locals(),
|
||||||
@ -103,13 +110,17 @@ LayergroupController.prototype.register = function(app) {
|
|||||||
credentials(),
|
credentials(),
|
||||||
authorize(this.authApi),
|
authorize(this.authApi),
|
||||||
dbConnSetup(this.pgConnection),
|
dbConnSetup(this.pgConnection),
|
||||||
createMapStoreMapConfigProvider(this.mapStore, this.userLimitsApi),
|
createMapStoreMapConfigProvider(
|
||||||
|
this.mapStore,
|
||||||
|
this.userLimitsApi,
|
||||||
|
this.pgConnection,
|
||||||
|
this.layergroupAffectedTablesCache
|
||||||
|
),
|
||||||
getTile(this.tileBackend, 'map_tile'),
|
getTile(this.tileBackend, 'map_tile'),
|
||||||
setCacheControlHeader(),
|
cacheControlHeader(),
|
||||||
setLastModifiedHeader(),
|
cacheChannelHeader(),
|
||||||
getAffectedTables(this.layergroupAffectedTables, this.pgConnection, this.mapStore),
|
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
|
||||||
setCacheChannelHeader(),
|
lastModifiedHeader(),
|
||||||
setSurrogateKeyHeader(this.surrogateKeysCache),
|
|
||||||
incrementSuccessMetrics(global.statsClient),
|
incrementSuccessMetrics(global.statsClient),
|
||||||
sendResponse(),
|
sendResponse(),
|
||||||
incrementErrorMetrics(global.statsClient),
|
incrementErrorMetrics(global.statsClient),
|
||||||
@ -118,7 +129,7 @@ LayergroupController.prototype.register = function(app) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
app.get(
|
app.get(
|
||||||
`${mapconfigBasePath}/:token/:layer/:z/:x/:y.(:format)`,
|
`${mapConfigBasePath}/:token/:layer/:z/:x/:y.(:format)`,
|
||||||
distinguishLayergroupFromStaticRoute(),
|
distinguishLayergroupFromStaticRoute(),
|
||||||
cors(),
|
cors(),
|
||||||
cleanUpQueryParams(),
|
cleanUpQueryParams(),
|
||||||
@ -129,13 +140,17 @@ LayergroupController.prototype.register = function(app) {
|
|||||||
credentials(),
|
credentials(),
|
||||||
authorize(this.authApi),
|
authorize(this.authApi),
|
||||||
dbConnSetup(this.pgConnection),
|
dbConnSetup(this.pgConnection),
|
||||||
createMapStoreMapConfigProvider(this.mapStore, this.userLimitsApi),
|
createMapStoreMapConfigProvider(
|
||||||
|
this.mapStore,
|
||||||
|
this.userLimitsApi,
|
||||||
|
this.pgConnection,
|
||||||
|
this.layergroupAffectedTablesCache
|
||||||
|
),
|
||||||
getTile(this.tileBackend, 'maplayer_tile'),
|
getTile(this.tileBackend, 'maplayer_tile'),
|
||||||
setCacheControlHeader(),
|
cacheControlHeader(),
|
||||||
setLastModifiedHeader(),
|
cacheChannelHeader(),
|
||||||
getAffectedTables(this.layergroupAffectedTables, this.pgConnection, this.mapStore),
|
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
|
||||||
setCacheChannelHeader(),
|
lastModifiedHeader(),
|
||||||
setSurrogateKeyHeader(this.surrogateKeysCache),
|
|
||||||
incrementSuccessMetrics(global.statsClient),
|
incrementSuccessMetrics(global.statsClient),
|
||||||
sendResponse(),
|
sendResponse(),
|
||||||
incrementErrorMetrics(global.statsClient),
|
incrementErrorMetrics(global.statsClient),
|
||||||
@ -144,7 +159,7 @@ LayergroupController.prototype.register = function(app) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
app.get(
|
app.get(
|
||||||
`${mapconfigBasePath}/:token/:layer/attributes/:fid`,
|
`${mapConfigBasePath}/:token/:layer/attributes/:fid`,
|
||||||
cors(),
|
cors(),
|
||||||
cleanUpQueryParams(),
|
cleanUpQueryParams(),
|
||||||
locals(),
|
locals(),
|
||||||
@ -154,20 +169,24 @@ LayergroupController.prototype.register = function(app) {
|
|||||||
credentials(),
|
credentials(),
|
||||||
authorize(this.authApi),
|
authorize(this.authApi),
|
||||||
dbConnSetup(this.pgConnection),
|
dbConnSetup(this.pgConnection),
|
||||||
createMapStoreMapConfigProvider(this.mapStore, this.userLimitsApi),
|
createMapStoreMapConfigProvider(
|
||||||
|
this.mapStore,
|
||||||
|
this.userLimitsApi,
|
||||||
|
this.pgConnection,
|
||||||
|
this.layergroupAffectedTablesCache
|
||||||
|
),
|
||||||
getFeatureAttributes(this.attributesBackend),
|
getFeatureAttributes(this.attributesBackend),
|
||||||
setCacheControlHeader(),
|
cacheControlHeader(),
|
||||||
setLastModifiedHeader(),
|
cacheChannelHeader(),
|
||||||
getAffectedTables(this.layergroupAffectedTables, this.pgConnection, this.mapStore),
|
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
|
||||||
setCacheChannelHeader(),
|
lastModifiedHeader(),
|
||||||
setSurrogateKeyHeader(this.surrogateKeysCache),
|
|
||||||
sendResponse()
|
sendResponse()
|
||||||
);
|
);
|
||||||
|
|
||||||
const forcedFormat = 'png';
|
const forcedFormat = 'png';
|
||||||
|
|
||||||
app.get(
|
app.get(
|
||||||
`${mapconfigBasePath}/static/center/:token/:z/:lat/:lng/:width/:height.:format`,
|
`${mapConfigBasePath}/static/center/:token/:z/:lat/:lng/:width/:height.:format`,
|
||||||
cors(),
|
cors(),
|
||||||
cleanUpQueryParams(['layer']),
|
cleanUpQueryParams(['layer']),
|
||||||
locals(),
|
locals(),
|
||||||
@ -177,18 +196,23 @@ LayergroupController.prototype.register = function(app) {
|
|||||||
credentials(),
|
credentials(),
|
||||||
authorize(this.authApi),
|
authorize(this.authApi),
|
||||||
dbConnSetup(this.pgConnection),
|
dbConnSetup(this.pgConnection),
|
||||||
createMapStoreMapConfigProvider(this.mapStore, this.userLimitsApi, forcedFormat),
|
createMapStoreMapConfigProvider(
|
||||||
|
this.mapStore,
|
||||||
|
this.userLimitsApi,
|
||||||
|
this.pgConnection,
|
||||||
|
this.layergroupAffectedTablesCache,
|
||||||
|
forcedFormat
|
||||||
|
),
|
||||||
getPreviewImageByCenter(this.previewBackend),
|
getPreviewImageByCenter(this.previewBackend),
|
||||||
setCacheControlHeader(),
|
cacheControlHeader(),
|
||||||
setLastModifiedHeader(),
|
cacheChannelHeader(),
|
||||||
getAffectedTables(this.layergroupAffectedTables, this.pgConnection, this.mapStore),
|
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
|
||||||
setCacheChannelHeader(),
|
lastModifiedHeader(),
|
||||||
setSurrogateKeyHeader(this.surrogateKeysCache),
|
|
||||||
sendResponse()
|
sendResponse()
|
||||||
);
|
);
|
||||||
|
|
||||||
app.get(
|
app.get(
|
||||||
`${mapconfigBasePath}/static/bbox/:token/:west,:south,:east,:north/:width/:height.:format`,
|
`${mapConfigBasePath}/static/bbox/:token/:west,:south,:east,:north/:width/:height.:format`,
|
||||||
cors(),
|
cors(),
|
||||||
cleanUpQueryParams(['layer']),
|
cleanUpQueryParams(['layer']),
|
||||||
locals(),
|
locals(),
|
||||||
@ -198,13 +222,18 @@ LayergroupController.prototype.register = function(app) {
|
|||||||
credentials(),
|
credentials(),
|
||||||
authorize(this.authApi),
|
authorize(this.authApi),
|
||||||
dbConnSetup(this.pgConnection),
|
dbConnSetup(this.pgConnection),
|
||||||
createMapStoreMapConfigProvider(this.mapStore, this.userLimitsApi, forcedFormat),
|
createMapStoreMapConfigProvider(
|
||||||
|
this.mapStore,
|
||||||
|
this.userLimitsApi,
|
||||||
|
this.pgConnection,
|
||||||
|
this.layergroupAffectedTablesCache,
|
||||||
|
forcedFormat
|
||||||
|
),
|
||||||
getPreviewImageByBoundingBox(this.previewBackend),
|
getPreviewImageByBoundingBox(this.previewBackend),
|
||||||
setCacheControlHeader(),
|
cacheControlHeader(),
|
||||||
setLastModifiedHeader(),
|
cacheChannelHeader(),
|
||||||
getAffectedTables(this.layergroupAffectedTables, this.pgConnection, this.mapStore),
|
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
|
||||||
setCacheChannelHeader(),
|
lastModifiedHeader(),
|
||||||
setSurrogateKeyHeader(this.surrogateKeysCache),
|
|
||||||
sendResponse()
|
sendResponse()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -227,7 +256,7 @@ LayergroupController.prototype.register = function(app) {
|
|||||||
];
|
];
|
||||||
|
|
||||||
app.get(
|
app.get(
|
||||||
`${mapconfigBasePath}/:token/dataview/:dataviewName`,
|
`${mapConfigBasePath}/:token/dataview/:dataviewName`,
|
||||||
cors(),
|
cors(),
|
||||||
cleanUpQueryParams(allowedDataviewQueryParams),
|
cleanUpQueryParams(allowedDataviewQueryParams),
|
||||||
locals(),
|
locals(),
|
||||||
@ -237,18 +266,22 @@ LayergroupController.prototype.register = function(app) {
|
|||||||
credentials(),
|
credentials(),
|
||||||
authorize(this.authApi),
|
authorize(this.authApi),
|
||||||
dbConnSetup(this.pgConnection),
|
dbConnSetup(this.pgConnection),
|
||||||
createMapStoreMapConfigProvider(this.mapStore, this.userLimitsApi),
|
createMapStoreMapConfigProvider(
|
||||||
|
this.mapStore,
|
||||||
|
this.userLimitsApi,
|
||||||
|
this.pgConnection,
|
||||||
|
this.layergroupAffectedTablesCache
|
||||||
|
),
|
||||||
getDataview(this.dataviewBackend),
|
getDataview(this.dataviewBackend),
|
||||||
setCacheControlHeader(),
|
cacheControlHeader(),
|
||||||
setLastModifiedHeader(),
|
cacheChannelHeader(),
|
||||||
getAffectedTables(this.layergroupAffectedTables, this.pgConnection, this.mapStore),
|
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
|
||||||
setCacheChannelHeader(),
|
lastModifiedHeader(),
|
||||||
setSurrogateKeyHeader(this.surrogateKeysCache),
|
|
||||||
sendResponse()
|
sendResponse()
|
||||||
);
|
);
|
||||||
|
|
||||||
app.get(
|
app.get(
|
||||||
`${mapconfigBasePath}/:token/:layer/widget/:dataviewName`,
|
`${mapConfigBasePath}/:token/:layer/widget/:dataviewName`,
|
||||||
cors(),
|
cors(),
|
||||||
cleanUpQueryParams(allowedDataviewQueryParams),
|
cleanUpQueryParams(allowedDataviewQueryParams),
|
||||||
locals(),
|
locals(),
|
||||||
@ -258,18 +291,22 @@ LayergroupController.prototype.register = function(app) {
|
|||||||
credentials(),
|
credentials(),
|
||||||
authorize(this.authApi),
|
authorize(this.authApi),
|
||||||
dbConnSetup(this.pgConnection),
|
dbConnSetup(this.pgConnection),
|
||||||
createMapStoreMapConfigProvider(this.mapStore, this.userLimitsApi),
|
createMapStoreMapConfigProvider(
|
||||||
|
this.mapStore,
|
||||||
|
this.userLimitsApi,
|
||||||
|
this.pgConnection,
|
||||||
|
this.layergroupAffectedTablesCache
|
||||||
|
),
|
||||||
getDataview(this.dataviewBackend),
|
getDataview(this.dataviewBackend),
|
||||||
setCacheControlHeader(),
|
cacheControlHeader(),
|
||||||
setLastModifiedHeader(),
|
cacheChannelHeader(),
|
||||||
getAffectedTables(this.layergroupAffectedTables, this.pgConnection, this.mapStore),
|
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
|
||||||
setCacheChannelHeader(),
|
lastModifiedHeader(),
|
||||||
setSurrogateKeyHeader(this.surrogateKeysCache),
|
|
||||||
sendResponse()
|
sendResponse()
|
||||||
);
|
);
|
||||||
|
|
||||||
app.get(
|
app.get(
|
||||||
`${mapconfigBasePath}/:token/dataview/:dataviewName/search`,
|
`${mapConfigBasePath}/:token/dataview/:dataviewName/search`,
|
||||||
cors(),
|
cors(),
|
||||||
cleanUpQueryParams(allowedDataviewQueryParams),
|
cleanUpQueryParams(allowedDataviewQueryParams),
|
||||||
locals(),
|
locals(),
|
||||||
@ -279,18 +316,22 @@ LayergroupController.prototype.register = function(app) {
|
|||||||
credentials(),
|
credentials(),
|
||||||
authorize(this.authApi),
|
authorize(this.authApi),
|
||||||
dbConnSetup(this.pgConnection),
|
dbConnSetup(this.pgConnection),
|
||||||
createMapStoreMapConfigProvider(this.mapStore, this.userLimitsApi),
|
createMapStoreMapConfigProvider(
|
||||||
|
this.mapStore,
|
||||||
|
this.userLimitsApi,
|
||||||
|
this.pgConnection,
|
||||||
|
this.layergroupAffectedTablesCache
|
||||||
|
),
|
||||||
dataviewSearch(this.dataviewBackend),
|
dataviewSearch(this.dataviewBackend),
|
||||||
setCacheControlHeader(),
|
cacheControlHeader(),
|
||||||
setLastModifiedHeader(),
|
cacheChannelHeader(),
|
||||||
getAffectedTables(this.layergroupAffectedTables, this.pgConnection, this.mapStore),
|
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
|
||||||
setCacheChannelHeader(),
|
lastModifiedHeader(),
|
||||||
setSurrogateKeyHeader(this.surrogateKeysCache),
|
|
||||||
sendResponse()
|
sendResponse()
|
||||||
);
|
);
|
||||||
|
|
||||||
app.get(
|
app.get(
|
||||||
`${mapconfigBasePath}/:token/:layer/widget/:dataviewName/search`,
|
`${mapConfigBasePath}/:token/:layer/widget/:dataviewName/search`,
|
||||||
cors(),
|
cors(),
|
||||||
cleanUpQueryParams(allowedDataviewQueryParams),
|
cleanUpQueryParams(allowedDataviewQueryParams),
|
||||||
locals(),
|
locals(),
|
||||||
@ -300,18 +341,22 @@ LayergroupController.prototype.register = function(app) {
|
|||||||
credentials(),
|
credentials(),
|
||||||
authorize(this.authApi),
|
authorize(this.authApi),
|
||||||
dbConnSetup(this.pgConnection),
|
dbConnSetup(this.pgConnection),
|
||||||
createMapStoreMapConfigProvider(this.mapStore, this.userLimitsApi),
|
createMapStoreMapConfigProvider(
|
||||||
|
this.mapStore,
|
||||||
|
this.userLimitsApi,
|
||||||
|
this.pgConnection,
|
||||||
|
this.layergroupAffectedTablesCache
|
||||||
|
),
|
||||||
dataviewSearch(this.dataviewBackend),
|
dataviewSearch(this.dataviewBackend),
|
||||||
setCacheControlHeader(),
|
cacheControlHeader(),
|
||||||
setLastModifiedHeader(),
|
cacheChannelHeader(),
|
||||||
getAffectedTables(this.layergroupAffectedTables, this.pgConnection, this.mapStore),
|
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
|
||||||
setCacheChannelHeader(),
|
lastModifiedHeader(),
|
||||||
setSurrogateKeyHeader(this.surrogateKeysCache),
|
|
||||||
sendResponse()
|
sendResponse()
|
||||||
);
|
);
|
||||||
|
|
||||||
app.get(
|
app.get(
|
||||||
`${mapconfigBasePath}/:token/analysis/node/:nodeId`,
|
`${mapConfigBasePath}/:token/analysis/node/:nodeId`,
|
||||||
cors(),
|
cors(),
|
||||||
cleanUpQueryParams(),
|
cleanUpQueryParams(),
|
||||||
locals(),
|
locals(),
|
||||||
@ -367,7 +412,13 @@ function getRequestParams(locals) {
|
|||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMapStoreMapConfigProvider (mapStore, userLimitsApi, forcedFormat = null) {
|
function createMapStoreMapConfigProvider (
|
||||||
|
mapStore,
|
||||||
|
userLimitsApi,
|
||||||
|
pgConnection,
|
||||||
|
affectedTablesCache,
|
||||||
|
forcedFormat = null
|
||||||
|
) {
|
||||||
return function createMapStoreMapConfigProviderMiddleware (req, res, next) {
|
return function createMapStoreMapConfigProviderMiddleware (req, res, next) {
|
||||||
const { user } = res.locals;
|
const { user } = res.locals;
|
||||||
|
|
||||||
@ -378,7 +429,14 @@ function createMapStoreMapConfigProvider (mapStore, userLimitsApi, forcedFormat
|
|||||||
params.layer = params.layer || 'all';
|
params.layer = params.layer || 'all';
|
||||||
}
|
}
|
||||||
|
|
||||||
res.locals.mapConfigProvider = new MapStoreMapConfigProvider(mapStore, user, userLimitsApi, params);
|
res.locals.mapConfigProvider = new MapStoreMapConfigProvider(
|
||||||
|
mapStore,
|
||||||
|
user,
|
||||||
|
userLimitsApi,
|
||||||
|
pgConnection,
|
||||||
|
affectedTablesCache,
|
||||||
|
params
|
||||||
|
);
|
||||||
|
|
||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
@ -553,110 +611,6 @@ function getPreviewImageByBoundingBox (previewBackend) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function setLastModifiedHeader () {
|
|
||||||
return function setLastModifiedHeaderMiddleware (req, res, next) {
|
|
||||||
let { cache_buster: cacheBuster } = res.locals;
|
|
||||||
|
|
||||||
cacheBuster = parseInt(cacheBuster, 10);
|
|
||||||
|
|
||||||
const lastUpdated = res.locals.cache_buster ? new Date(cacheBuster) : new Date();
|
|
||||||
|
|
||||||
res.set('Last-Modified', lastUpdated.toUTCString());
|
|
||||||
|
|
||||||
next();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function setCacheControlHeader () {
|
|
||||||
return function setCacheControlHeaderMiddleware (req, res, next) {
|
|
||||||
res.set('Cache-Control', 'public,max-age=31536000');
|
|
||||||
|
|
||||||
next();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAffectedTables (layergroupAffectedTables, pgConnection, mapStore) {
|
|
||||||
return function getAffectedTablesMiddleware (req, res, next) {
|
|
||||||
const { user, dbname, token } = res.locals;
|
|
||||||
|
|
||||||
if (layergroupAffectedTables.hasAffectedTables(dbname, token)) {
|
|
||||||
res.locals.affectedTables = layergroupAffectedTables.get(dbname, token);
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
|
|
||||||
mapStore.load(token, (err, mapconfig) => {
|
|
||||||
if (err) {
|
|
||||||
global.logger.warn('ERROR generating cache channel:', err);
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
|
|
||||||
const queries = [];
|
|
||||||
mapconfig.getLayers().forEach(function(layer) {
|
|
||||||
queries.push(layer.options.sql);
|
|
||||||
if (layer.options.affected_tables) {
|
|
||||||
layer.options.affected_tables.map(function(table) {
|
|
||||||
queries.push(`SELECT * FROM ${table} LIMIT 0`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const sql = queries.length ? queries.join(';') : null;
|
|
||||||
|
|
||||||
if (!sql) {
|
|
||||||
global.logger.warn('ERROR generating cache channel:' +
|
|
||||||
' this request doesn\'t need an X-Cache-Channel generated');
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
|
|
||||||
pgConnection.getConnection(user, (err, connection) => {
|
|
||||||
if (err) {
|
|
||||||
global.logger.warn('ERROR generating cache channel:', err);
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
|
|
||||||
QueryTables.getAffectedTablesFromQuery(connection, sql, (err, affectedTables) => {
|
|
||||||
req.profiler.done('getAffectedTablesFromQuery');
|
|
||||||
if (err) {
|
|
||||||
global.logger.warn('ERROR generating cache channel: ', err);
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
|
|
||||||
// feed affected tables cache so it can be reused from, for instance, map controller
|
|
||||||
layergroupAffectedTables.set(dbname, token, affectedTables);
|
|
||||||
|
|
||||||
res.locals.affectedTables = affectedTables;
|
|
||||||
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function setCacheChannelHeader () {
|
|
||||||
return function setCacheChannelHeaderMiddleware (req, res, next) {
|
|
||||||
const { affectedTables } = res.locals;
|
|
||||||
|
|
||||||
if (affectedTables) {
|
|
||||||
res.set('X-Cache-Channel', affectedTables.getCacheChannel());
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function setSurrogateKeyHeader (surrogateKeysCache) {
|
|
||||||
return function setSurrogateKeyHeaderMiddleware (req, res, next) {
|
|
||||||
const { affectedTables } = res.locals;
|
|
||||||
|
|
||||||
if (affectedTables) {
|
|
||||||
surrogateKeysCache.tag(res, affectedTables);
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function incrementSuccessMetrics (statsClient) {
|
function incrementSuccessMetrics (statsClient) {
|
||||||
return function incrementSuccessMetricsMiddleware (req, res, next) {
|
return function incrementSuccessMetricsMiddleware (req, res, next) {
|
||||||
const formatStat = parseFormat(req.params.format);
|
const formatStat = parseFormat(req.params.format);
|
||||||
|
@ -2,7 +2,6 @@ const _ = require('underscore');
|
|||||||
const windshaft = require('windshaft');
|
const windshaft = require('windshaft');
|
||||||
const MapConfig = windshaft.model.MapConfig;
|
const MapConfig = windshaft.model.MapConfig;
|
||||||
const Datasource = windshaft.model.Datasource;
|
const Datasource = windshaft.model.Datasource;
|
||||||
const QueryTables = require('cartodb-query-tables');
|
|
||||||
const ResourceLocator = require('../models/resource-locator');
|
const ResourceLocator = require('../models/resource-locator');
|
||||||
const cors = require('../middleware/cors');
|
const cors = require('../middleware/cors');
|
||||||
const user = require('../middleware/user');
|
const user = require('../middleware/user');
|
||||||
@ -12,8 +11,11 @@ const layergroupToken = require('../middleware/layergroup-token');
|
|||||||
const credentials = require('../middleware/credentials');
|
const credentials = require('../middleware/credentials');
|
||||||
const dbConnSetup = require('../middleware/db-conn-setup');
|
const dbConnSetup = require('../middleware/db-conn-setup');
|
||||||
const authorize = require('../middleware/authorize');
|
const authorize = require('../middleware/authorize');
|
||||||
|
const cacheControlHeader = require('../middleware/cache-control-header');
|
||||||
|
const cacheChannelHeader = require('../middleware/cache-channel-header');
|
||||||
|
const surrogateKeyHeader = require('../middleware/surrogate-key-header');
|
||||||
|
const lastModifiedHeader = require('../middleware/last-modified-header');
|
||||||
const sendResponse = require('../middleware/send-response');
|
const sendResponse = require('../middleware/send-response');
|
||||||
const NamedMapsCacheEntry = require('../cache/model/named_maps_entry');
|
|
||||||
const NamedMapMapConfigProvider = require('../models/mapconfig/provider/named-map-provider');
|
const NamedMapMapConfigProvider = require('../models/mapconfig/provider/named-map-provider');
|
||||||
const CreateLayergroupMapConfigProvider = require('../models/mapconfig/provider/create-layergroup-provider');
|
const CreateLayergroupMapConfigProvider = require('../models/mapconfig/provider/create-layergroup-provider');
|
||||||
const LayergroupMetadata = require('../utils/layergroup-metadata');
|
const LayergroupMetadata = require('../utils/layergroup-metadata');
|
||||||
@ -64,15 +66,15 @@ function MapController (
|
|||||||
module.exports = MapController;
|
module.exports = MapController;
|
||||||
|
|
||||||
MapController.prototype.register = function(app) {
|
MapController.prototype.register = function(app) {
|
||||||
const { base_url_mapconfig: mapconfigBasePath, base_url_templated: templateBasePath } = app;
|
const { base_url_mapconfig: mapConfigBasePath, base_url_templated: templateBasePath } = app;
|
||||||
|
|
||||||
app.get(
|
app.get(
|
||||||
`${mapconfigBasePath}`,
|
`${mapConfigBasePath}`,
|
||||||
this.composeCreateMapMiddleware(RATE_LIMIT_ENDPOINTS_GROUPS.ANONYMOUS)
|
this.composeCreateMapMiddleware(RATE_LIMIT_ENDPOINTS_GROUPS.ANONYMOUS)
|
||||||
);
|
);
|
||||||
|
|
||||||
app.post(
|
app.post(
|
||||||
`${mapconfigBasePath}`,
|
`${mapConfigBasePath}`,
|
||||||
this.composeCreateMapMiddleware(RATE_LIMIT_ENDPOINTS_GROUPS.ANONYMOUS)
|
this.composeCreateMapMiddleware(RATE_LIMIT_ENDPOINTS_GROUPS.ANONYMOUS)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -88,7 +90,7 @@ MapController.prototype.register = function(app) {
|
|||||||
this.composeCreateMapMiddleware(RATE_LIMIT_ENDPOINTS_GROUPS.NAMED, useTemplate)
|
this.composeCreateMapMiddleware(RATE_LIMIT_ENDPOINTS_GROUPS.NAMED, useTemplate)
|
||||||
);
|
);
|
||||||
|
|
||||||
app.options(app.base_url_mapconfig, cors('Content-Type'));
|
app.options(`${mapConfigBasePath}`, cors('Content-Type'));
|
||||||
};
|
};
|
||||||
|
|
||||||
MapController.prototype.composeCreateMapMiddleware = function (endpointGroup, useTemplate = false) {
|
MapController.prototype.composeCreateMapMiddleware = function (endpointGroup, useTemplate = false) {
|
||||||
@ -113,12 +115,11 @@ MapController.prototype.composeCreateMapMiddleware = function (endpointGroup, us
|
|||||||
this.getCreateMapMiddlewares(useTemplate),
|
this.getCreateMapMiddlewares(useTemplate),
|
||||||
incrementMapViewCount(this.metadataBackend),
|
incrementMapViewCount(this.metadataBackend),
|
||||||
augmentLayergroupData(),
|
augmentLayergroupData(),
|
||||||
getAffectedTables(this.pgConnection, this.layergroupAffectedTables),
|
cacheControlHeader({ ttl: global.environment.varnish.layergroupTtl || 86400, revalidate: true }),
|
||||||
setCacheChannelHeader(),
|
cacheChannelHeader(),
|
||||||
setSurrogateKeyHeader(this.surrogateKeysCache),
|
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
|
||||||
setLastModified(),
|
lastModifiedHeader({ now: true }),
|
||||||
setLastUpdatedTimeToLayergroup(),
|
setLastUpdatedTimeToLayergroup(),
|
||||||
setCacheControl(),
|
|
||||||
setLayerStats(this.pgConnection, this.statsBackend),
|
setLayerStats(this.pgConnection, this.statsBackend),
|
||||||
setLayergroupIdHeader(this.templateMaps ,useTemplateHash),
|
setLayergroupIdHeader(this.templateMaps ,useTemplateHash),
|
||||||
setDataviewsAndWidgetsUrlsToLayergroupMetadata(this.layergroupMetadata),
|
setDataviewsAndWidgetsUrlsToLayergroupMetadata(this.layergroupMetadata),
|
||||||
@ -140,16 +141,27 @@ MapController.prototype.getCreateMapMiddlewares = function (useTemplate) {
|
|||||||
this.pgConnection,
|
this.pgConnection,
|
||||||
this.metadataBackend,
|
this.metadataBackend,
|
||||||
this.userLimitsApi,
|
this.userLimitsApi,
|
||||||
this.mapConfigAdapter
|
this.mapConfigAdapter,
|
||||||
|
this.layergroupAffectedTables
|
||||||
),
|
),
|
||||||
instantiateLayergroup(this.mapBackend, this.userLimitsApi)
|
instantiateLayergroup(
|
||||||
|
this.mapBackend,
|
||||||
|
this.userLimitsApi,
|
||||||
|
this.pgConnection,
|
||||||
|
this.layergroupAffectedTables
|
||||||
|
)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
checkCreateLayergroup(),
|
checkCreateLayergroup(),
|
||||||
prepareAdapterMapConfig(this.mapConfigAdapter),
|
prepareAdapterMapConfig(this.mapConfigAdapter),
|
||||||
createLayergroup (this.mapBackend, this.userLimitsApi)
|
createLayergroup (
|
||||||
|
this.mapBackend,
|
||||||
|
this.userLimitsApi,
|
||||||
|
this.pgConnection,
|
||||||
|
this.layergroupAffectedTables
|
||||||
|
)
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -220,17 +232,25 @@ function checkCreateLayergroup () {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTemplate (templateMaps, pgConnection, metadataBackend, userLimitsApi, mapConfigAdapter) {
|
function getTemplate (
|
||||||
|
templateMaps,
|
||||||
|
pgConnection,
|
||||||
|
metadataBackend,
|
||||||
|
userLimitsApi,
|
||||||
|
mapConfigAdapter,
|
||||||
|
affectedTablesCache
|
||||||
|
) {
|
||||||
return function getTemplateMiddleware (req, res, next) {
|
return function getTemplateMiddleware (req, res, next) {
|
||||||
const templateParams = req.body;
|
const templateParams = req.body;
|
||||||
const { user } = res.locals;
|
const { user } = res.locals;
|
||||||
|
|
||||||
const mapconfigProvider = new NamedMapMapConfigProvider(
|
const mapConfigProvider = new NamedMapMapConfigProvider(
|
||||||
templateMaps,
|
templateMaps,
|
||||||
pgConnection,
|
pgConnection,
|
||||||
metadataBackend,
|
metadataBackend,
|
||||||
userLimitsApi,
|
userLimitsApi,
|
||||||
mapConfigAdapter,
|
mapConfigAdapter,
|
||||||
|
affectedTablesCache,
|
||||||
user,
|
user,
|
||||||
req.params.template_id,
|
req.params.template_id,
|
||||||
templateParams,
|
templateParams,
|
||||||
@ -238,15 +258,15 @@ function getTemplate (templateMaps, pgConnection, metadataBackend, userLimitsApi
|
|||||||
res.locals
|
res.locals
|
||||||
);
|
);
|
||||||
|
|
||||||
mapconfigProvider.getMapConfig((err, mapconfig, rendererParams) => {
|
mapConfigProvider.getMapConfig((err, mapConfig, rendererParams) => {
|
||||||
req.profiler.done('named.getMapConfig');
|
req.profiler.done('named.getMapConfig');
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
res.locals.mapconfig = mapconfig;
|
res.locals.mapConfig = mapConfig;
|
||||||
res.locals.rendererParams = rendererParams;
|
res.locals.rendererParams = rendererParams;
|
||||||
res.locals.mapconfigProvider = mapconfigProvider;
|
res.locals.mapConfigProvider = mapConfigProvider;
|
||||||
|
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
@ -289,38 +309,51 @@ function prepareAdapterMapConfig (mapConfigAdapter) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function createLayergroup (mapBackend, userLimitsApi) {
|
function createLayergroup (mapBackend, userLimitsApi, pgConnection, affectedTablesCache) {
|
||||||
return function createLayergroupMiddleware (req, res, next) {
|
return function createLayergroupMiddleware (req, res, next) {
|
||||||
const requestMapConfig = req.body;
|
const requestMapConfig = req.body;
|
||||||
const { context, user } = res.locals;
|
const { context, user } = res.locals;
|
||||||
const datasource = context.datasource || Datasource.EmptyDatasource();
|
const datasource = context.datasource || Datasource.EmptyDatasource();
|
||||||
const mapconfig = new MapConfig(requestMapConfig, datasource);
|
const mapConfig = new MapConfig(requestMapConfig, datasource);
|
||||||
const mapconfigProvider =
|
const mapConfigProvider = new CreateLayergroupMapConfigProvider(
|
||||||
new CreateLayergroupMapConfigProvider(mapconfig, user, userLimitsApi, res.locals);
|
mapConfig,
|
||||||
|
user,
|
||||||
|
userLimitsApi,
|
||||||
|
pgConnection,
|
||||||
|
affectedTablesCache,
|
||||||
|
res.locals
|
||||||
|
);
|
||||||
|
|
||||||
res.locals.mapconfig = mapconfig;
|
res.locals.mapConfig = mapConfig;
|
||||||
res.locals.analysesResults = context.analysesResults;
|
res.locals.analysesResults = context.analysesResults;
|
||||||
|
|
||||||
mapBackend.createLayergroup(mapconfig, res.locals, mapconfigProvider, (err, layergroup) => {
|
mapBackend.createLayergroup(mapConfig, res.locals, mapConfigProvider, (err, layergroup) => {
|
||||||
req.profiler.done('createLayergroup');
|
req.profiler.done('createLayergroup');
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
res.body = layergroup;
|
res.body = layergroup;
|
||||||
|
res.locals.mapConfigProvider = mapConfigProvider;
|
||||||
|
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function instantiateLayergroup (mapBackend, userLimitsApi) {
|
function instantiateLayergroup (mapBackend, userLimitsApi, pgConnection, affectedTablesCache) {
|
||||||
return function instantiateLayergroupMiddleware (req, res, next) {
|
return function instantiateLayergroupMiddleware (req, res, next) {
|
||||||
const { user, mapconfig, rendererParams } = res.locals;
|
const { user, mapConfig, rendererParams } = res.locals;
|
||||||
const mapconfigProvider =
|
const mapConfigProvider = new CreateLayergroupMapConfigProvider(
|
||||||
new CreateLayergroupMapConfigProvider(mapconfig, user, userLimitsApi, rendererParams);
|
mapConfig,
|
||||||
|
user,
|
||||||
|
userLimitsApi,
|
||||||
|
pgConnection,
|
||||||
|
affectedTablesCache,
|
||||||
|
rendererParams
|
||||||
|
);
|
||||||
|
|
||||||
mapBackend.createLayergroup(mapconfig, rendererParams, mapconfigProvider, (err, layergroup) => {
|
mapBackend.createLayergroup(mapConfig, rendererParams, mapConfigProvider, (err, layergroup) => {
|
||||||
req.profiler.done('createLayergroup');
|
req.profiler.done('createLayergroup');
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
@ -328,12 +361,11 @@ function instantiateLayergroup (mapBackend, userLimitsApi) {
|
|||||||
|
|
||||||
res.body = layergroup;
|
res.body = layergroup;
|
||||||
|
|
||||||
const { mapconfigProvider } = res.locals;
|
const { mapConfigProvider } = res.locals;
|
||||||
|
|
||||||
res.locals.analysesResults = mapconfigProvider.analysesResults;
|
res.locals.analysesResults = mapConfigProvider.analysesResults;
|
||||||
res.locals.template = mapconfigProvider.template;
|
res.locals.template = mapConfigProvider.template;
|
||||||
res.locals.templateName = mapconfigProvider.getTemplateName();
|
res.locals.context = mapConfigProvider.context;
|
||||||
res.locals.context = mapconfigProvider.context;
|
|
||||||
|
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
@ -342,10 +374,10 @@ function instantiateLayergroup (mapBackend, userLimitsApi) {
|
|||||||
|
|
||||||
function incrementMapViewCount (metadataBackend) {
|
function incrementMapViewCount (metadataBackend) {
|
||||||
return function incrementMapViewCountMiddleware(req, res, next) {
|
return function incrementMapViewCountMiddleware(req, res, next) {
|
||||||
const { mapconfig, user } = res.locals;
|
const { mapConfig, user } = res.locals;
|
||||||
|
|
||||||
// Error won't blow up, just be logged.
|
// Error won't blow up, just be logged.
|
||||||
metadataBackend.incMapviewCount(user, mapconfig.obj().stat_tag, (err) => {
|
metadataBackend.incMapviewCount(user, mapConfig.obj().stat_tag, (err) => {
|
||||||
req.profiler.done('incMapviewCount');
|
req.profiler.done('incMapviewCount');
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -370,98 +402,33 @@ function augmentLayergroupData () {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAffectedTables (pgConnection, layergroupAffectedTables) {
|
function setLastUpdatedTimeToLayergroup () {
|
||||||
return function getAffectedTablesMiddleware (req, res, next) {
|
return function setLastUpdatedTimeToLayergroupMiddleware (req, res, next) {
|
||||||
const { dbname, user, mapconfig } = res.locals;
|
const { mapConfigProvider, analysesResults } = res.locals;
|
||||||
const layergroup = res.body;
|
const layergroup = res.body;
|
||||||
|
|
||||||
pgConnection.getConnection(user, (err, connection) => {
|
mapConfigProvider.getAffectedTables((err, affectedTables) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
const sql = [];
|
if (!affectedTables) {
|
||||||
mapconfig.getLayers().forEach(function(layer) {
|
return next();
|
||||||
sql.push(layer.options.sql);
|
}
|
||||||
if (layer.options.affected_tables) {
|
|
||||||
layer.options.affected_tables.map(function(table) {
|
|
||||||
sql.push('SELECT * FROM ' + table + ' LIMIT 0');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
QueryTables.getAffectedTablesFromQuery(connection, sql.join(';'), (err, affectedTables) => {
|
var lastUpdateTime = affectedTables.getLastUpdatedAt();
|
||||||
req.profiler.done('getAffectedTablesFromQuery');
|
|
||||||
if (err) {
|
|
||||||
return next(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
// feed affected tables cache so it can be reused from, for instance, layergroup controller
|
lastUpdateTime = getLastUpdatedTime(analysesResults, lastUpdateTime) || lastUpdateTime;
|
||||||
layergroupAffectedTables.set(dbname, layergroup.layergroupId, affectedTables);
|
|
||||||
|
|
||||||
res.locals.affectedTables = affectedTables;
|
// last update for layergroup cache buster
|
||||||
|
layergroup.layergroupid = layergroup.layergroupid + ':' + lastUpdateTime;
|
||||||
|
layergroup.last_updated = new Date(lastUpdateTime).toISOString();
|
||||||
|
|
||||||
next();
|
next();
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function setCacheChannelHeader () {
|
|
||||||
return function setCacheChannelHeaderMiddleware (req, res, next) {
|
|
||||||
const { affectedTables } = res.locals;
|
|
||||||
|
|
||||||
if (req.method === 'GET') {
|
|
||||||
res.set('X-Cache-Channel', affectedTables.getCacheChannel());
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function setSurrogateKeyHeader (surrogateKeysCache) {
|
|
||||||
return function setSurrogateKeyHeaderMiddleware(req, res, next) {
|
|
||||||
const { affectedTables, user, templateName } = res.locals;
|
|
||||||
|
|
||||||
if (req.method === 'GET' && affectedTables.tables && affectedTables.tables.length > 0) {
|
|
||||||
surrogateKeysCache.tag(res, affectedTables);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (templateName) {
|
|
||||||
surrogateKeysCache.tag(res, new NamedMapsCacheEntry(user, templateName));
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function setLastModified () {
|
|
||||||
return function setLastModifiedMiddleware (req, res, next) {
|
|
||||||
if (req.method === 'GET') {
|
|
||||||
res.set('Last-Modified', (new Date()).toUTCString());
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function setLastUpdatedTimeToLayergroup () {
|
|
||||||
return function setLastUpdatedTimeToLayergroupMiddleware (req, res, next) {
|
|
||||||
const { affectedTables, analysesResults } = res.locals;
|
|
||||||
const layergroup = res.body;
|
|
||||||
|
|
||||||
var lastUpdateTime = affectedTables.getLastUpdatedAt();
|
|
||||||
|
|
||||||
lastUpdateTime = getLastUpdatedTime(analysesResults, lastUpdateTime) || lastUpdateTime;
|
|
||||||
|
|
||||||
// last update for layergroup cache buster
|
|
||||||
layergroup.layergroupid = layergroup.layergroupid + ':' + lastUpdateTime;
|
|
||||||
layergroup.last_updated = new Date(lastUpdateTime).toISOString();
|
|
||||||
|
|
||||||
next();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getLastUpdatedTime(analysesResults, lastUpdateTime) {
|
function getLastUpdatedTime(analysesResults, lastUpdateTime) {
|
||||||
if (!Array.isArray(analysesResults)) {
|
if (!Array.isArray(analysesResults)) {
|
||||||
return lastUpdateTime;
|
return lastUpdateTime;
|
||||||
@ -475,20 +442,9 @@ function getLastUpdatedTime(analysesResults, lastUpdateTime) {
|
|||||||
}, lastUpdateTime);
|
}, lastUpdateTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setCacheControl () {
|
|
||||||
return function setCacheControlMiddleware (req, res, next) {
|
|
||||||
if (req.method === 'GET') {
|
|
||||||
var ttl = global.environment.varnish.layergroupTtl || 86400;
|
|
||||||
res.set('Cache-Control', 'public,max-age='+ttl+',must-revalidate');
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function setLayerStats (pgConnection, statsBackend) {
|
function setLayerStats (pgConnection, statsBackend) {
|
||||||
return function setLayerStatsMiddleware(req, res, next) {
|
return function setLayerStatsMiddleware(req, res, next) {
|
||||||
const { user, mapconfig } = res.locals;
|
const { user, mapConfig } = res.locals;
|
||||||
const layergroup = res.body;
|
const layergroup = res.body;
|
||||||
|
|
||||||
pgConnection.getConnection(user, (err, connection) => {
|
pgConnection.getConnection(user, (err, connection) => {
|
||||||
@ -496,7 +452,7 @@ function setLayerStats (pgConnection, statsBackend) {
|
|||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
statsBackend.getStats(mapconfig, connection, function(err, layersStats) {
|
statsBackend.getStats(mapConfig, connection, function(err, layersStats) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
@ -531,10 +487,10 @@ function setLayergroupIdHeader (templateMaps, useTemplateHash) {
|
|||||||
|
|
||||||
function setDataviewsAndWidgetsUrlsToLayergroupMetadata (layergroupMetadata) {
|
function setDataviewsAndWidgetsUrlsToLayergroupMetadata (layergroupMetadata) {
|
||||||
return function setDataviewsAndWidgetsUrlsToLayergroupMetadataMiddleware (req, res, next) {
|
return function setDataviewsAndWidgetsUrlsToLayergroupMetadataMiddleware (req, res, next) {
|
||||||
const { user, mapconfig } = res.locals;
|
const { user, mapConfig } = res.locals;
|
||||||
const layergroup = res.body;
|
const layergroup = res.body;
|
||||||
|
|
||||||
layergroupMetadata.addDataviewsAndWidgetsUrls(user, layergroup, mapconfig.obj());
|
layergroupMetadata.addDataviewsAndWidgetsUrls(user, layergroup, mapConfig.obj());
|
||||||
|
|
||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
@ -553,10 +509,10 @@ function setAnalysesMetadataToLayergroup (layergroupMetadata, includeQuery) {
|
|||||||
|
|
||||||
function setTurboCartoMetadataToLayergroup (layergroupMetadata) {
|
function setTurboCartoMetadataToLayergroup (layergroupMetadata) {
|
||||||
return function setTurboCartoMetadataToLayergroupMiddleware (req, res, next) {
|
return function setTurboCartoMetadataToLayergroupMiddleware (req, res, next) {
|
||||||
const { mapconfig, context } = res.locals;
|
const { mapConfig, context } = res.locals;
|
||||||
const layergroup = res.body;
|
const layergroup = res.body;
|
||||||
|
|
||||||
layergroupMetadata.addTurboCartoContextMetadata(layergroup, mapconfig.obj(), context);
|
layergroupMetadata.addTurboCartoContextMetadata(layergroup, mapConfig.obj(), context);
|
||||||
|
|
||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
@ -564,10 +520,10 @@ function setTurboCartoMetadataToLayergroup (layergroupMetadata) {
|
|||||||
|
|
||||||
function setAggregationMetadataToLayergroup (layergroupMetadata) {
|
function setAggregationMetadataToLayergroup (layergroupMetadata) {
|
||||||
return function setAggregationMetadataToLayergroupMiddleware (req, res, next) {
|
return function setAggregationMetadataToLayergroupMiddleware (req, res, next) {
|
||||||
const { mapconfig, context } = res.locals;
|
const { mapConfig, context } = res.locals;
|
||||||
const layergroup = res.body;
|
const layergroup = res.body;
|
||||||
|
|
||||||
layergroupMetadata.addAggregationContextMetadata(layergroup, mapconfig.obj(), context);
|
layergroupMetadata.addAggregationContextMetadata(layergroup, mapConfig.obj(), context);
|
||||||
|
|
||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
@ -575,10 +531,10 @@ function setAggregationMetadataToLayergroup (layergroupMetadata) {
|
|||||||
|
|
||||||
function setTilejsonMetadataToLayergroup (layergroupMetadata) {
|
function setTilejsonMetadataToLayergroup (layergroupMetadata) {
|
||||||
return function augmentLayergroupTilejsonMiddleware (req, res, next) {
|
return function augmentLayergroupTilejsonMiddleware (req, res, next) {
|
||||||
const { user, mapconfig } = res.locals;
|
const { user, mapConfig } = res.locals;
|
||||||
const layergroup = res.body;
|
const layergroup = res.body;
|
||||||
|
|
||||||
layergroupMetadata.addTileJsonMetadata(layergroup, user, mapconfig);
|
layergroupMetadata.addTileJsonMetadata(layergroup, user, mapConfig);
|
||||||
|
|
||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
@ -589,10 +545,10 @@ function augmentError (options) {
|
|||||||
|
|
||||||
return function augmentErrorMiddleware (err, req, res, next) {
|
return function augmentErrorMiddleware (err, req, res, next) {
|
||||||
req.profiler.done('error');
|
req.profiler.done('error');
|
||||||
const { mapconfig } = res.locals;
|
const { mapConfig } = res.locals;
|
||||||
|
|
||||||
if (addContext) {
|
if (addContext) {
|
||||||
err = Number.isFinite(err.layerIndex) ? populateError(err, mapconfig) : err;
|
err = Number.isFinite(err.layerIndex) ? populateError(err, mapConfig) : err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err.label = label;
|
err.label = label;
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
const NamedMapsCacheEntry = require('../cache/model/named_maps_entry');
|
|
||||||
const cors = require('../middleware/cors');
|
const cors = require('../middleware/cors');
|
||||||
const user = require('../middleware/user');
|
const user = require('../middleware/user');
|
||||||
const locals = require('../middleware/locals');
|
const locals = require('../middleware/locals');
|
||||||
@ -7,6 +6,10 @@ const layergroupToken = require('../middleware/layergroup-token');
|
|||||||
const credentials = require('../middleware/credentials');
|
const credentials = require('../middleware/credentials');
|
||||||
const dbConnSetup = require('../middleware/db-conn-setup');
|
const dbConnSetup = require('../middleware/db-conn-setup');
|
||||||
const authorize = require('../middleware/authorize');
|
const authorize = require('../middleware/authorize');
|
||||||
|
const cacheControlHeader = require('../middleware/cache-control-header');
|
||||||
|
const cacheChannelHeader = require('../middleware/cache-channel-header');
|
||||||
|
const surrogateKeyHeader = require('../middleware/surrogate-key-header');
|
||||||
|
const lastModifiedHeader = require('../middleware/last-modified-header');
|
||||||
const sendResponse = require('../middleware/send-response');
|
const sendResponse = require('../middleware/send-response');
|
||||||
const vectorError = require('../middleware/vector-error');
|
const vectorError = require('../middleware/vector-error');
|
||||||
const rateLimit = require('../middleware/rate-limit');
|
const rateLimit = require('../middleware/rate-limit');
|
||||||
@ -28,8 +31,8 @@ function getRequestParams(locals) {
|
|||||||
const params = Object.assign({}, locals);
|
const params = Object.assign({}, locals);
|
||||||
|
|
||||||
delete params.template;
|
delete params.template;
|
||||||
delete params.affectedTablesAndLastUpdate;
|
delete params.affectedTables;
|
||||||
delete params.namedMapProvider;
|
delete params.mapConfigProvider;
|
||||||
delete params.allowedQueryParams;
|
delete params.allowedQueryParams;
|
||||||
|
|
||||||
return params;
|
return params;
|
||||||
@ -77,16 +80,15 @@ NamedMapsController.prototype.register = function(app) {
|
|||||||
namedMapProviderCache: this.namedMapProviderCache,
|
namedMapProviderCache: this.namedMapProviderCache,
|
||||||
label: 'NAMED_MAP_TILE'
|
label: 'NAMED_MAP_TILE'
|
||||||
}),
|
}),
|
||||||
getAffectedTables(),
|
|
||||||
getTile({
|
getTile({
|
||||||
tileBackend: this.tileBackend,
|
tileBackend: this.tileBackend,
|
||||||
label: 'NAMED_MAP_TILE'
|
label: 'NAMED_MAP_TILE'
|
||||||
}),
|
}),
|
||||||
setSurrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
|
|
||||||
setCacheChannelHeader(),
|
|
||||||
setLastModifiedHeader(),
|
|
||||||
setCacheControlHeader(),
|
|
||||||
setContentTypeHeader(),
|
setContentTypeHeader(),
|
||||||
|
cacheControlHeader(),
|
||||||
|
cacheChannelHeader(),
|
||||||
|
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
|
||||||
|
lastModifiedHeader(),
|
||||||
sendResponse(),
|
sendResponse(),
|
||||||
vectorError()
|
vectorError()
|
||||||
);
|
);
|
||||||
@ -106,7 +108,6 @@ NamedMapsController.prototype.register = function(app) {
|
|||||||
namedMapProviderCache: this.namedMapProviderCache,
|
namedMapProviderCache: this.namedMapProviderCache,
|
||||||
label: 'STATIC_VIZ_MAP', forcedFormat: 'png'
|
label: 'STATIC_VIZ_MAP', forcedFormat: 'png'
|
||||||
}),
|
}),
|
||||||
getAffectedTables(),
|
|
||||||
getTemplate({ label: 'STATIC_VIZ_MAP' }),
|
getTemplate({ label: 'STATIC_VIZ_MAP' }),
|
||||||
prepareLayerFilterFromPreviewLayers({
|
prepareLayerFilterFromPreviewLayers({
|
||||||
namedMapProviderCache: this.namedMapProviderCache,
|
namedMapProviderCache: this.namedMapProviderCache,
|
||||||
@ -114,12 +115,12 @@ NamedMapsController.prototype.register = function(app) {
|
|||||||
}),
|
}),
|
||||||
getStaticImageOptions({ tablesExtentApi: this.tablesExtentApi }),
|
getStaticImageOptions({ tablesExtentApi: this.tablesExtentApi }),
|
||||||
getImage({ previewBackend: this.previewBackend, label: 'STATIC_VIZ_MAP' }),
|
getImage({ previewBackend: this.previewBackend, label: 'STATIC_VIZ_MAP' }),
|
||||||
incrementMapViews({ metadataBackend: this.metadataBackend }),
|
|
||||||
setSurrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
|
|
||||||
setCacheChannelHeader(),
|
|
||||||
setLastModifiedHeader(),
|
|
||||||
setCacheControlHeader(),
|
|
||||||
setContentTypeHeader(),
|
setContentTypeHeader(),
|
||||||
|
incrementMapViews({ metadataBackend: this.metadataBackend }),
|
||||||
|
cacheControlHeader(),
|
||||||
|
cacheChannelHeader(),
|
||||||
|
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
|
||||||
|
lastModifiedHeader(),
|
||||||
sendResponse()
|
sendResponse()
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -143,25 +144,7 @@ function getNamedMapProvider ({ namedMapProviderCache, label, forcedFormat = nul
|
|||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
res.locals.namedMapProvider = namedMapProvider;
|
res.locals.mapConfigProvider = namedMapProvider;
|
||||||
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAffectedTables () {
|
|
||||||
return function getAffectedTables (req, res, next) {
|
|
||||||
const { namedMapProvider } = res.locals;
|
|
||||||
|
|
||||||
namedMapProvider.getAffectedTablesAndLastUpdatedTime((err, affectedTablesAndLastUpdate) => {
|
|
||||||
req.profiler.done('affectedTables');
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
return next(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
res.locals.affectedTablesAndLastUpdate = affectedTablesAndLastUpdate;
|
|
||||||
|
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
@ -170,9 +153,9 @@ function getAffectedTables () {
|
|||||||
|
|
||||||
function getTemplate ({ label }) {
|
function getTemplate ({ label }) {
|
||||||
return function getTemplateMiddleware (req, res, next) {
|
return function getTemplateMiddleware (req, res, next) {
|
||||||
const { namedMapProvider } = res.locals;
|
const { mapConfigProvider } = res.locals;
|
||||||
|
|
||||||
namedMapProvider.getTemplate((err, template) => {
|
mapConfigProvider.getTemplate((err, template) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
err.label = label;
|
err.label = label;
|
||||||
return next(err);
|
return next(err);
|
||||||
@ -220,7 +203,7 @@ function prepareLayerFilterFromPreviewLayers ({ namedMapProviderCache, label })
|
|||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
res.locals.namedMapProvider = provider;
|
res.locals.mapConfigProvider = provider;
|
||||||
|
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
@ -229,9 +212,9 @@ function prepareLayerFilterFromPreviewLayers ({ namedMapProviderCache, label })
|
|||||||
|
|
||||||
function getTile ({ tileBackend, label }) {
|
function getTile ({ tileBackend, label }) {
|
||||||
return function getTileMiddleware (req, res, next) {
|
return function getTileMiddleware (req, res, next) {
|
||||||
const { namedMapProvider, format } = res.locals;
|
const { mapConfigProvider, format } = res.locals;
|
||||||
|
|
||||||
tileBackend.getTile(namedMapProvider, req.params, (err, tile, headers, stats) => {
|
tileBackend.getTile(mapConfigProvider, req.params, (err, tile, headers, stats) => {
|
||||||
req.profiler.add(stats);
|
req.profiler.add(stats);
|
||||||
req.profiler.done('render-' + format);
|
req.profiler.done('render-' + format);
|
||||||
|
|
||||||
@ -253,7 +236,7 @@ function getTile ({ tileBackend, label }) {
|
|||||||
|
|
||||||
function getStaticImageOptions ({ tablesExtentApi }) {
|
function getStaticImageOptions ({ tablesExtentApi }) {
|
||||||
return function getStaticImageOptionsMiddleware(req, res, next) {
|
return function getStaticImageOptionsMiddleware(req, res, next) {
|
||||||
const { user, namedMapProvider, template } = res.locals;
|
const { user, mapConfigProvider, template } = res.locals;
|
||||||
|
|
||||||
const imageOpts = getImageOptions(res.locals, template);
|
const imageOpts = getImageOptions(res.locals, template);
|
||||||
|
|
||||||
@ -264,18 +247,18 @@ function getStaticImageOptions ({ tablesExtentApi }) {
|
|||||||
|
|
||||||
res.locals.imageOpts = DEFAULT_ZOOM_CENTER;
|
res.locals.imageOpts = DEFAULT_ZOOM_CENTER;
|
||||||
|
|
||||||
namedMapProvider.getAffectedTablesAndLastUpdatedTime((err, affectedTablesAndLastUpdate) => {
|
mapConfigProvider.getAffectedTables((err, affectedTables) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
var affectedTables = affectedTablesAndLastUpdate.tables || [];
|
var tables = affectedTables.tables || [];
|
||||||
|
|
||||||
if (affectedTables.length === 0) {
|
if (tables.length === 0) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
tablesExtentApi.getBounds(user, affectedTables, (err, bounds) => {
|
tablesExtentApi.getBounds(user, tables, (err, bounds) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
@ -355,7 +338,7 @@ function getImageOptionsFromBoundingBox (bbox = '') {
|
|||||||
|
|
||||||
function getImage({ previewBackend, label }) {
|
function getImage({ previewBackend, label }) {
|
||||||
return function getImageMiddleware (req, res, next) {
|
return function getImageMiddleware (req, res, next) {
|
||||||
const { imageOpts, namedMapProvider } = res.locals;
|
const { imageOpts, mapConfigProvider } = res.locals;
|
||||||
const { zoom, center, bounds } = imageOpts;
|
const { zoom, center, bounds } = imageOpts;
|
||||||
|
|
||||||
let { width, height } = req.params;
|
let { width, height } = req.params;
|
||||||
@ -366,7 +349,7 @@ function getImage({ previewBackend, label }) {
|
|||||||
const format = req.params.format === 'jpg' ? 'jpeg' : 'png';
|
const format = req.params.format === 'jpg' ? 'jpeg' : 'png';
|
||||||
|
|
||||||
if (zoom !== undefined && center) {
|
if (zoom !== undefined && center) {
|
||||||
return previewBackend.getImage(namedMapProvider, format, width, height, zoom, center,
|
return previewBackend.getImage(mapConfigProvider, format, width, height, zoom, center,
|
||||||
(err, image, headers, stats) => {
|
(err, image, headers, stats) => {
|
||||||
req.profiler.add(stats);
|
req.profiler.add(stats);
|
||||||
|
|
||||||
@ -385,7 +368,7 @@ function getImage({ previewBackend, label }) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
previewBackend.getImage(namedMapProvider, format, width, height, bounds, (err, image, headers, stats) => {
|
previewBackend.getImage(mapConfigProvider, format, width, height, bounds, (err, image, headers, stats) => {
|
||||||
req.profiler.add(stats);
|
req.profiler.add(stats);
|
||||||
req.profiler.done('render-' + format);
|
req.profiler.done('render-' + format);
|
||||||
|
|
||||||
@ -405,15 +388,23 @@ function getImage({ previewBackend, label }) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setContentTypeHeader () {
|
||||||
|
return function setContentTypeHeaderMiddleware(req, res, next) {
|
||||||
|
res.set('Content-Type', res.get('content-type') || res.get('Content-Type') || 'image/png');
|
||||||
|
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function incrementMapViewsError (ctx) {
|
function incrementMapViewsError (ctx) {
|
||||||
return `ERROR: failed to increment mapview count for user '${ctx.user}': ${ctx.err}`;
|
return `ERROR: failed to increment mapview count for user '${ctx.user}': ${ctx.err}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function incrementMapViews ({ metadataBackend }) {
|
function incrementMapViews ({ metadataBackend }) {
|
||||||
return function incrementMapViewsMiddleware(req, res, next) {
|
return function incrementMapViewsMiddleware(req, res, next) {
|
||||||
const { user, namedMapProvider } = res.locals;
|
const { user, mapConfigProvider } = res.locals;
|
||||||
|
|
||||||
namedMapProvider.getMapConfig((err, mapConfig) => {
|
mapConfigProvider.getMapConfig((err, mapConfig) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
global.logger.log(incrementMapViewsError({ user, err }));
|
global.logger.log(incrementMapViewsError({ user, err }));
|
||||||
return next();
|
return next();
|
||||||
@ -461,73 +452,3 @@ function templateBounds(view) {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSurrogateKeyHeader ({ surrogateKeysCache }) {
|
|
||||||
return function setSurrogateKeyHeaderMiddleware(req, res, next) {
|
|
||||||
const { user, namedMapProvider, affectedTablesAndLastUpdate } = res.locals;
|
|
||||||
|
|
||||||
surrogateKeysCache.tag(res, new NamedMapsCacheEntry(user, namedMapProvider.getTemplateName()));
|
|
||||||
if (!affectedTablesAndLastUpdate || !!affectedTablesAndLastUpdate.tables) {
|
|
||||||
if (affectedTablesAndLastUpdate.tables.length > 0) {
|
|
||||||
surrogateKeysCache.tag(res, affectedTablesAndLastUpdate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function setCacheChannelHeader () {
|
|
||||||
return function setCacheChannelHeaderMiddleware (req, res, next) {
|
|
||||||
const { affectedTablesAndLastUpdate } = res.locals;
|
|
||||||
|
|
||||||
if (!affectedTablesAndLastUpdate || !!affectedTablesAndLastUpdate.tables) {
|
|
||||||
res.set('X-Cache-Channel', affectedTablesAndLastUpdate.getCacheChannel());
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function setLastModifiedHeader () {
|
|
||||||
return function setLastModifiedHeaderMiddleware(req, res, next) {
|
|
||||||
const { affectedTablesAndLastUpdate } = res.locals;
|
|
||||||
|
|
||||||
if (!affectedTablesAndLastUpdate || !!affectedTablesAndLastUpdate.tables) {
|
|
||||||
var lastModifiedDate;
|
|
||||||
if (Number.isFinite(affectedTablesAndLastUpdate.lastUpdatedTime)) {
|
|
||||||
lastModifiedDate = new Date(affectedTablesAndLastUpdate.getLastUpdatedAt());
|
|
||||||
} else {
|
|
||||||
lastModifiedDate = new Date();
|
|
||||||
}
|
|
||||||
|
|
||||||
res.set('Last-Modified', lastModifiedDate.toUTCString());
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function setCacheControlHeader () {
|
|
||||||
return function setCacheControlHeaderMiddleware(req, res, next) {
|
|
||||||
const { affectedTablesAndLastUpdate } = res.locals;
|
|
||||||
|
|
||||||
res.set('Cache-Control', 'public,max-age=7200,must-revalidate');
|
|
||||||
|
|
||||||
if (!affectedTablesAndLastUpdate || !!affectedTablesAndLastUpdate.tables) {
|
|
||||||
// we increase cache control as we can invalidate it
|
|
||||||
res.set('Cache-Control', 'public,max-age=31536000');
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function setContentTypeHeader () {
|
|
||||||
return function setContentTypeHeaderMiddleware(req, res, next) {
|
|
||||||
|
|
||||||
res.set('Content-Type', res.get('content-type') || res.get('Content-Type') || 'image/png');
|
|
||||||
|
|
||||||
next();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
24
lib/cartodb/middleware/cache-channel-header.js
Normal file
24
lib/cartodb/middleware/cache-channel-header.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
module.exports = function setCacheChannelHeader () {
|
||||||
|
return function setCacheChannelHeaderMiddleware (req, res, next) {
|
||||||
|
if (req.method !== 'GET') {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
const { mapConfigProvider } = res.locals;
|
||||||
|
|
||||||
|
mapConfigProvider.getAffectedTables((err, affectedTables) => {
|
||||||
|
if (err) {
|
||||||
|
global.logger.warn('ERROR generating Cache Channel Header:', err);
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!affectedTables) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
res.set('X-Cache-Channel', affectedTables.getCacheChannel());
|
||||||
|
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
19
lib/cartodb/middleware/cache-control-header.js
Normal file
19
lib/cartodb/middleware/cache-control-header.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
const ONE_YEAR_IN_SECONDS = 60 * 60 * 24 * 365;
|
||||||
|
|
||||||
|
module.exports = function setCacheControlHeader ({ ttl = ONE_YEAR_IN_SECONDS, revalidate = false } = {}) {
|
||||||
|
return function setCacheControlHeaderMiddleware (req, res, next) {
|
||||||
|
if (req.method !== 'GET') {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
const directives = [ 'public', `max-age=${ttl}` ];
|
||||||
|
|
||||||
|
if (revalidate) {
|
||||||
|
directives.push('must-revalidate');
|
||||||
|
}
|
||||||
|
|
||||||
|
res.set('Cache-Control', directives.join(','));
|
||||||
|
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
};
|
45
lib/cartodb/middleware/last-modified-header.js
Normal file
45
lib/cartodb/middleware/last-modified-header.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
module.exports = function setLastModifiedHeader ({ now = false } = {}) {
|
||||||
|
return function setLastModifiedHeaderMiddleware(req, res, next) {
|
||||||
|
if (req.method !== 'GET') {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
const { mapConfigProvider, cache_buster } = res.locals;
|
||||||
|
|
||||||
|
if (cache_buster) {
|
||||||
|
const cacheBuster = parseInt(cache_buster, 10);
|
||||||
|
const lastModifiedDate = Number.isFinite(cacheBuster) ? new Date(cacheBuster) : new Date();
|
||||||
|
|
||||||
|
res.set('Last-Modified', lastModifiedDate.toUTCString());
|
||||||
|
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
// REVIEW: to keep 100% compatibility with maps controller
|
||||||
|
if (now) {
|
||||||
|
res.set('Last-Modified', new Date().toUTCString());
|
||||||
|
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
mapConfigProvider.getAffectedTables((err, affectedTables) => {
|
||||||
|
if (err) {
|
||||||
|
global.logger.warn('ERROR generating Last Modified Header:', err);
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!affectedTables) {
|
||||||
|
res.set('Last-Modified', new Date().toUTCString());
|
||||||
|
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastUpdatedAt = affectedTables.getLastUpdatedAt();
|
||||||
|
const lastModifiedDate = Number.isFinite(lastUpdatedAt) ? new Date(lastUpdatedAt) : new Date();
|
||||||
|
|
||||||
|
res.set('Last-Modified', lastModifiedDate.toUTCString());
|
||||||
|
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
31
lib/cartodb/middleware/surrogate-key-header.js
Normal file
31
lib/cartodb/middleware/surrogate-key-header.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
const NamedMapsCacheEntry = require('../cache/model/named_maps_entry');
|
||||||
|
const NamedMapMapConfigProvider = require('../models/mapconfig/provider/named-map-provider');
|
||||||
|
|
||||||
|
module.exports = function setSurrogateKeyHeader ({ surrogateKeysCache }) {
|
||||||
|
return function setSurrogateKeyHeaderMiddleware(req, res, next) {
|
||||||
|
const { user, mapConfigProvider } = res.locals;
|
||||||
|
|
||||||
|
if (mapConfigProvider instanceof NamedMapMapConfigProvider) {
|
||||||
|
surrogateKeysCache.tag(res, new NamedMapsCacheEntry(user, mapConfigProvider.getTemplateName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.method !== 'GET') {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
mapConfigProvider.getAffectedTables((err, affectedTables) => {
|
||||||
|
if (err) {
|
||||||
|
global.logger.warn('ERROR generating Surrogate Key Header:', err);
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!affectedTables || !affectedTables.tables || affectedTables.tables.length === 0) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
surrogateKeysCache.tag(res, affectedTables);
|
||||||
|
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
@ -2,6 +2,7 @@ var assert = require('assert');
|
|||||||
var step = require('step');
|
var step = require('step');
|
||||||
|
|
||||||
var MapStoreMapConfigProvider = require('./map-store-provider');
|
var MapStoreMapConfigProvider = require('./map-store-provider');
|
||||||
|
const QueryTables = require('cartodb-query-tables');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {MapConfig} mapConfig
|
* @param {MapConfig} mapConfig
|
||||||
@ -11,10 +12,13 @@ var MapStoreMapConfigProvider = require('./map-store-provider');
|
|||||||
* @constructor
|
* @constructor
|
||||||
* @type {CreateLayergroupMapConfigProvider}
|
* @type {CreateLayergroupMapConfigProvider}
|
||||||
*/
|
*/
|
||||||
function CreateLayergroupMapConfigProvider(mapConfig, user, userLimitsApi, params) {
|
|
||||||
|
function CreateLayergroupMapConfigProvider(mapConfig, user, userLimitsApi, pgConnection, affectedTablesCache, params) {
|
||||||
this.mapConfig = mapConfig;
|
this.mapConfig = mapConfig;
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.userLimitsApi = userLimitsApi;
|
this.userLimitsApi = userLimitsApi;
|
||||||
|
this.pgConnection = pgConnection;
|
||||||
|
this.affectedTablesCache = affectedTablesCache;
|
||||||
this.params = params;
|
this.params = params;
|
||||||
this.cacheBuster = params.cache_buster || 0;
|
this.cacheBuster = params.cache_buster || 0;
|
||||||
}
|
}
|
||||||
@ -23,7 +27,13 @@ module.exports = CreateLayergroupMapConfigProvider;
|
|||||||
|
|
||||||
CreateLayergroupMapConfigProvider.prototype.getMapConfig = function(callback) {
|
CreateLayergroupMapConfigProvider.prototype.getMapConfig = function(callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
if (this.mapConfig && this.params && this.context) {
|
||||||
|
return callback(null, this.mapConfig, this.params, this.context);
|
||||||
|
}
|
||||||
|
|
||||||
var context = {};
|
var context = {};
|
||||||
|
|
||||||
step(
|
step(
|
||||||
function prepareContextLimits() {
|
function prepareContextLimits() {
|
||||||
self.userLimitsApi.getRenderLimits(self.user, self.params.api_key, this);
|
self.userLimitsApi.getRenderLimits(self.user, self.params.api_key, this);
|
||||||
@ -31,6 +41,7 @@ CreateLayergroupMapConfigProvider.prototype.getMapConfig = function(callback) {
|
|||||||
function handleRenderLimits(err, renderLimits) {
|
function handleRenderLimits(err, renderLimits) {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
context.limits = renderLimits;
|
context.limits = renderLimits;
|
||||||
|
self.context = context;
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
function finish(err) {
|
function finish(err) {
|
||||||
@ -46,3 +57,52 @@ CreateLayergroupMapConfigProvider.prototype.getCacheBuster = MapStoreMapConfigPr
|
|||||||
CreateLayergroupMapConfigProvider.prototype.filter = MapStoreMapConfigProvider.prototype.filter;
|
CreateLayergroupMapConfigProvider.prototype.filter = MapStoreMapConfigProvider.prototype.filter;
|
||||||
|
|
||||||
CreateLayergroupMapConfigProvider.prototype.createKey = MapStoreMapConfigProvider.prototype.createKey;
|
CreateLayergroupMapConfigProvider.prototype.createKey = MapStoreMapConfigProvider.prototype.createKey;
|
||||||
|
|
||||||
|
CreateLayergroupMapConfigProvider.prototype.getAffectedTables = function (callback) {
|
||||||
|
this.getMapConfig((err, mapConfig) => {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { dbname } = this.params;
|
||||||
|
const token = mapConfig.id();
|
||||||
|
|
||||||
|
if (this.affectedTablesCache.hasAffectedTables(dbname, token)) {
|
||||||
|
const affectedTables = this.affectedTablesCache.get(dbname, token);
|
||||||
|
return callback(null, affectedTables);
|
||||||
|
}
|
||||||
|
|
||||||
|
const queries = [];
|
||||||
|
|
||||||
|
this.mapConfig.getLayers().forEach(layer => {
|
||||||
|
queries.push(layer.options.sql);
|
||||||
|
if (layer.options.affected_tables) {
|
||||||
|
layer.options.affected_tables.map(table => {
|
||||||
|
queries.push(`SELECT * FROM ${table} LIMIT 0`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const sql = queries.length ? queries.join(';') : null;
|
||||||
|
|
||||||
|
if (!sql) {
|
||||||
|
return callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pgConnection.getConnection(this.user, (err, connection) => {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryTables.getAffectedTablesFromQuery(connection, sql, (err, affectedTables) => {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.affectedTablesCache.set(dbname, token, affectedTables);
|
||||||
|
|
||||||
|
callback(null, affectedTables);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -2,6 +2,7 @@ var _ = require('underscore');
|
|||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var dot = require('dot');
|
var dot = require('dot');
|
||||||
var step = require('step');
|
var step = require('step');
|
||||||
|
const QueryTables = require('cartodb-query-tables');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {MapStore} mapStore
|
* @param {MapStore} mapStore
|
||||||
@ -11,20 +12,30 @@ var step = require('step');
|
|||||||
* @constructor
|
* @constructor
|
||||||
* @type {MapStoreMapConfigProvider}
|
* @type {MapStoreMapConfigProvider}
|
||||||
*/
|
*/
|
||||||
function MapStoreMapConfigProvider(mapStore, user, userLimitsApi, params) {
|
function MapStoreMapConfigProvider(mapStore, user, userLimitsApi, pgConnection, affectedTablesCache, params) {
|
||||||
this.mapStore = mapStore;
|
this.mapStore = mapStore;
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.userLimitsApi = userLimitsApi;
|
this.userLimitsApi = userLimitsApi;
|
||||||
this.params = params;
|
this.pgConnection = pgConnection;
|
||||||
|
this.affectedTablesCache = affectedTablesCache;
|
||||||
this.token = params.token;
|
this.token = params.token;
|
||||||
this.cacheBuster = params.cache_buster || 0;
|
this.cacheBuster = params.cache_buster || 0;
|
||||||
|
this.mapConfig = null;
|
||||||
|
this.params = params;
|
||||||
|
this.context = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = MapStoreMapConfigProvider;
|
module.exports = MapStoreMapConfigProvider;
|
||||||
|
|
||||||
MapStoreMapConfigProvider.prototype.getMapConfig = function(callback) {
|
MapStoreMapConfigProvider.prototype.getMapConfig = function(callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
if (this.mapConfig !== null) {
|
||||||
|
return callback(null, this.mapConfig, this.params, this.context);
|
||||||
|
}
|
||||||
|
|
||||||
var context = {};
|
var context = {};
|
||||||
|
|
||||||
step(
|
step(
|
||||||
function prepareContextLimits() {
|
function prepareContextLimits() {
|
||||||
self.userLimitsApi.getRenderLimits(self.user, self.params.api_key, this);
|
self.userLimitsApi.getRenderLimits(self.user, self.params.api_key, this);
|
||||||
@ -39,6 +50,8 @@ MapStoreMapConfigProvider.prototype.getMapConfig = function(callback) {
|
|||||||
self.mapStore.load(self.token, this);
|
self.mapStore.load(self.token, this);
|
||||||
},
|
},
|
||||||
function finish(err, mapConfig) {
|
function finish(err, mapConfig) {
|
||||||
|
self.mapConfig = mapConfig;
|
||||||
|
self.context = context;
|
||||||
return callback(err, mapConfig, self.params, context);
|
return callback(err, mapConfig, self.params, context);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -75,3 +88,53 @@ MapStoreMapConfigProvider.prototype.createKey = function(base) {
|
|||||||
});
|
});
|
||||||
return (base) ? baseKeyTpl(tplValues) : rendererKeyTpl(tplValues);
|
return (base) ? baseKeyTpl(tplValues) : rendererKeyTpl(tplValues);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
MapStoreMapConfigProvider.prototype.getAffectedTables = function(callback) {
|
||||||
|
this.getMapConfig((err, mapConfig) => {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { dbname } = this.params;
|
||||||
|
const token = mapConfig.id();
|
||||||
|
|
||||||
|
if (this.affectedTablesCache.hasAffectedTables(dbname, token)) {
|
||||||
|
const affectedTables = this.affectedTablesCache.get(dbname, token);
|
||||||
|
|
||||||
|
return callback(null, affectedTables);
|
||||||
|
}
|
||||||
|
|
||||||
|
const queries = [];
|
||||||
|
|
||||||
|
mapConfig.getLayers().forEach(layer => {
|
||||||
|
queries.push(layer.options.sql);
|
||||||
|
if (layer.options.affected_tables) {
|
||||||
|
layer.options.affected_tables.map(table => {
|
||||||
|
queries.push(`SELECT * FROM ${table} LIMIT 0`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const sql = queries.length ? queries.join(';') : null;
|
||||||
|
|
||||||
|
if (!sql) {
|
||||||
|
return callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pgConnection.getConnection(this.user, (err, connection) => {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryTables.getAffectedTablesFromQuery(connection, sql, (err, affectedTables) => {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.affectedTablesCache.set(dbname, token, affectedTables);
|
||||||
|
|
||||||
|
callback(err, affectedTables);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -11,8 +11,19 @@ var QueryTables = require('cartodb-query-tables');
|
|||||||
* @constructor
|
* @constructor
|
||||||
* @type {NamedMapMapConfigProvider}
|
* @type {NamedMapMapConfigProvider}
|
||||||
*/
|
*/
|
||||||
function NamedMapMapConfigProvider(templateMaps, pgConnection, metadataBackend, userLimitsApi, mapConfigAdapter,
|
function NamedMapMapConfigProvider(
|
||||||
owner, templateId, config, authToken, params) {
|
templateMaps,
|
||||||
|
pgConnection,
|
||||||
|
metadataBackend,
|
||||||
|
userLimitsApi,
|
||||||
|
mapConfigAdapter,
|
||||||
|
affectedTablesCache,
|
||||||
|
owner,
|
||||||
|
templateId,
|
||||||
|
config,
|
||||||
|
authToken,
|
||||||
|
params
|
||||||
|
) {
|
||||||
this.templateMaps = templateMaps;
|
this.templateMaps = templateMaps;
|
||||||
this.pgConnection = pgConnection;
|
this.pgConnection = pgConnection;
|
||||||
this.metadataBackend = metadataBackend;
|
this.metadataBackend = metadataBackend;
|
||||||
@ -30,7 +41,7 @@ function NamedMapMapConfigProvider(templateMaps, pgConnection, metadataBackend,
|
|||||||
// use template after call to mapConfig
|
// use template after call to mapConfig
|
||||||
this.template = null;
|
this.template = null;
|
||||||
|
|
||||||
this.affectedTablesAndLastUpdate = null;
|
this.affectedTablesCache = affectedTablesCache;
|
||||||
|
|
||||||
// providing
|
// providing
|
||||||
this.err = null;
|
this.err = null;
|
||||||
@ -189,7 +200,7 @@ NamedMapMapConfigProvider.prototype.getCacheBuster = function() {
|
|||||||
NamedMapMapConfigProvider.prototype.reset = function() {
|
NamedMapMapConfigProvider.prototype.reset = function() {
|
||||||
this.template = null;
|
this.template = null;
|
||||||
|
|
||||||
this.affectedTablesAndLastUpdate = null;
|
this.affectedTables = null;
|
||||||
|
|
||||||
this.err = null;
|
this.err = null;
|
||||||
this.mapConfig = null;
|
this.mapConfig = null;
|
||||||
@ -251,39 +262,51 @@ NamedMapMapConfigProvider.prototype.getTemplateName = function() {
|
|||||||
return this.templateName;
|
return this.templateName;
|
||||||
};
|
};
|
||||||
|
|
||||||
NamedMapMapConfigProvider.prototype.getAffectedTablesAndLastUpdatedTime = function(callback) {
|
NamedMapMapConfigProvider.prototype.getAffectedTables = function(callback) {
|
||||||
var self = this;
|
this.getMapConfig((err, mapConfig) => {
|
||||||
|
if (err) {
|
||||||
if (this.affectedTablesAndLastUpdate !== null) {
|
return callback(err);
|
||||||
return callback(null, this.affectedTablesAndLastUpdate);
|
|
||||||
}
|
|
||||||
|
|
||||||
step(
|
|
||||||
function getMapConfig() {
|
|
||||||
self.getMapConfig(this);
|
|
||||||
},
|
|
||||||
function getSql(err, mapConfig) {
|
|
||||||
assert.ifError(err);
|
|
||||||
return mapConfig.getLayers().map(function(layer) {
|
|
||||||
return layer.options.sql;
|
|
||||||
}).join(';');
|
|
||||||
},
|
|
||||||
function getAffectedTables(err, sql) {
|
|
||||||
assert.ifError(err);
|
|
||||||
step(
|
|
||||||
function getConnection() {
|
|
||||||
self.pgConnection.getConnection(self.owner, this);
|
|
||||||
},
|
|
||||||
function getAffectedTables(err, connection) {
|
|
||||||
assert.ifError(err);
|
|
||||||
QueryTables.getAffectedTablesFromQuery(connection, sql, this);
|
|
||||||
},
|
|
||||||
this
|
|
||||||
);
|
|
||||||
},
|
|
||||||
function finish(err, result) {
|
|
||||||
self.affectedTablesAndLastUpdate = result;
|
|
||||||
return callback(err, result);
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
const { dbname } = this.rendererParams;
|
||||||
|
const token = mapConfig.id();
|
||||||
|
|
||||||
|
if (this.affectedTablesCache.hasAffectedTables(dbname, token)) {
|
||||||
|
const affectedTables = this.affectedTablesCache.get(dbname, token);
|
||||||
|
return callback(null, affectedTables);
|
||||||
|
}
|
||||||
|
|
||||||
|
const queries = [];
|
||||||
|
|
||||||
|
mapConfig.getLayers().forEach(layer => {
|
||||||
|
queries.push(layer.options.sql);
|
||||||
|
if (layer.options.affected_tables) {
|
||||||
|
layer.options.affected_tables.map(table => {
|
||||||
|
queries.push(`SELECT * FROM ${table} LIMIT 0`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const sql = queries.length ? queries.join(';') : null;
|
||||||
|
|
||||||
|
if (!sql) {
|
||||||
|
return callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pgConnection.getConnection(this.owner, (err, connection) => {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryTables.getAffectedTablesFromQuery(connection, sql, (err, affectedTables) => {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.affectedTablesCache.set(dbname, token, affectedTables);
|
||||||
|
|
||||||
|
callback(err, affectedTables);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
@ -200,7 +200,8 @@ module.exports = function(serverOptions) {
|
|||||||
pgConnection,
|
pgConnection,
|
||||||
metadataBackend,
|
metadataBackend,
|
||||||
userLimitsApi,
|
userLimitsApi,
|
||||||
mapConfigAdapter
|
mapConfigAdapter,
|
||||||
|
layergroupAffectedTablesCache
|
||||||
);
|
);
|
||||||
|
|
||||||
['update', 'delete'].forEach(function(eventType) {
|
['update', 'delete'].forEach(function(eventType) {
|
||||||
|
@ -1272,6 +1272,8 @@ describe(suiteName, function() {
|
|||||||
it("cache control for layergroup default value", function(done) {
|
it("cache control for layergroup default value", function(done) {
|
||||||
global.environment.varnish.layergroupTtl = null;
|
global.environment.varnish.layergroupTtl = null;
|
||||||
|
|
||||||
|
var server = new CartodbWindshaft(serverOptions);
|
||||||
|
|
||||||
assert.response(server, layergroupTtlRequest, layergroupTtlResponseExpectation,
|
assert.response(server, layergroupTtlRequest, layergroupTtlResponseExpectation,
|
||||||
function(res) {
|
function(res) {
|
||||||
assert.equal(res.headers['cache-control'], 'public,max-age=86400,must-revalidate');
|
assert.equal(res.headers['cache-control'], 'public,max-age=86400,must-revalidate');
|
||||||
@ -1287,6 +1289,8 @@ describe(suiteName, function() {
|
|||||||
var layergroupTtl = 300;
|
var layergroupTtl = 300;
|
||||||
global.environment.varnish.layergroupTtl = layergroupTtl;
|
global.environment.varnish.layergroupTtl = layergroupTtl;
|
||||||
|
|
||||||
|
var server = new CartodbWindshaft(serverOptions);
|
||||||
|
|
||||||
assert.response(server, layergroupTtlRequest, layergroupTtlResponseExpectation,
|
assert.response(server, layergroupTtlRequest, layergroupTtlResponseExpectation,
|
||||||
function(res) {
|
function(res) {
|
||||||
assert.equal(res.headers['cache-control'], 'public,max-age=' + layergroupTtl + ',must-revalidate');
|
assert.equal(res.headers['cache-control'], 'public,max-age=' + layergroupTtl + ',must-revalidate');
|
||||||
|
Loading…
Reference in New Issue
Block a user