This commit is contained in:
acalcutt 2022-09-16 17:47:30 -04:00
parent 982b32acd6
commit 3bf3a1cb07
13 changed files with 12150 additions and 134 deletions

11
.eslintrc.yml Normal file
View file

@ -0,0 +1,11 @@
env:
browser: false
es2021: true
extends: google
overrides: []
parserOptions:
ecmaVersion: latest
sourceType: module
ignorePatterns:
- /public/resources
rules: {}

12000
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -19,11 +19,11 @@
},
"dependencies": {
"@mapbox/glyph-pbf-composite": "0.0.3",
"@maplibre/maplibre-gl-native": "5.0.1-pre.0",
"@maplibre/maplibre-gl-style-spec": "17.0.1",
"@mapbox/mbtiles": "0.12.1",
"@mapbox/sphericalmercator": "1.2.0",
"@mapbox/vector-tile": "1.3.1",
"@maplibre/maplibre-gl-native": "5.0.1-pre.0",
"@maplibre/maplibre-gl-style-spec": "17.0.1",
"advanced-pool": "0.3.3",
"canvas": "2.10.1",
"chokidar": "3.5.3",
@ -42,8 +42,11 @@
"tileserver-gl-styles": "2.0.0"
},
"devDependencies": {
"mocha": "^10.0.0",
"chai": "4.3.6",
"eslint": "^8.23.1",
"eslint-config-google": "^0.14.0",
"lint": "^0.7.0",
"mocha": "^10.0.0",
"supertest": "^6.2.4"
}
}

View file

