Merge 53dada5a56 into a28df7ef8f
This commit is contained in:
commit
97991e940c
12 changed files with 130 additions and 78 deletions
|
|
@ -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
3
Jenkinsfile
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
@Library("jenkins-devops-scripts") _
|
||||||
|
tileserver-gl {
|
||||||
|
}
|
||||||
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
||||||
44
README.md
44
README.md
|
|
@ -1,48 +1,14 @@
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
# TileServer GL
|
# TileServer GL
|
||||||
[](https://travis-ci.org/klokantech/tileserver-gl)
|
|
||||||
[](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/.
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
# TileServer GL light
|
|
||||||
[](https://travis-ci.org/klokantech/tileserver-gl)
|
|
||||||
[](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/.
|
|
||||||
11
package.json
11
package.json
|
|
@ -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",
|
||||||
|
|
|
||||||
BIN
public/resources/images/dropoff-marker.png
Normal file
BIN
public/resources/images/dropoff-marker.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 474 B |
BIN
public/resources/images/pickup-marker.png
Normal file
BIN
public/resources/images/pickup-marker.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 486 B |
42
src/avgresp.js
Normal file
42
src/avgresp.js
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue