From 7f8be27844e23a3dd42d717c51277d71ecd85f4a Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Sat, 21 Dec 2019 14:09:20 -0500 Subject: [PATCH] Update code to ES6 * var -> let / const * [].forEach -> for (... of ...) * '...' + var -> template strings `...${var}` * function -> arrow functions `=>` * use === and !== instead of == and != --- src/main.js | 124 +++++---- src/serve_data.js | 113 ++++---- src/serve_font.js | 51 ++-- src/serve_rendered.js | 594 +++++++++++++++++++++--------------------- src/serve_style.js | 92 +++---- src/server.js | 311 +++++++++++----------- src/utils.js | 149 +++++------ 7 files changed, 701 insertions(+), 733 deletions(-) diff --git a/src/main.js b/src/main.js index f8fd519..826e052 100644 --- a/src/main.js +++ b/src/main.js @@ -2,20 +2,20 @@ 'use strict'; -var fs = require('fs'), - path = require('path'), - request = require('request'); +const fs = require('fs'); +const path = require('path'); +const request = require('request'); -var mbtiles = require('@mapbox/mbtiles'); +const MBTiles = require('@mapbox/mbtiles'); -var packageJson = require('../package'); +const packageJson = require('../package'); -var args = process.argv; -if (args.length >= 3 && args[2][0] != '-') { +const args = process.argv; +if (args.length >= 3 && args[2][0] !== '-') { args.splice(2, 0, '--mbtiles'); } -var opts = require('commander') +const opts = require('commander') .description('tileserver-gl startup options') .usage('tileserver-gl [mbtiles] [options]') .option( @@ -68,10 +68,10 @@ var opts = require('commander') ) .parse(args); -console.log('Starting ' + packageJson.name + ' v' + packageJson.version); +console.log(`Starting ${packageJson.name} v${packageJson.version}`); -var startServer = function(configPath, config) { - var publicUrl = opts.public_url; +const startServer = (configPath, config) => { + let publicUrl = opts.public_url; if (publicUrl && publicUrl.lastIndexOf('/') !== publicUrl.length - 1) { publicUrl += '/'; } @@ -89,29 +89,34 @@ var startServer = function(configPath, config) { }); }; -var startWithMBTiles = function(mbtilesFile) { - console.log('Automatically creating config file for ' + mbtilesFile); +const startWithMBTiles = (mbtilesFile) => { + console.log(`Automatically creating config file for ${mbtilesFile}`); mbtilesFile = path.resolve(process.cwd(), mbtilesFile); - var mbtilesStats = fs.statSync(mbtilesFile); + const mbtilesStats = fs.statSync(mbtilesFile); if (!mbtilesStats.isFile() || mbtilesStats.size === 0) { - console.log('ERROR: Not valid MBTiles file: ' + mbtilesFile); + console.log(`ERROR: Not valid MBTiles file: ${mbtilesFile}`); process.exit(1); } - var instance = new mbtiles(mbtilesFile, function(err) { - instance.getInfo(function(err, info) { + const instance = new MBTiles(mbtilesFile, (err) => { + if (err) { + console.log('ERROR: Unable to open MBTiles.'); + console.log(` Make sure ${path.basename(mbtilesFile)} is valid MBTiles.`); + process.exit(1); + } + + instance.getInfo((err, info) => { if (err || !info) { console.log('ERROR: Metadata missing in the MBTiles.'); - console.log(' Make sure ' + path.basename(mbtilesFile) + - ' is valid MBTiles.'); + console.log(` Make sure ${path.basename(mbtilesFile)} is valid MBTiles.`); process.exit(1); } - var bounds = info.bounds; + const bounds = info.bounds; - var styleDir = path.resolve(__dirname, "../node_modules/tileserver-gl-styles/"); + const styleDir = path.resolve(__dirname, "../node_modules/tileserver-gl-styles/"); - var config = { + const config = { "options": { "paths": { "root": styleDir, @@ -124,33 +129,32 @@ var startWithMBTiles = function(mbtilesFile) { "data": {} }; - if (info.format == 'pbf' && - info.name.toLowerCase().indexOf('openmaptiles') > -1) { - var omtV = (info.version || '').split('.'); + if (info.format === 'pbf' && + info.name.toLowerCase().indexOf('openmaptiles') > -1) { + const omtV = (info.version || '').split('.'); - config['data']['v' + omtV[0]] = { + config['data'][`v${omtV[0]}`] = { "mbtiles": path.basename(mbtilesFile) }; - var styles = fs.readdirSync(path.resolve(styleDir, 'styles')); - for (var i = 0; i < styles.length; i++) { - var styleName = styles[i]; - var styleFileRel = styleName + '/style.json'; - var styleFile = path.resolve(styleDir, 'styles', styleFileRel); + const styles = fs.readdirSync(path.resolve(styleDir, 'styles')); + for (let styleName of styles) { + const styleFileRel = styleName + '/style.json'; + const styleFile = path.resolve(styleDir, 'styles', styleFileRel); if (fs.existsSync(styleFile)) { - var styleJSON = require(styleFile); - var omtVersionCompatibility = + const styleJSON = require(styleFile); + const omtVersionCompatibility = ((styleJSON || {}).metadata || {})['openmaptiles:version'] || 'x'; - var m = omtVersionCompatibility.toLowerCase().split('.'); + const m = omtVersionCompatibility.toLowerCase().split('.'); - var isCompatible = !( - m[0] != 'x' && ( - m[0] != omtV[0] || ( - (m[1] || 'x') != 'x' && ( - m[1] != omtV[1] || ( - (m[2] || 'x') != 'x' && - m[2] != omtV[2] + const isCompatible = !( + m[0] !== 'x' && ( + m[0] !== omtV[0] || ( + (m[1] || 'x') !== 'x' && ( + m[1] !== omtV[1] || ( + (m[2] || 'x') !== 'x' && + m[2] !== omtV[2] ) ) ) @@ -158,25 +162,22 @@ var startWithMBTiles = function(mbtilesFile) { ); if (isCompatible) { - var styleObject = { + config['styles'][styleName] = { "style": styleFileRel, "tilejson": { "bounds": bounds } }; - config['styles'][styleName] = styleObject; } else { - console.log('Style', styleName, 'requires OpenMapTiles version', - omtVersionCompatibility, 'but mbtiles is version', info.version); + console.log(`Style ${styleName} requires OpenMapTiles version ${omtVersionCompatibility} but mbtiles is version ${info.version}`); } } } } else { - console.log('WARN: MBTiles not in "openmaptiles" format. ' + - 'Serving raw data only...'); + console.log(`WARN: MBTiles not in "openmaptiles" format. Serving raw data only...`); config['data'][(info.id || 'mbtiles') .replace(/\//g, '_') - .replace(/\:/g, '_') + .replace(/:/g, '_') .replace(/\?/g, '_')] = { "mbtiles": path.basename(mbtilesFile) }; @@ -193,16 +194,15 @@ var startWithMBTiles = function(mbtilesFile) { }); }; -fs.stat(path.resolve(opts.config), function(err, stats) { +fs.stat(path.resolve(opts.config), (err, stats) => { if (err || !stats.isFile() || stats.size === 0) { - var mbtiles = opts.mbtiles; + let mbtiles = opts.mbtiles; if (!mbtiles) { // try to find in the cwd - var files = fs.readdirSync(process.cwd()); - for (var i=0; i < files.length; i++) { - var filename = files[i]; + const files = fs.readdirSync(process.cwd()); + for (let filename of files) { if (filename.endsWith('.mbtiles')) { - var mbTilesStats = fs.statSync(filename); + const mbTilesStats = fs.statSync(filename); if (mbTilesStats.isFile() && mbTilesStats.size > 0) { mbtiles = filename; break; @@ -210,16 +210,14 @@ fs.stat(path.resolve(opts.config), function(err, stats) { } } if (mbtiles) { - console.log('No MBTiles specified, using ' + mbtiles); + console.log(`No MBTiles specified, using ${mbtiles}`); return startWithMBTiles(mbtiles); } else { - var url = 'https://github.com/klokantech/tileserver-gl/releases/download/v1.3.0/zurich_switzerland.mbtiles'; - var filename = 'zurich_switzerland.mbtiles'; - var stream = fs.createWriteStream(filename); - console.log('Downloading sample data (' + filename + ') from ' + url); - stream.on('finish', function() { - return startWithMBTiles(filename); - }); + const url = 'https://github.com/klokantech/tileserver-gl/releases/download/v1.3.0/zurich_switzerland.mbtiles'; + const filename = 'zurich_switzerland.mbtiles'; + const stream = fs.createWriteStream(filename); + console.log(`Downloading sample data (${filename}) from ${url}`); + stream.on('finish', () => startWithMBTiles(filename)); return request.get(url).pipe(stream); } } @@ -227,7 +225,7 @@ fs.stat(path.resolve(opts.config), function(err, stats) { return startWithMBTiles(mbtiles); } } else { - console.log('Using specified config file from ' + opts.config); + console.log(`Using specified config file from ${opts.config}`); return startServer(opts.config, null); } }); diff --git a/src/serve_data.js b/src/serve_data.js index 8b6d487..a7929d2 100644 --- a/src/serve_data.js +++ b/src/serve_data.js @@ -1,47 +1,47 @@ 'use strict'; -var fs = require('fs'), - path = require('path'), - zlib = require('zlib'); +const fs = require('fs'); +const path = require('path'); +const zlib = require('zlib'); -var clone = require('clone'), - express = require('express'), - mbtiles = require('@mapbox/mbtiles'), - pbf = require('pbf'), - VectorTile = require('@mapbox/vector-tile').VectorTile; +const clone = require('clone'); +const express = require('express'); +const MBTiles = require('@mapbox/mbtiles'); +const Pbf = require('pbf'); +const VectorTile = require('@mapbox/vector-tile').VectorTile; -var tileshrinkGl; +let tileshrinkGl; try { tileshrinkGl = require('tileshrink-gl'); global.addStyleParam = true; } catch (e) {} -var utils = require('./utils'); +const utils = require('./utils'); -module.exports = function(options, repo, params, id, styles, publicUrl) { - var app = express().disable('x-powered-by'); +module.exports = (options, repo, params, id, styles, publicUrl) => { + const app = express().disable('x-powered-by'); - var mbtilesFile = path.resolve(options.paths.mbtiles, params.mbtiles); - var tileJSON = { + const mbtilesFile = path.resolve(options.paths.mbtiles, params.mbtiles); + let tileJSON = { 'tiles': params.domains || options.domains }; - var shrinkers = {}; + const shrinkers = {}; repo[id] = tileJSON; - var mbtilesFileStats = fs.statSync(mbtilesFile); - if (!mbtilesFileStats.isFile() || mbtilesFileStats.size == 0) { - throw Error('Not valid MBTiles file: ' + mbtilesFile); + const mbtilesFileStats = fs.statSync(mbtilesFile); + if (!mbtilesFileStats.isFile() || mbtilesFileStats.size === 0) { + throw Error(`Not valid MBTiles file: ${mbtilesFile}`); } - var source; - var sourceInfoPromise = new Promise(function(resolve, reject) { - source = new mbtiles(mbtilesFile, function(err) { + let source; + const sourceInfoPromise = new Promise((resolve, reject) => { + source = new MBTiles(mbtilesFile, err => { if (err) { reject(err); return; } - source.getInfo(function(err, info) { + source.getInfo((err, info) => { if (err) { reject(err); return; @@ -67,18 +67,18 @@ module.exports = function(options, repo, params, id, styles, publicUrl) { }); }); - var tilePattern = '/' + id + '/:z(\\d+)/:x(\\d+)/:y(\\d+).:format([\\w.]+)'; + const tilePattern = `/${id}/:z(\\d+)/:x(\\d+)/:y(\\d+).:format([\\w.]+)`; - app.get(tilePattern, function(req, res, next) { - var z = req.params.z | 0, - x = req.params.x | 0, - y = req.params.y | 0; - var format = req.params.format; - if (format == options.pbfAlias) { + app.get(tilePattern, (req, res, next) => { + const z = req.params.z | 0; + const x = req.params.x | 0; + const y = req.params.y | 0; + let format = req.params.format; + if (format === options.pbfAlias) { format = 'pbf'; } - if (format != tileJSON.format && - !(format == 'geojson' && tileJSON.format == 'pbf')) { + if (format !== tileJSON.format && + !(format === 'geojson' && tileJSON.format === 'pbf')) { return res.status(404).send('Invalid format'); } if (z < tileJSON.minzoom || 0 || x < 0 || y < 0 || @@ -86,7 +86,8 @@ module.exports = function(options, repo, params, id, styles, publicUrl) { x >= Math.pow(2, z) || y >= Math.pow(2, z)) { return res.status(404).send('Out of bounds'); } - source.getTile(z, x, y, function(err, data, headers) { + source.getTile(z, x, y, (err, data, headers) => { + let isGzipped; if (err) { if (/does not exist/.test(err.message)) { return res.status(204).send(); @@ -97,20 +98,20 @@ module.exports = function(options, repo, params, id, styles, publicUrl) { if (data == null) { return res.status(404).send('Not found'); } else { - if (tileJSON['format'] == 'pbf') { - var isGzipped = data.slice(0,2).indexOf( - new Buffer([0x1f, 0x8b])) === 0; - var style = req.query.style; + if (tileJSON['format'] === 'pbf') { + isGzipped = data.slice(0, 2).indexOf( + new Buffer([0x1f, 0x8b])) === 0; + const style = req.query.style; if (style && tileshrinkGl) { if (!shrinkers[style]) { - var styleJSON = styles[style]; + const styleJSON = styles[style]; if (styleJSON) { - var sourceName = null; - for (var sourceName_ in styleJSON.sources) { - var source = styleJSON.sources[sourceName_]; + let sourceName = null; + for (let sourceName_ in styleJSON.sources) { + const source = styleJSON.sources[sourceName_]; if (source && - source.type == 'vector' && - source.url.endsWith('/' + id + '.json')) { + source.type === 'vector' && + source.url.endsWith(`/${id}.json`)) { sourceName = sourceName_; } } @@ -134,9 +135,9 @@ module.exports = function(options, repo, params, id, styles, publicUrl) { data = options.dataDecoratorFunc(id, 'data', data, z, x, y); } } - if (format == 'pbf') { + if (format === 'pbf') { headers['Content-Type'] = 'application/x-protobuf'; - } else if (format == 'geojson') { + } else if (format === 'geojson') { headers['Content-Type'] = 'application/json'; if (isGzipped) { @@ -144,16 +145,16 @@ module.exports = function(options, repo, params, id, styles, publicUrl) { isGzipped = false; } - var tile = new VectorTile(new pbf(data)); - var geojson = { + const tile = new VectorTile(new Pbf(data)); + const geojson = { "type": "FeatureCollection", "features": [] }; - for (var layerName in tile.layers) { - var layer = tile.layers[layerName]; - for (var i = 0; i < layer.length; i++) { - var feature = layer.feature(i); - var featureGeoJSON = feature.toGeoJSON(x, y, z); + for (let layerName in tile.layers) { + const layer = tile.layers[layerName]; + for (let i = 0; i < layer.length; i++) { + const feature = layer.feature(i); + const featureGeoJSON = feature.toGeoJSON(x, y, z); featureGeoJSON.properties.layer = layerName; geojson.features.push(featureGeoJSON); } @@ -175,16 +176,14 @@ module.exports = function(options, repo, params, id, styles, publicUrl) { }); }); - app.get('/' + id + '.json', function(req, res, next) { - var info = clone(tileJSON); + app.get(`/${id}.json`, (req, res, next) => { + const info = clone(tileJSON); info.tiles = utils.getTileUrls(req, info.tiles, - 'data/' + id, info.format, publicUrl, { + `data/${id}`, info.format, publicUrl, { 'pbf': options.pbfAlias }); return res.send(info); }); - return sourceInfoPromise.then(function() { - return app; - }); + return sourceInfoPromise.then(() => app); }; diff --git a/src/serve_font.js b/src/serve_font.js index b9ec76e..9123fe6 100644 --- a/src/serve_font.js +++ b/src/serve_font.js @@ -1,66 +1,61 @@ 'use strict'; -var clone = require('clone'), - express = require('express'), - fs = require('fs'), - path = require('path'); +const clone = require('clone'); +const express = require('express'); +const fs = require('fs'); +const path = require('path'); -var utils = require('./utils'); +const utils = require('./utils'); -module.exports = function(options, allowedFonts) { - var app = express().disable('x-powered-by'); +module.exports = (options, allowedFonts) => { + const app = express().disable('x-powered-by'); - var lastModified = new Date().toUTCString(); + const lastModified = new Date().toUTCString(); - var fontPath = options.paths.fonts; + const fontPath = options.paths.fonts; - var existingFonts = {}; - var fontListingPromise = new Promise(function(resolve, reject) { - fs.readdir(options.paths.fonts, function(err, files) { + const existingFonts = {}; + const fontListingPromise = new Promise((resolve, reject) => { + fs.readdir(options.paths.fonts, (err, files) => { if (err) { reject(err); return; } - files.forEach(function(file) { - fs.stat(path.join(fontPath, file), function(err, stats) { + for (const file of files) { + fs.stat(path.join(fontPath, file), (err, stats) => { if (err) { reject(err); return; } if (stats.isDirectory() && - fs.existsSync(path.join(fontPath, file, '0-255.pbf'))) { + fs.existsSync(path.join(fontPath, file, '0-255.pbf'))) { existingFonts[path.basename(file)] = true; } }); - }); + } resolve(); }); }); - app.get('/fonts/:fontstack/:range([\\d]+-[\\d]+).pbf', - function(req, res, next) { - var fontstack = decodeURI(req.params.fontstack); - var range = req.params.range; + app.get('/fonts/:fontstack/:range([\\d]+-[\\d]+).pbf', (req, res, next) => { + const fontstack = decodeURI(req.params.fontstack); + const range = req.params.range; utils.getFontsPbf(options.serveAllFonts ? null : allowedFonts, - fontPath, fontstack, range, existingFonts).then(function(concated) { + fontPath, fontstack, range, existingFonts).then(concated => { res.header('Content-type', 'application/x-protobuf'); res.header('Last-Modified', lastModified); return res.send(concated); - }, function(err) { - return res.status(400).send(err); - } + }, err => res.status(400).send(err) ); }); - app.get('/fonts.json', function(req, res, next) { + app.get('/fonts.json', (req, res, next) => { res.header('Content-type', 'application/json'); return res.send( Object.keys(options.serveAllFonts ? existingFonts : allowedFonts).sort() ); }); - return fontListingPromise.then(function() { - return app; - }); + return fontListingPromise.then(() => app); }; diff --git a/src/serve_rendered.js b/src/serve_rendered.js index 3458384..d79cdba 100644 --- a/src/serve_rendered.js +++ b/src/serve_rendered.js @@ -1,37 +1,35 @@ 'use strict'; -var advancedPool = require('advanced-pool'), - fs = require('fs'), - path = require('path'), - url = require('url'), - util = require('util'), - zlib = require('zlib'); +const advancedPool = require('advanced-pool'); +const fs = require('fs'); +const path = require('path'); +const url = require('url'); +const util = require('util'); +const zlib = require('zlib'); // sharp has to be required before node-canvas // see https://github.com/lovell/sharp/issues/371 -var sharp = require('sharp'); +const sharp = require('sharp'); const { createCanvas } = require('canvas'); -var clone = require('clone'), - Color = require('color'), - express = require('express'), - mercator = new (require('@mapbox/sphericalmercator'))(), - mbgl = require('@mapbox/mapbox-gl-native'), - mbtiles = require('@mapbox/mbtiles'), - proj4 = require('proj4'), - request = require('request'); +const clone = require('clone'); +const Color = require('color'); +const express = require('express'); +const mercator = new (require('@mapbox/sphericalmercator'))(); +const mbgl = require('@mapbox/mapbox-gl-native'); +const MBTiles = require('@mapbox/mbtiles'); +const proj4 = require('proj4'); +const request = require('request'); -var utils = require('./utils'); +const utils = require('./utils'); -var FLOAT_PATTERN = '[+-]?(?:\\d+|\\d+\.?\\d+)'; +const FLOAT_PATTERN = '[+-]?(?:\\d+|\\d+\.?\\d+)'; -var getScale = function(scale) { - return (scale || '@1x').slice(1, 2) | 0; -}; +const getScale = scale => (scale || '@1x').slice(1, 2) | 0; -mbgl.on('message', function(e) { - if (e.severity == 'WARNING' || e.severity == 'ERROR') { +mbgl.on('message', e => { + if (e.severity === 'WARNING' || e.severity === 'ERROR') { console.log('mbgl:', e); } }); @@ -39,7 +37,7 @@ mbgl.on('message', function(e) { /** * Lookup of sharp output formats by file extension. */ -var extensionToFormat = { +const extensionToFormat = { '.jpg': 'jpeg', '.jpeg': 'jpeg', '.png': 'png', @@ -50,7 +48,7 @@ var extensionToFormat = { * Cache of response data by sharp output format and color. Entry for empty * string is for unknown or unsupported formats. */ -var cachedEmptyResponses = { +const cachedEmptyResponses = { '': new Buffer(0) }; @@ -73,24 +71,24 @@ function createEmptyResponse(format, color, callback) { color = 'rgba(255,255,255,0)'; } - var cacheKey = format + ',' + color; - var data = cachedEmptyResponses[cacheKey]; + const cacheKey = `${format},${color}`; + const 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; + color = new Color(color); + const array = color.array(); + const 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) { + }).toFormat(format).toBuffer((err, buffer, info) => { if (!err) { cachedEmptyResponses[cacheKey] = buffer; } @@ -98,37 +96,35 @@ function createEmptyResponse(format, color, callback) { }); } -module.exports = function(options, repo, params, id, publicUrl, dataResolver) { - var app = express().disable('x-powered-by'); +module.exports = (options, repo, params, id, publicUrl, dataResolver) => { + const app = express().disable('x-powered-by'); - var maxScaleFactor = Math.min(Math.floor(options.maxScaleFactor || 3), 9); - var scalePattern = ''; - for (var i = 2; i <= maxScaleFactor; i++) { + const maxScaleFactor = Math.min(Math.floor(options.maxScaleFactor || 3), 9); + let scalePattern = ''; + for (let i = 2; i <= maxScaleFactor; i++) { scalePattern += i.toFixed(); } - scalePattern = '@[' + scalePattern + ']x'; + scalePattern = `@[${scalePattern}]x`; - var lastModified = new Date().toUTCString(); + const lastModified = new Date().toUTCString(); - var rootPath = options.paths.root; + const watermark = params.watermark || options.watermark; - var watermark = params.watermark || options.watermark; - - var styleFile = params.style; - var map = { + const styleFile = params.style; + const map = { renderers: [], sources: {} }; - var existingFonts = {}; - var fontListingPromise = new Promise(function(resolve, reject) { - fs.readdir(options.paths.fonts, function(err, files) { + const existingFonts = {}; + const fontListingPromise = new Promise((resolve, reject) => { + fs.readdir(options.paths.fonts, (err, files) => { if (err) { reject(err); return; } - files.forEach(function(file) { - fs.stat(path.join(options.paths.fonts, file), function(err, stats) { + for (const file of files) { + fs.stat(path.join(options.paths.fonts, file), (err, stats) => { if (err) { reject(err); return; @@ -137,62 +133,61 @@ module.exports = function(options, repo, params, id, publicUrl, dataResolver) { existingFonts[path.basename(file)] = true; } }); - }); + } resolve(); }); }); - var styleJSON; - var createPool = function(ratio, min, max) { - var createRenderer = function(ratio, createCallback) { - var renderer = new mbgl.Map({ + let styleJSON; + const createPool = (ratio, min, max) => { + const createRenderer = (ratio, createCallback) => { + const renderer = new mbgl.Map({ ratio: ratio, - request: function(req, callback) { - var protocol = req.url.split(':')[0]; + request: (req, callback) => { + const protocol = req.url.split(':')[0]; //console.log('Handling request:', req); - if (protocol == 'sprites') { - var dir = options.paths[protocol]; - var file = unescape(req.url).substring(protocol.length + 3); - fs.readFile(path.join(dir, file), function(err, data) { + if (protocol === 'sprites') { + const dir = options.paths[protocol]; + const file = unescape(req.url).substring(protocol.length + 3); + fs.readFile(path.join(dir, file), (err, data) => { callback(err, { data: data }); }); - } else if (protocol == 'fonts') { - var parts = req.url.split('/'); - var fontstack = unescape(parts[2]); - var range = parts[3].split('.')[0]; + } else if (protocol === 'fonts') { + const parts = req.url.split('/'); + const fontstack = unescape(parts[2]); + const range = parts[3].split('.')[0]; utils.getFontsPbf( null, options.paths[protocol], fontstack, range, existingFonts - ).then(function(concated) { - callback(null, {data: concated}); - }, function(err) { - callback(err, {data: null}); + ).then(concated => { + callback(null, { data: concated }); + }, err => { + callback(err, { data: null }); }); - } else if (protocol == 'mbtiles') { - var parts = req.url.split('/'); - var sourceId = parts[2]; - var source = map.sources[sourceId]; - var sourceInfo = styleJSON.sources[sourceId]; - var z = parts[3] | 0, - x = parts[4] | 0, - y = parts[5].split('.')[0] | 0, - format = parts[5].split('.')[1]; - source.getTile(z, x, y, function(err, data, headers) { + } else if (protocol === 'mbtiles') { + const parts = req.url.split('/'); + const sourceId = parts[2]; + const source = map.sources[sourceId]; + const sourceInfo = styleJSON.sources[sourceId]; + const z = parts[3] | 0, + x = parts[4] | 0, + y = parts[5].split('.')[0] | 0, + format = parts[5].split('.')[1]; + source.getTile(z, x, y, (err, data, headers) => { if (err) { if (options.verbose) console.log('MBTiles error, serving empty', err); createEmptyResponse(sourceInfo.format, sourceInfo.color, callback); return; } - var response = {}; + const response = {}; if (headers['Last-Modified']) { response.modified = new Date(headers['Last-Modified']); } - if (format == 'pbf') { + if (format === 'pbf') { try { response.data = zlib.unzipSync(data); - } - catch (err) { + } catch (err) { console.log("Skipping incorrect header for tile mbtiles://%s/%s/%s/%s.pbf", id, z, x, y); } if (options.dataDecoratorFunc) { @@ -205,34 +200,34 @@ module.exports = function(options, repo, params, id, publicUrl, dataResolver) { callback(null, response); }); - } else if (protocol == 'http' || protocol == 'https') { + } else if (protocol === 'http' || protocol === 'https') { request({ - url: req.url, - encoding: null, - gzip: true - }, function(err, res, body) { - var parts = url.parse(req.url); - var extension = path.extname(parts.pathname).toLowerCase(); - var format = extensionToFormat[extension] || ''; - if (err || res.statusCode < 200 || res.statusCode >= 300) { - // console.log('HTTP error', err || res.statusCode); - createEmptyResponse(format, '', callback); - return; - } + url: req.url, + encoding: null, + gzip: true + }, (err, res, body) => { + const parts = url.parse(req.url); + const extension = path.extname(parts.pathname).toLowerCase(); + const format = extensionToFormat[extension] || ''; + if (err || res.statusCode < 200 || res.statusCode >= 300) { + // console.log('HTTP error', err || res.statusCode); + createEmptyResponse(format, '', callback); + return; + } - 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; - } + const 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); + response.data = body; + callback(null, response); }); } } @@ -244,16 +239,16 @@ module.exports = function(options, repo, params, id, publicUrl, dataResolver) { min: min, max: max, create: createRenderer.bind(null, ratio), - destroy: function(renderer) { + destroy: renderer => { renderer.release(); } }); }; - var styleJSONPath = path.resolve(options.paths.styles, styleFile); + const styleJSONPath = path.resolve(options.paths.styles, styleFile); styleJSON = clone(require(styleJSONPath)); - var httpTester = /^(http(s)?:)?\/\//; + const httpTester = /^(http(s)?:)?\/\//; if (styleJSON.sprite && !httpTester.test(styleJSON.sprite)) { styleJSON.sprite = 'sprites://' + styleJSON.sprite @@ -261,10 +256,10 @@ module.exports = function(options, repo, params, id, publicUrl, dataResolver) { .replace('{styleJsonFolder}', path.relative(options.paths.sprites, path.dirname(styleJSONPath))); } if (styleJSON.glyphs && !httpTester.test(styleJSON.glyphs)) { - styleJSON.glyphs = 'fonts://' + styleJSON.glyphs; + styleJSON.glyphs = `fonts://${styleJSON.glyphs}`; } - (styleJSON.layers || []).forEach(function(layer) { + for (const layer of (styleJSON.layers || [])) { if (layer && layer.paint) { // Remove (flatten) 3D buildings if (layer.paint['fill-extrusion-height']) { @@ -274,9 +269,9 @@ module.exports = function(options, repo, params, id, publicUrl, dataResolver) { layer.paint['fill-extrusion-base'] = 0; } } - }); + } - var tileJSON = { + const tileJSON = { 'tilejson': '2.0.0', 'name': styleJSON.name, 'attribution': '', @@ -286,47 +281,47 @@ module.exports = function(options, repo, params, id, publicUrl, dataResolver) { 'format': 'png', 'type': 'baselayer' }; - var attributionOverride = params.tilejson && params.tilejson.attribution; + const attributionOverride = params.tilejson && params.tilejson.attribution; Object.assign(tileJSON, params.tilejson || {}); tileJSON.tiles = params.domains || options.domains; utils.fixTileJSONCenter(tileJSON); - var dataProjWGStoInternalWGS = null; + let dataProjWGStoInternalWGS = null; - var queue = []; - Object.keys(styleJSON.sources).forEach(function(name) { - var source = styleJSON.sources[name]; - var url = source.url; + const queue = []; + for (const name of Object.keys(styleJSON.sources)) { + let source = styleJSON.sources[name]; + const url = source.url; if (url && url.lastIndexOf('mbtiles:', 0) === 0) { // found mbtiles source, replace with info from local file delete source.url; - var mbtilesFile = url.substring('mbtiles://'.length); - var fromData = mbtilesFile[0] == '{' && - mbtilesFile[mbtilesFile.length - 1] == '}'; + let mbtilesFile = url.substring('mbtiles://'.length); + const fromData = mbtilesFile[0] === '{' && + mbtilesFile[mbtilesFile.length - 1] === '}'; if (fromData) { mbtilesFile = mbtilesFile.substr(1, mbtilesFile.length - 2); - var mapsTo = (params.mapping || {})[mbtilesFile]; + const mapsTo = (params.mapping || {})[mbtilesFile]; if (mapsTo) { mbtilesFile = mapsTo; } mbtilesFile = dataResolver(mbtilesFile); if (!mbtilesFile) { - console.error('ERROR: data "' + mbtilesFile + '" not found!'); + console.error(`ERROR: data "${mbtilesFile}" not found!`); process.exit(1); } } - queue.push(new Promise(function(resolve, reject) { + queue.push(new Promise((resolve, reject) => { mbtilesFile = path.resolve(options.paths.mbtiles, mbtilesFile); - var mbtilesFileStats = fs.statSync(mbtilesFile); - if (!mbtilesFileStats.isFile() || mbtilesFileStats.size == 0) { - throw Error('Not valid MBTiles file: ' + mbtilesFile); + const mbtilesFileStats = fs.statSync(mbtilesFile); + if (!mbtilesFileStats.isFile() || mbtilesFileStats.size === 0) { + throw Error(`Not valid MBTiles file: ${mbtilesFile}`); } - map.sources[name] = new mbtiles(mbtilesFile, function(err) { - map.sources[name].getInfo(function(err, info) { + map.sources[name] = new MBTiles(mbtilesFile, err => { + map.sources[name].getInfo((err, info) => { if (err) { console.error(err); return; @@ -334,19 +329,17 @@ module.exports = function(options, repo, params, id, publicUrl, dataResolver) { if (!dataProjWGStoInternalWGS && info.proj4) { // how to do this for multiple sources with different proj4 defs? - var to3857 = proj4('EPSG:3857'); - var toDataProj = proj4(info.proj4); - dataProjWGStoInternalWGS = function(xy) { - return to3857.inverse(toDataProj.forward(xy)); - }; + const to3857 = proj4('EPSG:3857'); + const toDataProj = proj4(info.proj4); + dataProjWGStoInternalWGS = xy => to3857.inverse(toDataProj.forward(xy)); } - var type = source.type; + const type = source.type; Object.assign(source, info); source.type = type; source.tiles = [ // meta url which will be detected when requested - 'mbtiles://' + name + '/{z}/{x}/{y}.' + (info.format || 'pbf') + `mbtiles://${name}/{z}/{x}/{y}.${info.format || 'pbf'}` ]; delete source.scheme; @@ -366,49 +359,48 @@ module.exports = function(options, repo, params, id, publicUrl, dataResolver) { }); })); } - }); + } - var renderersReadyPromise = Promise.all(queue).then(function() { + const renderersReadyPromise = Promise.all(queue).then(() => { // standard and @2x tiles are much more usual -> default to larger pools - var minPoolSizes = options.minRendererPoolSizes || [8, 4, 2]; - var maxPoolSizes = options.maxRendererPoolSizes || [16, 8, 4]; - for (var s = 1; s <= maxScaleFactor; s++) { - var i = Math.min(minPoolSizes.length - 1, s - 1); - var j = Math.min(maxPoolSizes.length - 1, s - 1); - var minPoolSize = minPoolSizes[i]; - var maxPoolSize = Math.max(minPoolSize, maxPoolSizes[j]); + const minPoolSizes = options.minRendererPoolSizes || [8, 4, 2]; + const maxPoolSizes = options.maxRendererPoolSizes || [16, 8, 4]; + for (let s = 1; s <= maxScaleFactor; s++) { + const i = Math.min(minPoolSizes.length - 1, s - 1); + const j = Math.min(maxPoolSizes.length - 1, s - 1); + const minPoolSize = minPoolSizes[i]; + const maxPoolSize = Math.max(minPoolSize, maxPoolSizes[j]); map.renderers[s] = createPool(s, minPoolSize, maxPoolSize); } }); repo[id] = tileJSON; - var tilePattern = '/' + id + '/:z(\\d+)/:x(\\d+)/:y(\\d+)' + - ':scale(' + scalePattern + ')?\.:format([\\w]+)'; + const tilePattern = `/${id}/:z(\\d+)/:x(\\d+)/:y(\\d+):scale(${scalePattern})?.:format([\\w]+)`; - var respondImage = function(z, lon, lat, bearing, pitch, - width, height, scale, format, res, next, - opt_overlay) { + const respondImage = (z, lon, lat, bearing, pitch, + width, height, scale, format, res, next, + opt_overlay) => { if (Math.abs(lon) > 180 || Math.abs(lat) > 85.06 || - lon != lon || lat != lat) { + lon !== lon || lat !== lat) { return res.status(400).send('Invalid center'); } if (Math.min(width, height) <= 0 || - Math.max(width, height) * scale > (options.maxSize || 2048) || - width != width || height != height) { + Math.max(width, height) * scale > (options.maxSize || 2048) || + width !== width || height !== height) { return res.status(400).send('Invalid size'); } - if (format == 'png' || format == 'webp') { - } else if (format == 'jpg' || format == 'jpeg') { + if (format === 'png' || format === 'webp') { + } else if (format === 'jpg' || format === 'jpeg') { format = 'jpeg'; } else { return res.status(400).send('Invalid format'); } - var pool = map.renderers[scale]; - pool.acquire(function(err, renderer) { - var mbglZ = Math.max(0, z - 1); - var params = { + const pool = map.renderers[scale]; + pool.acquire((err, renderer) => { + const mbglZ = Math.max(0, z - 1); + const params = { zoom: mbglZ, center: [lon, lat], bearing: bearing, @@ -416,25 +408,25 @@ module.exports = function(options, repo, params, id, publicUrl, dataResolver) { width: width, height: height }; - if (z == 0) { + if (z === 0) { params.width *= 2; params.height *= 2; } - var tileMargin = Math.max(options.tileMargin || 0, 0); + const tileMargin = Math.max(options.tileMargin || 0, 0); if (z > 2 && tileMargin > 0) { params.width += tileMargin * 2 * scale; params.height += tileMargin * 2 * scale; } - renderer.render(params, function(err, data) { + renderer.render(params, (err, data) => { pool.release(renderer); if (err) { console.error(err); return; } - var image = sharp(data, { + const image = sharp(data, { raw: { width: params.width * scale, height: params.height * scale, @@ -443,10 +435,15 @@ module.exports = function(options, repo, params, id, publicUrl, dataResolver) { }); if (z > 2 && tileMargin > 0) { - image.extract({ left: tileMargin * scale, top: tileMargin * scale, width: width * scale, height: height * scale }); + image.extract({ + left: tileMargin * scale, + top: tileMargin * scale, + width: width * scale, + height: height * scale + }); } - if (z == 0) { + if (z === 0) { // HACK: when serving zoom 0, resize the 0 tile from 512 to 256 image.resize(width * scale, height * scale); } @@ -455,8 +452,8 @@ module.exports = function(options, repo, params, id, publicUrl, dataResolver) { image.composite([{ input: opt_overlay }]); } if (watermark) { - var canvas = createCanvas(scale * width, scale * height); - var ctx = canvas.getContext('2d'); + const canvas = createCanvas(scale * width, scale * height); + const ctx = canvas.getContext('2d'); ctx.scale(scale, scale); ctx.font = '10px sans-serif'; ctx.strokeWidth = '1px'; @@ -468,24 +465,24 @@ module.exports = function(options, repo, params, id, publicUrl, dataResolver) { image.composite([{ input: canvas.toBuffer() }]); } - var formatQuality = (params.formatQuality || {})[format] || - (options.formatQuality || {})[format]; + const formatQuality = (params.formatQuality || {})[format] || + (options.formatQuality || {})[format]; - if (format == 'png') { - image.png({adaptiveFiltering: false}); - } else if (format == 'jpeg') { - image.jpeg({quality: formatQuality || 80}); - } else if (format == 'webp') { - image.webp({quality: formatQuality || 90}); + if (format === 'png') { + image.png({ adaptiveFiltering: false }); + } else if (format === 'jpeg') { + image.jpeg({ quality: formatQuality || 80 }); + } else if (format === 'webp') { + image.webp({ quality: formatQuality || 90 }); } - image.toBuffer(function(err, buffer, info) { + image.toBuffer((err, buffer, info) => { if (!buffer) { return res.status(404).send('Not found'); } res.set({ 'Last-Modified': lastModified, - 'Content-Type': 'image/' + format + 'Content-Type': `image/${format}` }); return res.status(200).send(buffer); }); @@ -493,25 +490,25 @@ module.exports = function(options, repo, params, id, publicUrl, dataResolver) { }); }; - app.get(tilePattern, function(req, res, next) { - var modifiedSince = req.get('if-modified-since'), cc = req.get('cache-control'); - if (modifiedSince && (!cc || cc.indexOf('no-cache') == -1)) { + app.get(tilePattern, (req, res, next) => { + const modifiedSince = req.get('if-modified-since'), cc = req.get('cache-control'); + if (modifiedSince && (!cc || cc.indexOf('no-cache') === -1)) { if (new Date(lastModified) <= new Date(modifiedSince)) { return res.sendStatus(304); } } - var z = req.params.z | 0, - x = req.params.x | 0, - y = req.params.y | 0, - scale = getScale(req.params.scale), - format = req.params.format; + const z = req.params.z | 0, + x = req.params.x | 0, + y = req.params.y | 0, + scale = getScale(req.params.scale), + format = req.params.format; if (z < 0 || x < 0 || y < 0 || z > 20 || x >= Math.pow(2, z) || y >= Math.pow(2, z)) { return res.status(404).send('Out of bounds'); } - var tileSize = 256; - var tileCenter = mercator.ll([ + const tileSize = 256; + const tileCenter = mercator.ll([ ((x + 0.5) / (1 << z)) * (256 << z), ((y + 0.5) / (1 << z)) * (256 << z) ], z); @@ -519,14 +516,14 @@ module.exports = function(options, repo, params, id, publicUrl, dataResolver) { tileSize, tileSize, scale, format, res, next); }); - var extractPathFromQuery = function(query, transformer) { - var pathParts = (query.path || '').split('|'); - var path = []; - pathParts.forEach(function(pair) { - var pairParts = pair.split(','); - if (pairParts.length == 2) { - var pair; - if (query.latlng == '1' || query.latlng == 'true') { + const extractPathFromQuery = (query, transformer) => { + const pathParts = (query.path || '').split('|'); + const path = []; + for (const pair of pathParts) { + const pairParts = pair.split(','); + if (pairParts.length === 2) { + let pair; + if (query.latlng === '1' || query.latlng === 'true') { pair = [+(pairParts[1]), +(pairParts[0])]; } else { pair = [+(pairParts[0]), +(pairParts[1])]; @@ -536,34 +533,34 @@ module.exports = function(options, repo, params, id, publicUrl, dataResolver) { } path.push(pair); } - }); + } return path; }; - var renderOverlay = function(z, x, y, bearing, pitch, w, h, scale, - path, query) { + const renderOverlay = (z, x, y, bearing, pitch, w, h, scale, + path, query) => { if (!path || path.length < 2) { return null; } - var precisePx = function(ll, zoom) { - var px = mercator.px(ll, 20); - var scale = Math.pow(2, zoom - 20); + const precisePx = (ll, zoom) => { + const px = mercator.px(ll, 20); + const scale = Math.pow(2, zoom - 20); return [px[0] * scale, px[1] * scale]; }; - var center = precisePx([x, y], z); + const center = precisePx([x, y], z); - var mapHeight = 512 * (1 << z); - var maxEdge = center[1] + h / 2; - var minEdge = center[1] - h / 2; + const mapHeight = 512 * (1 << z); + const maxEdge = center[1] + h / 2; + const minEdge = center[1] - h / 2; if (maxEdge > mapHeight) { center[1] -= (maxEdge - mapHeight); } else if (minEdge < 0) { center[1] -= minEdge; } - var canvas = createCanvas(scale * w, scale * h); - var ctx = canvas.getContext('2d'); + const canvas = createCanvas(scale * w, scale * h); + const ctx = canvas.getContext('2d'); ctx.scale(scale, scale); if (bearing) { ctx.translate(w / 2, h / 2); @@ -573,18 +570,18 @@ module.exports = function(options, repo, params, id, publicUrl, dataResolver) { // optimized path ctx.translate(-center[0] + w / 2, -center[1] + h / 2); } - var lineWidth = query.width !== undefined ? - parseFloat(query.width) : 1; + const lineWidth = query.width !== undefined ? + parseFloat(query.width) : 1; ctx.lineWidth = lineWidth; ctx.strokeStyle = query.stroke || 'rgba(0,64,255,0.7)'; ctx.fillStyle = query.fill || 'rgba(255,255,255,0.4)'; ctx.beginPath(); - path.forEach(function(pair) { - var px = precisePx(pair, z); + for (const pair of path) { + const px = precisePx(pair, z); ctx.lineTo(px[0], px[1]); - }); - if (path[0][0] == path[path.length - 1][0] && - path[0][1] == path[path.length - 1][1]) { + } + if (path[0][0] === path[path.length - 1][0] && + path[0][1] === path[path.length - 1][1]) { ctx.closePath(); } ctx.fill(); @@ -595,16 +592,16 @@ module.exports = function(options, repo, params, id, publicUrl, dataResolver) { return canvas.toBuffer(); }; - var calcZForBBox = function(bbox, w, h, query) { - var z = 25; + const calcZForBBox = (bbox, w, h, query) => { + let z = 25; - var padding = query.padding !== undefined ? - parseFloat(query.padding) : 0.1; + const padding = query.padding !== undefined ? + parseFloat(query.padding) : 0.1; - var minCorner = mercator.px([bbox[0], bbox[3]], z), - maxCorner = mercator.px([bbox[2], bbox[1]], z); - var w_ = w / (1 + 2 * padding); - var h_ = h / (1 + 2 * padding); + const minCorner = mercator.px([bbox[0], bbox[3]], z), + maxCorner = mercator.px([bbox[2], bbox[1]], z); + const w_ = w / (1 + 2 * padding); + const h_ = h / (1 + 2 * padding); z -= Math.max( Math.log((maxCorner[0] - minCorner[0]) / w_), @@ -617,60 +614,59 @@ module.exports = function(options, repo, params, id, publicUrl, dataResolver) { }; if (options.serveStaticMaps !== false) { - var staticPattern = - '/' + id + '/static/:raw(raw)?/%s/:width(\\d+)x:height(\\d+)' + - ':scale(' + scalePattern + ')?\.:format([\\w]+)'; + const staticPattern = + `/${id}/static/:raw(raw)?/%s/:width(\\d+)x:height(\\d+):scale(${scalePattern})?.:format([\\w]+)`; - var centerPattern = - util.format(':x(%s),:y(%s),:z(%s)(@:bearing(%s)(,:pitch(%s))?)?', - FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN, - FLOAT_PATTERN, FLOAT_PATTERN); + const centerPattern = + util.format(':x(%s),:y(%s),:z(%s)(@:bearing(%s)(,:pitch(%s))?)?', + FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN, + FLOAT_PATTERN, FLOAT_PATTERN); - app.get(util.format(staticPattern, centerPattern), function(req, res, next) { - var raw = req.params.raw; - var z = +req.params.z, - x = +req.params.x, - y = +req.params.y, - bearing = +(req.params.bearing || '0'), - pitch = +(req.params.pitch || '0'), - w = req.params.width | 0, - h = req.params.height | 0, - scale = getScale(req.params.scale), - format = req.params.format; + app.get(util.format(staticPattern, centerPattern), (req, res, next) => { + const raw = req.params.raw; + let z = +req.params.z, + x = +req.params.x, + y = +req.params.y, + bearing = +(req.params.bearing || '0'), + pitch = +(req.params.pitch || '0'), + w = req.params.width | 0, + h = req.params.height | 0, + scale = getScale(req.params.scale), + format = req.params.format; if (z < 0) { return res.status(404).send('Invalid zoom'); } - var transformer = raw ? + const transformer = raw ? mercator.inverse.bind(mercator) : dataProjWGStoInternalWGS; if (transformer) { - var ll = transformer([x, y]); + const ll = transformer([x, y]); x = ll[0]; y = ll[1]; } - var path = extractPathFromQuery(req.query, transformer); - var overlay = renderOverlay(z, x, y, bearing, pitch, w, h, scale, - path, req.query); + const path = extractPathFromQuery(req.query, transformer); + const overlay = renderOverlay(z, x, y, bearing, pitch, w, h, scale, + path, req.query); return respondImage(z, x, y, bearing, pitch, w, h, scale, format, res, next, overlay); }); - var serveBounds = function(req, res, next) { - var raw = req.params.raw; - var bbox = [+req.params.minx, +req.params.miny, - +req.params.maxx, +req.params.maxy]; - var center = [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2]; + const serveBounds = (req, res, next) => { + const raw = req.params.raw; + const bbox = [+req.params.minx, +req.params.miny, + +req.params.maxx, +req.params.maxy]; + let center = [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2]; - var transformer = raw ? + const transformer = raw ? mercator.inverse.bind(mercator) : dataProjWGStoInternalWGS; if (transformer) { - var minCorner = transformer(bbox.slice(0, 2)); - var maxCorner = transformer(bbox.slice(2)); + const minCorner = transformer(bbox.slice(0, 2)); + const maxCorner = transformer(bbox.slice(2)); bbox[0] = minCorner[0]; bbox[1] = minCorner[1]; bbox[2] = maxCorner[0]; @@ -678,37 +674,37 @@ module.exports = function(options, repo, params, id, publicUrl, dataResolver) { center = transformer(center); } - var w = req.params.width | 0, - h = req.params.height | 0, - scale = getScale(req.params.scale), - format = req.params.format; + const w = req.params.width | 0, + h = req.params.height | 0, + scale = getScale(req.params.scale), + format = req.params.format; - var z = calcZForBBox(bbox, w, h, req.query), - x = center[0], - y = center[1], - bearing = 0, - pitch = 0; + const z = calcZForBBox(bbox, w, h, req.query), + x = center[0], + y = center[1], + bearing = 0, + pitch = 0; - var path = extractPathFromQuery(req.query, transformer); - var overlay = renderOverlay(z, x, y, bearing, pitch, w, h, scale, - path, req.query); + const path = extractPathFromQuery(req.query, transformer); + const overlay = renderOverlay(z, x, y, bearing, pitch, w, h, scale, + path, req.query); return respondImage(z, x, y, bearing, pitch, w, h, scale, format, - res, next, overlay); + res, next, overlay); }; - var boundsPattern = - util.format(':minx(%s),:miny(%s),:maxx(%s),:maxy(%s)', - FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN); + const boundsPattern = + util.format(':minx(%s),:miny(%s),:maxx(%s),:maxy(%s)', + FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN); app.get(util.format(staticPattern, boundsPattern), serveBounds); - app.get('/' + id + '/static/', function(req, res, next) { - for (var key in req.query) { + app.get(`/${id}/static/`, (req, res, next) => { + for (let key in req.query) { req.query[key.toLowerCase()] = req.query[key]; } req.params.raw = true; req.params.format = (req.query.format || 'image/png').split('/').pop(); - var bbox = (req.query.bbox || '').split(','); + const bbox = (req.query.bbox || '').split(','); req.params.minx = bbox[0]; req.params.miny = bbox[1]; req.params.maxx = bbox[2]; @@ -718,65 +714,63 @@ module.exports = function(options, repo, params, id, publicUrl, dataResolver) { if (req.query.scale) { req.params.width /= req.query.scale; req.params.height /= req.query.scale; - req.params.scale = '@' + req.query.scale; + req.params.scale = `@${req.query.scale}`; } return serveBounds(req, res, next); }); - var autoPattern = 'auto'; + const autoPattern = 'auto'; - app.get(util.format(staticPattern, autoPattern), function(req, res, next) { - var raw = req.params.raw; - var w = req.params.width | 0, - h = req.params.height | 0, - bearing = 0, - pitch = 0, - scale = getScale(req.params.scale), - format = req.params.format; + app.get(util.format(staticPattern, autoPattern), (req, res, next) => { + const raw = req.params.raw; + const w = req.params.width | 0, + h = req.params.height | 0, + bearing = 0, + pitch = 0, + scale = getScale(req.params.scale), + format = req.params.format; - var transformer = raw ? + const transformer = raw ? mercator.inverse.bind(mercator) : dataProjWGStoInternalWGS; - var path = extractPathFromQuery(req.query, transformer); + const path = extractPathFromQuery(req.query, transformer); if (path.length < 2) { return res.status(400).send('Invalid path'); } - var bbox = [Infinity, Infinity, -Infinity, -Infinity]; - path.forEach(function(pair) { + const bbox = [Infinity, Infinity, -Infinity, -Infinity]; + for (const pair of path) { bbox[0] = Math.min(bbox[0], pair[0]); bbox[1] = Math.min(bbox[1], pair[1]); bbox[2] = Math.max(bbox[2], pair[0]); bbox[3] = Math.max(bbox[3], pair[1]); - }); + } - var bbox_ = mercator.convert(bbox, '900913'); - var center = mercator.inverse( + const bbox_ = mercator.convert(bbox, '900913'); + const center = mercator.inverse( [(bbox_[0] + bbox_[2]) / 2, (bbox_[1] + bbox_[3]) / 2] ); - var z = calcZForBBox(bbox, w, h, req.query), - x = center[0], - y = center[1]; + const z = calcZForBBox(bbox, w, h, req.query), + x = center[0], + y = center[1]; - var overlay = renderOverlay(z, x, y, bearing, pitch, w, h, scale, - path, req.query); + const overlay = renderOverlay(z, x, y, bearing, pitch, w, h, scale, + path, req.query); return respondImage(z, x, y, bearing, pitch, w, h, scale, format, res, next, overlay); }); } - app.get('/' + id + '.json', function(req, res, next) { - var info = clone(tileJSON); + app.get(`/${id}.json`, (req, res, next) => { + const info = clone(tileJSON); info.tiles = utils.getTileUrls(req, info.tiles, - 'styles/' + id, info.format, publicUrl); + `styles/${id}`, info.format, publicUrl); return res.send(info); }); - return Promise.all([fontListingPromise, renderersReadyPromise]).then(function() { - return app; - }); + return Promise.all([fontListingPromise, renderersReadyPromise]).then(() => app); }; diff --git a/src/serve_style.js b/src/serve_style.js index a4b8601..71cd4ee 100644 --- a/src/serve_style.js +++ b/src/serve_style.js @@ -1,42 +1,42 @@ 'use strict'; -var path = require('path'), - fs = require('fs'); +const path = require('path'); +const fs = require('fs'); -var clone = require('clone'), - express = require('express'); +const clone = require('clone'); +const express = require('express'); -var utils = require('./utils'); +const utils = require('./utils'); -module.exports = function(options, repo, params, id, publicUrl, reportTiles, reportFont) { - var app = express().disable('x-powered-by'); +module.exports = (options, repo, params, id, publicUrl, reportTiles, reportFont) => { + const app = express().disable('x-powered-by'); - var styleFile = path.resolve(options.paths.styles, params.style); + const styleFile = path.resolve(options.paths.styles, params.style); - var styleJSON = clone(require(styleFile)); - Object.keys(styleJSON.sources).forEach(function(name) { - var source = styleJSON.sources[name]; - var url = source.url; + const styleJSON = clone(require(styleFile)); + for (const name of Object.keys(styleJSON.sources)) { + const source = styleJSON.sources[name]; + const url = source.url; if (url && url.lastIndexOf('mbtiles:', 0) === 0) { - var mbtilesFile = url.substring('mbtiles://'.length); - var fromData = mbtilesFile[0] == '{' && - mbtilesFile[mbtilesFile.length - 1] == '}'; + let mbtilesFile = url.substring('mbtiles://'.length); + const fromData = mbtilesFile[0] === '{' && + mbtilesFile[mbtilesFile.length - 1] === '}'; if (fromData) { mbtilesFile = mbtilesFile.substr(1, mbtilesFile.length - 2); - var mapsTo = (params.mapping || {})[mbtilesFile]; + const mapsTo = (params.mapping || {})[mbtilesFile]; if (mapsTo) { mbtilesFile = mapsTo; } } - var identifier = reportTiles(mbtilesFile, fromData); - source.url = 'local://data/' + identifier + '.json'; + const identifier = reportTiles(mbtilesFile, fromData); + source.url = `local://data/${identifier}.json`; } - }); + } - styleJSON.layers.forEach(function(obj) { - if (obj['type'] == 'symbol') { - var fonts = (obj['layout'] || {})['text-font']; + for(let obj of styleJSON.layers) { + if (obj['type'] === 'symbol') { + const fonts = (obj['layout'] || {})['text-font']; if (fonts && fonts.length) { fonts.forEach(reportFont); } else { @@ -44,18 +44,18 @@ module.exports = function(options, repo, params, id, publicUrl, reportTiles, rep reportFont('Arial Unicode MS Regular'); } } - }); + } - var spritePath; + let spritePath; - var httpTester = /^(http(s)?:)?\/\//; + const httpTester = /^(http(s)?:)?\/\//; if (styleJSON.sprite && !httpTester.test(styleJSON.sprite)) { spritePath = path.join(options.paths.sprites, styleJSON.sprite .replace('{style}', path.basename(styleFile, '.json')) .replace('{styleJsonFolder}', path.relative(options.paths.sprites, path.dirname(styleFile))) ); - styleJSON.sprite = 'local://styles/' + id + '/sprite'; + styleJSON.sprite = `local://styles/${id}/sprite`; } if (styleJSON.glyphs && !httpTester.test(styleJSON.glyphs)) { styleJSON.glyphs = 'local://fonts/{fontstack}/{range}.pbf'; @@ -63,31 +63,31 @@ module.exports = function(options, repo, params, id, publicUrl, reportTiles, rep repo[id] = styleJSON; - app.get('/' + id + '/style.json', function(req, res, next) { - var fixUrl = function(url, opt_nokey, opt_nostyle) { + app.get(`/${id}/style.json`, (req, res, next) => { + const fixUrl = (url, opt_nokey, opt_nostyle) => { if (!url || (typeof url !== 'string') || url.indexOf('local://') !== 0) { return url; } - var queryParams = []; + const queryParams = []; if (!opt_nostyle && global.addStyleParam) { - queryParams.push('style=' + id); + queryParams.push(`style=${id}`); } if (!opt_nokey && req.query.key) { - queryParams.unshift('key=' + req.query.key); + queryParams.unshift(`key=${req.query.key}`); } - var query = ''; + let query = ''; if (queryParams.length) { - query = '?' + queryParams.join('&'); + query = `?${queryParams.join('&')}`; } return url.replace( - 'local://', utils.getPublicUrl(publicUrl, req)) + query; + 'local://', utils.getPublicUrl(publicUrl, req)) + query; }; - var styleJSON_ = clone(styleJSON); - Object.keys(styleJSON_.sources).forEach(function(name) { - var source = styleJSON_.sources[name]; + const styleJSON_ = clone(styleJSON); + for (const name of Object.keys(styleJSON_.sources)) { + const source = styleJSON_.sources[name]; source.url = fixUrl(source.url); - }); + } // mapbox-gl-js viewer cannot handle sprite urls with query if (styleJSON_.sprite) { styleJSON_.sprite = fixUrl(styleJSON_.sprite, true, true); @@ -98,21 +98,21 @@ module.exports = function(options, repo, params, id, publicUrl, reportTiles, rep return res.send(styleJSON_); }); - app.get('/' + id + '/sprite:scale(@[23]x)?\.:format([\\w]+)', - function(req, res, next) { + app.get(`/${id}/sprite:scale(@[23]x)?.:format([\\w]+)`, + (req, res, next) => { if (!spritePath) { return res.status(404).send('File not found'); } - var scale = req.params.scale, - format = req.params.format; - var filename = spritePath + (scale || '') + '.' + format; - return fs.readFile(filename, function(err, data) { + const scale = req.params.scale, + format = req.params.format; + const filename = `${spritePath + (scale || '')}.${format}`; + return fs.readFile(filename, (err, data) => { if (err) { console.log('Sprite load error:', filename); return res.status(404).send('File not found'); } else { - if (format == 'json') res.header('Content-type', 'application/json'); - if (format == 'png') res.header('Content-type', 'image/png'); + if (format === 'json') res.header('Content-type', 'application/json'); + if (format === 'png') res.header('Content-type', 'image/png'); return res.send(data); } }); diff --git a/src/server.js b/src/server.js index 9ae85c6..9e2d070 100644 --- a/src/server.js +++ b/src/server.js @@ -4,25 +4,25 @@ process.env.UV_THREADPOOL_SIZE = Math.ceil(Math.max(4, require('os').cpus().length * 1.5)); -var fs = require('fs'), - path = require('path'); +const fs = require('fs'); +const path = require('path'); -var clone = require('clone'), - cors = require('cors'), - enableShutdown = require('http-shutdown'), - express = require('express'), - handlebars = require('handlebars'), - mercator = new (require('@mapbox/sphericalmercator'))(), - morgan = require('morgan'); +const clone = require('clone'); +const cors = require('cors'); +const enableShutdown = require('http-shutdown'); +const express = require('express'); +const handlebars = require('handlebars'); +const mercator = new (require('@mapbox/sphericalmercator'))(); +const morgan = require('morgan'); -var packageJson = require('../package'), - serve_font = require('./serve_font'), - serve_rendered = null, - serve_style = require('./serve_style'), - serve_data = require('./serve_data'), - utils = require('./utils'); +const packageJson = require('../package'); +const serve_font = require('./serve_font'); +const serve_style = require('./serve_style'); +const serve_data = require('./serve_data'); +const utils = require('./utils'); -var isLight = packageJson.name.slice(-6) == '-light'; +let serve_rendered = null; +const isLight = packageJson.name.slice(-6) === '-light'; if (!isLight) { // do not require `serve_rendered` in the light package serve_rendered = require('./serve_rendered'); @@ -31,27 +31,27 @@ if (!isLight) { function start(opts) { console.log('Starting server'); - var app = express().disable('x-powered-by'), - serving = { - styles: {}, - rendered: {}, - data: {}, - fonts: {} - }; + const app = express().disable('x-powered-by'), + serving = { + styles: {}, + rendered: {}, + data: {}, + fonts: {} + }; app.enable('trust proxy'); if (process.env.NODE_ENV !== 'test') { - var defaultLogFormat = process.env.NODE_ENV == 'production' ? 'tiny' : 'dev'; - var logFormat = opts.logFormat || defaultLogFormat; + const defaultLogFormat = process.env.NODE_ENV === 'production' ? 'tiny' : 'dev'; + const logFormat = opts.logFormat || defaultLogFormat; app.use(morgan(logFormat, { stream: opts.logFile ? fs.createWriteStream(opts.logFile, { flags: 'a' }) : process.stdout, - skip: function(req, res) { return opts.silent && (res.statusCode == 200 || res.statusCode == 304) } + skip: (req, res) => opts.silent && (res.statusCode === 200 || res.statusCode === 304) })); } - var config = opts.config || null; - var configPath = null; + let config = opts.config || null; + let configPath = null; if (opts.configPath) { configPath = path.resolve(opts.configPath); try { @@ -67,8 +67,8 @@ function start(opts) { process.exit(1); } - var options = config.options || {}; - var paths = options.paths || {}; + const options = config.options || {}; + const paths = options.paths || {}; options.paths = paths; paths.root = path.resolve( configPath ? path.dirname(configPath) : process.cwd(), @@ -78,11 +78,11 @@ function start(opts) { paths.sprites = path.resolve(paths.root, paths.sprites || ''); paths.mbtiles = path.resolve(paths.root, paths.mbtiles || ''); - var startupPromises = []; + const startupPromises = []; - var checkPath = function(type) { + const checkPath = type => { if (!fs.existsSync(paths[type])) { - console.error('The specified path for "' + type + '" does not exist (' + paths[type] + ').'); + console.error(`The specified path for "${type}" does not exist (${paths[type]}).`); process.exit(1); } }; @@ -97,50 +97,50 @@ function start(opts) { } catch (e) {} } - var data = clone(config.data || {}); + const data = clone(config.data || {}); if (opts.cors) { app.use(cors()); } - Object.keys(config.styles || {}).forEach(function(id) { - var item = config.styles[id]; - if (!item.style || item.style.length == 0) { - console.log('Missing "style" property for ' + id); - return; + 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; } if (item.serve_data !== false) { startupPromises.push(serve_style(options, serving.styles, item, id, opts.publicUrl, - function(mbtiles, fromData) { - var dataItemId; - Object.keys(data).forEach(function(id) { + (mbtiles, fromData) => { + let dataItemId; + for (const id of Object.keys(data)) { if (fromData) { - if (id == mbtiles) { + if (id === mbtiles) { dataItemId = id; } } else { - if (data[id].mbtiles == mbtiles) { + if (data[id].mbtiles === mbtiles) { dataItemId = id; } } - }); + } if (dataItemId) { // mbtiles exist in the data config return dataItemId; } else if (fromData) { - console.log('ERROR: data "' + mbtiles + '" not found!'); + console.log(`ERROR: data "${mbtiles}" not found!`); process.exit(1); } else { - var id = mbtiles.substr(0, mbtiles.lastIndexOf('.')) || mbtiles; + let id = mbtiles.substr(0, mbtiles.lastIndexOf('.')) || mbtiles; while (data[id]) id += '_'; data[id] = { 'mbtiles': mbtiles }; return id; } - }, function(font) { + }, font => { serving.fonts[font] = true; - }).then(function(sub) { + }).then(sub => { app.use('/styles/', sub); })); } @@ -148,16 +148,16 @@ function start(opts) { if (serve_rendered) { startupPromises.push( serve_rendered(options, serving.rendered, item, id, opts.publicUrl, - function(mbtiles) { - var mbtilesFile; - Object.keys(data).forEach(function(id) { - if (id == mbtiles) { + mbtiles => { + let mbtilesFile; + for (const id of Object.keys(data)) { + if (id === mbtiles) { mbtilesFile = data[id].mbtiles; } - }); + } return mbtilesFile; } - ).then(function(sub) { + ).then(sub => { app.use('/styles/', sub); }) ); @@ -165,68 +165,67 @@ function start(opts) { item.serve_rendered = false; } } - }); + } startupPromises.push( - serve_font(options, serving.fonts).then(function(sub) { + serve_font(options, serving.fonts).then(sub => { app.use('/', sub); }) ); - Object.keys(data).forEach(function(id) { - var item = data[id]; - if (!item.mbtiles || item.mbtiles.length == 0) { - console.log('Missing "mbtiles" property for ' + id); - return; + for (const id of Object.keys(data)) { + const item = data[id]; + if (!item.mbtiles || item.mbtiles.length === 0) { + console.log(`Missing "mbtiles" property for ${id}`); + continue; } startupPromises.push( - serve_data(options, serving.data, item, id, serving.styles, opts.publicUrl).then(function(sub) { + serve_data(options, serving.data, item, id, serving.styles, opts.publicUrl).then(sub => { app.use('/data/', sub); }) ); - }); + } - app.get('/styles.json', function(req, res, next) { - var result = []; - var query = req.query.key ? ('?key=' + req.query.key) : ''; - Object.keys(serving.styles).forEach(function(id) { - var styleJSON = serving.styles[id]; + app.get('/styles.json', (req, res, next) => { + const result = []; + const query = req.query.key ? (`?key=${req.query.key}`) : ''; + for (const id of Object.keys(serving.styles)) { + const styleJSON = serving.styles[id]; result.push({ version: styleJSON.version, name: styleJSON.name, id: id, - url: utils.getPublicUrl(opts.publicUrl, req) + - 'styles/' + id + '/style.json' + query + url: `${utils.getPublicUrl(opts.publicUrl, req)}styles/${id}/style.json${query}` }); - }); + } res.send(result); }); - var addTileJSONs = function(arr, req, type) { - Object.keys(serving[type]).forEach(function(id) { - var info = clone(serving[type][id]); - var path = ''; - if (type == 'rendered') { - path = 'styles/' + id; + const addTileJSONs = (arr, req, type) => { + for (const id of Object.keys(serving[type])) { + const info = clone(serving[type][id]); + let path = ''; + if (type === 'rendered') { + path = `styles/${id}`; } else { - path = type + '/' + id; + path = `${type}/${id}`; } info.tiles = utils.getTileUrls(req, info.tiles, path, info.format, opts.publicUrl, { 'pbf': options.pbfAlias }); arr.push(info); - }); + } return arr; }; - app.get('/rendered.json', function(req, res, next) { + app.get('/rendered.json', (req, res, next) => { res.send(addTileJSONs([], req, 'rendered')); }); - app.get('/data.json', function(req, res, next) { + app.get('/data.json', (req, res, next) => { res.send(addTileJSONs([], req, 'data')); }); - app.get('/index.json', function(req, res, next) { + app.get('/index.json', (req, res, next) => { res.send(addTileJSONs(addTileJSONs([], req, 'rendered'), req, 'data')); }); @@ -234,40 +233,40 @@ function start(opts) { // serve web presentations app.use('/', express.static(path.join(__dirname, '../public/resources'))); - var templates = path.join(__dirname, '../public/templates'); - var serveTemplate = function(urlPath, template, dataGetter) { - var templateFile = templates + '/' + template + '.tmpl'; - if (template == 'index') { + const templates = path.join(__dirname, '../public/templates'); + const serveTemplate = (urlPath, template, dataGetter) => { + let templateFile = `${templates}/${template}.tmpl`; + if (template === 'index') { if (options.frontPage === false) { return; } else if (options.frontPage && - options.frontPage.constructor === String) { + options.frontPage.constructor === String) { templateFile = path.resolve(paths.root, options.frontPage); } } - startupPromises.push(new Promise(function(resolve, reject) { - fs.readFile(templateFile, function(err, content) { + startupPromises.push(new Promise((resolve, reject) => { + fs.readFile(templateFile, (err, content) => { if (err) { - err = new Error('Template not found: ' + err.message); + err = new Error(`Template not found: ${err.message}`); reject(err); return; } - var compiled = handlebars.compile(content.toString()); + const compiled = handlebars.compile(content.toString()); - app.use(urlPath, function(req, res, next) { - var data = {}; + app.use(urlPath, (req, res, next) => { + let data = {}; if (dataGetter) { data = dataGetter(req); if (!data) { return res.status(404).send('Not found'); } } - data['server_version'] = packageJson.name + ' v' + packageJson.version; + data['server_version'] = `${packageJson.name} v${packageJson.version}`; data['public_url'] = opts.publicUrl || '/'; data['is_light'] = isLight; data['key_query_part'] = - req.query.key ? 'key=' + req.query.key + '&' : ''; - data['key_query'] = req.query.key ? '?key=' + req.query.key : ''; + req.query.key ? `key=${req.query.key}&` : ''; + data['key_query'] = req.query.key ? `?key=${req.query.key}` : ''; if (template === 'wmts') res.set('Content-Type', 'text/xml'); return res.status(200).send(compiled(data)); }); @@ -276,59 +275,49 @@ function start(opts) { })); }; - serveTemplate('/$', 'index', function(req) { - var styles = clone(config.styles || {}); - Object.keys(styles).forEach(function(id) { - var style = styles[id]; + serveTemplate('/$', 'index', req => { + const styles = clone(config.styles || {}); + for (const id of Object.keys(styles)) { + const style = styles[id]; style.name = (serving.styles[id] || serving.rendered[id] || {}).name; style.serving_data = serving.styles[id]; style.serving_rendered = serving.rendered[id]; if (style.serving_rendered) { - var center = style.serving_rendered.center; + const center = style.serving_rendered.center; if (center) { - style.viewer_hash = '#' + center[2] + '/' + - center[1].toFixed(5) + '/' + - center[0].toFixed(5); + style.viewer_hash = `#${center[2]}/${center[1].toFixed(5)}/${center[0].toFixed(5)}`; - var centerPx = mercator.px([center[0], center[1]], center[2]); - style.thumbnail = center[2] + '/' + - Math.floor(centerPx[0] / 256) + '/' + - Math.floor(centerPx[1] / 256) + '.png'; + const centerPx = mercator.px([center[0], center[1]], center[2]); + style.thumbnail = `${center[2]}/${Math.floor(centerPx[0] / 256)}/${Math.floor(centerPx[1] / 256)}.png`; } - var tiles = utils.getTileUrls( - req, style.serving_rendered.tiles, - 'styles/' + id, style.serving_rendered.format, opts.publicUrl); - style.xyz_link = tiles[0]; + style.xyz_link = utils.getTileUrls( + req, style.serving_rendered.tiles, + `styles/${id}`, style.serving_rendered.format, opts.publicUrl)[0]; } - }); - var data = clone(serving.data || {}); - Object.keys(data).forEach(function(id) { - var data_ = data[id]; - var center = data_.center; + } + const data = clone(serving.data || {}); + for (const id of Object.keys(data)) { + const data_ = data[id]; + const center = data_.center; if (center) { - data_.viewer_hash = '#' + center[2] + '/' + - center[1].toFixed(5) + '/' + - center[0].toFixed(5); + data_.viewer_hash = `#${center[2]}/${center[1].toFixed(5)}/${center[0].toFixed(5)}`; } - data_.is_vector = data_.format == 'pbf'; + data_.is_vector = data_.format === 'pbf'; if (!data_.is_vector) { if (center) { - var centerPx = mercator.px([center[0], center[1]], center[2]); - data_.thumbnail = center[2] + '/' + - Math.floor(centerPx[0] / 256) + '/' + - Math.floor(centerPx[1] / 256) + '.' + data_.format; + const centerPx = mercator.px([center[0], center[1]], center[2]); + data_.thumbnail = `${center[2]}/${Math.floor(centerPx[0] / 256)}/${Math.floor(centerPx[1] / 256)}.${data_.format}`; } - var tiles = utils.getTileUrls( - req, data_.tiles, 'data/' + id, data_.format, opts.publicUrl, { - 'pbf': options.pbfAlias - }); - data_.xyz_link = tiles[0]; + data_.xyz_link = utils.getTileUrls( + req, data_.tiles, `data/${id}`, data_.format, opts.publicUrl, { + 'pbf': options.pbfAlias + })[0]; } if (data_.filesize) { - var suffix = 'kB'; - var size = parseInt(data_.filesize, 10) / 1024; + let suffix = 'kB'; + let size = parseInt(data_.filesize, 10) / 1024; if (size > 1024) { suffix = 'MB'; size /= 1024; @@ -337,18 +326,18 @@ function start(opts) { suffix = 'GB'; size /= 1024; } - data_.formatted_filesize = size.toFixed(2) + ' ' + suffix; + data_.formatted_filesize = `${size.toFixed(2)} ${suffix}`; } - }); + } return { styles: Object.keys(styles).length ? styles : null, data: Object.keys(data).length ? data : null }; }); - serveTemplate('/styles/:id/$', 'viewer', function(req) { - var id = req.params.id; - var style = clone((config.styles || {})[id]); + serveTemplate('/styles/:id/$', 'viewer', req => { + const id = req.params.id; + const style = clone((config.styles || {})[id]); if (!style) { return null; } @@ -364,9 +353,9 @@ function start(opts) { return res.redirect(301, '/styles/' + req.params.id + '/'); }); */ - serveTemplate('/styles/:id/wmts.xml', 'wmts', function(req) { - var id = req.params.id; - var wmts = clone((config.styles || {})[id]); + serveTemplate('/styles/:id/wmts.xml', 'wmts', req => { + const id = req.params.id; + const wmts = clone((config.styles || {})[id]); if (!wmts) { return null; } @@ -375,27 +364,27 @@ function start(opts) { } wmts.id = id; wmts.name = (serving.styles[id] || serving.rendered[id]).name; - wmts.baseUrl = (req.get('X-Forwarded-Protocol')?req.get('X-Forwarded-Protocol'):req.protocol) + '://' + req.get('host'); + wmts.baseUrl = `${req.get('X-Forwarded-Protocol') ? req.get('X-Forwarded-Protocol') : req.protocol}://${req.get('host')}`; return wmts; }); - serveTemplate('/data/:id/$', 'data', function(req) { - var id = req.params.id; - var data = clone(serving.data[id]); + serveTemplate('/data/:id/$', 'data', req => { + const id = req.params.id; + const data = clone(serving.data[id]); if (!data) { return null; } data.id = id; - data.is_vector = data.format == 'pbf'; + data.is_vector = data.format === 'pbf'; return data; }); - var startupComplete = false; - var startupPromise = Promise.all(startupPromises).then(function() { + let startupComplete = false; + const startupPromise = Promise.all(startupPromises).then(() => { console.log('Startup complete'); startupComplete = true; }); - app.get('/health', function(req, res, next) { + app.get('/health', (req, res, next) => { if (startupComplete) { return res.status(200).send('OK'); } else { @@ -403,12 +392,12 @@ function start(opts) { } }); - var server = app.listen(process.env.PORT || opts.port, process.env.BIND || opts.bind, function() { - var address = this.address().address; + const server = app.listen(process.env.PORT || opts.port, process.env.BIND || opts.bind, function () { + let address = this.address().address; if (address.indexOf('::') === 0) { - address = '[' + address + ']'; // literal IPv6 address + address = `[${address}]`; // literal IPv6 address } - console.log('Listening at http://%s:%d/', address, this.address().port); + console.log(`Listening at http://${address}:${this.address().port}/`); }); // add server.shutdown() to gracefully stop serving @@ -421,27 +410,27 @@ function start(opts) { }; } -module.exports = function(opts) { - var running = start(opts); +module.exports = opts => { + const running = start(opts); - running.startupPromise.catch(function(err) { + running.startupPromise.catch(err => { console.error(err.message); process.exit(1); }); - process.on('SIGINT', function() { + process.on('SIGINT', () => { process.exit(); }); - process.on('SIGHUP', function() { + process.on('SIGHUP', () => { console.log('Stopping server and reloading config'); - running.server.shutdown(function() { - for (var key in require.cache) { + running.server.shutdown(() => { + for (const key in require.cache) { delete require.cache[key]; } - var restarted = start(opts); + const restarted = start(opts); running.server = restarted.server; running.app = restarted.app; }); diff --git a/src/utils.js b/src/utils.js index dc58b31..e9ffd6b 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,75 +1,72 @@ 'use strict'; -var path = require('path'), - fs = require('fs'); +const path = require('path'); +const fs = require('fs'); -var clone = require('clone'), - glyphCompose = require('glyph-pbf-composite'); +const clone = require('clone'); +const glyphCompose = require('glyph-pbf-composite'); -module.exports.getPublicUrl = function(publicUrl, req) { - return publicUrl || (req.protocol + '://' + req.headers.host + '/') -} +module.exports.getPublicUrl = (publicUrl, req) => publicUrl || `${req.protocol}://${req.headers.host}/`; -module.exports.getTileUrls = function(req, domains, path, format, publicUrl, aliases) { +module.exports.getTileUrls = (req, domains, path, format, publicUrl, aliases) => { if (domains) { if (domains.constructor === String && domains.length > 0) { domains = domains.split(','); } - var host = req.headers.host; - var hostParts = host.split('.'); - var relativeSubdomainsUsable = hostParts.length > 1 && - !/^([0-9]{1,3}\.){3}[0-9]{1,3}(\:[0-9]+)?$/.test(host); - var newDomains = []; - domains.forEach(function(domain) { + const host = req.headers.host; + const hostParts = host.split('.'); + const relativeSubdomainsUsable = hostParts.length > 1 && + !/^([0-9]{1,3}\.){3}[0-9]{1,3}(\:[0-9]+)?$/.test(host); + const newDomains = []; + for (const domain of domains) { if (domain.indexOf('*') !== -1) { if (relativeSubdomainsUsable) { - var newParts = hostParts.slice(1); + const newParts = hostParts.slice(1); newParts.unshift(domain.replace('*', hostParts[0])); newDomains.push(newParts.join('.')); } } else { newDomains.push(domain); } - }); + } domains = newDomains; } if (!domains || domains.length == 0) { domains = [req.headers.host]; } - var key = req.query.key; - var queryParams = []; + const key = req.query.key; + const queryParams = []; if (req.query.key) { - queryParams.push('key=' + req.query.key); + queryParams.push(`key=${req.query.key}`); } if (req.query.style) { - queryParams.push('style=' + req.query.style); + queryParams.push(`style=${req.query.style}`); } - var query = queryParams.length > 0 ? ('?' + queryParams.join('&')) : ''; + const query = queryParams.length > 0 ? (`?${queryParams.join('&')}`) : ''; if (aliases && aliases[format]) { format = aliases[format]; } - var uris = []; + const uris = []; if (!publicUrl) { - domains.forEach(function(domain) { - uris.push(req.protocol + '://' + domain + '/' + path + - '/{z}/{x}/{y}.' + format + query); - }); + for (const domain of domains) { + uris.push(`${req.protocol}://${domain}/${path}/{z}/{x}/{y}.${format}${query}`); + } } else { - uris.push(publicUrl + path + '/{z}/{x}/{y}.' + format + query) + uris.push(`${publicUrl}${path}/{z}/{x}/{y}.${format}${query}`) } return uris; }; -module.exports.fixTileJSONCenter = function(tileJSON) { +module.exports.fixTileJSONCenter = tileJSON => { if (tileJSON.bounds && !tileJSON.center) { - var fitWidth = 1024; - var tiles = fitWidth / 256; + const fitWidth = 1024; + const tiles = fitWidth / 256; tileJSON.center = [ (tileJSON.bounds[0] + tileJSON.bounds[2]) / 2, (tileJSON.bounds[1] + tileJSON.bounds[3]) / 2, @@ -81,58 +78,54 @@ module.exports.fixTileJSONCenter = function(tileJSON) { } }; -var getFontPbf = function(allowedFonts, fontPath, name, range, fallbacks) { - return new Promise(function(resolve, reject) { - if (!allowedFonts || (allowedFonts[name] && fallbacks)) { - var filename = path.join(fontPath, name, range + '.pbf'); - if (!fallbacks) { - fallbacks = clone(allowedFonts || {}); - } - delete fallbacks[name]; - fs.readFile(filename, function(err, data) { - if (err) { - console.error('ERROR: Font not found:', name); - if (fallbacks && Object.keys(fallbacks).length) { - var fallbackName; - - var fontStyle = name.split(' ').pop(); - if (['Regular', 'Bold', 'Italic'].indexOf(fontStyle) < 0) { - fontStyle = 'Regular'; - } - fallbackName = 'Noto Sans ' + fontStyle; - if (!fallbacks[fallbackName]) { - fallbackName = 'Open Sans ' + fontStyle; - if (!fallbacks[fallbackName]) { - fallbackName = Object.keys(fallbacks)[0]; - } - } - - console.error('ERROR: Trying to use', fallbackName, 'as a fallback'); - delete fallbacks[fallbackName]; - getFontPbf(null, fontPath, fallbackName, range, fallbacks).then(resolve, reject); - } else { - reject('Font load error: ' + name); - } - } else { - resolve(data); - } - }); - } else { - reject('Font not allowed: ' + name); +const getFontPbf = (allowedFonts, fontPath, name, range, fallbacks) => new Promise((resolve, reject) => { + if (!allowedFonts || (allowedFonts[name] && fallbacks)) { + const filename = path.join(fontPath, name, `${range}.pbf`); + if (!fallbacks) { + fallbacks = clone(allowedFonts || {}); } - }); -}; + delete fallbacks[name]; + fs.readFile(filename, (err, data) => { + if (err) { + console.error(`ERROR: Font not found: ${name}`); + if (fallbacks && Object.keys(fallbacks).length) { + let fallbackName; -module.exports.getFontsPbf = function(allowedFonts, fontPath, names, range, fallbacks) { - var fonts = names.split(','); - var queue = []; - fonts.forEach(function(font) { + let fontStyle = name.split(' ').pop(); + if (['Regular', 'Bold', 'Italic'].indexOf(fontStyle) < 0) { + fontStyle = 'Regular'; + } + fallbackName = `Noto Sans ${fontStyle}`; + if (!fallbacks[fallbackName]) { + fallbackName = `Open Sans ${fontStyle}`; + if (!fallbacks[fallbackName]) { + fallbackName = Object.keys(fallbacks)[0]; + } + } + + console.error(`ERROR: Trying to use ${fallbackName} as a fallback`); + delete fallbacks[fallbackName]; + getFontPbf(null, fontPath, fallbackName, range, fallbacks).then(resolve, reject); + } else { + reject(`Font load error: ${name}`); + } + } else { + resolve(data); + } + }); + } else { + reject(`Font not allowed: ${name}`); + } +}); + +module.exports.getFontsPbf = (allowedFonts, fontPath, names, range, fallbacks) => { + const fonts = names.split(','); + const queue = []; + for (const font of fonts) { queue.push( getFontPbf(allowedFonts, fontPath, font, range, clone(allowedFonts || fallbacks)) ); - }); + } - return Promise.all(queue).then(function(values) { - return glyphCompose.combine(values); - }); + return Promise.all(queue).then(values => glyphCompose.combine(values)); };