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) 2018, Beat (markers feature)
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
|
44
README.md
44
README.md
|
@ -1,48 +1,14 @@
|
|||

|
||||
|
||||
|
||||
# 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.
|
||||
|
||||
## 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/.
|
||||
|
|
|
@ -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"
|
||||
},
|
||||
"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",
|
||||
|
|
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 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;
|
||||
});
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in a new issue