Ensure each controller only receives one router

This commit is contained in:
Daniel García Aubert 2018-03-28 19:11:19 +02:00
parent 04b65c7c0d
commit 51fade6bd3
6 changed files with 168 additions and 118 deletions

View File

@ -2,7 +2,5 @@ module.exports = {
Analyses: require('./analyses'), Analyses: require('./analyses'),
Layergroup: require('./layergroup'), Layergroup: require('./layergroup'),
Map: require('./map'), Map: require('./map'),
NamedMaps: require('./named_maps'),
NamedMapsAdmin: require('./named_maps_admin'),
ServerInfo: require('./server_info') ServerInfo: require('./server_info')
}; };

View File

@ -1,9 +1,9 @@
const { templateName } = require('../backends/template_maps'); const { templateName } = require('../../backends/template_maps');
const cors = require('../middleware/cors'); const cors = require('../../middleware/cors');
const credentials = require('../middleware/credentials'); const credentials = require('../../middleware/credentials');
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 sendResponse = require('../middleware/send-response'); const sendResponse = require('../../middleware/send-response');
/** /**
* @param {AuthApi} authApi * @param {AuthApi} authApi
@ -11,21 +11,21 @@ const sendResponse = require('../middleware/send-response');
* @param {TemplateMaps} templateMaps * @param {TemplateMaps} templateMaps
* @constructor * @constructor
*/ */
function NamedMapsAdminController(authApi, templateMaps, userLimitsApi) { function AdminTemplateController(authApi, templateMaps, userLimitsApi) {
this.authApi = authApi; this.authApi = authApi;
this.templateMaps = templateMaps; this.templateMaps = templateMaps;
this.userLimitsApi = userLimitsApi; this.userLimitsApi = userLimitsApi;
} }
module.exports = NamedMapsAdminController; module.exports = AdminTemplateController;
NamedMapsAdminController.prototype.register = function (templateRouter) { AdminTemplateController.prototype.register = function (templateRouter) {
templateRouter.post( templateRouter.post(
`/`, `/`,
credentials(), credentials(),
checkContentType({ action: 'POST', label: 'POST TEMPLATE' }),
authorizedByAPIKey({ authApi: this.authApi, action: 'create', label: 'POST TEMPLATE' }), authorizedByAPIKey({ authApi: this.authApi, action: 'create', label: 'POST TEMPLATE' }),
rateLimit(this.userLimitsApi, RATE_LIMIT_ENDPOINTS_GROUPS.NAMED_CREATE), rateLimit(this.userLimitsApi, RATE_LIMIT_ENDPOINTS_GROUPS.NAMED_CREATE),
checkContentType({ action: 'POST', label: 'POST TEMPLATE' }),
createTemplate({ templateMaps: this.templateMaps }), createTemplate({ templateMaps: this.templateMaps }),
sendResponse() sendResponse()
); );
@ -33,9 +33,9 @@ NamedMapsAdminController.prototype.register = function (templateRouter) {
templateRouter.put( templateRouter.put(
`/:template_id`, `/:template_id`,
credentials(), credentials(),
checkContentType({ action: 'PUT', label: 'PUT TEMPLATE' }),
authorizedByAPIKey({ authApi: this.authApi, action: 'update', label: 'PUT TEMPLATE' }), authorizedByAPIKey({ authApi: this.authApi, action: 'update', label: 'PUT TEMPLATE' }),
rateLimit(this.userLimitsApi, RATE_LIMIT_ENDPOINTS_GROUPS.NAMED_UPDATE), rateLimit(this.userLimitsApi, RATE_LIMIT_ENDPOINTS_GROUPS.NAMED_UPDATE),
checkContentType({ action: 'PUT', label: 'PUT TEMPLATE' }),
updateTemplate({ templateMaps: this.templateMaps }), updateTemplate({ templateMaps: this.templateMaps }),
sendResponse() sendResponse()
); );

View File

@ -0,0 +1,32 @@
module.exports = function getNamedMapProvider ({ namedMapProviderCache, label, forcedFormat = null }) {
return function getNamedMapProviderMiddleware (req, res, next) {
const { user, token, cache_buster, api_key } = res.locals;
const { dbuser, dbname, dbpassword, dbhost, dbport } = res.locals;
const { template_id, layer: layerFromParams, z, x, y, format } = req.params;
const { layer: layerFromQuery } = req.query;
const params = {
user, token, cache_buster, api_key,
dbuser, dbname, dbpassword, dbhost, dbport,
template_id, layer: (layerFromQuery || layerFromParams), z, x, y, format
};
if (forcedFormat) {
params.format = forcedFormat;
params.layer = params.layer || 'all';
}
const { config, auth_token } = req.query;
namedMapProviderCache.get(user, template_id, config, auth_token, params, (err, namedMapProvider) => {
if (err) {
err.label = label;
return next(err);
}
res.locals.mapConfigProvider = namedMapProvider;
next();
});
};
};

View File

@ -1,14 +1,14 @@
const cleanUpQueryParams = require('../middleware/clean-up-query-params'); const cleanUpQueryParams = require('../../middleware/clean-up-query-params');
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 namedMapProvider = require('./middlewares/named-map-provider');
const cacheChannelHeader = require('../middleware/cache-channel-header'); const cacheControlHeader = require('../../middleware/cache-control-header');
const surrogateKeyHeader = require('../middleware/surrogate-key-header'); const cacheChannelHeader = require('../../middleware/cache-channel-header');
const lastModifiedHeader = require('../middleware/last-modified-header'); const surrogateKeyHeader = require('../../middleware/surrogate-key-header');
const sendResponse = require('../middleware/send-response'); const lastModifiedHeader = require('../../middleware/last-modified-header');
const vectorError = require('../middleware/vector-error'); const sendResponse = require('../../middleware/send-response');
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 DEFAULT_ZOOM_CENTER = { const DEFAULT_ZOOM_CENTER = {
@ -23,9 +23,8 @@ function numMapper(n) {
return +n; return +n;
} }
function NamedMapsController ( function PreviewTemplateController (
namedMapProviderCache, namedMapProviderCache,
tileBackend,
previewBackend, previewBackend,
surrogateKeysCache, surrogateKeysCache,
tablesExtentApi, tablesExtentApi,
@ -35,7 +34,6 @@ function NamedMapsController (
userLimitsApi userLimitsApi
) { ) {
this.namedMapProviderCache = namedMapProviderCache; this.namedMapProviderCache = namedMapProviderCache;
this.tileBackend = tileBackend;
this.previewBackend = previewBackend; this.previewBackend = previewBackend;
this.surrogateKeysCache = surrogateKeysCache; this.surrogateKeysCache = surrogateKeysCache;
this.tablesExtentApi = tablesExtentApi; this.tablesExtentApi = tablesExtentApi;
@ -45,34 +43,9 @@ function NamedMapsController (
this.userLimitsApi = userLimitsApi; this.userLimitsApi = userLimitsApi;
} }
module.exports = NamedMapsController; module.exports = PreviewTemplateController;
NamedMapsController.prototype.register = function(mapRouter, templateRouter) {
templateRouter.get(
`/:template_id/:layer/:z/:x/:y.(:format)`,
credentials(),
authorize(this.authApi),
dbConnSetup(this.pgConnection),
rateLimit(this.userLimitsApi, RATE_LIMIT_ENDPOINTS_GROUPS.NAMED_TILES),
cleanUpQueryParams(),
getNamedMapProvider({
namedMapProviderCache: this.namedMapProviderCache,
label: 'NAMED_MAP_TILE'
}),
getTile({
tileBackend: this.tileBackend,
label: 'NAMED_MAP_TILE'
}),
setContentTypeHeader(),
cacheControlHeader(),
cacheChannelHeader(),
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
lastModifiedHeader(),
sendResponse(),
vectorError()
);
PreviewTemplateController.prototype.register = function (mapRouter) {
mapRouter.get( mapRouter.get(
`/static/named/:template_id/:width/:height.:format`, `/static/named/:template_id/:width/:height.:format`,
credentials(), credentials(),
@ -80,7 +53,7 @@ NamedMapsController.prototype.register = function(mapRouter, templateRouter) {
dbConnSetup(this.pgConnection), dbConnSetup(this.pgConnection),
rateLimit(this.userLimitsApi, RATE_LIMIT_ENDPOINTS_GROUPS.STATIC_NAMED), rateLimit(this.userLimitsApi, RATE_LIMIT_ENDPOINTS_GROUPS.STATIC_NAMED),
cleanUpQueryParams(['layer', 'zoom', 'lon', 'lat', 'bbox']), cleanUpQueryParams(['layer', 'zoom', 'lon', 'lat', 'bbox']),
getNamedMapProvider({ namedMapProvider({
namedMapProviderCache: this.namedMapProviderCache, namedMapProviderCache: this.namedMapProviderCache,
label: 'STATIC_VIZ_MAP', forcedFormat: 'png' label: 'STATIC_VIZ_MAP', forcedFormat: 'png'
}), }),
@ -101,39 +74,6 @@ NamedMapsController.prototype.register = function(mapRouter, templateRouter) {
); );
}; };
function getNamedMapProvider ({ namedMapProviderCache, label, forcedFormat = null }) {
return function getNamedMapProviderMiddleware (req, res, next) {
const { user, token, cache_buster, api_key } = res.locals;
const { dbuser, dbname, dbpassword, dbhost, dbport } = res.locals;
const { template_id, layer: layerFromParams, z, x, y, format } = req.params;
const { layer: layerFromQuery } = req.query;
const params = {
user, token, cache_buster, api_key,
dbuser, dbname, dbpassword, dbhost, dbport,
template_id, layer: (layerFromQuery || layerFromParams), z, x, y, format
};
if (forcedFormat) {
params.format = forcedFormat;
params.layer = params.layer || 'all';
}
const { config, auth_token } = req.query;
namedMapProviderCache.get(user, template_id, config, auth_token, params, (err, namedMapProvider) => {
if (err) {
err.label = label;
return next(err);
}
res.locals.mapConfigProvider = namedMapProvider;
next();
});
};
}
function getTemplate ({ label }) { function getTemplate ({ label }) {
return function getTemplateMiddleware (req, res, next) { return function getTemplateMiddleware (req, res, next) {
const { mapConfigProvider } = res.locals; const { mapConfigProvider } = res.locals;
@ -200,32 +140,6 @@ function prepareLayerFilterFromPreviewLayers ({ namedMapProviderCache, label })
}; };
} }
function getTile ({ tileBackend, label }) {
return function getTileMiddleware (req, res, next) {
const { mapConfigProvider } = res.locals;
const { layer, z, x, y, format } = req.params;
const params = { layer, z, x, y, format };
tileBackend.getTile(mapConfigProvider, params, (err, tile, headers, stats) => {
req.profiler.add(stats);
req.profiler.done('render-' + format);
if (err) {
err.label = label;
return next(err);
}
if (headers) {
res.set(headers);
}
res.body = tile;
next();
});
};
}
function getStaticImageOptions ({ tablesExtentApi }) { function getStaticImageOptions ({ tablesExtentApi }) {
return function getStaticImageOptionsMiddleware(req, res, next) { return function getStaticImageOptionsMiddleware(req, res, next) {
const { user, mapConfigProvider, template } = res.locals; const { user, mapConfigProvider, template } = res.locals;

View File

@ -0,0 +1,91 @@
const cleanUpQueryParams = require('../../middleware/clean-up-query-params');
const credentials = require('../../middleware/credentials');
const dbConnSetup = require('../../middleware/db-conn-setup');
const authorize = require('../../middleware/authorize');
const namedMapProvider = require('./middlewares/named-map-provider');
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 vectorError = require('../../middleware/vector-error');
const rateLimit = require('../../middleware/rate-limit');
const { RATE_LIMIT_ENDPOINTS_GROUPS } = rateLimit;
function TileTemplateController (
namedMapProviderCache,
tileBackend,
surrogateKeysCache,
pgConnection,
authApi,
userLimitsApi
) {
this.namedMapProviderCache = namedMapProviderCache;
this.tileBackend = tileBackend;
this.surrogateKeysCache = surrogateKeysCache;
this.pgConnection = pgConnection;
this.authApi = authApi;
this.userLimitsApi = userLimitsApi;
}
module.exports = TileTemplateController;
TileTemplateController.prototype.register = function (templateRouter) {
templateRouter.get(
`/:template_id/:layer/:z/:x/:y.(:format)`,
credentials(),
authorize(this.authApi),
dbConnSetup(this.pgConnection),
rateLimit(this.userLimitsApi, RATE_LIMIT_ENDPOINTS_GROUPS.NAMED_TILES),
cleanUpQueryParams(),
namedMapProvider({
namedMapProviderCache: this.namedMapProviderCache,
label: 'NAMED_MAP_TILE'
}),
getTile({
tileBackend: this.tileBackend,
label: 'NAMED_MAP_TILE'
}),
setContentTypeHeader(),
cacheControlHeader(),
cacheChannelHeader(),
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
lastModifiedHeader(),
sendResponse(),
vectorError()
);
};
function getTile ({ tileBackend, label }) {
return function getTileMiddleware (req, res, next) {
const { mapConfigProvider } = res.locals;
const { layer, z, x, y, format } = req.params;
const params = { layer, z, x, y, format };
tileBackend.getTile(mapConfigProvider, params, (err, tile, headers, stats) => {
req.profiler.add(stats);
req.profiler.done('render-' + format);
if (err) {
err.label = label;
return next(err);
}
if (headers) {
res.set(headers);
}
res.body = tile;
next();
});
};
}
function setContentTypeHeader () {
return function setContentTypeHeaderMiddleware(req, res, next) {
res.set('Content-Type', res.get('content-type') || res.get('Content-Type') || 'image/png');
next();
};
}

View File

@ -7,6 +7,9 @@ var cartodbRedis = require('cartodb-redis');
var _ = require('underscore'); var _ = require('underscore');
var controller = require('./controllers'); var controller = require('./controllers');
const AdminTemplateController = require('./controllers/template/admin');
const PreviewTemplateController = require('./controllers/template/preview');
const TileTemplateController = require('./controllers/template/tile');
var SurrogateKeysCache = require('./cache/surrogate_keys_cache'); var SurrogateKeysCache = require('./cache/surrogate_keys_cache');
var NamedMapsCacheEntry = require('./cache/model/named_maps_entry'); var NamedMapsCacheEntry = require('./cache/model/named_maps_entry');
@ -224,8 +227,6 @@ module.exports = function(serverOptions) {
const templateRouter = express.Router(); const templateRouter = express.Router();
const monitorRouter = express.Router(); const monitorRouter = express.Router();
const { base_url_mapconfig: mapConfigBasePath, base_url_templated: templateBasePath } = serverOptions;
new controller.Layergroup( new controller.Layergroup(
pgConnection, pgConnection,
mapStore, mapStore,
@ -252,9 +253,17 @@ module.exports = function(serverOptions) {
authApi authApi
).register(mapRouter, templateRouter); ).register(mapRouter, templateRouter);
new controller.NamedMaps( new TileTemplateController(
namedMapProviderCache, namedMapProviderCache,
tileBackend, tileBackend,
surrogateKeysCache,
pgConnection,
authApi,
userLimitsApi
).register(templateRouter);
new PreviewTemplateController(
namedMapProviderCache,
previewBackend, previewBackend,
surrogateKeysCache, surrogateKeysCache,
tablesExtentApi, tablesExtentApi,
@ -262,14 +271,20 @@ module.exports = function(serverOptions) {
pgConnection, pgConnection,
authApi, authApi,
userLimitsApi userLimitsApi
).register(mapRouter, templateRouter); ).register(mapRouter);
new controller.NamedMapsAdmin(authApi, templateMaps, userLimitsApi).register(templateRouter); new AdminTemplateController(
authApi,
templateMaps,
userLimitsApi
).register(templateRouter);
new controller.Analyses(pgConnection, authApi, userLimitsApi).register(mapRouter); new controller.Analyses(pgConnection, authApi, userLimitsApi).register(mapRouter);
new controller.ServerInfo(versions).register(monitorRouter); new controller.ServerInfo(versions).register(monitorRouter);
const { base_url_mapconfig: mapConfigBasePath, base_url_templated: templateBasePath } = serverOptions;
app.use(mapConfigBasePath, mapRouter); app.use(mapConfigBasePath, mapRouter);
app.use(templateBasePath, templateRouter); app.use(templateBasePath, templateRouter);
app.use('/', monitorRouter); app.use('/', monitorRouter);