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) 2018, Beat (markers feature)
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
[![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.
## 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
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"
},
"dependencies": {
"@mapbox/mapbox-gl-native": "3.5.4",
"@mapbox/mapbox-gl-native": "3.5.8",
"@mapbox/mbtiles": "0.9.0",
"@mapbox/sphericalmercator": "1.0.5",
"@mapbox/vector-tile": "1.3.0",
"advanced-pool": "0.3.3",
"base64url": "2.0.0",
"canvas": "1.6.8",
"canvas": "^1.6.8",
"clone": "2.1.1",
"color": "1.0.3",
"commander": "2.1.0",
@ -35,11 +35,14 @@
"handlebars": "4.0.11",
"http-shutdown": "^1.2.0",
"morgan": "1.9.0",
"nomnom": "1.8.1",
"npm": "^5.7.1",
"pbf": "3.0.5",
"proj4": "2.4.4",
"request": "2.83.0",
"sharp": "0.18.2",
"tileserver-gl-styles": "1.2.0"
"sharp": "^0.20.0",
"tileserver-gl-styles": "1.2.0",
"prom-client": "11.0.0"
},
"devDependencies": {
"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 markerSize = 20;
var FLOAT_PATTERN = '[+-]?(?:\\d+|\\d+\.?\\d+)';
var getScale = function(scale) {
@ -263,6 +265,27 @@ module.exports = function(options, repo, params, id, dataResolver) {
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 = {
'tilejson': '2.0.0',
'name': styleJSON.name,
@ -568,6 +591,20 @@ module.exports = function(options, repo, params, id, dataResolver) {
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();
};
@ -615,7 +652,7 @@ module.exports = function(options, repo, params, id, dataResolver) {
format = req.params.format;
if (z < 0) {
return res.status(404).send('Invalid zoom');
return res.status(400).send('Invalid zoom');
}
var transformer = raw ?
@ -751,7 +788,7 @@ module.exports = function(options, repo, params, id, dataResolver) {
return res.send(info);
});
return Promise.all([fontListingPromise, renderersReadyPromise]).then(function() {
return Promise.all([markerLoadPromise, fontListingPromise, renderersReadyPromise]).then(function() {
return app;
});

View file

@ -21,7 +21,11 @@ var packageJson = require('../package'),
serve_rendered = null,
serve_style = require('./serve_style'),
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';
if (!isLight) {
@ -52,6 +56,8 @@ function start(opts) {
}));
}
app.use(/\/styles\/.*\/static\/.*$/, avgresp.avgresp());
var config = opts.config || null;
var configPath = null;
if (opts.configPath) {
@ -391,12 +397,30 @@ function start(opts) {
console.log('Startup complete');
startupComplete = true;
});
app.get('/health', function(req, res, next) {
var healthTemplate = {
"service": "tileserver",
"status": "200",
"message": "OK"
};
var statusCode = 200;
if (startupComplete) {
return res.status(200).send('OK');
statusCode = 200;
healthTemplate.message = "OK";
} 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() {

View file

@ -49,7 +49,7 @@ describe('Static endpoints', function() {
testStatic(prefix, '0,0,0/256x256', 'gif', 400);
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,/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/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() {