tileserver-gl-light 4.1.2 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.cjs +32 -0
- package/.gitattributes +11 -0
- package/.husky/commit-msg +21 -0
- package/.husky/pre-push +4 -0
- package/Dockerfile +4 -1
- package/commitlint.config.cjs +3 -0
- package/docker-entrypoint.sh +1 -1
- package/docs/installation.rst +1 -1
- package/lint-staged.config.cjs +4 -0
- package/package.json +28 -11
- package/prettier.config.cjs +13 -0
- package/publish.js +17 -9
- package/run.sh +1 -1
- package/src/healthcheck.js +18 -0
- package/src/main.js +57 -65
- package/src/serve_data.js +99 -82
- package/src/serve_font.js +19 -10
- package/src/serve_light.js +5 -6
- package/src/serve_rendered.js +550 -309
- package/src/serve_style.js +31 -16
- package/src/server.js +248 -156
- package/src/utils.js +62 -43
- package/test/metadata.js +44 -43
- package/test/setup.js +8 -7
- package/test/static.js +127 -31
- package/test/style.js +31 -26
- package/test/tiles_data.js +5 -5
- package/test/tiles_rendered.js +7 -7
package/src/server.js
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
import os from 'os';
|
|
5
|
-
process.env.UV_THREADPOOL_SIZE =
|
|
6
|
-
Math.ceil(Math.max(4, os.cpus().length * 1.5));
|
|
5
|
+
process.env.UV_THREADPOOL_SIZE = Math.ceil(Math.max(4, os.cpus().length * 1.5));
|
|
7
6
|
|
|
8
7
|
import fs from 'node:fs';
|
|
9
8
|
import path from 'path';
|
|
@@ -17,19 +16,27 @@ import handlebars from 'handlebars';
|
|
|
17
16
|
import SphericalMercator from '@mapbox/sphericalmercator';
|
|
18
17
|
const mercator = new SphericalMercator();
|
|
19
18
|
import morgan from 'morgan';
|
|
20
|
-
import {serve_data} from './serve_data.js';
|
|
21
|
-
import {serve_style} from './serve_style.js';
|
|
22
|
-
import {serve_font} from './serve_font.js';
|
|
23
|
-
import {getTileUrls, getPublicUrl} from './utils.js';
|
|
19
|
+
import { serve_data } from './serve_data.js';
|
|
20
|
+
import { serve_style } from './serve_style.js';
|
|
21
|
+
import { serve_font } from './serve_font.js';
|
|
22
|
+
import { getTileUrls, getPublicUrl } from './utils.js';
|
|
24
23
|
|
|
25
|
-
import {fileURLToPath} from 'url';
|
|
24
|
+
import { fileURLToPath } from 'url';
|
|
26
25
|
const __filename = fileURLToPath(import.meta.url);
|
|
27
26
|
const __dirname = path.dirname(__filename);
|
|
28
|
-
const packageJson = JSON.parse(
|
|
27
|
+
const packageJson = JSON.parse(
|
|
28
|
+
fs.readFileSync(__dirname + '/../package.json', 'utf8'),
|
|
29
|
+
);
|
|
29
30
|
|
|
30
31
|
const isLight = packageJson.name.slice(-6) === '-light';
|
|
31
|
-
const serve_rendered = (
|
|
32
|
+
const serve_rendered = (
|
|
33
|
+
await import(`${!isLight ? `./serve_rendered.js` : `./serve_light.js`}`)
|
|
34
|
+
).serve_rendered;
|
|
32
35
|
|
|
36
|
+
/**
|
|
37
|
+
*
|
|
38
|
+
* @param opts
|
|
39
|
+
*/
|
|
33
40
|
function start(opts) {
|
|
34
41
|
console.log('Starting server');
|
|
35
42
|
|
|
@@ -38,18 +45,24 @@ function start(opts) {
|
|
|
38
45
|
styles: {},
|
|
39
46
|
rendered: {},
|
|
40
47
|
data: {},
|
|
41
|
-
fonts: {}
|
|
48
|
+
fonts: {},
|
|
42
49
|
};
|
|
43
50
|
|
|
44
51
|
app.enable('trust proxy');
|
|
45
52
|
|
|
46
53
|
if (process.env.NODE_ENV !== 'test') {
|
|
47
|
-
const defaultLogFormat =
|
|
54
|
+
const defaultLogFormat =
|
|
55
|
+
process.env.NODE_ENV === 'production' ? 'tiny' : 'dev';
|
|
48
56
|
const logFormat = opts.logFormat || defaultLogFormat;
|
|
49
|
-
app.use(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
57
|
+
app.use(
|
|
58
|
+
morgan(logFormat, {
|
|
59
|
+
stream: opts.logFile
|
|
60
|
+
? fs.createWriteStream(opts.logFile, { flags: 'a' })
|
|
61
|
+
: process.stdout,
|
|
62
|
+
skip: (req, res) =>
|
|
63
|
+
opts.silent && (res.statusCode === 200 || res.statusCode === 304),
|
|
64
|
+
}),
|
|
65
|
+
);
|
|
53
66
|
}
|
|
54
67
|
|
|
55
68
|
let config = opts.config || null;
|
|
@@ -74,7 +87,8 @@ function start(opts) {
|
|
|
74
87
|
options.paths = paths;
|
|
75
88
|
paths.root = path.resolve(
|
|
76
89
|
configPath ? path.dirname(configPath) : process.cwd(),
|
|
77
|
-
paths.root || ''
|
|
90
|
+
paths.root || '',
|
|
91
|
+
);
|
|
78
92
|
paths.styles = path.resolve(paths.root, paths.styles || '');
|
|
79
93
|
paths.fonts = path.resolve(paths.root, paths.fonts || '');
|
|
80
94
|
paths.sprites = path.resolve(paths.root, paths.sprites || '');
|
|
@@ -85,7 +99,9 @@ function start(opts) {
|
|
|
85
99
|
|
|
86
100
|
const checkPath = (type) => {
|
|
87
101
|
if (!fs.existsSync(paths[type])) {
|
|
88
|
-
console.error(
|
|
102
|
+
console.error(
|
|
103
|
+
`The specified path for "${type}" does not exist (${paths[type]}).`,
|
|
104
|
+
);
|
|
89
105
|
process.exit(1);
|
|
90
106
|
}
|
|
91
107
|
};
|
|
@@ -96,37 +112,48 @@ function start(opts) {
|
|
|
96
112
|
checkPath('icons');
|
|
97
113
|
|
|
98
114
|
/**
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
115
|
+
* Recursively get all files within a directory.
|
|
116
|
+
* Inspired by https://stackoverflow.com/a/45130990/10133863
|
|
117
|
+
*
|
|
118
|
+
* @param {string} directory Absolute path to a directory to get files from.
|
|
119
|
+
*/
|
|
103
120
|
const getFiles = async (directory) => {
|
|
104
121
|
// Fetch all entries of the directory and attach type information
|
|
105
|
-
const dirEntries = await fs.promises.readdir(directory, {
|
|
122
|
+
const dirEntries = await fs.promises.readdir(directory, {
|
|
123
|
+
withFileTypes: true,
|
|
124
|
+
});
|
|
106
125
|
|
|
107
126
|
// Iterate through entries and return the relative file-path to the icon directory if it is not a directory
|
|
108
127
|
// otherwise initiate a recursive call
|
|
109
|
-
const files = await Promise.all(
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
128
|
+
const files = await Promise.all(
|
|
129
|
+
dirEntries.map((dirEntry) => {
|
|
130
|
+
const entryPath = path.resolve(directory, dirEntry.name);
|
|
131
|
+
return dirEntry.isDirectory()
|
|
132
|
+
? getFiles(entryPath)
|
|
133
|
+
: entryPath.replace(paths.icons + path.sep, '');
|
|
134
|
+
}),
|
|
135
|
+
);
|
|
114
136
|
|
|
115
137
|
// Flatten the list of files to a single array
|
|
116
138
|
return files.flat();
|
|
117
|
-
}
|
|
139
|
+
};
|
|
118
140
|
|
|
119
141
|
// Load all available icons into a settings object
|
|
120
|
-
startupPromises.push(
|
|
121
|
-
|
|
122
|
-
paths.
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
142
|
+
startupPromises.push(
|
|
143
|
+
new Promise((resolve) => {
|
|
144
|
+
getFiles(paths.icons).then((files) => {
|
|
145
|
+
paths.availableIcons = files;
|
|
146
|
+
resolve();
|
|
147
|
+
});
|
|
148
|
+
}),
|
|
149
|
+
);
|
|
126
150
|
|
|
127
151
|
if (options.dataDecorator) {
|
|
128
152
|
try {
|
|
129
|
-
options.dataDecoratorFunc = require(path.resolve(
|
|
153
|
+
options.dataDecoratorFunc = require(path.resolve(
|
|
154
|
+
paths.root,
|
|
155
|
+
options.dataDecorator,
|
|
156
|
+
));
|
|
130
157
|
} catch (e) {}
|
|
131
158
|
}
|
|
132
159
|
|
|
@@ -140,54 +167,69 @@ function start(opts) {
|
|
|
140
167
|
app.use('/styles/', serve_style.init(options, serving.styles));
|
|
141
168
|
if (!isLight) {
|
|
142
169
|
startupPromises.push(
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
})
|
|
170
|
+
serve_rendered.init(options, serving.rendered).then((sub) => {
|
|
171
|
+
app.use('/styles/', sub);
|
|
172
|
+
}),
|
|
147
173
|
);
|
|
148
174
|
}
|
|
149
175
|
|
|
150
176
|
const addStyle = (id, item, allowMoreData, reportFonts) => {
|
|
151
177
|
let success = true;
|
|
152
178
|
if (item.serve_data !== false) {
|
|
153
|
-
success = serve_style.add(
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
179
|
+
success = serve_style.add(
|
|
180
|
+
options,
|
|
181
|
+
serving.styles,
|
|
182
|
+
item,
|
|
183
|
+
id,
|
|
184
|
+
opts.publicUrl,
|
|
185
|
+
(mbtiles, fromData) => {
|
|
186
|
+
let dataItemId;
|
|
187
|
+
for (const id of Object.keys(data)) {
|
|
188
|
+
if (fromData) {
|
|
189
|
+
if (id === mbtiles) {
|
|
190
|
+
dataItemId = id;
|
|
165
191
|
}
|
|
166
|
-
}
|
|
167
|
-
if (dataItemId) { // mbtiles exist in the data config
|
|
168
|
-
return dataItemId;
|
|
169
192
|
} else {
|
|
170
|
-
if (
|
|
171
|
-
|
|
172
|
-
return undefined;
|
|
173
|
-
} else {
|
|
174
|
-
let id = mbtiles.substr(0, mbtiles.lastIndexOf('.')) || mbtiles;
|
|
175
|
-
while (data[id]) id += '_';
|
|
176
|
-
data[id] = {
|
|
177
|
-
'mbtiles': mbtiles
|
|
178
|
-
};
|
|
179
|
-
return id;
|
|
193
|
+
if (data[id].mbtiles === mbtiles) {
|
|
194
|
+
dataItemId = id;
|
|
180
195
|
}
|
|
181
196
|
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
|
|
197
|
+
}
|
|
198
|
+
if (dataItemId) {
|
|
199
|
+
// mbtiles exist in the data config
|
|
200
|
+
return dataItemId;
|
|
201
|
+
} else {
|
|
202
|
+
if (fromData || !allowMoreData) {
|
|
203
|
+
console.log(
|
|
204
|
+
`ERROR: style "${item.style}" using unknown mbtiles "${mbtiles}"! Skipping...`,
|
|
205
|
+
);
|
|
206
|
+
return undefined;
|
|
207
|
+
} else {
|
|
208
|
+
let id = mbtiles.substr(0, mbtiles.lastIndexOf('.')) || mbtiles;
|
|
209
|
+
while (data[id]) id += '_';
|
|
210
|
+
data[id] = {
|
|
211
|
+
mbtiles: mbtiles,
|
|
212
|
+
};
|
|
213
|
+
return id;
|
|
185
214
|
}
|
|
186
|
-
}
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
(font) => {
|
|
218
|
+
if (reportFonts) {
|
|
219
|
+
serving.fonts[font] = true;
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
);
|
|
187
223
|
}
|
|
188
224
|
if (success && item.serve_rendered !== false) {
|
|
189
225
|
if (!isLight) {
|
|
190
|
-
startupPromises.push(
|
|
226
|
+
startupPromises.push(
|
|
227
|
+
serve_rendered.add(
|
|
228
|
+
options,
|
|
229
|
+
serving.rendered,
|
|
230
|
+
item,
|
|
231
|
+
id,
|
|
232
|
+
opts.publicUrl,
|
|
191
233
|
(mbtiles) => {
|
|
192
234
|
let mbtilesFile;
|
|
193
235
|
for (const id of Object.keys(data)) {
|
|
@@ -196,8 +238,9 @@ function start(opts) {
|
|
|
196
238
|
}
|
|
197
239
|
}
|
|
198
240
|
return mbtilesFile;
|
|
199
|
-
}
|
|
200
|
-
|
|
241
|
+
},
|
|
242
|
+
),
|
|
243
|
+
);
|
|
201
244
|
} else {
|
|
202
245
|
item.serve_rendered = false;
|
|
203
246
|
}
|
|
@@ -215,9 +258,9 @@ function start(opts) {
|
|
|
215
258
|
}
|
|
216
259
|
|
|
217
260
|
startupPromises.push(
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
261
|
+
serve_font(options, serving.fonts).then((sub) => {
|
|
262
|
+
app.use('/', sub);
|
|
263
|
+
}),
|
|
221
264
|
);
|
|
222
265
|
|
|
223
266
|
for (const id of Object.keys(data)) {
|
|
@@ -228,61 +271,65 @@ function start(opts) {
|
|
|
228
271
|
}
|
|
229
272
|
|
|
230
273
|
startupPromises.push(
|
|
231
|
-
|
|
274
|
+
serve_data.add(options, serving.data, item, id, opts.publicUrl),
|
|
232
275
|
);
|
|
233
276
|
}
|
|
234
277
|
|
|
235
278
|
if (options.serveAllStyles) {
|
|
236
|
-
fs.readdir(options.paths.styles, {withFileTypes: true}, (err, files) => {
|
|
279
|
+
fs.readdir(options.paths.styles, { withFileTypes: true }, (err, files) => {
|
|
237
280
|
if (err) {
|
|
238
281
|
return;
|
|
239
282
|
}
|
|
240
283
|
for (const file of files) {
|
|
241
|
-
if (file.isFile() &&
|
|
242
|
-
path.extname(file.name).toLowerCase() == '.json') {
|
|
284
|
+
if (file.isFile() && path.extname(file.name).toLowerCase() == '.json') {
|
|
243
285
|
const id = path.basename(file.name, '.json');
|
|
244
286
|
const item = {
|
|
245
|
-
style: file.name
|
|
287
|
+
style: file.name,
|
|
246
288
|
};
|
|
247
289
|
addStyle(id, item, false, false);
|
|
248
290
|
}
|
|
249
291
|
}
|
|
250
292
|
});
|
|
251
293
|
|
|
252
|
-
const watcher = chokidar.watch(
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
294
|
+
const watcher = chokidar.watch(
|
|
295
|
+
path.join(options.paths.styles, '*.json'),
|
|
296
|
+
{},
|
|
297
|
+
);
|
|
298
|
+
watcher.on('all', (eventType, filename) => {
|
|
299
|
+
if (filename) {
|
|
300
|
+
const id = path.basename(filename, '.json');
|
|
301
|
+
console.log(`Style "${id}" changed, updating...`);
|
|
302
|
+
|
|
303
|
+
serve_style.remove(serving.styles, id);
|
|
304
|
+
if (!isLight) {
|
|
305
|
+
serve_rendered.remove(serving.rendered, id);
|
|
306
|
+
}
|
|
265
307
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
308
|
+
if (eventType == 'add' || eventType == 'change') {
|
|
309
|
+
const item = {
|
|
310
|
+
style: filename,
|
|
311
|
+
};
|
|
312
|
+
addStyle(id, item, false, false);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
});
|
|
274
316
|
}
|
|
275
317
|
|
|
276
318
|
app.get('/styles.json', (req, res, next) => {
|
|
277
319
|
const result = [];
|
|
278
|
-
const query = req.query.key
|
|
320
|
+
const query = req.query.key
|
|
321
|
+
? `?key=${encodeURIComponent(req.query.key)}`
|
|
322
|
+
: '';
|
|
279
323
|
for (const id of Object.keys(serving.styles)) {
|
|
280
324
|
const styleJSON = serving.styles[id].styleJSON;
|
|
281
325
|
result.push({
|
|
282
326
|
version: styleJSON.version,
|
|
283
327
|
name: styleJSON.name,
|
|
284
328
|
id: id,
|
|
285
|
-
url: `${getPublicUrl(
|
|
329
|
+
url: `${getPublicUrl(
|
|
330
|
+
opts.publicUrl,
|
|
331
|
+
req,
|
|
332
|
+
)}styles/${id}/style.json${query}`,
|
|
286
333
|
});
|
|
287
334
|
}
|
|
288
335
|
res.send(result);
|
|
@@ -297,9 +344,16 @@ function start(opts) {
|
|
|
297
344
|
} else {
|
|
298
345
|
path = `${type}/${id}`;
|
|
299
346
|
}
|
|
300
|
-
info.tiles = getTileUrls(
|
|
301
|
-
|
|
302
|
-
|
|
347
|
+
info.tiles = getTileUrls(
|
|
348
|
+
req,
|
|
349
|
+
info.tiles,
|
|
350
|
+
path,
|
|
351
|
+
info.format,
|
|
352
|
+
opts.publicUrl,
|
|
353
|
+
{
|
|
354
|
+
pbf: options.pbfAlias,
|
|
355
|
+
},
|
|
356
|
+
);
|
|
303
357
|
arr.push(info);
|
|
304
358
|
}
|
|
305
359
|
return arr;
|
|
@@ -325,40 +379,49 @@ function start(opts) {
|
|
|
325
379
|
if (template === 'index') {
|
|
326
380
|
if (options.frontPage === false) {
|
|
327
381
|
return;
|
|
328
|
-
} else if (
|
|
329
|
-
options.frontPage
|
|
382
|
+
} else if (
|
|
383
|
+
options.frontPage &&
|
|
384
|
+
options.frontPage.constructor === String
|
|
385
|
+
) {
|
|
330
386
|
templateFile = path.resolve(paths.root, options.frontPage);
|
|
331
387
|
}
|
|
332
388
|
}
|
|
333
|
-
startupPromises.push(
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
const compiled = handlebars.compile(content.toString());
|
|
341
|
-
|
|
342
|
-
app.use(urlPath, (req, res, next) => {
|
|
343
|
-
let data = {};
|
|
344
|
-
if (dataGetter) {
|
|
345
|
-
data = dataGetter(req);
|
|
346
|
-
if (!data) {
|
|
347
|
-
return res.status(404).send('Not found');
|
|
348
|
-
}
|
|
389
|
+
startupPromises.push(
|
|
390
|
+
new Promise((resolve, reject) => {
|
|
391
|
+
fs.readFile(templateFile, (err, content) => {
|
|
392
|
+
if (err) {
|
|
393
|
+
err = new Error(`Template not found: ${err.message}`);
|
|
394
|
+
reject(err);
|
|
395
|
+
return;
|
|
349
396
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
397
|
+
const compiled = handlebars.compile(content.toString());
|
|
398
|
+
|
|
399
|
+
app.use(urlPath, (req, res, next) => {
|
|
400
|
+
let data = {};
|
|
401
|
+
if (dataGetter) {
|
|
402
|
+
data = dataGetter(req);
|
|
403
|
+
if (!data) {
|
|
404
|
+
return res.status(404).send('Not found');
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
data[
|
|
408
|
+
'server_version'
|
|
409
|
+
] = `${packageJson.name} v${packageJson.version}`;
|
|
410
|
+
data['public_url'] = opts.publicUrl || '/';
|
|
411
|
+
data['is_light'] = isLight;
|
|
412
|
+
data['key_query_part'] = req.query.key
|
|
413
|
+
? `key=${encodeURIComponent(req.query.key)}&`
|
|
414
|
+
: '';
|
|
415
|
+
data['key_query'] = req.query.key
|
|
416
|
+
? `?key=${encodeURIComponent(req.query.key)}`
|
|
417
|
+
: '';
|
|
418
|
+
if (template === 'wmts') res.set('Content-Type', 'text/xml');
|
|
419
|
+
return res.status(200).send(compiled(data));
|
|
420
|
+
});
|
|
421
|
+
resolve();
|
|
358
422
|
});
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
}));
|
|
423
|
+
}),
|
|
424
|
+
);
|
|
362
425
|
};
|
|
363
426
|
|
|
364
427
|
serveTemplate('/$', 'index', (req) => {
|
|
@@ -371,15 +434,23 @@ function start(opts) {
|
|
|
371
434
|
if (style.serving_rendered) {
|
|
372
435
|
const center = style.serving_rendered.tileJSON.center;
|
|
373
436
|
if (center) {
|
|
374
|
-
style.viewer_hash = `#${center[2]}/${center[1].toFixed(
|
|
437
|
+
style.viewer_hash = `#${center[2]}/${center[1].toFixed(
|
|
438
|
+
5,
|
|
439
|
+
)}/${center[0].toFixed(5)}`;
|
|
375
440
|
|
|
376
441
|
const centerPx = mercator.px([center[0], center[1]], center[2]);
|
|
377
|
-
style.thumbnail = `${center[2]}/${Math.floor(
|
|
442
|
+
style.thumbnail = `${center[2]}/${Math.floor(
|
|
443
|
+
centerPx[0] / 256,
|
|
444
|
+
)}/${Math.floor(centerPx[1] / 256)}.png`;
|
|
378
445
|
}
|
|
379
446
|
|
|
380
447
|
style.xyz_link = getTileUrls(
|
|
381
|
-
|
|
382
|
-
|
|
448
|
+
req,
|
|
449
|
+
style.serving_rendered.tileJSON.tiles,
|
|
450
|
+
`styles/${id}`,
|
|
451
|
+
style.serving_rendered.tileJSON.format,
|
|
452
|
+
opts.publicUrl,
|
|
453
|
+
)[0];
|
|
383
454
|
}
|
|
384
455
|
}
|
|
385
456
|
const data = clone(serving.data || {});
|
|
@@ -388,19 +459,29 @@ function start(opts) {
|
|
|
388
459
|
const tilejson = data[id].tileJSON;
|
|
389
460
|
const center = tilejson.center;
|
|
390
461
|
if (center) {
|
|
391
|
-
data_.viewer_hash = `#${center[2]}/${center[1].toFixed(
|
|
462
|
+
data_.viewer_hash = `#${center[2]}/${center[1].toFixed(
|
|
463
|
+
5,
|
|
464
|
+
)}/${center[0].toFixed(5)}`;
|
|
392
465
|
}
|
|
393
466
|
data_.is_vector = tilejson.format === 'pbf';
|
|
394
467
|
if (!data_.is_vector) {
|
|
395
468
|
if (center) {
|
|
396
469
|
const centerPx = mercator.px([center[0], center[1]], center[2]);
|
|
397
|
-
data_.thumbnail = `${center[2]}/${Math.floor(
|
|
470
|
+
data_.thumbnail = `${center[2]}/${Math.floor(
|
|
471
|
+
centerPx[0] / 256,
|
|
472
|
+
)}/${Math.floor(centerPx[1] / 256)}.${data_.tileJSON.format}`;
|
|
398
473
|
}
|
|
399
474
|
|
|
400
475
|
data_.xyz_link = getTileUrls(
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
476
|
+
req,
|
|
477
|
+
tilejson.tiles,
|
|
478
|
+
`data/${id}`,
|
|
479
|
+
tilejson.format,
|
|
480
|
+
opts.publicUrl,
|
|
481
|
+
{
|
|
482
|
+
pbf: options.pbfAlias,
|
|
483
|
+
},
|
|
484
|
+
)[0];
|
|
404
485
|
}
|
|
405
486
|
if (data_.filesize) {
|
|
406
487
|
let suffix = 'kB';
|
|
@@ -418,7 +499,7 @@ function start(opts) {
|
|
|
418
499
|
}
|
|
419
500
|
return {
|
|
420
501
|
styles: Object.keys(styles).length ? styles : null,
|
|
421
|
-
data: Object.keys(data).length ? data : null
|
|
502
|
+
data: Object.keys(data).length ? data : null,
|
|
422
503
|
};
|
|
423
504
|
});
|
|
424
505
|
|
|
@@ -453,9 +534,12 @@ function start(opts) {
|
|
|
453
534
|
wmts.name = (serving.styles[id] || serving.rendered[id]).name;
|
|
454
535
|
if (opts.publicUrl) {
|
|
455
536
|
wmts.baseUrl = opts.publicUrl;
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
|
|
537
|
+
} else {
|
|
538
|
+
wmts.baseUrl = `${
|
|
539
|
+
req.get('X-Forwarded-Protocol')
|
|
540
|
+
? req.get('X-Forwarded-Protocol')
|
|
541
|
+
: req.protocol
|
|
542
|
+
}://${req.get('host')}/`;
|
|
459
543
|
}
|
|
460
544
|
return wmts;
|
|
461
545
|
});
|
|
@@ -484,13 +568,17 @@ function start(opts) {
|
|
|
484
568
|
}
|
|
485
569
|
});
|
|
486
570
|
|
|
487
|
-
const server = app.listen(
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
571
|
+
const server = app.listen(
|
|
572
|
+
process.env.PORT || opts.port,
|
|
573
|
+
process.env.BIND || opts.bind,
|
|
574
|
+
function () {
|
|
575
|
+
let address = this.address().address;
|
|
576
|
+
if (address.indexOf('::') === 0) {
|
|
577
|
+
address = `[${address}]`; // literal IPv6 address
|
|
578
|
+
}
|
|
579
|
+
console.log(`Listening at http://${address}:${this.address().port}/`);
|
|
580
|
+
},
|
|
581
|
+
);
|
|
494
582
|
|
|
495
583
|
// add server.shutdown() to gracefully stop serving
|
|
496
584
|
enableShutdown(server);
|
|
@@ -498,10 +586,14 @@ function start(opts) {
|
|
|
498
586
|
return {
|
|
499
587
|
app: app,
|
|
500
588
|
server: server,
|
|
501
|
-
startupPromise: startupPromise
|
|
589
|
+
startupPromise: startupPromise,
|
|
502
590
|
};
|
|
503
591
|
}
|
|
504
592
|
|
|
593
|
+
/**
|
|
594
|
+
*
|
|
595
|
+
* @param opts
|
|
596
|
+
*/
|
|
505
597
|
export function server(opts) {
|
|
506
598
|
const running = start(opts);
|
|
507
599
|
|
|
@@ -525,4 +617,4 @@ export function server(opts) {
|
|
|
525
617
|
});
|
|
526
618
|
|
|
527
619
|
return running;
|
|
528
|
-
}
|
|
620
|
+
}
|