feat: allow web https based pmtiles to be loaded
Signed-off-by: Andrew Calcutt <acalcutt@techidiots.net>
This commit is contained in:
parent
3f45c38663
commit
fde9ed96a5
6 changed files with 80 additions and 39 deletions
29
src/main.js
29
src/main.js
|
|
@ -8,6 +8,7 @@ import { fileURLToPath } from 'url';
|
||||||
import request from 'request';
|
import request from 'request';
|
||||||
import { server } from './server.js';
|
import { server } from './server.js';
|
||||||
import MBTiles from '@mapbox/mbtiles';
|
import MBTiles from '@mapbox/mbtiles';
|
||||||
|
import { isValidHttpUrl } from './utils.js';
|
||||||
import {
|
import {
|
||||||
PMtilesOpen,
|
PMtilesOpen,
|
||||||
PMtilesClose,
|
PMtilesClose,
|
||||||
|
|
@ -91,13 +92,19 @@ const startWithinputFile = async (inputFile) => {
|
||||||
`[INFO] See documentation to learn how to create config.json file.`,
|
`[INFO] See documentation to learn how to create config.json file.`,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let inputFilePath;
|
||||||
|
if (isValidHttpUrl(inputFile)) {
|
||||||
|
inputFilePath = process.cwd();
|
||||||
|
} else {
|
||||||
inputFile = path.resolve(process.cwd(), inputFile);
|
inputFile = path.resolve(process.cwd(), inputFile);
|
||||||
|
inputFilePath = path.dirname(inputFile);
|
||||||
|
|
||||||
const inputFileStats = fs.statSync(inputFile);
|
const inputFileStats = fs.statSync(inputFile);
|
||||||
if (!inputFileStats.isFile() || inputFileStats.size === 0) {
|
if (!inputFileStats.isFile() || inputFileStats.size === 0) {
|
||||||
console.log(`ERROR: Not a valid input file: ${inputFile}`);
|
console.log(`ERROR: Not a valid input file: `);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const styleDir = path.resolve(
|
const styleDir = path.resolve(
|
||||||
__dirname,
|
__dirname,
|
||||||
|
|
@ -110,8 +117,8 @@ const startWithinputFile = async (inputFile) => {
|
||||||
root: styleDir,
|
root: styleDir,
|
||||||
fonts: 'fonts',
|
fonts: 'fonts',
|
||||||
styles: 'styles',
|
styles: 'styles',
|
||||||
mbtiles: path.dirname(inputFile),
|
mbtiles: inputFilePath,
|
||||||
pmtiles: path.dirname(inputFile),
|
pmtiles: inputFilePath,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
styles: {},
|
styles: {},
|
||||||
|
|
@ -132,9 +139,15 @@ const startWithinputFile = async (inputFile) => {
|
||||||
metadata.format === 'pbf' &&
|
metadata.format === 'pbf' &&
|
||||||
metadata.name.toLowerCase().indexOf('openmaptiles') > -1
|
metadata.name.toLowerCase().indexOf('openmaptiles') > -1
|
||||||
) {
|
) {
|
||||||
|
if (isValidHttpUrl(inputFile)) {
|
||||||
|
config['data'][`v3`] = {
|
||||||
|
pmtiles: inputFile,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
config['data'][`v3`] = {
|
config['data'][`v3`] = {
|
||||||
pmtiles: path.basename(inputFile),
|
pmtiles: path.basename(inputFile),
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const styles = fs.readdirSync(path.resolve(styleDir, 'styles'));
|
const styles = fs.readdirSync(path.resolve(styleDir, 'styles'));
|
||||||
for (const styleName of styles) {
|
for (const styleName of styles) {
|
||||||
|
|
@ -153,10 +166,16 @@ const startWithinputFile = async (inputFile) => {
|
||||||
console.log(
|
console.log(
|
||||||
`WARN: PMTiles not in "openmaptiles" format. Serving raw data only...`,
|
`WARN: PMTiles not in "openmaptiles" format. Serving raw data only...`,
|
||||||
);
|
);
|
||||||
|
if (isValidHttpUrl(inputFile)) {
|
||||||
|
config['data'][(metadata.id || 'pmtiles').replace(/[?/:]/g, '_')] = {
|
||||||
|
pmtiles: inputFile,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
config['data'][(metadata.id || 'pmtiles').replace(/[?/:]/g, '_')] = {
|
config['data'][(metadata.id || 'pmtiles').replace(/[?/:]/g, '_')] = {
|
||||||
pmtiles: path.basename(inputFile),
|
pmtiles: path.basename(inputFile),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (opts.verbose) {
|
if (opts.verbose) {
|
||||||
console.log(JSON.stringify(config, undefined, 2));
|
console.log(JSON.stringify(config, undefined, 2));
|
||||||
|
|
@ -166,6 +185,10 @@ const startWithinputFile = async (inputFile) => {
|
||||||
|
|
||||||
return startServer(null, config);
|
return startServer(null, config);
|
||||||
} else {
|
} else {
|
||||||
|
if (isValidHttpUrl(inputFile)) {
|
||||||
|
console.log(`ERROR: MBTiles does not support web based files: `);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
const instance = new MBTiles(inputFile + '?mode=ro', (err) => {
|
const instance = new MBTiles(inputFile + '?mode=ro', (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log('ERROR: Unable to open MBTiles.');
|
console.log('ERROR: Unable to open MBTiles.');
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import PMTiles from 'pmtiles';
|
import PMTiles from 'pmtiles';
|
||||||
|
import { isValidHttpUrl } from './utils.js';
|
||||||
|
|
||||||
const PMTilesFileSource = class {
|
const PMTilesFileSource = class {
|
||||||
constructor(fd) {
|
constructor(fd) {
|
||||||
|
|
@ -122,19 +123,3 @@ const ArrayBufferToBuffer = (array_buffer) => {
|
||||||
}
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param string
|
|
||||||
*/
|
|
||||||
function isValidHttpUrl(string) {
|
|
||||||
let url;
|
|
||||||
|
|
||||||
try {
|
|
||||||
url = new URL(string);
|
|
||||||
} catch (_) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return url.protocol === 'http:' || url.protocol === 'https:';
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ 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, fixTileJSONCenter } from './utils.js';
|
import { getTileUrls, isValidHttpUrl, fixTileJSONCenter } from './utils.js';
|
||||||
import {
|
import {
|
||||||
PMtilesOpen,
|
PMtilesOpen,
|
||||||
GetPMtilesInfo,
|
GetPMtilesInfo,
|
||||||
|
|
@ -194,21 +194,33 @@ export const serve_data = {
|
||||||
let inputFile;
|
let inputFile;
|
||||||
let inputType;
|
let inputType;
|
||||||
if (params.pmtiles) {
|
if (params.pmtiles) {
|
||||||
inputFile = path.resolve(options.paths.pmtiles, params.pmtiles);
|
|
||||||
inputType = 'pmtiles';
|
inputType = 'pmtiles';
|
||||||
|
if (isValidHttpUrl(params.pmtiles)) {
|
||||||
|
inputFile = params.pmtiles;
|
||||||
|
} else {
|
||||||
|
inputFile = path.resolve(options.paths.pmtiles, params.pmtiles);
|
||||||
|
}
|
||||||
} else if (params.mbtiles) {
|
} else if (params.mbtiles) {
|
||||||
inputFile = path.resolve(options.paths.mbtiles, params.mbtiles);
|
|
||||||
inputType = 'mbtiles';
|
inputType = 'mbtiles';
|
||||||
|
if (isValidHttpUrl(params.pmtiles)) {
|
||||||
|
throw Error(
|
||||||
|
`ERROR: MBTiles does not support web based files: ${inputFile}`,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
inputFile = path.resolve(options.paths.mbtiles, params.mbtiles);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let tileJSON = {
|
let tileJSON = {
|
||||||
tiles: params.domains || options.domains,
|
tiles: params.domains || options.domains,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!isValidHttpUrl(inputFile)) {
|
||||||
const inputFileStats = fs.statSync(inputFile);
|
const inputFileStats = fs.statSync(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}`);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let source;
|
let source;
|
||||||
let source_type;
|
let source_type;
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,12 @@ import MBTiles from '@mapbox/mbtiles';
|
||||||
import polyline from '@mapbox/polyline';
|
import polyline from '@mapbox/polyline';
|
||||||
import proj4 from 'proj4';
|
import proj4 from 'proj4';
|
||||||
import request from 'request';
|
import request from 'request';
|
||||||
import { getFontsPbf, getTileUrls, fixTileJSONCenter } from './utils.js';
|
import {
|
||||||
|
getFontsPbf,
|
||||||
|
getTileUrls,
|
||||||
|
isValidHttpUrl,
|
||||||
|
fixTileJSONCenter,
|
||||||
|
} from './utils.js';
|
||||||
import {
|
import {
|
||||||
PMtilesOpen,
|
PMtilesOpen,
|
||||||
GetPMtilesInfo,
|
GetPMtilesInfo,
|
||||||
|
|
@ -1489,9 +1494,11 @@ export const serve_rendered = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isValidHttpUrl(inputFile)) {
|
||||||
const inputFileStats = fs.statSync(inputFile);
|
const inputFileStats = fs.statSync(inputFile);
|
||||||
if (!inputFileStats.isFile() || inputFileStats.size === 0) {
|
if (!inputFileStats.isFile() || inputFileStats.size === 0) {
|
||||||
throw Error(`Not valid MBTiles file: ${inputFile}`);
|
throw Error(`Not valid PMTiles file: ${inputFile}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source_type === 'pmtiles') {
|
if (source_type === 'pmtiles') {
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,7 @@ function start(opts) {
|
||||||
paths.fonts = path.resolve(paths.root, paths.fonts || '');
|
paths.fonts = path.resolve(paths.root, paths.fonts || '');
|
||||||
paths.sprites = path.resolve(paths.root, paths.sprites || '');
|
paths.sprites = path.resolve(paths.root, paths.sprites || '');
|
||||||
paths.mbtiles = path.resolve(paths.root, paths.mbtiles || '');
|
paths.mbtiles = path.resolve(paths.root, paths.mbtiles || '');
|
||||||
|
paths.pmtiles = path.resolve(paths.root, paths.pmtiles || '');
|
||||||
paths.icons = path.resolve(paths.root, paths.icons || '');
|
paths.icons = path.resolve(paths.root, paths.icons || '');
|
||||||
|
|
||||||
const startupPromises = [];
|
const startupPromises = [];
|
||||||
|
|
@ -109,6 +110,7 @@ function start(opts) {
|
||||||
checkPath('fonts');
|
checkPath('fonts');
|
||||||
checkPath('sprites');
|
checkPath('sprites');
|
||||||
checkPath('mbtiles');
|
checkPath('mbtiles');
|
||||||
|
checkPath('pmtiles');
|
||||||
checkPath('icons');
|
checkPath('icons');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
12
src/utils.js
12
src/utils.js
|
|
@ -162,3 +162,15 @@ export const getFontsPbf = (
|
||||||
|
|
||||||
return Promise.all(queue).then((values) => glyphCompose.combine(values));
|
return Promise.all(queue).then((values) => glyphCompose.combine(values));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const isValidHttpUrl = (string) => {
|
||||||
|
let url;
|
||||||
|
|
||||||
|
try {
|
||||||
|
url = new URL(string);
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return url.protocol === 'http:' || url.protocol === 'https:';
|
||||||
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue