Add "serveAllStyles" option + watch the directory

This commit is contained in:
Petr Sloup 2020-01-07 15:59:38 +01:00
parent cb700181d3
commit d7a34f3a74
5 changed files with 110 additions and 29 deletions

View file

@ -27,6 +27,7 @@ Example::
"maxSize": 2048, "maxSize": 2048,
"pbfAlias": "pbf", "pbfAlias": "pbf",
"serveAllFonts": false, "serveAllFonts": false,
"serveAllStyles": false,
"serveStaticMaps": true, "serveStaticMaps": true,
"tileMargin": 0 "tileMargin": 0
}, },
@ -124,6 +125,13 @@ If you have plenty of memory, try setting these equal to or slightly above your
If you need to conserve memory, try lower values for scale factors that are less common. If you need to conserve memory, try lower values for scale factors that are less common.
Default is ``[16, 8, 4]``. Default is ``[16, 8, 4]``.
``serveAllStyles``
------------------------
If this option is enabled, all the styles from the ``paths.styles`` will be served. (No recursion, only ``.json`` files are used.)
The process will also watch for changes in this directory and remove/add more styles dynamically.
It is recommended to also use the ``serveAllFonts`` option when using this option.
``watermark`` ``watermark``
----------- -----------

View file

@ -32,6 +32,7 @@
"handlebars": "4.5.3", "handlebars": "4.5.3",
"http-shutdown": "1.2.1", "http-shutdown": "1.2.1",
"morgan": "1.9.1", "morgan": "1.9.1",
"node-watch": "0.6.3",
"pbf": "3.2.1", "pbf": "3.2.1",
"proj4": "2.6.0", "proj4": "2.6.0",
"request": "2.88.0", "request": "2.88.0",

View file

@ -663,7 +663,12 @@ module.exports = {
const styleFile = params.style; const styleFile = params.style;
const styleJSONPath = path.resolve(options.paths.styles, styleFile); const styleJSONPath = path.resolve(options.paths.styles, styleFile);
styleJSON = clone(require(styleJSONPath)); try {
styleJSON = JSON.parse(fs.readFileSync(styleJSONPath));
} catch (e) {
console.log('Error parsing style file');
return false;
}
if (styleJSON.sprite && !httpTester.test(styleJSON.sprite)) { if (styleJSON.sprite && !httpTester.test(styleJSON.sprite)) {
styleJSON.sprite = 'sprites://' + styleJSON.sprite = 'sprites://' +
@ -798,5 +803,14 @@ module.exports = {
}); });
return Promise.all([renderersReadyPromise]); return Promise.all([renderersReadyPromise]);
},
remove: (repo, id) => {
let item = repo[id];
if (item) {
item.map.renderers.forEach(pool => {
pool.close();
});
} }
delete repo[id];
},
}; };

View file

@ -72,10 +72,19 @@ module.exports = {
return app; return app;
}, },
remove: (repo, id) => {
delete repo[id];
},
add: (options, repo, params, id, publicUrl, reportTiles, reportFont) => { add: (options, repo, params, id, publicUrl, reportTiles, reportFont) => {
const styleFile = path.resolve(options.paths.styles, params.style); const styleFile = path.resolve(options.paths.styles, params.style);
let styleJSON;
try {
styleJSON = JSON.parse(fs.readFileSync(styleFile));
} catch (e) {
console.log('Error parsing style file');
return false;
}
const styleJSON = clone(require(styleFile));
for (const name of Object.keys(styleJSON.sources)) { for (const name of Object.keys(styleJSON.sources)) {
const source = styleJSON.sources[name]; const source = styleJSON.sources[name];
const url = source.url; const url = source.url;
@ -92,6 +101,9 @@ module.exports = {
} }
} }
const identifier = reportTiles(mbtilesFile, fromData); const identifier = reportTiles(mbtilesFile, fromData);
if (!identifier) {
return false;
}
source.url = `local://data/${identifier}.json`; source.url = `local://data/${identifier}.json`;
} }
} }
@ -128,5 +140,7 @@ module.exports = {
publicUrl, publicUrl,
name: styleJSON.name name: styleJSON.name
}; };
return true;
} }
}; };

View file