@ -12,12 +12,12 @@
// SYNC THE `light` FOLDER
require('child_process').execSync('rsync -av --exclude="light" --exclude=".git" --exclude="node_modules" --delete . light', {
stdio: 'inherit'
stdio: 'inherit',
});
// PATCH `package.json`
var fs = require('fs');
var packageJson = require('./package');
const fs = require('fs');
const packageJson = require('./package');
packageJson.name += '-light';
packageJson.description = 'Map tile server for JSON GL styles - serving vector tiles';
@ -30,25 +30,25 @@ delete packageJson.devDependencies;
packageJson.engines.node = '>= 10';
var str = JSON.stringify(packageJson, undefined, 2);
const str = JSON.stringify(packageJson, undefined, 2);
fs.writeFileSync('light/package.json', str);
fs.renameSync('light/README_light.md', 'light/README.md');
fs.renameSync('light/Dockerfile_light', 'light/Dockerfile');
fs.renameSync('light/docker-entrypoint_light.sh', 'light/docker-entrypoint.sh');
// for Build tileserver-gl-light docker image, don't publish
if (process.argv.length > 2 && process.argv[2] == "--no-publish") {
process.exit(0)
if (process.argv.length > 2 && process.argv[2] == '--no-publish') {
process.exit(0);
}
/* PUBLISH */
// tileserver-gl
require('child_process').execSync('npm publish .', {
stdio: 'inherit'
stdio: 'inherit',
});
// tileserver-gl-light
require('child_process').execSync('npm publish light', {
stdio: 'inherit'
stdio: 'inherit',
});

View file

@ -19,58 +19,58 @@ if (args.length >= 3 && args[2][0] !== '-') {
args.splice(2, 0, '--mbtiles');
}
import { program } from 'commander';
import {program} from 'commander';
program
.description('tileserver-gl startup options')
.usage('tileserver-gl [mbtiles] [options]')
.option(
'--mbtiles <file>',
'MBTiles file (uses demo configuration);\n' +
'\t ignored if the configuration file is also specified'
)
.option(
'-c, --config <file>',
'Configuration file [config.json]',
'config.json'
)
.option(
'-b, --bind <address>',
'Bind address'
)
.option(
'-p, --port <port>',
'Port [8080]',
8080,
parseInt
)
.option(
'-C|--no-cors',
'Disable Cross-origin resource sharing headers'
)
.option(
'-u|--public_url <url>',
'Enable exposing the server on subpaths, not necessarily the root of the domain'
)
.option(
'-V, --verbose',
'More verbose output'
)
.option(
'-s, --silent',
'Less verbose output'
)
.option(
'-l|--log_file <file>',
'output log file (defaults to standard out)'
)
.option(
'-f|--log_format <format>',
'define the log format: https://github.com/expressjs/morgan#morganformat-options'
)
.version(
packageJson.version,
'-v, --version'
)
.description('tileserver-gl startup options')
.usage('tileserver-gl [mbtiles] [options]')
.option(
'--mbtiles <file>',
'MBTiles file (uses demo configuration);\n' +
'\t ignored if the configuration file is also specified',
)
.option(
'-c, --config <file>',
'Configuration file [config.json]',
'config.json',
)
.option(
'-b, --bind <address>',
'Bind address',
)
.option(
'-p, --port <port>',
'Port [8080]',
8080,
parseInt,
)
.option(
'-C|--no-cors',
'Disable Cross-origin resource sharing headers',
)
.option(
'-u|--public_url <url>',
'Enable exposing the server on subpaths, not necessarily the root of the domain',
)
.option(
'-V, --verbose',
'More verbose output',
)
.option(
'-s, --silent',
'Less verbose output',
)
.option(
'-l|--log_file <file>',
'output log file (defaults to standard out)',
)
.option(
'-f|--log_format <format>',
'define the log format: https://github.com/expressjs/morgan#morganformat-options',
)
.version(
packageJson.version,
'-v, --version',
);
program.parse(process.argv);
const opts = program.opts();
console.log(`Starting ${packageJson.name} v${packageJson.version}`);

View file

@ -129,7 +129,7 @@ export const serve_data = {
}
let source;
const sourceInfoPromise = new Promise((resolve, reject) => {
source = new MBTiles(mbtilesFile, err => {
source = new MBTiles(mbtilesFile, (err) => {
if (err) {
reject(err);
return;

View file

@ -299,7 +299,7 @@ export const serve_rendered = {
if (z > 2 && tileMargin > 0) {
const [_, y] = mercator.px(params.center, z);
let yoffset = Math.max(Math.min(0, y - 128 - tileMargin), y + 128 + tileMargin - Math.pow(2, z + 8));
const yoffset = Math.max(Math.min(0, y - 128 - tileMargin), y + 128 + tileMargin - Math.pow(2, z + 8));
image.extract({
left: tileMargin * scale,
top: (tileMargin + yoffset) * scale,
@ -764,7 +764,7 @@ export const serve_rendered = {
if (!mbtilesFileStats.isFile() || mbtilesFileStats.size === 0) {
throw Error(`Not valid MBTiles file: ${mbtilesFile}`);
}
map.sources[name] = new MBTiles(mbtilesFile + '?mode=ro', err => {
map.sources[name] = new MBTiles(mbtilesFile + '?mode=ro', (err) => {
map.sources[name].getInfo((err, info) => {
if (err) {
console.error(err);

View file

@ -1,38 +1,38 @@
var testTileJSONArray = function(url) {
const testTileJSONArray = function(url) {
describe(url + ' is array of TileJSONs', function() {
it('is json', function(done) {
supertest(app)
.get(url)
.expect(200)
.expect('Content-Type', /application\/json/, done);
.get(url)
.expect(200)
.expect('Content-Type', /application\/json/, done);
});
it('is non-empty array', function(done) {
supertest(app)
.get(url)
.expect(function(res) {
expect(res.body).to.be.a('array');
expect(res.body.length).to.be.greaterThan(0);
}).end(done);
.get(url)
.expect(function(res) {
expect(res.body).to.be.a('array');
expect(res.body.length).to.be.greaterThan(0);
}).end(done);
});
});
};
var testTileJSON = function(url) {
const testTileJSON = function(url) {
describe(url + ' is TileJSON', function() {
it('is json', function(done) {
supertest(app)
.get(url)
.expect(200)
.expect('Content-Type', /application\/json/, done);
.get(url)
.expect(200)
.expect('Content-Type', /application\/json/, done);
});
it('has valid tiles', function(done) {
supertest(app)
.get(url)
.expect(function(res) {
expect(res.body.tiles.length).to.be.greaterThan(0);
}).end(done);
.get(url)
.expect(function(res) {
expect(res.body.tiles.length).to.be.greaterThan(0);
}).end(done);
});
});
};
@ -41,8 +41,8 @@ describe('Metadata', function() {
describe('/health', function() {
it('returns 200', function(done) {
supertest(app)
.get('/health')
.expect(200, done);
.get('/health')
.expect(200, done);
});
});
@ -53,21 +53,21 @@ describe('Metadata', function() {
describe('/styles.json is valid array', function() {
it('is json', function(done) {
supertest(app)
.get('/styles.json')
.expect(200)
.expect('Content-Type', /application\/json/, done);
.get('/styles.json')
.expect(200)
.expect('Content-Type', /application\/json/, done);
});
it('contains valid item', function(done) {
supertest(app)
.get('/styles.json')
.expect(function(res) {
expect(res.body).to.be.a('array');
expect(res.body.length).to.be.greaterThan(0);
expect(res.body[0].version).to.be.equal(8);
expect(res.body[0].id).to.be.a('string');
expect(res.body[0].name).to.be.a('string');
}).end(done);
.get('/styles.json')
.expect(function(res) {
expect(res.body).to.be.a('array');
expect(res.body.length).to.be.greaterThan(0);
expect(res.body[0].version).to.be.equal(8);
expect(res.body[0].id).to.be.a('string');
expect(res.body[0].name).to.be.a('string');
}).end(done);
});
});

View file

@ -1,19 +1,19 @@
process.env.NODE_ENV = 'test';
import { expect } from 'chai';
import supertest from "supertest";
import { server } from '../src/server.js';
import {expect} from 'chai';
import supertest from 'supertest';
import {server} from '../src/server.js';
global.expect = expect
global.supertest = supertest
global.expect = expect;
global.supertest = supertest;
before(function() {
console.log('global setup');
process.chdir('test_data');
var running = server({
const running = server({
configPath: 'config.json',
port: 8888,
publicUrl: '/test/'
publicUrl: '/test/',
});
global.app = running.app;
global.server = running.server;
@ -22,5 +22,7 @@ before(function() {
after(function() {
console.log('global teardown');
global.server.close(function() { console.log('Done'); process.exit(); });
global.server.close(function() {
console.log('Done'); process.exit();
});
});

View file

@ -1,18 +1,18 @@
var testStatic = function(prefix, q, format, status, scale, type, query) {
const testStatic = function(prefix, q, format, status, scale, type, query) {
if (scale) q += '@' + scale + 'x';
var path = '/styles/' + prefix + '/static/' + q + '.' + format;
let path = '/styles/' + prefix + '/static/' + q + '.' + format;
if (query) {
path += query;
}
it(path + ' returns ' + status, function(done) {
var test = supertest(app).get(path);
const test = supertest(app).get(path);
if (status) test.expect(status);
if (type) test.expect('Content-Type', type);
test.end(done);
});
};
var prefix = 'test-style';
const prefix = 'test-style';
describe('Static endpoints', function() {
describe('center-based', function() {

View file

@ -1,14 +1,14 @@
var testIs = function(url, type, status) {
const testIs = function(url, type, status) {
it(url + ' return ' + (status || 200) + ' and is ' + type.toString(),
function(done) {
supertest(app)
.get(url)
.expect(status || 200)
.expect('Content-Type', type, done);
});
supertest(app)
.get(url)
.expect(status || 200)
.expect('Content-Type', type, done);
});
};
var prefix = 'test-style';
const prefix = 'test-style';
describe('Styles', function() {
describe('/styles/' + prefix + '/style.json is valid style', function() {
@ -16,16 +16,16 @@ describe('Styles', function() {
it('contains expected properties', function(done) {
supertest(app)
.get('/styles/' + prefix + '/style.json')
.expect(function(res) {
expect(res.body.version).to.be.equal(8);
expect(res.body.name).to.be.a('string');
expect(res.body.sources).to.be.a('object');
expect(res.body.glyphs).to.be.a('string');
expect(res.body.sprite).to.be.a('string');
expect(res.body.sprite).to.be.equal('/test/styles/test-style/sprite');
expect(res.body.layers).to.be.a('array');
}).end(done);
.get('/styles/' + prefix + '/style.json')
.expect(function(res) {
expect(res.body.version).to.be.equal(8);
expect(res.body.name).to.be.a('string');
expect(res.body.sources).to.be.a('object');
expect(res.body.glyphs).to.be.a('string');
expect(res.body.sprite).to.be.a('string');
expect(res.body.sprite).to.be.equal('/test/styles/test-style/sprite');
expect(res.body.layers).to.be.a('array');
}).end(done);
});
});
describe('/styles/streets/style.json is not served', function() {
@ -44,7 +44,7 @@ describe('Fonts', function() {
testIs('/fonts/Open Sans Bold/0-255.pbf', /application\/x-protobuf/);
testIs('/fonts/Open Sans Regular/65280-65535.pbf', /application\/x-protobuf/);
testIs('/fonts/Open Sans Bold,Open Sans Regular/0-255.pbf',
/application\/x-protobuf/);
/application\/x-protobuf/);
testIs('/fonts/Nonsense,Open Sans Bold/0-255.pbf', /./, 400);
testIs('/fonts/Nonsense/0-255.pbf', /./, 400);

View file

@ -1,14 +1,14 @@
var testTile = function(prefix, z, x, y, status) {
var path = '/data/' + prefix + '/' + z + '/' + x + '/' + y + '.pbf';
const testTile = function(prefix, z, x, y, status) {
const path = '/data/' + prefix + '/' + z + '/' + x + '/' + y + '.pbf';
it(path + ' returns ' + status, function(done) {
var test = supertest(app).get(path);
const test = supertest(app).get(path);
if (status) test.expect(status);
if (status == 200) test.expect('Content-Type', /application\/x-protobuf/);
test.end(done);
});
};
var prefix = 'openmaptiles';
const prefix = 'openmaptiles';
describe('Vector tiles', function() {
describe('existing tiles', function() {

View file

@ -1,15 +1,15 @@
var testTile = function(prefix, z, x, y, format, status, scale, type) {
const testTile = function(prefix, z, x, y, format, status, scale, type) {
if (scale) y += '@' + scale + 'x';
var path = '/styles/' + prefix + '/' + z + '/' + x + '/' + y + '.' + format;
const path = '/styles/' + prefix + '/' + z + '/' + x + '/' + y + '.' + format;
it(path + ' returns ' + status, function(done) {
var test = supertest(app).get(path);
const test = supertest(app).get(path);
test.expect(status);
if (type) test.expect('Content-Type', type);
test.end(done);
});
};
var prefix = 'test-style';
const prefix = 'test-style';
describe('Raster tiles', function() {
describe('valid requests', function() {
@ -41,6 +41,6 @@ describe('Raster tiles', function() {
testTile(prefix, 0, 0, 0, 'png', 404, 1);
testTile(prefix, 0, 0, 0, 'png', 404, 5);
//testTile('hybrid', 0, 0, 0, 'png', 404); //TODO: test this
// testTile('hybrid', 0, 0, 0, 'png', 404); //TODO: test this
});
});