This commit is contained in:
Panagiotis Atmatzidis 2018-03-30 10:56:24 +00:00 committed by GitHub
commit 97991e940c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 130 additions and 78 deletions

View file

@ -1,12 +0,0 @@
FROM node:6
MAINTAINER Petr Sloup <petr.sloup@klokantech.com>
ENV NODE_ENV="production"
EXPOSE 80
VOLUME /data
WORKDIR /data
ENTRYPOINT ["node", "/usr/src/app/", "-p", "80"]
RUN mkdir -p /usr/src/app
COPY / /usr/src/app
RUN cd /usr/src/app && npm install --production

3
Jenkinsfile vendored Normal file
View file

@ -0,0 +1,3 @@
@Library("jenkins-devops-scripts") _
tileserver-gl {
}

View file

@ -2,6 +2,7 @@ TileServer GL
============= =============
Copyright (c) 2016, Klokan Technologies GmbH Copyright (c) 2016, Klokan Technologies GmbH
Copyright (c) 2018, Beat (markers feature)
All rights reserved. All rights reserved.

View file

@ -1,48 +1,14 @@
![tileserver-gl](https://cloud.githubusercontent.com/assets/59284/18173467/fa3aa2ca-7069-11e6-86b1-0f1266befeb6.jpeg)
# TileServer GL # TileServer GL
[![Build Status](https://travis-ci.org/klokantech/tileserver-gl.svg?branch=master)](https://travis-ci.org/klokantech/tileserver-gl)
[![Docker Hub](https://img.shields.io/badge/docker-hub-blue.svg)](https://hub.docker.com/r/klokantech/tileserver-gl/)
Vector and raster maps with GL styles. Server side rendering by Mapbox GL Native. Map tile server for Mapbox GL JS, Android, iOS, Leaflet, OpenLayers, GIS via WMTS, etc. Vector and raster maps with GL styles. Server side rendering by Mapbox GL Native. Map tile server for Mapbox GL JS, Android, iOS, Leaflet, OpenLayers, GIS via WMTS, etc.
## Get Started This fork adds features used by BEAT, including:
Make sure you have Node.js version **6** installed (running `node -v` it should output something like `v6.11.3`). * Marker support in the static (rendered) maps
* Prometheus compatible `/metrics` endpoint
* Improved `/health/` endpoint
Install `tileserver-gl` with server-side raster rendering of vector tiles with npm
```bash
npm install -g tileserver-gl
```
Now download vector tiles from [OpenMapTiles](https://openmaptiles.org/downloads/).
```bash
curl -o zurich_switzerland.mbtiles https://[GET-YOUR-LINK]/extracts/zurich_switzerland.mbtiles
```
Start `tileserver-gl` with the downloaded vector tiles.
```bash
tileserver-gl zurich_switzerland.mbtiles
```
Alternatively, you can use the `tileserver-gl-light` package instead, which is pure javascript (does not have any native dependencies) and can run anywhere, but does not contain rasterization on the server side made with MapBox GL Native.
## Using Docker
An alternative to npm to start the packed software easier is to install [Docker](http://www.docker.com/) on your computer and then run in the directory with the downloaded MBTiles the command:
```bash
docker run --rm -it -v $(pwd):/data -p 8080:80 klokantech/tileserver-gl
```
This will download and start a ready to use container on your computer and the maps are going to be available in webbrowser on localhost:8080.
On laptop you can use [Docker Kitematic](https://kitematic.com/) and search "tileserver-gl" and run it, then drop in the 'data' folder the MBTiles.
## Documentation ## Documentation
You can read full documentation of this project at http://tileserver.readthedocs.io/. You can read full documentation of the upstream project at http://tileserver.readthedocs.io/.

View file

@ -1,17 +0,0 @@
# TileServer GL light
[![Build Status](https://travis-ci.org/klokantech/tileserver-gl.svg?branch=master)](https://travis-ci.org/klokantech/tileserver-gl)
[![Docker Hub](https://img.shields.io/badge/docker-hub-blue.svg)](https://hub.docker.com/r/klokantech/tileserver-gl/)
Vector maps with GL styles. Map tile server for Mapbox Android, iOS, GL JS, Leaflet, OpenLayers, etc. without server side rendering.
## Quickstart
Use `npm install -g tileserver-gl-light` to install the package from npm.
Then you can simply run `tileserver-gl-light zurich_switzerland.mbtiles` to start the server for the given mbtiles.
See also `tileserver-gl` which contains server side rendering.
Prepared vector tiles can be downloaded from [OSM2VectorTiles](http://osm2vectortiles.org/).
## Documentation
You can read full documentation of this project at http://tileserver.readthedocs.io/.

View file

@ -19,13 +19,13 @@
"test": "mocha test/**.js --timeout 10000" "test": "mocha test/**.js --timeout 10000"
}, },
"dependencies": { "dependencies": {
"@mapbox/mapbox-gl-native": "3.5.4", "@mapbox/mapbox-gl-native": "3.5.8",
"@mapbox/mbtiles": "0.9.0", "@mapbox/mbtiles": "0.9.0",
"@mapbox/sphericalmercator": "1.0.5", "@mapbox/sphericalmercator": "1.0.5",
"@mapbox/vector-tile": "1.3.0", "@mapbox/vector-tile": "1.3.0",
"advanced-pool": "0.3.3", "advanced-pool": "0.3.3",
"base64url": "2.0.0", "base64url": "2.0.0",
"canvas": "1.6.8", "canvas": "^1.6.8",
"clone": "2.1.1", "clone": "2.1.1",
"color": "1.0.3", "color": "1.0.3",
"commander": "2.1.0", "commander": "2.1.0",
@ -35,11 +35,14 @@
"handlebars": "4.0.11", "handlebars": "4.0.11",
"http-shutdown": "^1.2.0", "http-shutdown": "^1.2.0",
"morgan": "1.9.0", "morgan": "1.9.0",
"nomnom": "1.8.1",
"npm": "^5.7.1",
"pbf": "3.0.5", "pbf": "3.0.5",
"proj4": "2.4.4", "proj4": "2.4.4",
"request": "2.83.0", "request": "2.83.0",
"sharp": "0.18.2", "sharp": "^0.20.0",
"tileserver-gl-styles": "1.2.0" "tileserver-gl-styles": "1.2.0",
"prom-client": "11.0.0"
}, },
"devDependencies": { "devDependencies": {
"should": "^11.2.0", "should": "^11.2.0",

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

42
src/avgresp.js Normal file
View file

@ -0,0 +1,42 @@
#!/usr/bin/env node
'use strict';
var prometheus = require('prom-client');
module.exports = {
avgresp: avgresp
};
var history;
var samples;
var fullhistory = false;
/**
* Create middleware to record and output average response times
* @param {Object} options
* @return {function}
*/
function avgresp(options) {
var opts = options || {};
history = 50;
samples = new Array(history);
var currentIndex = 0;
const respSummary = new prometheus.Summary({
name: "tileserver_static_latency_seconds",
help: "The tileserver response time in seconds"
});
return function avgresp(req, res, next) {
var end = respSummary.startTimer();
res.on('finish', function() {
end();
})
next();
}
}

View file

@ -23,6 +23,8 @@ var Canvas = require('canvas'),
var utils = require('./utils'); var utils = require('./utils');
var markerSize = 20;
var FLOAT_PATTERN = '[+-]?(?:\\d+|\\d+\.?\\d+)'; var FLOAT_PATTERN = '[+-]?(?:\\d+|\\d+\.?\\d+)';
var getScale = function(scale) { var getScale = function(scale) {
@ -263,6 +265,27 @@ module.exports = function(options, repo, params, id, dataResolver) {
styleJSON.glyphs = 'fonts://' + styleJSON.glyphs; styleJSON.glyphs = 'fonts://' + styleJSON.glyphs;
} }
var markerImages = [];
var markerImageNames = ['pickup','dropoff'];
var markerLoadPromise = new Promise(function(resolveCallback, rejectCallback) {
markerImageNames.forEach(function(imageName){
fs.readFile(path.join(__dirname, "../public/resources/images/") + imageName + '-marker.png', function(err, fileData) {
if (err) {
rejectCallback(err);
}
var mkrImage = new Canvas.Image();
mkrImage.src = fileData;
markerImages.push(mkrImage);
});
});
resolveCallback();
});
var tileJSON = { var tileJSON = {
'tilejson': '2.0.0', 'tilejson': '2.0.0',
'name': styleJSON.name, 'name': styleJSON.name,
@ -568,6 +591,20 @@ module.exports = function(options, repo, params, id, dataResolver) {
ctx.stroke(); ctx.stroke();
} }
if (query.showMarkers && query.showMarkers == 1) {
// Add the markers, if requested to do so.
var markers = [
[markerImages[0], precisePx(path[0],z).map(function(loc,idx){ return (idx ==1)? loc - markerSize/2: loc - markerSize/2;})],
[markerImages[1], precisePx(path[path.length-1],z).map(function(loc,idx){ return (idx == 1)?loc - markerSize/2: loc - markerSize/2;})]
];
markers.forEach(function(imgSpec){
var coordinates = imgSpec[1];
ctx.drawImage(imgSpec[0], coordinates[0], coordinates[1], markerSize, markerSize);
});
}
return canvas.toBuffer(); return canvas.toBuffer();
}; };
@ -615,7 +652,7 @@ module.exports = function(options, repo, params, id, dataResolver) {
format = req.params.format; format = req.params.format;
if (z < 0) { if (z < 0) {
return res.status(404).send('Invalid zoom'); return res.status(400).send('Invalid zoom');
} }
var transformer = raw ? var transformer = raw ?
@ -751,7 +788,7 @@ module.exports = function(options, repo, params, id, dataResolver) {
return res.send(info); return res.send(info);
}); });
return Promise.all([fontListingPromise, renderersReadyPromise]).then(function() { return Promise.all([markerLoadPromise, fontListingPromise, renderersReadyPromise]).then(function() {
return app; return app;
}); });

View file

@ -21,7 +21,11 @@ var packageJson = require('../package'),
serve_rendered = null, serve_rendered = null,
serve_style = require('./serve_style'), serve_style = require('./serve_style'),
serve_data = require('./serve_data'), serve_data = require('./serve_data'),
utils = require('./utils'); utils = require('./utils'),
avgresp = require('./avgresp'),
prometheus = require('prom-client');
prometheus.collectDefaultMetrics({ timeout: 5000 });
var isLight = packageJson.name.slice(-6) == '-light'; var isLight = packageJson.name.slice(-6) == '-light';
if (!isLight) { if (!isLight) {
@ -52,6 +56,8 @@ function start(opts) {
})); }));
} }
app.use(/\/styles\/.*\/static\/.*$/, avgresp.avgresp());
var config = opts.config || null; var config = opts.config || null;
var configPath = null; var configPath = null;
if (opts.configPath) { if (opts.configPath) {
@ -391,12 +397,30 @@ function start(opts) {
console.log('Startup complete'); console.log('Startup complete');
startupComplete = true; startupComplete = true;
}); });
app.get('/health', function(req, res, next) { app.get('/health', function(req, res, next) {
var healthTemplate = {
"service": "tileserver",
"status": "200",
"message": "OK"
};
var statusCode = 200;
if (startupComplete) { if (startupComplete) {
return res.status(200).send('OK'); statusCode = 200;
healthTemplate.message = "OK";
} else { } else {
return res.status(503).send('Starting'); statusCode = 503;
healthTemplate.message = "Starting";
} }
healthTemplate.status = statusCode;
return res.status(statusCode).send(healthTemplate);
});
app.get('/metrics', function(req, res, next){
res.end(prometheus.register.metrics());
}); });
var server = app.listen(process.env.PORT || opts.port, process.env.BIND || opts.bind, function() { var server = app.listen(process.env.PORT || opts.port, process.env.BIND || opts.bind, function() {

View file

@ -49,7 +49,7 @@ describe('Static endpoints', function() {
testStatic(prefix, '0,0,0/256x256', 'gif', 400); testStatic(prefix, '0,0,0/256x256', 'gif', 400);
testStatic(prefix, '0,0,0/256x256', 'png', 404, 1); testStatic(prefix, '0,0,0/256x256', 'png', 404, 1);
testStatic(prefix, '0,0,-1/256x256', 'png', 404); testStatic(prefix, '0,0,-1/256x256', 'png', 400);
testStatic(prefix, '0,0,0/256.5x256.5', 'png', 404); testStatic(prefix, '0,0,0/256.5x256.5', 'png', 404);
testStatic(prefix, '0,0,0,/256x256', 'png', 404); testStatic(prefix, '0,0,0,/256x256', 'png', 404);
@ -91,6 +91,11 @@ describe('Static endpoints', function() {
testStatic(prefix, 'auto/20x20', 'png', 200, 2, /image\/png/, '?path=10,10|20,20'); testStatic(prefix, 'auto/20x20', 'png', 200, 2, /image\/png/, '?path=10,10|20,20');
testStatic(prefix, 'auto/200x200', 'png', 200, 3, /image\/png/, '?path=-10,-10|-20,-20'); testStatic(prefix, 'auto/200x200', 'png', 200, 3, /image\/png/, '?path=-10,-10|-20,-20');
}); });
describe('with markers', function() {
testStatic(prefix, 'auto/20x20', 'png', 200, 2, /image\/png/, '?path=10,10|20,20&showMarkers=1');
testStatic(prefix, 'auto/20x20', 'png', 200, 2, /image\/png/, '?path=10,10|20,20&showMarkers=0');
})
}); });
describe('invalid requests return 4xx', function() { describe('invalid requests return 4xx', function() {