@ -14,6 +14,7 @@ const express = require('express');
const handlebars = require('handlebars'); const handlebars = require('handlebars');
const mercator = new (require('@mapbox/sphericalmercator'))(); const mercator = new (require('@mapbox/sphericalmercator'))();
const morgan = require('morgan'); const morgan = require('morgan');
const watch = require('node-watch');
const packageJson = require('../package'); const packageJson = require('../package');
const serve_font = require('./serve_font'); const serve_font = require('./serve_font');
@ -114,15 +115,10 @@ function start(opts) {
); );
} }
for (const id of Object.keys(config.styles || {})) { let addStyle = (id, item, allowMoreData, reportFonts) => {
const item = config.styles[id]; let success = true;
if (!item.style || item.style.length === 0) {
console.log(`Missing "style" property for ${id}`);
continue;
}
if (item.serve_data !== false) { if (item.serve_data !== false) {
serve_style.add(options, serving.styles, item, id, opts.publicUrl, success = serve_style.add(options, serving.styles, item, id, opts.publicUrl,
(mbtiles, fromData) => { (mbtiles, fromData) => {
let dataItemId; let dataItemId;
for (const id of Object.keys(data)) { for (const id of Object.keys(data)) {
@ -138,9 +134,10 @@ function start(opts) {
} }
if (dataItemId) { // mbtiles exist in the data config if (dataItemId) { // mbtiles exist in the data config
return dataItemId; return dataItemId;
} else if (fromData) { } else {
console.log(`ERROR: data "${mbtiles}" not found!`); if (fromData || !allowMoreData) {
process.exit(1); console.log(`ERROR: style "${file.name}" using unknown mbtiles "${mbtiles}"! Skipping...`);
return undefined;
} else { } else {
let id = mbtiles.substr(0, mbtiles.lastIndexOf('.')) || mbtiles; let id = mbtiles.substr(0, mbtiles.lastIndexOf('.')) || mbtiles;
while (data[id]) id += '_'; while (data[id]) id += '_';
@ -149,11 +146,14 @@ function start(opts) {
}; };
return id; return id;
} }
}
}, font => { }, font => {
if (reportFonts) {
serving.fonts[font] = true; serving.fonts[font] = true;
}
}); });
} }
if (item.serve_rendered !== false) { if (success && item.serve_rendered !== false) {
if (serve_rendered) { if (serve_rendered) {
startupPromises.push(serve_rendered.add(options, serving.rendered, item, id, opts.publicUrl, startupPromises.push(serve_rendered.add(options, serving.rendered, item, id, opts.publicUrl,
mbtiles => { mbtiles => {
@ -170,6 +170,16 @@ function start(opts) {
item.serve_rendered = false; item.serve_rendered = false;
} }
} }
};
for (const id of Object.keys(config.styles || {})) {
const item = config.styles[id];
if (!item.style || item.style.length === 0) {
console.log(`Missing "style" property for ${id}`);
continue;
}
addStyle(id, item, true, true);
} }
startupPromises.push( startupPromises.push(
@ -190,6 +200,41 @@ function start(opts) {
); );
} }
if (options.serveAllStyles) {
fs.readdir(options.paths.styles, {withFileTypes: true}, (err, files) => {
if (err) {
return;
}
for (const file of files) {
if (file.isFile() &&
path.extname(file.name).toLowerCase() == '.json') {
let id = path.basename(file.name, '.json');
let item = {
style: file.name
};
addStyle(id, item, false, false);
}
}
});
watch(options.paths.styles,
{ persistent: false, filter: /\.json$/ },
(eventType, filename) => {
let id = path.basename(filename, '.json');
console.log(`Style "${id}" changed, updating...`);
serve_style.remove(serving.styles, id);
serve_rendered.remove(serving.rendered, id);
if (eventType == "update") {
let item = {
style: filename
};
addStyle(id, item, false, false);
}
});
}
app.get('/styles.json', (req, res, next) => { app.get('/styles.json', (req, res, next) => {
const result = []; const result = [];
const query = req.query.key ? (`?key=${req.query.key}`) : ''; const query = req.query.key ? (`?key=${req.query.key}`) : '';
@ -207,10 +252,9 @@ function start(opts) {
const addTileJSONs = (arr, req, type) => { const addTileJSONs = (arr, req, type) => {
for (const id of Object.keys(serving[type])) { for (const id of Object.keys(serving[type])) {
let info = clone(serving[type][id]); const info = clone(serving[type][id].tileJSON);
let path = ''; let path = '';
if (type === 'rendered') { if (type === 'rendered') {
info = info.tileJSON;
path = `styles/${id}`; path = `styles/${id}`;
} else { } else {
path = `${type}/${id}`; path = `${type}/${id}`;
@ -280,7 +324,7 @@ function start(opts) {
}; };
serveTemplate('/$', 'index', req => { serveTemplate('/$', 'index', req => {
const styles = clone(config.styles || {}); const styles = clone(serving.styles || {});
for (const id of Object.keys(styles)) { for (const id of Object.keys(styles)) {
const style = styles[id]; const style = styles[id];
style.name = (serving.styles[id] || serving.rendered[id] || {}).name; style.name = (serving.styles[id] || serving.rendered[id] || {}).name;
@ -341,7 +385,7 @@ function start(opts) {
serveTemplate('/styles/:id/$', 'viewer', req => { serveTemplate('/styles/:id/$', 'viewer', req => {
const id = req.params.id; const id = req.params.id;
const style = clone((config.styles || {})[id]); const style = clone(((serving.styles || {})[id] || {}).styleJSON);
if (!style) { if (!style) {
return null; return null;
} }
@ -359,7 +403,7 @@ function start(opts) {
*/ */
serveTemplate('/styles/:id/wmts.xml', 'wmts', req => { serveTemplate('/styles/:id/wmts.xml', 'wmts', req => {
const id = req.params.id; const id = req.params.id;
const wmts = clone((config.styles || {})[id]); const wmts = clone((serving.styles || {})[id]);
if (!wmts) { if (!wmts) {
return null; return null;
} }