Skip to content

Commit

Permalink
Update project to use most recent version of Windshaft
Browse files Browse the repository at this point in the history
Most of the changes are in the `http/` directory, which attempts to provide
a facade of the former API to make the changes required in the rest of the
project minimal. This was heavily cribbed from an Windshaft example server:
https://github.com/CartoDB/Windshaft/blob/50897ad/examples/http/server.js

Other changes include:
 - Switching from using npm to yarn, with an accompanying yarn.lock instead of
   the previously used npm-shrinkwrap.json
 - Updated Rollbar to the latest version, which required minimal changes
 - Updated Underscore, which required some minimal changes
 - Fixing the healthCheck to directly use dependencies instead "reaching into"
   Windshaft. As yarn places dependencies in the top-level 'node_modules/'
   whenever possible, we are still effectively using the same code as Windshaft
 - Removing parentheses on outermost SQL queries - these are now added by Windshaft
 - Updating the watch script to enable the debugging with the Chrome dev tools
 - Support for statsd was removed from Windshaft, so I have removed it from
   our configuration in server.js as well

Connects to #47
  • Loading branch information
maurizi committed Sep 14, 2017
1 parent 5463111 commit e6d4430
Show file tree
Hide file tree
Showing 12 changed files with 3,136 additions and 1,654 deletions.
6 changes: 3 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
language: node_js
node_js:
- '0.10'
- '6'

env:
global:
secure: ik/JY6nr4qCza3wKROQy/cCiP82r6tsMyPwJP2v1AbyfplVM25EQ6WCRuJOKM5zmciewoVm6YWTz7ficoX+Fgs8CKnHVL/uRhQFr1HjbuVviL8kHqwKtxB64Rh40Tf0Wzu7Vdn27SKAOGMR2q24LIU95X4C+avbtUbpe+b72UA0=

before_install:
- sudo add-apt-repository -y ppa:mapnik/v2.2.0
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
- sudo apt-get update -y
- sudo apt-get install libboost-dev libgdal1h libgdal-dev libmapnik libmapnik-dev
- sudo apt-get install checkinstall g++ libstdc++-5-dev pkg-config libcairo2-dev libjpeg8-dev libgif-dev libpango1.0-dev

install: make all
script: make lint coverage
Expand Down
5 changes: 2 additions & 3 deletions config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use strict";

