diff --git a/README.md b/README.md index ba34aa5..99f2d8d 100644 --- a/README.md +++ b/README.md @@ -301,7 +301,7 @@ In order to use this package on a headless server, you need to use `xvfb`. See ` ## Changes -### O.5.0 (in development) +### O.5.0 - upgraded Docker to NodeJS 10 - reduced size of Docker image and simplified Xvfb management diff --git a/dist/cli.js b/dist/cli.js index d85ed29..1104bbe 100755 --- a/dist/cli.js +++ b/dist/cli.js @@ -102,6 +102,14 @@ if (bounds !== null) { raiseError("Bounds must be west,south,east,north. Invalid value found: ".concat((0, _toConsumableArray2["default"])(bounds))); } + bounds.forEach(function (b) { + if (Number.isNaN(b)) { + raiseError("Bounds must be west,south,east,north. Invalid value found: ".concat((0, _toConsumableArray2["default"])(bounds))); + } + + return null; + }); + var _bounds = (0, _slicedToArray2["default"])(bounds, 4), west = _bounds[0], south = _bounds[1], diff --git a/dist/server.js b/dist/server.js index bdfd42b..b127432 100755 --- a/dist/server.js +++ b/dist/server.js @@ -3,8 +3,17 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports["default"] = exports.server = void 0; + +var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); + var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); +var _fs = _interopRequireDefault(require("fs")); + var _restify = _interopRequireDefault(require("restify")); var _nodeRestifyValidation = _interopRequireDefault(require("node-restify-validation")); @@ -15,12 +24,17 @@ var _commander = _interopRequireDefault(require("commander")); var _package = require("../package.json"); -var _render = _interopRequireDefault(require("./render")); +var _render = require("./render"); var parseListToFloat = function parseListToFloat(text) { return text.split(',').map(Number); }; +var raiseError = function raiseError(msg) { + console.error('ERROR:', msg); + process.exit(1); +}; + var PARAMS = { style: { isRequired: true, @@ -136,6 +150,21 @@ var renderImage = function renderImage(params, response, next, tilePath) { return null; }); + + var _bounds = bounds, + _bounds2 = (0, _slicedToArray2["default"])(_bounds, 4), + west = _bounds2[0], + south = _bounds2[1], + east = _bounds2[2], + north = _bounds2[3]; + + if (west === east) { + return next(new _restifyErrors["default"].BadRequestError("Bounds west and east coordinate are the same value")); + } + + if (south === north) { + return next(new _restifyErrors["default"].BadRequestError("Bounds south and north coordinate are the same value")); + } } if (bearing !== null) { @@ -155,7 +184,7 @@ var renderImage = function renderImage(params, response, next, tilePath) { } try { - (0, _render["default"])(style, parseInt(width, 10), parseInt(height, 10), { + (0, _render.render)(style, parseInt(width, 10), parseInt(height, 10), { zoom: zoom, center: center, bounds: bounds, @@ -203,6 +232,7 @@ var server = _restify["default"].createServer({ ignoreTrailingSlash: true }); +exports.server = server; server.use(_restify["default"].plugins.queryParser()); server.use(_restify["default"].plugins.bodyParser()); server.use(_nodeRestifyValidation["default"].validationPlugin({ @@ -248,9 +278,17 @@ server.get({ }); if (tilePath !== null) { + if (!_fs["default"].existsSync(tilePath)) { + raiseError("Path to mbtiles files does not exist: ".concat(tilePath)); + } + console.log('Using local mbtiles in: %j', tilePath); } server.listen(port, function () { console.log('Mapbox GL static rendering server started and listening at %s', server.url); -}); \ No newline at end of file +}); +var _default = { + server: server +}; +exports["default"] = _default; \ No newline at end of file diff --git a/src/cli.js b/src/cli.js index b5d17a4..172e364 100755 --- a/src/cli.js +++ b/src/cli.js @@ -121,6 +121,18 @@ if (bounds !== null) { ]}` ) } + + bounds.forEach(b => { + if (Number.isNaN(b)) { + raiseError( + `Bounds must be west,south,east,north. Invalid value found: ${[ + ...bounds, + ]}` + ) + } + return null + }) + const [west, south, east, north] = bounds if (west === east) { raiseError(`Bounds west and east coordinate are the same value`) diff --git a/src/server.js b/src/server.js index 6404e05..9d74cd0 100755 --- a/src/server.js +++ b/src/server.js @@ -1,14 +1,20 @@ #!/usr/bin/env node +import fs from 'fs' import restify from 'restify' import restifyValidation from 'node-restify-validation' import restifyErrors from 'restify-errors' import cli from 'commander' import { version } from '../package.json' -import render from './render' +import { render } from './render' const parseListToFloat = text => text.split(',').map(Number) +const raiseError = msg => { + console.error('ERROR:', msg) + process.exit(1) +} + const PARAMS = { style: { isRequired: true, isString: true }, width: { isRequired: true, isInt: true }, @@ -119,6 +125,22 @@ const renderImage = (params, response, next, tilePath) => { } return null }) + + const [west, south, east, north] = bounds + if (west === east) { + return next( + new restifyErrors.BadRequestError( + `Bounds west and east coordinate are the same value` + ) + ) + } + if (south === north) { + return next( + new restifyErrors.BadRequestError( + `Bounds south and north coordinate are the same value` + ) + ) + } } if (bearing !== null) { @@ -208,7 +230,7 @@ cli.version(version) const { port = 8000, tiles: tilePath = null } = cli -const server = restify.createServer({ +export const server = restify.createServer({ ignoreTrailingSlash: true, }) server.use(restify.plugins.queryParser()) @@ -258,6 +280,10 @@ server.get({ url: '/' }, (req, res) => { }) if (tilePath !== null) { + if (!fs.existsSync(tilePath)) { + raiseError(`Path to mbtiles files does not exist: ${tilePath}`) + } + console.log('Using local mbtiles in: %j', tilePath) } @@ -267,3 +293,5 @@ server.listen(port, () => { server.url ) }) + +export default { server } diff --git a/tests/cli.test.js b/tests/cli.test.js index e70b7a4..427a7d6 100644 --- a/tests/cli.test.js +++ b/tests/cli.test.js @@ -6,7 +6,7 @@ import dotenv from 'dotenv-flow' import sharp from 'sharp' import { createTempDir } from 'jest-fixtures' -import { imageDiff } from './util' +import { imageDiff, cliEndpoint } from './util' import { version } from '../package.json' @@ -20,23 +20,7 @@ if (!MAPBOX_API_TOKEN) { ) } -// from: https://medium.com/@ole.ersoy/unit-testing-commander-scripts-with-jest-bc32465709d6 -function cli(args, cwd) { - return new Promise(resolve => { - exec( - `node ${path.resolve('./dist/cli')} ${args.join(' ')}`, - { cwd }, - (error, stdout, stderr) => { - resolve({ - code: error && error.code ? error.code : 0, - error, - stdout, - stderr, - }) - } - ) - }) -} +const cli = cliEndpoint('./dist/cli') test('returns correct version', async () => { const { stdout } = await cli(['-V'], '.') diff --git a/tests/server.test.js b/tests/server.test.js new file mode 100644 index 0000000..8a2d9a6 --- /dev/null +++ b/tests/server.test.js @@ -0,0 +1,15 @@ +import { cliEndpoint } from './util' + +import { version } from '../package.json' + +const cli = cliEndpoint('./dist/server') + +test('returns correct version', async () => { + const { stdout } = await cli(['-V'], '.') + expect(stdout).toContain(version) +}) + +test('fails with invalid tile path', async () => { + const { stderr } = await cli(['-t', './bad-tile-path'], '.') + expect(stderr).toContain('ERROR: Path to mbtiles files does not exist') +}) diff --git a/tests/util.js b/tests/util.js index e130b34..2881cd3 100644 --- a/tests/util.js +++ b/tests/util.js @@ -1,4 +1,7 @@ +import path from 'path' +import { exec } from 'child_process' import sharp from 'sharp' + import pixelmatch from 'pixelmatch' /** @@ -25,4 +28,36 @@ export async function imageDiff(pngData, expectedPath) { return pixelmatch(rawData, expected, null, width, height) } -export default { imageDiff } +/** + * Create a test endpoint for the CLI at the passed in path. + * + * @param {String} cliPath - path to CLI to test (BUILT version) + */ +export function cliEndpoint(cliPath) { + /** + * Test the CLI (built version) with the passed in arguments. + * Derived from from: https://medium.com/@ole.ersoy/unit-testing-commander-scripts-with-jest-bc32465709d6 + * + * + * @param {String} args - arguments to pass to CLI command + * @param {String} cwd - current working directory + */ + return function cli(args, cwd) { + return new Promise(resolve => { + exec( + `node ${path.resolve(cliPath)} ${args.join(' ')}`, + { cwd }, + (error, stdout, stderr) => { + resolve({ + code: error && error.code ? error.code : 0, + error, + stdout, + stderr, + }) + } + ) + }) + } +} + +export default { imageDiff, cliEndpoint }