tileblaster 0.2.6 → 0.3.2
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/bin/tileblaster.js +13 -2
- package/config.js.dist +6 -0
- package/lib/tileblaster.js +197 -50
- package/package.json +8 -6
- package/readme.md +8 -0
- package/.gitignore~ +0 -4
- package/renovate.json +0 -5
package/bin/tileblaster.js
CHANGED
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
var argv = require('minimist')(process.argv.slice(2));
|
|
3
|
-
require(
|
|
3
|
+
var watch = require('node-watch');
|
|
4
|
+
var configfile = require("path").resolve.apply(global, (!!argv._[0]) ? [ process.cwd(), argv._[0] ] : [ "../config.js" ]);
|
|
5
|
+
var tb = require("../lib/tileblaster.js")(
|
|
4
6
|
(function(config){
|
|
5
7
|
["socket","tiles","queue","id"].forEach(function(n){
|
|
6
8
|
if (!!argv[n]) config[n] = argv[n];
|
|
7
9
|
});
|
|
10
|
+
// watch changes in config file
|
|
11
|
+
watch(configfile, function(evt,f){
|
|
12
|
+
if (evt === "update") try {
|
|
13
|
+
delete require.cache[require.resolve(configfile)];
|
|
14
|
+
tb.reconfigure(require(configfile));
|
|
15
|
+
} catch (err) {
|
|
16
|
+
console.error("Unable to read changed config file", err);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
8
19
|
return config;
|
|
9
20
|
})((function(){
|
|
10
21
|
try {
|
|
11
|
-
return
|
|
22
|
+
return require(configfile);
|
|
12
23
|
} catch (err) {
|
|
13
24
|
console.error("usage: tileblaster <config.js> [--socket tileblaster.sock] [--tiles /path/to/tiles] [--queue 100] [--id mytileblaster]");
|
|
14
25
|
process.exit(1);
|
package/config.js.dist
CHANGED
|
@@ -56,6 +56,12 @@ module.exports = {
|
|
|
56
56
|
// * .png with `optipng`
|
|
57
57
|
// * .jpg with `mozjpeg`
|
|
58
58
|
"optimize": true,
|
|
59
|
+
|
|
60
|
+
// compress tiles (only makes sense for non-rastered tiles like json, pbf, mvt)
|
|
61
|
+
"compress": [ "gz", "br" ],
|
|
62
|
+
|
|
63
|
+
// write tiles to disk
|
|
64
|
+
"cache": true,
|
|
59
65
|
|
|
60
66
|
// minimum time tiles are kept
|
|
61
67
|
"expires": "1d",
|
package/lib/tileblaster.js
CHANGED
|
@@ -5,6 +5,7 @@ var url = require("url");
|
|
|
5
5
|
var path = require("path");
|
|
6
6
|
var http = require("http");
|
|
7
7
|
var util = require("util");
|
|
8
|
+
var zlib = require("zlib");
|
|
8
9
|
var stream = require("stream");
|
|
9
10
|
|
|
10
11
|
var debug = require("debug")("tileblaster");
|
|
@@ -17,6 +18,7 @@ var dur = require("dur");
|
|
|
17
18
|
// optional dependencies; if only
|
|
18
19
|
try { var pnck = require("pnck"); } catch (err) { var pnck = null; }
|
|
19
20
|
try { var jpck = require("jpck"); } catch (err) { var jpck = null; }
|
|
21
|
+
try { var zopfli = require("node-zopfli"); } catch (err) { var zopfli = null; }
|
|
20
22
|
|
|
21
23
|
// load package
|
|
22
24
|
var pckg = require("../package.json");
|
|
@@ -47,6 +49,9 @@ tileblaster.prototype.mime = {
|
|
|
47
49
|
arcamf: 'application/octet-stream',
|
|
48
50
|
};
|
|
49
51
|
|
|
52
|
+
// compression formats
|
|
53
|
+
tileblaster.prototype.comp = [ "gz", "br" ];
|
|
54
|
+
|
|
50
55
|
// initialize
|
|
51
56
|
tileblaster.prototype.init = function(config){
|
|
52
57
|
var self = this;
|
|
@@ -56,6 +61,36 @@ tileblaster.prototype.init = function(config){
|
|
|
56
61
|
// server
|
|
57
62
|
self.srvr = null;
|
|
58
63
|
|
|
64
|
+
// statistics
|
|
65
|
+
self.statistics = {
|
|
66
|
+
hits: 0,
|
|
67
|
+
phits: 0,
|
|
68
|
+
served: 0,
|
|
69
|
+
last: Date.now()
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// compression queue
|
|
73
|
+
self.cqueue = queue(1);
|
|
74
|
+
|
|
75
|
+
// have maps with active expires?
|
|
76
|
+
self.expiration = false;
|
|
77
|
+
|
|
78
|
+
// reconfigure
|
|
79
|
+
self.reconfigure(config);
|
|
80
|
+
|
|
81
|
+
return this;
|
|
82
|
+
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// reconfigure
|
|
86
|
+
tileblaster.prototype.reconfigure = function(config){
|
|
87
|
+
var self = this;
|
|
88
|
+
|
|
89
|
+
debug("<init> reconfiguring");
|
|
90
|
+
|
|
91
|
+
// cache
|
|
92
|
+
self.errcache = {};
|
|
93
|
+
|
|
59
94
|
// keep config
|
|
60
95
|
self.config = config || {};
|
|
61
96
|
|
|
@@ -74,26 +109,12 @@ tileblaster.prototype.init = function(config){
|
|
|
74
109
|
// queue size
|
|
75
110
|
self.config.queue = Math.max(parseInt(self.config.queue,10)||100,1);
|
|
76
111
|
|
|
77
|
-
// cache
|
|
78
|
-
self.errcache = {};
|
|
79
|
-
|
|
80
|
-
// statistics
|
|
81
|
-
self.statistics = {
|
|
82
|
-
hits: 0,
|
|
83
|
-
phits: 0,
|
|
84
|
-
served: 0,
|
|
85
|
-
last: Date.now()
|
|
86
|
-
};
|
|
87
|
-
|
|
88
112
|
// extend mime types
|
|
89
113
|
if (!!self.config.mime) Object.keys(self.config.mime).map(function(ext){ self.mime[ext] = self.config.mime[ext] });
|
|
90
114
|
|
|
91
115
|
// queue
|
|
92
116
|
self.queue = queue(self.config.queue);
|
|
93
|
-
|
|
94
|
-
// have maps with active expires?
|
|
95
|
-
self.expiration = false;
|
|
96
|
-
|
|
117
|
+
|
|
97
118
|
// check configured maps
|
|
98
119
|
self.maps = Object.keys(self.config.maps).reduce(function(maps, id){
|
|
99
120
|
|
|
@@ -112,10 +133,10 @@ tileblaster.prototype.init = function(config){
|
|
|
112
133
|
}
|
|
113
134
|
|
|
114
135
|
// resolutions
|
|
115
|
-
if (!map.res) map.res = [];
|
|
136
|
+
if (!map.res) map.res = [ "" ];
|
|
116
137
|
if (!(map.res instanceof Array)) map.res = [ map.res ];
|
|
117
138
|
map.res = map.res.filter(function(res){
|
|
118
|
-
return /^@[1-9][0-9]*(\.[0-9]+)?x$/.test(res);
|
|
139
|
+
return (res === "") || /^@[1-9][0-9]*(\.[0-9]+)?x$/.test(res);
|
|
119
140
|
});
|
|
120
141
|
|
|
121
142
|
// precalculate bbox for zoom levels
|
|
@@ -151,6 +172,13 @@ tileblaster.prototype.init = function(config){
|
|
|
151
172
|
// expires
|
|
152
173
|
if (!!map.expires) map.expires = dur(map.expires);
|
|
153
174
|
if (!!map.expires) self.expiration = true;
|
|
175
|
+
if (!map.expires) map.expires = Infinity;
|
|
176
|
+
|
|
177
|
+
// cache
|
|
178
|
+
map.cache = (!map.hasOwnProperty("cache")) ? true : (!!map.cache);
|
|
179
|
+
|
|
180
|
+
// compression
|
|
181
|
+
map.compress = map.compress.filter(function(c){ return (self.comp.indexOf(c) >= 0) });
|
|
154
182
|
|
|
155
183
|
return map;
|
|
156
184
|
|
|
@@ -159,13 +187,13 @@ tileblaster.prototype.init = function(config){
|
|
|
159
187
|
},{});
|
|
160
188
|
|
|
161
189
|
// build user agent
|
|
162
|
-
if (!self.config.useragent) self.config.useragent = util.format("%s/%s (
|
|
190
|
+
if (!self.config.useragent) self.config.useragent = util.format("%s/%s (+%s)", pckg.name, pckg.version, pckg.homepage);
|
|
163
191
|
|
|
164
192
|
// cleanup timer
|
|
165
193
|
self.config.cleanup = (!!self.config.cleanup) ? dur(self.config.cleanup) : false;
|
|
194
|
+
if (!!self.cleaner) clearInterval(self.cleaner);
|
|
166
195
|
if (self.config.cleanup && self.expiration) self.cleaner = setInterval(function(){ self.cleanup(); }, self.config.cleanup).unref();
|
|
167
|
-
|
|
168
|
-
return this;
|
|
196
|
+
|
|
169
197
|
};
|
|
170
198
|
|
|
171
199
|
// return server
|
|
@@ -179,32 +207,40 @@ tileblaster.prototype.server = function(){
|
|
|
179
207
|
// check http method
|
|
180
208
|
if (req.method !== "GET") return debug("<server> invalid method: %s", req.method), (!!self.config.hints&&res.setHeader("x-err-hint","invalid method")), res.statusCode = 405, res.end();
|
|
181
209
|
|
|
182
|
-
//
|
|
183
|
-
|
|
210
|
+
// parse request
|
|
211
|
+
var t = self._tilepath(url.parse(req.url).pathname.toLowerCase());
|
|
212
|
+
if (!t) return debug("<server> invalid request: %s", url.parse(req.url).pathname), (!!self.config.hints&&res.setHeader("x-err-hint","invalid request")), res.statusCode = 404, res.end();
|
|
184
213
|
|
|
185
|
-
// asselmble information
|
|
186
|
-
var p = RegExp.$1;
|
|
187
|
-
var mapid = RegExp.$2;
|
|
188
|
-
|
|
189
214
|
// check if map exists
|
|
190
|
-
if (!self.maps.hasOwnProperty(mapid)) return debug("<server> requested invalid map: %s", mapid), (!!self.config.hints&&res.setHeader("x-err-hint","invalid map")), res.statusCode = 404, res.end();
|
|
215
|
+
if (!self.maps.hasOwnProperty(t.mapid)) return debug("<server> requested invalid map: %s", t.mapid), (!!self.config.hints&&res.setHeader("x-err-hint","invalid map")), res.statusCode = 404, res.end();
|
|
216
|
+
|
|
217
|
+
// deliver file if requested
|
|
218
|
+
if (t.type === "file") {
|
|
219
|
+
switch (t.file) {
|
|
220
|
+
case "tile.json":
|
|
221
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
222
|
+
res.end(self._tilejson(t.mapid, ((req.headers["x-https"] === "on") ? "https://" : "http://")+req.headers["host"]));
|
|
223
|
+
break;
|
|
224
|
+
default:
|
|
225
|
+
return debug("<server> requested invalid file: %s", t.p), (!!self.config.hints&&res.setHeader("x-err-hint","invalid file")), res.statusCode = 404, res.end();
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
191
230
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
var y = parseInt(RegExp.$5,10);
|
|
195
|
-
var r = ((self.maps[mapid].res.indexOf(RegExp.$6) >= 0) ? RegExp.$6 : false);
|
|
196
|
-
var ext = RegExp.$8;
|
|
231
|
+
// res
|
|
232
|
+
t.r = (!!t.r && (self.maps[t.mapid].res.indexOf(t.r) >= 0) ? t.r : false);
|
|
197
233
|
|
|
198
|
-
debug("<server> [%s] requested", p);
|
|
234
|
+
debug("<server> [%s] requested", t.p);
|
|
199
235
|
|
|
200
|
-
self.tile(mapid, z, x, y, r, ext, function(err, stream, meta){
|
|
201
|
-
if (err) return debug("<server> [%s] error: %s", p, err), (!!self.config.hints&&res.setHeader("x-err-hint",err.toString())), res.statusCode = 204, res.end();
|
|
236
|
+
self.tile(t.mapid, t.z, t.x, t.y, t.r, t.ext, function(err, stream, meta){
|
|
237
|
+
if (err) return debug("<server> [%s] error: %s", t.p, err.toString()), (!!self.config.hints&&res.setHeader("x-err-hint",err.toString())), res.statusCode = 204, res.end();
|
|
202
238
|
|
|
203
239
|
// send headers
|
|
204
240
|
res.writeHead(200, { "Content-Type": meta['content-type'] });
|
|
205
241
|
|
|
206
242
|
stream.on("end", function(){
|
|
207
|
-
debug("<server> [%s] done", p);
|
|
243
|
+
debug("<server> [%s] done", t.p);
|
|
208
244
|
self.statistics.served++;
|
|
209
245
|
});
|
|
210
246
|
|
|
@@ -300,8 +336,16 @@ tileblaster.prototype.heartbeat = function(){
|
|
|
300
336
|
// delete expired tiles
|
|
301
337
|
tileblaster.prototype.cleanup = function(){
|
|
302
338
|
var self = this;
|
|
339
|
+
|
|
340
|
+
// clean up error cache
|
|
341
|
+
var d = Date.now();
|
|
342
|
+
self.errcache = self.errcache.filter(function(e){
|
|
343
|
+
return (e.until > d);
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
// FIXME: extra process
|
|
303
347
|
|
|
304
|
-
//
|
|
348
|
+
// clean up map tiles
|
|
305
349
|
Object.keys(self.maps).filter(function(mapid){
|
|
306
350
|
return (!!self.maps[mapid].expires);
|
|
307
351
|
}).forEach(function(mapid){
|
|
@@ -357,7 +401,7 @@ tileblaster.prototype.tile = function(mapid, z, x, y, r, e, fn){
|
|
|
357
401
|
debug("<tile> [%s] valid", tilefile);
|
|
358
402
|
|
|
359
403
|
// check for cached 404 tiles
|
|
360
|
-
if (!!self.errcache[tilefile] && self.errcache[tilefile] >
|
|
404
|
+
if (!!self.errcache[tilefile] && (self.errcache[tilefile].until > Date.now())) return fn(new Error("Known bad tile: "+self.errcache[tilefile].err), null);
|
|
361
405
|
|
|
362
406
|
// resolve tile path
|
|
363
407
|
var tilepath = path.resolve(self.config.tiles, tilefile);
|
|
@@ -367,23 +411,31 @@ tileblaster.prototype.tile = function(mapid, z, x, y, r, e, fn){
|
|
|
367
411
|
|
|
368
412
|
self.fetchtile(tileurl, mapid, function(err, stream, meta){
|
|
369
413
|
|
|
370
|
-
|
|
371
|
-
|
|
414
|
+
if (err) {
|
|
415
|
+
if (stream !== null) {
|
|
416
|
+
// cache error tile
|
|
417
|
+
self.errcache[tilefile] = { until: (Date.now()+self.config.maps[mapid].expires), err: err, code: stream };
|
|
372
418
|
|
|
373
|
-
|
|
374
|
-
|
|
419
|
+
// mark tile as erronous in file system
|
|
420
|
+
fs.writeFile(tilepath+".err", JSON.stringify(self.errcache[tilefile]), function(err){
|
|
421
|
+
if (err) return debug("<tile> [%s.err] error: %s", tilefile, err.toString());
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
return debug("<tile> [%s] error: %s", tilefile, err.toString()), fn(err, stream);
|
|
425
|
+
}
|
|
375
426
|
|
|
376
427
|
debug("<tile> [%s] fetched", tilefile);
|
|
377
428
|
|
|
378
|
-
|
|
379
|
-
stream.pipe(self.optimize(mapid, e)).pipe(self._mux(function(stream){
|
|
429
|
+
var streams = [];
|
|
380
430
|
|
|
431
|
+
streams.push(function(stream){
|
|
381
432
|
// call back with stream
|
|
382
433
|
fn(null, stream, {
|
|
383
434
|
'content-type': (self.mime[e])
|
|
384
435
|
});
|
|
385
|
-
|
|
386
|
-
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
if (!!self.config.maps[mapid].cache) streams.push(function(stream){
|
|
387
439
|
|
|
388
440
|
// don't overwrite if tile exists
|
|
389
441
|
fs.access(tilepath, fs.constants.F_OK, function(err){
|
|
@@ -394,6 +446,10 @@ tileblaster.prototype.tile = function(mapid, z, x, y, r, e, fn){
|
|
|
394
446
|
// save to tmp file, rename when done
|
|
395
447
|
stream.pipe(fs.createWriteStream(tilepath+".tmp").on('finish', function(){
|
|
396
448
|
fs.rename(tilepath+".tmp", tilepath, function(){
|
|
449
|
+
|
|
450
|
+
// compress
|
|
451
|
+
if (self.config.maps[mapid].compress instanceof Array && self.config.maps[mapid].compress.length > 0) self.compress(tilepath, self.config.maps[mapid].compress);
|
|
452
|
+
|
|
397
453
|
debug("<tile> [%s] saved", tilefile);
|
|
398
454
|
});
|
|
399
455
|
}));
|
|
@@ -404,8 +460,10 @@ tileblaster.prototype.tile = function(mapid, z, x, y, r, e, fn){
|
|
|
404
460
|
|
|
405
461
|
});
|
|
406
462
|
|
|
463
|
+
});
|
|
407
464
|
|
|
408
|
-
|
|
465
|
+
// stream mux
|
|
466
|
+
stream.pipe(self.optimize(mapid, e)).pipe(self._mux.apply(self, streams));
|
|
409
467
|
|
|
410
468
|
});
|
|
411
469
|
|
|
@@ -434,7 +492,7 @@ tileblaster.prototype.fetchtile = function(tileurl, mapid, fn){
|
|
|
434
492
|
// check mime type, status code, content-length, FIXME: cache!
|
|
435
493
|
if (resp.statusCode !== 200) return fn(new Error("status code "+resp.statusCode), resp.statusCode);
|
|
436
494
|
if (!resp.headers['content-type']||(!!self.maps[mapid].mime&&self.maps[mapid].mime.indexOf(resp.headers['content-type'])<0)) return fn(new Error("invalid content type "+resp.headers['content-type']), resp.statusCode);
|
|
437
|
-
if (!!resp.headers['content-length']&&parseInt(resp.headers['content-
|
|
495
|
+
if (!!resp.headers['content-length']&&parseInt(resp.headers['content-length'],10)===0) return fn(new Error("no content"), resp.statusCode);
|
|
438
496
|
|
|
439
497
|
// signal queue when read stream has finished
|
|
440
498
|
this.once('end', function(){ (!d++)&&done(); });
|
|
@@ -444,7 +502,7 @@ tileblaster.prototype.fetchtile = function(tileurl, mapid, fn){
|
|
|
444
502
|
return fn(null, this, {
|
|
445
503
|
date: (new Date(resp.headers.date||Date.now()).valueOf()),
|
|
446
504
|
size: (parseInt(resp.headers['content-length'],10)||null),
|
|
447
|
-
mime: (resp.headers['content-type']||'
|
|
505
|
+
mime: (resp.headers['content-type']||'application/octet-stream'),
|
|
448
506
|
});
|
|
449
507
|
|
|
450
508
|
}).on('error', function(err){
|
|
@@ -485,6 +543,54 @@ tileblaster.prototype.optimize = function(mapid, ext){
|
|
|
485
543
|
|
|
486
544
|
};
|
|
487
545
|
|
|
546
|
+
// compression
|
|
547
|
+
tileblaster.prototype.compress = function(file, comp){
|
|
548
|
+
var self = this;
|
|
549
|
+
comp.forEach(function(c){
|
|
550
|
+
self.cqueue.push(function(done){
|
|
551
|
+
switch (c) {
|
|
552
|
+
case "br":
|
|
553
|
+
// use builtin brotli
|
|
554
|
+
fs.createReadStream(file).pipe(zlib.createBrotliCompress({
|
|
555
|
+
level: 6
|
|
556
|
+
})).pipe(fs.createWriteStream(file+".br.tmp")).on("finish", function(){
|
|
557
|
+
fs.rename(file+".br.tmp", file+".br", function(){
|
|
558
|
+
debug("<tile> [%s] compressed with brotli", file);
|
|
559
|
+
done();
|
|
560
|
+
});
|
|
561
|
+
});
|
|
562
|
+
break;
|
|
563
|
+
case "gz":
|
|
564
|
+
if (zopfli !== null) {
|
|
565
|
+
// use zopfli
|
|
566
|
+
fs.createReadStream(file).pipe(zopfli.createGzip({
|
|
567
|
+
numiterations: 5, // don't block the queue too long
|
|
568
|
+
})).pipe(fs.createWriteStream(file+".gz.tmp")).on("finish", function(){
|
|
569
|
+
fs.rename(file+".gz.tmp", file+".gz", function(){
|
|
570
|
+
debug("<tile> [%s] compressed with zopfli", file);
|
|
571
|
+
done();
|
|
572
|
+
});
|
|
573
|
+
});
|
|
574
|
+
} else {
|
|
575
|
+
// use builtin gzip
|
|
576
|
+
fs.createReadStream(file).pipe(zlib.createGzip({
|
|
577
|
+
level: 6
|
|
578
|
+
})).pipe(fs.createWriteStream(file+".gz.tmp")).on("finish", function(){
|
|
579
|
+
fs.rename(file+".gz.tmp", file+".gz", function(){
|
|
580
|
+
debug("<tile> [%s] compressed with gzip", file);
|
|
581
|
+
done();
|
|
582
|
+
});
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
break;
|
|
586
|
+
default:
|
|
587
|
+
done();
|
|
588
|
+
break;
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
});
|
|
592
|
+
};
|
|
593
|
+
|
|
488
594
|
// stream multiplexer
|
|
489
595
|
tileblaster.prototype._mux = function(fn){
|
|
490
596
|
var self = this;
|
|
@@ -550,7 +656,8 @@ tileblaster.prototype._checktile = function(mapid, z, x, y, r, ext, fn){
|
|
|
550
656
|
// check extension
|
|
551
657
|
if (!!self.maps[mapid].ext && self.maps[mapid].ext.indexOf(ext) < 0) return debug("<check> disallowed extension '%s' for map '%s'", ext, mapid), fn(new Error("Disallowed extension"));
|
|
552
658
|
|
|
553
|
-
//
|
|
659
|
+
// check density
|
|
660
|
+
if (!!r && self.maps[mapid].res.indexOf(r) < 0) return debug("<check> disallowed density '%s' for map '%s'", res, mapid), fn(new Error("Disallowed density"));
|
|
554
661
|
|
|
555
662
|
// check zoom level
|
|
556
663
|
var zf = parseFloat(z,10);
|
|
@@ -584,4 +691,44 @@ tileblaster.prototype._tilefile = function(mapid, z, x, y, r, e){
|
|
|
584
691
|
return (mapid+"/"+z.toFixed(0)+"/"+x.toFixed(0)+"/"+y.toFixed(0)+((!!r)?r:"")+"."+((e) ? e : ""));
|
|
585
692
|
};
|
|
586
693
|
|
|
694
|
+
// path parsing regular expression
|
|
695
|
+
tileblaster.prototype._pathregx = /\/(([a-z0-9\-\_\.]+)\/((tile\.json)|([0-9]+)\/([0-9]+)\/([0-9]+)(@([0-9]+(\.[0-9]+)?)x)?\.([a-z0-9\.]+)))$/;
|
|
696
|
+
|
|
697
|
+
// transform path to parameters
|
|
698
|
+
tileblaster.prototype._tilepath = function(p) {
|
|
699
|
+
var r = (this._pathregx.exec(p));
|
|
700
|
+
if (!r) return false;
|
|
701
|
+
if (!r[4]) {
|
|
702
|
+
return {
|
|
703
|
+
type: "tile",
|
|
704
|
+
p: r[1],
|
|
705
|
+
mapid: r[2],
|
|
706
|
+
z: parseInt(r[5],10),
|
|
707
|
+
x: parseInt(r[6],10),
|
|
708
|
+
y: parseInt(r[7],10),
|
|
709
|
+
r: r[8],
|
|
710
|
+
ext: r[11],
|
|
711
|
+
};
|
|
712
|
+
} else {
|
|
713
|
+
return {
|
|
714
|
+
type: "file",
|
|
715
|
+
p: r[1],
|
|
716
|
+
mapid: r[2],
|
|
717
|
+
file: r[4],
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
};
|
|
721
|
+
|
|
722
|
+
// assemble tilejson (good enough)
|
|
723
|
+
tileblaster.prototype._tilejson = function(id, base) {
|
|
724
|
+
var self = this;
|
|
725
|
+
return JSON.stringify({
|
|
726
|
+
tilejson: "2.2.0",
|
|
727
|
+
minzoom: self.config.maps[id].zoom[0],
|
|
728
|
+
maxzoom: self.config.maps[id].zoom[1],
|
|
729
|
+
bounds: self.config.maps[id].bbox,
|
|
730
|
+
tiles: [ (self.config.base||base)+"/"+id+"/{z}/{x}/{y}"+(self.config.maps[id].res[0]||"")+"."+self.config.maps[id].ext[0] ],
|
|
731
|
+
});
|
|
732
|
+
};
|
|
733
|
+
|
|
587
734
|
module.exports = tileblaster;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tileblaster",
|
|
3
|
-
"version": "0.2
|
|
4
|
-
"description": "pretty fast optimizing tile caching proxy",
|
|
3
|
+
"version": "0.3.2",
|
|
4
|
+
"description": "pretty fast optimizing & compressing tile caching proxy",
|
|
5
5
|
"main": "lib/tileblaster.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"tileblaster": "bin/tileblaster.js"
|
|
@@ -17,17 +17,19 @@
|
|
|
17
17
|
},
|
|
18
18
|
"homepage": "https://github.com/yetzt/tileblaster#readme",
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"debug": "^4",
|
|
21
|
-
"dur": "^0",
|
|
22
|
-
"glob": "^7.
|
|
20
|
+
"debug": "^4.3.3",
|
|
21
|
+
"dur": "^0.0.3",
|
|
22
|
+
"glob": "^7.2.0",
|
|
23
23
|
"minimist": "^1.2.5",
|
|
24
24
|
"mkdirp": "^1",
|
|
25
|
+
"node-watch": "^0.7.3",
|
|
25
26
|
"nsa": "^0.2",
|
|
26
|
-
"quu": "^0.
|
|
27
|
+
"quu": "^0.4.1",
|
|
27
28
|
"request": "^2.88"
|
|
28
29
|
},
|
|
29
30
|
"optionalDependencies": {
|
|
30
31
|
"jpck": "^1.0.2",
|
|
32
|
+
"node-zopfli": "^2.1.4",
|
|
31
33
|
"pnck": "^1.0.1"
|
|
32
34
|
}
|
|
33
35
|
}
|
package/readme.md
CHANGED
|
@@ -28,6 +28,13 @@ upstream upstream_tileblaster {
|
|
|
28
28
|
server {
|
|
29
29
|
listen 80;
|
|
30
30
|
server_name tileblaster;
|
|
31
|
+
|
|
32
|
+
gzip_static on;
|
|
33
|
+
# brotli_static on; # if ngx_brotli is available
|
|
34
|
+
|
|
35
|
+
if (-f $document_root/$uri.err) {
|
|
36
|
+
return 204;
|
|
37
|
+
}
|
|
31
38
|
|
|
32
39
|
location / {
|
|
33
40
|
root /path/to/tileblaster/tiles;
|
|
@@ -48,3 +55,4 @@ get the tiles via `http://server/<mapid>/<z>/<x>/<y>[<d>].<ext>`
|
|
|
48
55
|
* `<z>`, `<x>` and `<z>` are the tile coorinates
|
|
49
56
|
* `<d>` is the optional pixel density marker, for example `@2x`
|
|
50
57
|
* `<ext>` is the extension, for example `png`, `geojson` or `mvt`
|
|
58
|
+
|
package/.gitignore~
DELETED