var canopyBoundarySql = [
"(SELECT the_geom_webmercator",
"SELECT the_geom_webmercator",
", canopy_percent * 100 as percent",
", FORMAT('%s (%s%%)',",
// Remove parent boundary name suffix.
Expand All @@ -15,7 +15,6 @@ var canopyBoundarySql = [
" AND b.canopy_percent IS NOT NULL",
" AND b.canopy_percent >= <%= canopy_min %>",
" AND b.canopy_percent <= <%= canopy_max %>",
") otmfiltersql"
].join('');

module.exports = {
Expand Down Expand Up @@ -88,7 +87,7 @@ module.exports = {
}
},
"treeDisplayFilters": ["EmptyPlot", "Tree"],
"boundaryGrainstoreSql": "(SELECT the_geom_webmercator FROM treemap_boundary JOIN treemap_instance_boundaries ON treemap_instance_boundaries.boundary_id = treemap_boundary.id WHERE treemap_instance_boundaries.instance_id=<%= instanceid %> AND treemap_boundary.searchable=true) otmfiltersql",
"boundaryGrainstoreSql": "SELECT the_geom_webmercator FROM treemap_boundary JOIN treemap_instance_boundaries ON treemap_instance_boundaries.boundary_id = treemap_boundary.id WHERE treemap_instance_boundaries.instance_id=<%= instanceid %> AND treemap_boundary.searchable=true",
"getBoundarySql" : "SELECT the_geom_webmercator FROM treemap_boundary WHERE id=<%= boundaryId %>",
"canopyBoundarySql": canopyBoundarySql,
"showAtZoomSql": "(treemap_mapfeature.hide_at_zoom IS NULL OR treemap_mapfeature.hide_at_zoom < <%= zoom %>)",
Expand Down
2 changes: 1 addition & 1 deletion filterObjectToWhere.js
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ function fieldNameAndPredicateToSql(fieldName, predicate) {
// name somewhere besides the LHS so we provide it via
// an underscore template
if (f.sql_template) {
return _.template(f.sql_template, { 'column': columnName });
return _.template(f.sql_template)({ 'column': columnName });
} else {
if (columnName.indexOf('->') !== -1) {
// if the column is an hstore field and the value is a
Expand Down
6 changes: 3 additions & 3 deletions healthCheck.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"use strict";

var Step = require('windshaft/node_modules/step');
var Pg = require('windshaft/node_modules/pg');
var Redis = require('windshaft/node_modules/redis-mpool/node_modules/redis');
var Step = require('step');
var Pg = require('pg');
var Redis = require('redis');

/**
* Attempts to connect to a PostgreSQL database, providing the
Expand Down
117 changes: 117 additions & 0 deletions http/mapController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
"use strict";

var assert = require('assert');
var step = require('step');
var windshaft = require('windshaft');

var MapConfig = windshaft.model.MapConfig;
var DummyMapConfigProvider = require('../node_modules/windshaft/lib/windshaft/models/providers/dummy_mapconfig_provider');

var MapStoreMapConfigProvider = windshaft.model.provider.MapStoreMapConfig;

/**
* @param app
* @param {MapStore} mapStore
* @param {MapBackend} mapBackend
* @param {TileBackend} tileBackend
* @constructor
*/
function MapController(app, mapStore, mapBackend, tileBackend) {
this._app = app;
this.mapStore = mapStore;
this.mapBackend = mapBackend;
this.tileBackend = tileBackend;

// TODO: _layers needs to be a LRU cache or memory use can grow unbounded
this._layers = {};
}

module.exports = MapController;


MapController.prototype.register = function(app) {
app.get(app.base_url + '/:z/:x/:y@:scale_factor?x.:format(png|grid\.json)', this.tile.bind(this));
app.get(app.base_url + '/:z/:x/:y.:format(png|grid\.json)', this.tile.bind(this));
app.options(app.base_url, this.cors.bind(this));
};

// send CORS headers when client send options.
MapController.prototype.cors = function(req, res, next) {
this._app.doCORS(res, "Content-Type");
return next();
};

MapController.prototype.create = function initLayergroup(req, mapConfig, callback) {
this.mapBackend.createLayergroup(
mapConfig, req.params, new DummyMapConfigProvider(mapConfig, req.params), callback
);
};

// Gets a tile for a given token and set of tile ZXY coords. (OSM style)
MapController.prototype.tile = function(req, res) {
var self = this;
var mapConfig;

this._app.doCORS(res);
step(
function mapController$prepareParams() {
self._app.req2params(req, this);
},
function mapController$getMapConfig(err) {
mapConfig = MapConfig.create({
layers: [{
type: 'mapnik',
options: {
sql: req.params.sql,
cartocss: req.params.style,
cartocss_version: '2.0.1',
interactivity: req.params.interactivity
}
}]
});
self.mapStore.load(mapConfig.id(), this);
},
function mapController$saveMapConfig(err, layer) {
if (layer) {
this(null, layer);
} else {
self.create(req, mapConfig, this);
}
},
function mapController$getTile(err, layer) {
if ( err ) {
throw err;
}
req.params.token = layer.layergroupid;
self.tileBackend.getTile(new MapStoreMapConfigProvider(self.mapStore, req.params), req.params, this);
},
function mapController$finalize(err, tile, headers) {
self.finalizeGetTileOrGrid(err, req, res, tile, headers);
return null;
},
function finish(err) {
if ( err ) {
console.error("windshaft.tiles: " + err);
}
}
);
};

// This function is meant for being called as the very last
// step by all endpoints serving tiles or grids
MapController.prototype.finalizeGetTileOrGrid = function(err, req, res, tile, headers) {
if (err) {
// See https://github.com/Vizzuality/Windshaft-cartodb/issues/68
var errMsg = err.message ? ( '' + err.message ) : ( '' + err );

// Rewrite mapnik parsing errors to start with layer number
var matches = errMsg.match("(.*) in style 'layer([0-9]+)'");
if (matches) {
errMsg = 'style'+matches[2]+': ' + matches[1];
}

this._app.sendError(res, { errors: ['' + errMsg] }, this._app.findStatusCode(err), 'TILE', err);
} else {
res.send(tile, headers, 200);
}
};
Loading

0 comments on commit e6d4430

Please sign in to comment.