Merge branch 'master' into feat/layer-search

This commit is contained in:
Martijn van Exel 2024-07-31 17:45:30 -06:00 committed by GitHub
commit 634fdcca7b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 46 additions and 28 deletions

View file

@ -3,6 +3,7 @@
'use strict'; 'use strict';
import fs from 'node:fs'; import fs from 'node:fs';
import fsp from 'node:fs/promises';
import path from 'path'; import path from 'path';
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
import axios from 'axios'; import axios from 'axios';
@ -23,6 +24,7 @@ if (args.length >= 3 && args[2][0] !== '-') {
} }
import { program } from 'commander'; import { program } from 'commander';
import { existsP } from './promises.js';
program program
.description('tileserver-gl startup options') .description('tileserver-gl startup options')
.usage('tileserver-gl [mbtiles] [options]') .usage('tileserver-gl [mbtiles] [options]')
@ -95,7 +97,7 @@ const startWithInputFile = async (inputFile) => {
inputFile = path.resolve(process.cwd(), inputFile); inputFile = path.resolve(process.cwd(), inputFile);
inputFilePath = path.dirname(inputFile); inputFilePath = path.dirname(inputFile);
const inputFileStats = fs.statSync(inputFile); const inputFileStats = await fsp.stat(inputFile);
if (!inputFileStats.isFile() || inputFileStats.size === 0) { if (!inputFileStats.isFile() || inputFileStats.size === 0) {
console.log(`ERROR: Not a valid input file: `); console.log(`ERROR: Not a valid input file: `);
process.exit(1); process.exit(1);
@ -140,11 +142,11 @@ const startWithInputFile = async (inputFile) => {
}; };
} }
const styles = fs.readdirSync(path.resolve(styleDir, 'styles')); const styles = await fsp.readdir(path.resolve(styleDir, 'styles'));
for (const styleName of styles) { for (const styleName of styles) {
const styleFileRel = styleName + '/style.json'; const styleFileRel = styleName + '/style.json';
const styleFile = path.resolve(styleDir, 'styles', styleFileRel); const styleFile = path.resolve(styleDir, 'styles', styleFileRel);
if (fs.existsSync(styleFile)) { if (await existsP(styleFile)) {
config['styles'][styleName] = { config['styles'][styleName] = {
style: styleFileRel, style: styleFileRel,
tilejson: { tilejson: {
@ -189,7 +191,7 @@ const startWithInputFile = async (inputFile) => {
process.exit(1); process.exit(1);
} }
instance.getInfo((err, info) => { instance.getInfo(async (err, info) => {
if (err || !info) { if (err || !info) {
console.log('ERROR: Metadata missing in the MBTiles.'); console.log('ERROR: Metadata missing in the MBTiles.');
console.log( console.log(
@ -207,11 +209,11 @@ const startWithInputFile = async (inputFile) => {
mbtiles: path.basename(inputFile), mbtiles: path.basename(inputFile),
}; };
const styles = fs.readdirSync(path.resolve(styleDir, 'styles')); const styles = await fsp.readdir(path.resolve(styleDir, 'styles'));
for (const styleName of styles) { for (const styleName of styles) {
const styleFileRel = styleName + '/style.json'; const styleFileRel = styleName + '/style.json';
const styleFile = path.resolve(styleDir, 'styles', styleFileRel); const styleFile = path.resolve(styleDir, 'styles', styleFileRel);
if (fs.existsSync(styleFile)) { if (await existsP(styleFile)) {
config['styles'][styleName] = { config['styles'][styleName] = {
style: styleFileRel, style: styleFileRel,
tilejson: { tilejson: {
@ -254,10 +256,10 @@ fs.stat(path.resolve(opts.config), async (err, stats) => {
return startWithInputFile(inputFile); return startWithInputFile(inputFile);
} else { } else {
// try to find in the cwd // try to find in the cwd
const files = fs.readdirSync(process.cwd()); const files = await fsp.readdir(process.cwd());
for (const filename of files) { for (const filename of files) {
if (filename.endsWith('.mbtiles') || filename.endsWith('.pmtiles')) { if (filename.endsWith('.mbtiles') || filename.endsWith('.pmtiles')) {
const inputFilesStats = fs.statSync(filename); const inputFilesStats = await fsp.stat(filename);
if (inputFilesStats.isFile() && inputFilesStats.size > 0) { if (inputFilesStats.isFile() && inputFilesStats.size > 0) {
inputFile = filename; inputFile = filename;
break; break;

14
src/promises.js Normal file
View file

@ -0,0 +1,14 @@
import util from 'node:util';
import fsp from 'node:fs/promises';
import zlib from 'zlib';
export const gzipP = util.promisify(zlib.gzip);
export const gunzipP = util.promisify(zlib.gunzip);
export const existsP = async (path) => {
try {
await fsp.access(path); // Defaults to F_OK: indicating that the file is visible to the calling process
return true;
} catch (err) {
return false;
}
};

View file

@ -1,8 +1,7 @@
'use strict'; 'use strict';
import fs from 'node:fs'; import fsp from 'node:fs/promises';
import path from 'path'; import path from 'path';
import zlib from 'zlib';
import clone from 'clone'; import clone from 'clone';
import express from 'express'; import express from 'express';
@ -10,12 +9,13 @@ import MBTiles from '@mapbox/mbtiles';
import Pbf from 'pbf'; import Pbf from 'pbf';
import { VectorTile } from '@mapbox/vector-tile'; import { VectorTile } from '@mapbox/vector-tile';
import { getTileUrls, isValidHttpUrl, fixTileJSONCenter } from './utils.js'; import { fixTileJSONCenter, getTileUrls, isValidHttpUrl } from './utils.js';
import { import {
openPMtiles,
getPMtilesInfo, getPMtilesInfo,
getPMtilesTile, getPMtilesTile,
openPMtiles,
} from './pmtiles_adapter.js'; } from './pmtiles_adapter.js';
import { gunzipP, gzipP } from './promises.js';
export const serve_data = { export const serve_data = {
init: (options, repo) => { init: (options, repo) => {
@ -89,12 +89,12 @@ export const serve_data = {
headers['Content-Encoding'] = 'gzip'; headers['Content-Encoding'] = 'gzip';
res.set(headers); res.set(headers);
data = zlib.gzipSync(data); data = await gzipP(data);
return res.status(200).send(data); return res.status(200).send(data);
} }
} else if (item.sourceType === 'mbtiles') { } else if (item.sourceType === 'mbtiles') {
item.source.getTile(z, x, y, (err, data, headers) => { item.source.getTile(z, x, y, async (err, data, headers) => {
let isGzipped; let isGzipped;
if (err) { if (err) {
if (/does not exist/.test(err.message)) { if (/does not exist/.test(err.message)) {
@ -114,7 +114,7 @@ export const serve_data = {
data.slice(0, 2).indexOf(Buffer.from([0x1f, 0x8b])) === 0; data.slice(0, 2).indexOf(Buffer.from([0x1f, 0x8b])) === 0;
if (options.dataDecoratorFunc) { if (options.dataDecoratorFunc) {
if (isGzipped) { if (isGzipped) {
data = zlib.unzipSync(data); data = await gunzipP(data);
isGzipped = false; isGzipped = false;
} }
data = options.dataDecoratorFunc(id, 'data', data, z, x, y); data = options.dataDecoratorFunc(id, 'data', data, z, x, y);
@ -126,7 +126,7 @@ export const serve_data = {
headers['Content-Type'] = 'application/json'; headers['Content-Type'] = 'application/json';
if (isGzipped) { if (isGzipped) {
data = zlib.unzipSync(data); data = await gunzipP(data);
isGzipped = false; isGzipped = false;
} }
@ -151,7 +151,7 @@ export const serve_data = {
res.set(headers); res.set(headers);
if (!isGzipped) { if (!isGzipped) {
data = zlib.gzipSync(data); data = await gzipP(data);
} }
return res.status(200).send(data); return res.status(200).send(data);
@ -212,7 +212,7 @@ export const serve_data = {
}; };
if (!isValidHttpUrl(inputFile)) { if (!isValidHttpUrl(inputFile)) {
const inputFileStats = fs.statSync(inputFile); const inputFileStats = await fsp.stat(inputFile);
if (!inputFileStats.isFile() || inputFileStats.size === 0) { if (!inputFileStats.isFile() || inputFileStats.size === 0) {
throw Error(`Not valid input file: "${inputFile}"`); throw Error(`Not valid input file: "${inputFile}"`);
} }

View file

@ -17,7 +17,6 @@ import fs from 'node:fs';
import path from 'path'; import path from 'path';
import url from 'url'; import url from 'url';
import util from 'util'; import util from 'util';
import zlib from 'zlib';
import sharp from 'sharp'; import sharp from 'sharp';
import clone from 'clone'; import clone from 'clone';
import Color from 'color'; import Color from 'color';
@ -42,6 +41,8 @@ import {
getPMtilesTile, getPMtilesTile,
} from './pmtiles_adapter.js'; } from './pmtiles_adapter.js';
import { renderOverlay, renderWatermark, renderAttribution } from './render.js'; import { renderOverlay, renderWatermark, renderAttribution } from './render.js';
import fsp from 'node:fs/promises';
import { gunzipP } from './promises.js';
const FLOAT_PATTERN = '[+-]?(?:\\d+|\\d+.?\\d+)'; const FLOAT_PATTERN = '[+-]?(?:\\d+|\\d+.?\\d+)';
const PATH_PATTERN = const PATH_PATTERN =
@ -943,7 +944,7 @@ export const serve_rendered = {
callback(null, response); callback(null, response);
} }
} else if (sourceType === 'mbtiles') { } else if (sourceType === 'mbtiles') {
source.getTile(z, x, y, (err, data, headers) => { source.getTile(z, x, y, async (err, data, headers) => {
if (err) { if (err) {
if (options.verbose) if (options.verbose)
console.log('MBTiles error, serving empty', err); console.log('MBTiles error, serving empty', err);
@ -962,7 +963,7 @@ export const serve_rendered = {
if (format === 'pbf') { if (format === 'pbf') {
try { try {
response.data = zlib.unzipSync(data); response.data = await gunzipP(data);
} catch (err) { } catch (err) {
console.log( console.log(
'Skipping incorrect header for tile mbtiles://%s/%s/%s/%s.pbf', 'Skipping incorrect header for tile mbtiles://%s/%s/%s/%s.pbf',
@ -1039,7 +1040,7 @@ export const serve_rendered = {
const styleFile = params.style; const styleFile = params.style;
const styleJSONPath = path.resolve(options.paths.styles, styleFile); const styleJSONPath = path.resolve(options.paths.styles, styleFile);
try { try {
styleJSON = JSON.parse(fs.readFileSync(styleJSONPath)); styleJSON = JSON.parse(await fsp.readFile(styleJSONPath));
} catch (e) { } catch (e) {
console.log('Error parsing style file'); console.log('Error parsing style file');
return false; return false;
@ -1145,7 +1146,7 @@ export const serve_rendered = {
} }
if (!isValidHttpUrl(inputFile)) { if (!isValidHttpUrl(inputFile)) {
const inputFileStats = fs.statSync(inputFile); const inputFileStats = await fsp.stat(inputFile);
if (!inputFileStats.isFile() || inputFileStats.size === 0) { if (!inputFileStats.isFile() || inputFileStats.size === 0) {
throw Error(`Not valid PMTiles file: "${inputFile}"`); throw Error(`Not valid PMTiles file: "${inputFile}"`);
} }
@ -1187,9 +1188,9 @@ export const serve_rendered = {
} }
} else { } else {
queue.push( queue.push(
new Promise((resolve, reject) => { new Promise(async (resolve, reject) => {
inputFile = path.resolve(options.paths.mbtiles, inputFile); inputFile = path.resolve(options.paths.mbtiles, inputFile);
const inputFileStats = fs.statSync(inputFile); const inputFileStats = await fsp.stat(inputFile);
if (!inputFileStats.isFile() || inputFileStats.size === 0) { if (!inputFileStats.isFile() || inputFileStats.size === 0) {
throw Error(`Not valid MBTiles file: "${inputFile}"`); throw Error(`Not valid MBTiles file: "${inputFile}"`);
} }

View file

@ -87,7 +87,7 @@ export const serve_style = {
let styleFileData; let styleFileData;
try { try {
styleFileData = fs.readFileSync(styleFile); styleFileData = fs.readFileSync(styleFile); // TODO: could be made async if this function was
} catch (e) { } catch (e) {
console.log('Error reading style file'); console.log('Error reading style file');
return false; return false;

View file

@ -2,9 +2,10 @@
import path from 'path'; import path from 'path';
import fsPromises from 'fs/promises'; import fsPromises from 'fs/promises';
import fs, { existsSync } from 'node:fs'; import fs from 'node:fs';
import clone from 'clone'; import clone from 'clone';
import { combine } from '@jsse/pbfont'; import { combine } from '@jsse/pbfont';
import { existsP } from './promises.js';
/** /**
* Restrict user input to an allowed set of options. * Restrict user input to an allowed set of options.
@ -225,7 +226,7 @@ export const listFonts = async (fontPath) => {
const stats = await fsPromises.stat(path.join(fontPath, file)); const stats = await fsPromises.stat(path.join(fontPath, file));
if ( if (
stats.isDirectory() && stats.isDirectory() &&
existsSync(path.join(fontPath, file, '0-255.pbf')) (await existsP(path.join(fontPath, file, '0-255.pbf')))
) { ) {
existingFonts[path.basename(file)] = true; existingFonts[path.basename(file)] = true;
} }