fix: avoid synchronous calls where possible (#1320)

Signed-off-by: Aarni Koskela <akx@iki.fi>
This commit is contained in:
Aarni Koskela 2024-07-31 15:51:56 +03:00 committed by GitHub
parent f64f95f80b
commit 1d4c1ff188
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';
import fs from 'node:fs';
import fsp from 'node:fs/promises';
import path from 'path';
import { fileURLToPath } from 'url';
import axios from 'axios';
@ -23,6 +24,7 @@ if (args.length >= 3 && args[2][0] !== '-') {
}
import { program } from 'commander';
import { existsP } from './promises.js';
program
.description('tileserver-gl startup options')
.usage('tileserver-gl [mbtiles] [options]')
@ -95,7 +97,7 @@ const startWithInputFile = async (inputFile) => {
inputFile = path.resolve(process.cwd(), inputFile);
inputFilePath = path.dirname(inputFile);
const inputFileStats = fs.statSync(inputFile);
const inputFileStats = await fsp.stat(inputFile);
if (!inputFileStats.isFile() || inputFileStats.size === 0) {
console.log(`ERROR: Not a valid input file: `);
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) {
const styleFileRel = styleName + '/style.json';
const styleFile = path.resolve(styleDir, 'styles', styleFileRel);
if (fs.existsSync(styleFile)) {
if (await existsP(styleFile)) {
config['styles'][styleName] = {
style: styleFileRel,
tilejson: {
@ -189,7 +191,7 @@ const startWithInputFile = async (inputFile) => {
process.exit(1);
}
instance.getInfo((err, info) => {
instance.getInfo(async (err, info) => {
if (err || !info) {
console.log('ERROR: Metadata missing in the MBTiles.');
console.log(
@ -207,11 +209,11 @@ const startWithInputFile = async (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) {
const styleFileRel = styleName + '/style.json';
const styleFile = path.resolve(styleDir, 'styles', styleFileRel);
if (fs.existsSync(styleFile)) {
if (await existsP(styleFile)) {
config['styles'][styleName] = {
style: styleFileRel,
tilejson: {
@ -254,10 +256,10 @@ fs.stat(path.resolve(opts.config), async (err, stats) => {
return startWithInputFile(inputFile);
} else {
// try to find in the cwd
const files = fs.readdirSync(process.cwd());
const files = await fsp.readdir(process.cwd());
for (const filename of files) {
if (filename.endsWith('.mbtiles') || filename.endsWith('.pmtiles')) {
const inputFilesStats = fs.statSync(filename);
const inputFilesStats = await fsp.stat(filename);
if (inputFilesStats.isFile() && inputFilesStats.size > 0) {
inputFile = filename;
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';
import fs from 'node:fs';
import fsp from 'node:fs/promises';
import path from 'path';
import zlib from 'zlib';
import clone from 'clone';
import express from 'express';
@ -10,12 +9,13 @@ import MBTiles from '@mapbox/mbtiles';
import Pbf from 'pbf';
import { VectorTile } from '@mapbox/vector-tile';
import { getTileUrls, isValidHttpUrl, fixTileJSONCenter } from './utils.js';
import { fixTileJSONCenter, getTileUrls, isValidHttpUrl } from './utils.js';
import {
openPMtiles,
getPMtilesInfo,
getPMtilesTile,
openPMtiles,
} from './pmtiles_adapter.js';
import { gunzipP, gzipP } from './promises.js';
export const serve_data = {
init: (options, repo) => {
@ -89,12 +89,12 @@ export const serve_data = {
headers['Content-Encoding'] = 'gzip';
res.set(headers);
data = zlib.gzipSync(data);
data = await gzipP(data);
return res.status(200).send(data);
}
} 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;
if (err) {
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;
if (options.dataDecoratorFunc) {
if (isGzipped) {
data = zlib.unzipSync(data);
data = await gunzipP(data);
isGzipped = false;
}
data = options.dataDecoratorFunc(id, 'data', data, z, x, y);
@ -126,7 +126,7 @@ export const serve_data = {
headers['Content-Type'] = 'application/json';
if (isGzipped) {
data = zlib.unzipSync(data);
data = await gunzipP(data);
isGzipped = false;
}
@ -151,7 +151,7 @@ export const serve_data = {
res.set(headers);
if (!isGzipped) {
data = zlib.gzipSync(data);
data = await gzipP(data);
}
return res.status(200).send(data);
@ -212,7 +212,7 @@ export const serve_data = {
};
if (!isValidHttpUrl(inputFile)) {
const inputFileStats = fs.statSync(inputFile);
const inputFileStats = await fsp.stat(inputFile);
if (!inputFileStats.isFile() || inputFileStats.size === 0) {
throw Error(`Not valid input file: "${inputFile}"`);
}

View File

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

View File

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

View File

@ -2,9 +2,10 @@
import path from 'path';
import fsPromises from 'fs/promises';
import fs, { existsSync } from 'node:fs';
import fs from 'node:fs';
import clone from 'clone';
import { combine } from '@jsse/pbfont';
import { existsP } from './promises.js';
/**
* 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));
if (
stats.isDirectory() &&
existsSync(path.join(fontPath, file, '0-255.pbf'))
(await existsP(path.join(fontPath, file, '0-255.pbf')))
) {
existingFonts[path.basename(file)] = true;
}