241 lines
7.7 KiB
JavaScript
241 lines
7.7 KiB
JavaScript
var step = require('step');
|
|
var assert = require('assert');
|
|
var _ = require('underscore');
|
|
var NamedMapsCacheEntry = require('../cache/model/named_maps_entry');
|
|
var cors = require('../middleware/cors');
|
|
|
|
var TablesCacheEntry = require('../cache/model/database_tables_entry');
|
|
|
|
function NamedMapsController(app, namedMapProviderCache, tileBackend, previewBackend, surrogateKeysCache,
|
|
tablesExtentApi) {
|
|
this.app = app;
|
|
this.namedMapProviderCache = namedMapProviderCache;
|
|
this.tileBackend = tileBackend;
|
|
this.previewBackend = previewBackend;
|
|
this.surrogateKeysCache = surrogateKeysCache;
|
|
this.tablesExtentApi = tablesExtentApi;
|
|
}
|
|
|
|
module.exports = NamedMapsController;
|
|
|
|
NamedMapsController.prototype.register = function(app) {
|
|
app.get(app.base_url_templated + '/:template_id/:layer/:z/:x/:y.(:format)', cors(), this.tile.bind(this));
|
|
app.get(
|
|
app.base_url_mapconfig + '/static/named/:template_id/:width/:height.:format', cors(), this.staticMap.bind(this)
|
|
);
|
|
};
|
|
|
|
NamedMapsController.prototype.sendResponse = function(req, res, resource, headers, namedMapProvider) {
|
|
this.surrogateKeysCache.tag(res, new NamedMapsCacheEntry(req.context.user, namedMapProvider.getTemplateName()));
|
|
res.header('Content-Type', headers['Content-Type']);
|
|
res.header('Cache-Control', 'public,max-age=7200,must-revalidate');
|
|
|
|
var self = this;
|
|
|
|
var dbName = req.params.dbname;
|
|
step(
|
|
function getAffectedTablesAndLastUpdatedTime() {
|
|
namedMapProvider.getAffectedTablesAndLastUpdatedTime(this);
|
|
},
|
|
function sendResponse(err, result) {
|
|
req.profiler.done('affectedTables');
|
|
if (err) {
|
|
console.log('ERROR generating cache channel: ' + err);
|
|
}
|
|
if (!result || !!result.affectedTables) {
|
|
// we increase cache control as we can invalidate it
|
|
res.header('Cache-Control', 'public,max-age=31536000');
|
|
|
|
var lastModifiedDate;
|
|
if (Number.isFinite(result.lastUpdatedTime)) {
|
|
lastModifiedDate = new Date(result.lastUpdatedTime);
|
|
} else {
|
|
lastModifiedDate = new Date();
|
|
}
|
|
res.header('Last-Modified', lastModifiedDate.toUTCString());
|
|
|
|
var tablesCacheEntry = new TablesCacheEntry(dbName, result.affectedTables);
|
|
res.header('X-Cache-Channel', tablesCacheEntry.getCacheChannel());
|
|
if (result.affectedTables.length > 0) {
|
|
self.surrogateKeysCache.tag(res, tablesCacheEntry);
|
|
}
|
|
}
|
|
self.app.sendResponse(res, [resource, 200]);
|
|
}
|
|
);
|
|
};
|
|
|
|
NamedMapsController.prototype.tile = function(req, res) {
|
|
var self = this;
|
|
|
|
var cdbUser = req.context.user;
|
|
|
|
var namedMapProvider;
|
|
step(
|
|
function reqParams() {
|
|
self.app.req2params(req, this);
|
|
},
|
|
function getTile() {
|
|
namedMapProvider = self.namedMapProviderCache.get(
|
|
cdbUser,
|
|
req.params.template_id,
|
|
req.query.config,
|
|
req.query.auth_token,
|
|
req.params
|
|
);
|
|
self.tileBackend.getTile(namedMapProvider, req.params, this);
|
|
},
|
|
function handleImage(err, tile, headers, stats) {
|
|
if (req.profiler) {
|
|
req.profiler.add(stats);
|
|
}
|
|
if (err) {
|
|
if (!err.error) {
|
|
err.error = err.message;
|
|
}
|
|
self.app.sendError(res, err, self.app.findStatusCode(err), 'NAMED_MAP_TILE', err);
|
|
} else {
|
|
self.sendResponse(req, res, tile, headers, namedMapProvider);
|
|
}
|
|
}
|
|
);
|
|
};
|
|
|
|
NamedMapsController.prototype.staticMap = function(req, res) {
|
|
var self = this;
|
|
|
|
var cdbUser = req.context.user;
|
|
|
|
var format = req.params.format === 'jpg' ? 'jpeg' : 'png';
|
|
req.params.format = 'png';
|
|
req.params.layer = 'all';
|
|
|
|
var namedMapProvider;
|
|
step(
|
|
function reqParams() {
|
|
self.app.req2params(req, this);
|
|
},
|
|
function getTemplate(err) {
|
|
assert.ifError(err);
|
|
namedMapProvider = self.namedMapProviderCache.get(
|
|
cdbUser,
|
|
req.params.template_id,
|
|
req.query.config,
|
|
req.query.auth_token,
|
|
req.params
|
|
);
|
|
namedMapProvider.getTemplate(this);
|
|
},
|
|
function prepareStaticImageOptions(err, template) {
|
|
assert.ifError(err);
|
|
getStaticImageOptions(template, this);
|
|
},
|
|
function estimateBounds(err, imageOpts) {
|
|
assert.ifError(err);
|
|
if (imageOpts) {
|
|
return imageOpts;
|
|
}
|
|
|
|
var defaultZoomCenter = {
|
|
zoom: 1,
|
|
center: {
|
|
lng: 0,
|
|
lat: 0
|
|
}
|
|
};
|
|
|
|
var cacheChannel = '';
|
|
|
|
var dbTables = cacheChannel.split(':');
|
|
if (dbTables.length <= 1 || dbTables[1].length === 0) {
|
|
return defaultZoomCenter;
|
|
}
|
|
|
|
var tableNames = dbTables[1].split(',');
|
|
if (tableNames.length === 0) {
|
|
return defaultZoomCenter;
|
|
}
|
|
|
|
var next = this;
|
|
self.tablesExtentApi.getBounds(cdbUser, tableNames, function(err, result) {
|
|
next(null, result || defaultZoomCenter);
|
|
});
|
|
},
|
|
function getImage(err, imageOpts) {
|
|
assert.ifError(err);
|
|
|
|
var width = +req.params.width;
|
|
var height = +req.params.height;
|
|
|
|
if (!_.isUndefined(imageOpts.zoom) && imageOpts.center) {
|
|
self.previewBackend.getImage(
|
|
namedMapProvider, format, width, height, imageOpts.zoom, imageOpts.center, this);
|
|
} else {
|
|
self.previewBackend.getImage(
|
|
namedMapProvider, format, width, height, imageOpts.bounds, this);
|
|
}
|
|
},
|
|
function handleImage(err, image, headers, stats) {
|
|
if (req.profiler) {
|
|
req.profiler.done('render-' + format);
|
|
req.profiler.add(stats || {});
|
|
}
|
|
|
|
if (err) {
|
|
if (!err.error) {
|
|
err.error = err.message;
|
|
}
|
|
self.app.sendError(res, err, self.app.findStatusCode(err), 'STATIC_VIZ_MAP', err);
|
|
} else {
|
|
self.sendResponse(req, res, image, headers, namedMapProvider);
|
|
}
|
|
}
|
|
);
|
|
};
|
|
|
|
function getStaticImageOptions(template, callback) {
|
|
if (template.view) {
|
|
var zoomCenter = templateZoomCenter(template.view);
|
|
if (zoomCenter) {
|
|
return callback(null, zoomCenter);
|
|
}
|
|
|
|
var bounds = templateBounds(template.view);
|
|
if (bounds) {
|
|
return callback(null, bounds);
|
|
}
|
|
}
|
|
return callback(null, null);
|
|
}
|
|
|
|
function templateZoomCenter(view) {
|
|
if (!_.isUndefined(view.zoom) && view.center) {
|
|
return {
|
|
zoom: view.zoom,
|
|
center: view.center
|
|
};
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function templateBounds(view) {
|
|
if (view.bounds) {
|
|
var hasAllBounds = _.every(['west', 'south', 'east', 'north'], function(prop) {
|
|
return !!view.bounds[prop];
|
|
});
|
|
if (hasAllBounds) {
|
|
return {
|
|
bounds: {
|
|
west: view.bounds.west,
|
|
south: view.bounds.south,
|
|
east: view.bounds.east,
|
|
north: view.bounds.north
|
|
}
|
|
};
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
}
|