Compare commits

...

12 Commits

Author SHA1 Message Date
Petr Sloup
54f11a2125 Update package version to 2.2.0 2017-09-01 11:37:18 +02:00
Petr Sloup
598c8c590b Update package dependencies 2017-09-01 11:30:52 +02:00
Petr Sloup
438a18eec1 Merge pull request #207 from tschaub/handle-request-failures
Try to create the appropriate data type on http errors
2017-08-24 09:33:22 +02:00
Tim Schaub
7bdb7afcb9 Reuse the function for creating empty responses 2017-08-23 11:30:05 -04:00
Tim Schaub
2e46700cd9 Try to create the appropriate data type on http errors 2017-08-22 14:17:53 -04:00
Petr Sloup
bb09f3df64 Add --rm to docker run instruction to run it more cleanly 2017-07-28 09:54:12 +02:00
Petr Sloup
42f24c2c99 Add concept of data decorator function 2017-07-28 09:53:32 +02:00
Petr Sloup
427a0f0687 Update package version to 2.1.0 2017-07-03 09:41:27 +02:00
Petr Sloup
da5ea4b426 Update Mapbox GL JS to v0.38.0 (close #188) 2017-07-03 09:39:55 +02:00
Petr Sloup
2208ff1e24 Merge pull request #187 from aleksejleonov/debian_stretch_nodejs_repo
Use debian stretch nodejs repo
2017-07-03 09:29:29 +02:00
Oleksii Leonov
cf521058be Use debian stretch nodejs repo
Dockerfile based on debian:stretch, so better to use native stretch nodejs repo instead of jessie repo.
2017-06-30 00:54:13 +03:00
Petr Sloup
a9b38022bb Give xvfb some time to start up before starting the server in docker (#185) 2017-06-29 10:50:02 +02:00
10 changed files with 600 additions and 498 deletions

View File

@@ -15,8 +15,8 @@ RUN apt-get -qq update \
libprotobuf-dev \ libprotobuf-dev \
libxxf86vm-dev \ libxxf86vm-dev \
xvfb \ xvfb \
&& echo "deb https://deb.nodesource.com/node_6.x jessie main" >> /etc/apt/sources.list.d/nodejs.list \ && echo "deb https://deb.nodesource.com/node_6.x stretch main" >> /etc/apt/sources.list.d/nodejs.list \
&& echo "deb-src https://deb.nodesource.com/node_6.x jessie main" >> /etc/apt/sources.list.d/nodejs.list \ && echo "deb-src https://deb.nodesource.com/node_6.x stretch main" >> /etc/apt/sources.list.d/nodejs.list \
&& apt-get -qq update \ && apt-get -qq update \
&& DEBIAN_FRONTEND=noninteractive apt-get -y --allow-unauthenticated install \ && DEBIAN_FRONTEND=noninteractive apt-get -y --allow-unauthenticated install \
nodejs \ nodejs \

View File

@@ -34,7 +34,7 @@ Alternatively, you can use the `tileserver-gl-light` package instead, which is p
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: 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 ```bash
docker run -it -v $(pwd):/data -p 8080:80 klokantech/tileserver-gl 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. 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.

View File

@@ -7,7 +7,7 @@ Docker
When running docker image, no special installation is needed -- the docker will automatically download the image if not present. When running docker image, no special installation is needed -- the docker will automatically download the image if not present.
Just run ``docker run -it -v $(pwd):/data -p 8080:80 klokantech/tileserver-gl``. Just run ``docker run --rm -it -v $(pwd):/data -p 8080:80 klokantech/tileserver-gl``.
Additional options (see :doc:`/usage`) can be passed to the TileServer GL by appending them to the end of this command. You can, for example, do the following: Additional options (see :doc:`/usage`) can be passed to the TileServer GL by appending them to the end of this command. You can, for example, do the following:

View File

@@ -1,6 +1,6 @@
{ {
"name": "tileserver-gl", "name": "tileserver-gl",
"version": "2.0.0", "version": "2.2.0",
"description": "Map tile server for JSON GL styles - vector and server side generated raster tiles", "description": "Map tile server for JSON GL styles - vector and server side generated raster tiles",
"main": "src/main.js", "main": "src/main.js",
"bin": "src/main.js", "bin": "src/main.js",
@@ -23,24 +23,24 @@
"@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.2", "advanced-pool": "0.3.3",
"base64url": "2.0.0", "base64url": "2.0.0",
"canvas": "1.6.5", "canvas": "1.6.6",
"clone": "2.1.1", "clone": "2.1.1",
"color": "1.0.3", "color": "1.0.3",
"cors": "2.8.3", "cors": "2.8.4",
"express": "4.15.3", "express": "4.15.4",
"glyph-pbf-composite": "0.0.2", "glyph-pbf-composite": "0.0.2",
"handlebars": "4.0.10", "handlebars": "4.0.10",
"http-shutdown": "^1.2.0", "http-shutdown": "^1.2.0",
"morgan": "1.8.2", "morgan": "1.8.2",
"node-pngquant-native": "1.0.4", "node-pngquant-native": "1.0.5",
"nomnom": "1.8.1", "nomnom": "1.8.1",
"pbf": "3.0.5", "pbf": "3.0.5",
"proj4": "2.4.3", "proj4": "2.4.4",
"request": "2.81.0", "request": "2.81.0",
"sharp": "0.18.1", "sharp": "0.18.2",
"tileserver-gl-styles": "1.1.1" "tileserver-gl-styles": "1.2.0"
}, },
"devDependencies": { "devDependencies": {
"should": "^11.2.0", "should": "^11.2.0",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

7
run.sh
View File

@@ -1,3 +1,8 @@
#!/bin/bash #!/bin/bash
start-stop-daemon --start --pidfile ~/xvfb.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -screen 0 1024x768x24 -ac +extension GLX +render -noreset
sleep 1
export DISPLAY=:99.0
cd /data cd /data
xvfb-run -a -e /dev/stdout --server-args="-screen 0 1024x768x24" node /usr/src/app/ -p 80 "$@" node /usr/src/app/ -p 80 "$@"

View File

@@ -50,6 +50,10 @@ module.exports = function(options, repo, params, id, styles) {
Object.assign(tileJSON, params.tilejson || {}); Object.assign(tileJSON, params.tilejson || {});
utils.fixTileJSONCenter(tileJSON); utils.fixTileJSONCenter(tileJSON);
if (options.dataDecoratorFunc) {
tileJSON = options.dataDecoratorFunc(id, 'tilejson', tileJSON);
}
resolve(); resolve();
}); });
}); });
@@ -114,6 +118,13 @@ module.exports = function(options, repo, params, id, styles) {
//console.log(shrinkers[style].getStats()); //console.log(shrinkers[style].getStats());
} }
} }
if (options.dataDecoratorFunc) {
if (isGzipped) {
data = zlib.unzipSync(data);
isGzipped = false;
}
data = options.dataDecoratorFunc(id, 'data', data, z, x, y);
}
} }
if (format == 'pbf') { if (format == 'pbf') {
headers['Content-Type'] = 'application/x-protobuf'; headers['Content-Type'] = 'application/x-protobuf';

View File

@@ -3,6 +3,7 @@
var advancedPool = require('advanced-pool'), var advancedPool = require('advanced-pool'),
fs = require('fs'), fs = require('fs'),
path = require('path'), path = require('path'),
url = require('url'),
util = require('util'), util = require('util'),
zlib = require('zlib'); zlib = require('zlib');
@@ -35,6 +36,68 @@ mbgl.on('message', function(e) {
} }
}); });
/**
* Lookup of sharp output formats by file extension.
*/
var extensionToFormat = {
'.jpg': 'jpeg',
'.jpeg': 'jpeg',
'.png': 'png',
'.webp': 'webp'
};
/**
* Cache of response data by sharp output format and color. Entry for empty
* string is for unknown or unsupported formats.
*/
var cachedEmptyResponses = {
'': new Buffer(0)
};
/**
* Create an appropriate mbgl response for http errors.
* @param {string} format The format (a sharp format or 'pbf').
* @param {string} color The background color (or empty string for transparent).
* @param {Function} callback The mbgl callback.
*/
function createEmptyResponse(format, color, callback) {
if (!format || format === 'pbf') {
callback(null, {data: cachedEmptyResponses['']});
return;
}
if (format === 'jpg') {
format = 'jpeg';
}
if (!color) {
color = 'rgba(255,255,255,0)';
}
var cacheKey = format + ',' + color;
var data = cachedEmptyResponses[cacheKey];
if (data) {
callback(null, {data: data});
return;
}
// create an "empty" response image
var color = new Color(color);
var array = color.array();
var channels = array.length == 4 && format != 'jpeg' ? 4 : 3;
sharp(new Buffer(array), {
raw: {
width: 1,
height: 1,
channels: channels
}
}).toFormat(format).toBuffer(function(err, buffer, info) {
if (!err) {
cachedEmptyResponses[cacheKey] = buffer;
}
callback(null, {data: buffer});
});
}
module.exports = function(options, repo, params, id, dataResolver) { module.exports = function(options, repo, params, id, dataResolver) {
var app = express().disable('x-powered-by'); var app = express().disable('x-powered-by');
@@ -100,7 +163,8 @@ module.exports = function(options, repo, params, id, dataResolver) {
}); });
} else if (protocol == 'mbtiles') { } else if (protocol == 'mbtiles') {
var parts = req.url.split('/'); var parts = req.url.split('/');
var source = map.sources[parts[2]]; var sourceId = parts[2];
var source = map.sources[sourceId];
var z = parts[3] | 0, var z = parts[3] | 0,
x = parts[4] | 0, x = parts[4] | 0,
y = parts[5].split('.')[0] | 0, y = parts[5].split('.')[0] | 0,
@@ -108,22 +172,26 @@ module.exports = function(options, repo, params, id, dataResolver) {
source.getTile(z, x, y, function(err, data, headers) { source.getTile(z, x, y, function(err, data, headers) {
if (err) { if (err) {
//console.log('MBTiles error, serving empty', err); //console.log('MBTiles error, serving empty', err);
callback(null, { data: source.emptyTile }); createEmptyResponse(source.format, source.color, callback);
} else { return;
var response = {};
if (headers['Last-Modified']) {
response.modified = new Date(headers['Last-Modified']);
}
if (format == 'pbf') {
response.data = zlib.unzipSync(data);
} else {
response.data = data;
}
callback(null, response);
} }
var response = {};
if (headers['Last-Modified']) {
response.modified = new Date(headers['Last-Modified']);
}
if (format == 'pbf') {
response.data = zlib.unzipSync(data);
if (options.dataDecoratorFunc) {
response.data = options.dataDecoratorFunc(
sourceId, 'data', response.data, z, x, y);
}
} else {
response.data = data;
}
callback(null, response);
}); });
} else if (protocol == 'http' || protocol == 'https') { } else if (protocol == 'http' || protocol == 'https') {
request({ request({
@@ -131,29 +199,28 @@ module.exports = function(options, repo, params, id, dataResolver) {
encoding: null, encoding: null,
gzip: true gzip: true
}, function(err, res, body) { }, function(err, res, body) {
if (err) { var parts = url.parse(req.url);
//console.log('HTTP tile error', err); var extension = path.extname(parts.pathname).toLowerCase();
callback(null, { data: new Buffer(0) }); var format = extensionToFormat[extension] || '';
} else if (res.statusCode == 200) { if (err || res.statusCode < 200 || res.statusCode >= 300) {
var response = {}; // console.log('HTTP error', err || res.statusCode);
createEmptyResponse(format, '', callback);
if (res.headers.modified) { return;
response.modified = new Date(res.headers.modified);
}
if (res.headers.expires) {
response.expires = new Date(res.headers.expires);
}
if (res.headers.etag) {
response.etag = res.headers.etag;
}
response.data = body;
callback(null, response);
} else {
//console.log('HTTP error', JSON.parse(body).message);
callback(null, { data: new Buffer(0) });
} }
var response = {};
if (res.headers.modified) {
response.modified = new Date(res.headers.modified);
}
if (res.headers.expires) {
response.expires = new Date(res.headers.expires);
}
if (res.headers.etag) {
response.etag = res.headers.etag;
}
response.data = body;
callback(null, response);
}); });
} }
} }
@@ -258,26 +325,11 @@ module.exports = function(options, repo, params, id, dataResolver) {
'mbtiles://' + name + '/{z}/{x}/{y}.' + (info.format || 'pbf') 'mbtiles://' + name + '/{z}/{x}/{y}.' + (info.format || 'pbf')
]; ];
delete source.scheme; delete source.scheme;
if (source.format == 'pbf') {
map.sources[name].emptyTile = new Buffer(0); if (options.dataDecoratorFunc) {
} else { source = options.dataDecoratorFunc(name, 'tilejson', source);
var color = new Color(source.color || 'rgba(255,255,255,0)');
var format = source.format;
if (format == 'jpg') {
format = 'jpeg';
}
var array = color.array();
var channels = array.length == 4 && format != 'jpeg' ? 4 : 3;
sharp(new Buffer(array), {
raw: {
width: 1,
height: 1,
channels: channels
}
}).toFormat(format).toBuffer(function(err, buffer, info) {
map.sources[name].emptyTile = buffer;
});
} }
if (!attributionOverride && if (!attributionOverride &&
source.attribution && source.attribution.length > 0) { source.attribution && source.attribution.length > 0) {
if (tileJSON.attribution.length > 0) { if (tileJSON.attribution.length > 0) {

View File

@@ -89,6 +89,12 @@ function start(opts) {
checkPath('sprites'); checkPath('sprites');
checkPath('mbtiles'); checkPath('mbtiles');
if (options.dataDecorator) {
try {
options.dataDecoratorFunc = require(path.resolve(paths.root, options.dataDecorator));
} catch (e) {}
}
var data = clone(config.data || {}); var data = clone(config.data || {});
if (opts.cors) { if (opts.cors) {