pmtiles-swarm 0.55.0 → 0.55.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/CHANGELOG.md +25 -0
- package/package.json +1 -1
- package/src/api.js +26 -5
- package/src/pmtiles-probe.js +19 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,31 @@
|
|
|
7
7
|
### 🐞 Bug fixes
|
|
8
8
|
- _...Add new stuff here..._
|
|
9
9
|
|
|
10
|
+
## 0.55.2
|
|
11
|
+
### 🐞 Bug fixes
|
|
12
|
+
- **The stale-summary re-read never ran for a category URL.** 0.55.1 added it to
|
|
13
|
+
`/archives/<infohash>/tiles.json` and nowhere else, which missed exactly the archives that matter:
|
|
14
|
+
`/latest/<category>/tiles.json` is the URL a style points at, so a category consumed through the
|
|
15
|
+
documented path was the one place a summary stayed stale for ever. An archive only healed if
|
|
16
|
+
somebody happened to ask for it by infohash.
|
|
17
|
+
|
|
18
|
+
## 0.55.1
|
|
19
|
+
### 🐞 Bug fixes
|
|
20
|
+
- **0.55.0 reached new archives only.** `encoding` sits in the metadata of archives some nodes have
|
|
21
|
+
been serving for months, the prober learned to read it, and nothing changed — because a summary is
|
|
22
|
+
written into the catalog once and never questioned. Every path that re-read one was gated on the
|
|
23
|
+
summary being *absent*, and these summaries were present, merely old.
|
|
24
|
+
|
|
25
|
+
The summary now carries a `summaryVersion`, and one written by an older prober is re-read once, in
|
|
26
|
+
the background, on the next TileJSON request for that archive. Rate-limited to once a minute per
|
|
27
|
+
archive, as the vector-layer backfill beside it already was, and written back on any read that
|
|
28
|
+
produced something newer — the old early return threw away everything except vector layers, which
|
|
29
|
+
would have discarded the encoding it went to fetch.
|
|
30
|
+
|
|
31
|
+
This is general, not a fix for one field: raise `SUMMARY_VERSION` whenever the prober learns to
|
|
32
|
+
read something new, and every archive already in the catalog picks it up on its own. Nothing is
|
|
33
|
+
needed on an upgrade beyond asking for the archive's TileJSON, which anything using it does anyway.
|
|
34
|
+
|
|
10
35
|
## 0.55.0
|
|
11
36
|
### ✨ Features and improvements
|
|
12
37
|
- **The TileJSON now carries a `raster-dem` archive's `encoding`**, read out of the archive's own
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmtiles-swarm",
|
|
3
|
-
"version": "0.55.
|
|
3
|
+
"version": "0.55.2",
|
|
4
4
|
"description": "BitTorrent distribution for PMTiles map archives: create torrents, watch folders, publish and subscribe to RSS feeds, and seed through qBittorrent or an embedded client",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
package/src/api.js
CHANGED
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
} from './sources.js';
|
|
34
34
|
import { limitFor, remaining } from './seeding.js';
|
|
35
35
|
import { buildTileJson, extensionMatches } from './tilejson.js';
|
|
36
|
+
import { SUMMARY_VERSION } from './pmtiles-probe.js';
|
|
36
37
|
import { TileReadError } from './tiles.js';
|
|
37
38
|
|
|
38
39
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -363,9 +364,18 @@ export function createApp({
|
|
|
363
364
|
* @returns {boolean} - True to attempt a read now.
|
|
364
365
|
*/
|
|
365
366
|
const metadataRetries = new Map();
|
|
366
|
-
const
|
|
367
|
-
if (!summary
|
|
368
|
-
|
|
367
|
+
const needsReread = (summary, infoHash) => {
|
|
368
|
+
if (!summary) return false;
|
|
369
|
+
// Two reasons to go back to the archive. The first is the one this began
|
|
370
|
+
// as: a vector archive whose layers have not been read yet. The second is
|
|
371
|
+
// the general case it turned out to be — a summary written by an older
|
|
372
|
+
// prober, missing whatever that prober did not know to look for. Without
|
|
373
|
+
// it, adding a field to the summary reaches new archives only, and every
|
|
374
|
+
// archive already in the catalog keeps its hole until somebody removes and
|
|
375
|
+
// re-adds it by hand.
|
|
376
|
+
const stale = summary.summaryVersion !== SUMMARY_VERSION;
|
|
377
|
+
const missingLayers = summary.format === 'pbf' && !summary.vectorLayers;
|
|
378
|
+
if (!stale && !missingLayers) return false;
|
|
369
379
|
const last = metadataRetries.get(infoHash) ?? 0;
|
|
370
380
|
if (Date.now() - last < 60000) return false;
|
|
371
381
|
metadataRetries.set(infoHash, Date.now());
|
|
@@ -388,13 +398,18 @@ export function createApp({
|
|
|
388
398
|
// .torrent endpoints work without one. Enriching a summary is the least
|
|
389
399
|
// important thing here and must never be what takes a reply down.
|
|
390
400
|
if (typeof tiles?.summarize !== 'function') return;
|
|
391
|
-
if (!
|
|
401
|
+
if (!needsReread(entry.pmtiles, entry.infoHash)) return;
|
|
392
402
|
|
|
393
403
|
const timeoutMs = config.tiles?.metadataTimeoutMs ?? 120000;
|
|
394
404
|
tiles
|
|
395
405
|
.summarize(entry.infoHash, { timeoutMs })
|
|
396
406
|
.then(async (summary) => {
|
|
397
|
-
|
|
407
|
+
// Written back whenever the read produced something newer than what
|
|
408
|
+
// was stored. Returning early unless vector layers turned up was right
|
|
409
|
+
// when layers were the only thing this looked for; it would now throw
|
|
410
|
+
// away the encoding it went to fetch.
|
|
411
|
+
const fresh = summary.summaryVersion !== entry.pmtiles?.summaryVersion;
|
|
412
|
+
if (!summary.vectorLayers && !fresh) return;
|
|
398
413
|
await catalog.put({
|
|
399
414
|
infoHash: entry.infoHash,
|
|
400
415
|
pmtiles: { ...entry.pmtiles, ...summary },
|
|
@@ -2259,6 +2274,12 @@ export function createApp({
|
|
|
2259
2274
|
});
|
|
2260
2275
|
}
|
|
2261
2276
|
|
|
2277
|
+
// The same background re-read the per-archive route does. Left out
|
|
2278
|
+
// here, it missed exactly the archives that matter most: /latest/ is the
|
|
2279
|
+
// URL a style points at, so a category anyone actually consumes through
|
|
2280
|
+
// the documented path was the one place a stale summary never healed.
|
|
2281
|
+
startMetadataBackfill(entry);
|
|
2282
|
+
|
|
2262
2283
|
res.setHeader('access-control-allow-origin', '*');
|
|
2263
2284
|
// Short-lived, and the only mutable document in the system: everything
|
|
2264
2285
|
// it points at is content-addressed and cached for a year, and this is
|
package/src/pmtiles-probe.js
CHANGED
|
@@ -110,6 +110,24 @@ export function customEncodingFactors(metadata) {
|
|
|
110
110
|
* @param {string} location - Local path or http(s) URL.
|
|
111
111
|
* @returns {Promise<PMTilesSummary>} - The summary.
|
|
112
112
|
*/
|
|
113
|
+
/**
|
|
114
|
+
* What this prober reads, as a number that goes up when that changes.
|
|
115
|
+
*
|
|
116
|
+
* A summary is stored in the catalog and never read again, which is right --
|
|
117
|
+
* re-reading a header out of the swarm is not free, and the answer does not
|
|
118
|
+
* change for a given infohash. It goes wrong the moment the prober learns to
|
|
119
|
+
* read something new: every archive probed before that keeps a summary with a
|
|
120
|
+
* hole in it, for ever, and the only way out was to remove and re-add it.
|
|
121
|
+
*
|
|
122
|
+
* `encoding` was the case that made this obvious. It sat in the metadata of
|
|
123
|
+
* archives this node had been serving for months, and adding the code to read
|
|
124
|
+
* it changed nothing at all, because nothing ever asked again.
|
|
125
|
+
*
|
|
126
|
+
* So: stamp what the prober knew at the time, and re-read once when that is
|
|
127
|
+
* behind. Raise this whenever a field is added to the summary below.
|
|
128
|
+
*/
|
|
129
|
+
export const SUMMARY_VERSION = 2;
|
|
130
|
+
|
|
113
131
|
export function summarize(header, metadata = {}) {
|
|
114
132
|
const type = TILE_TYPES[header.tileType] ?? TILE_TYPES[0];
|
|
115
133
|
|
|
@@ -123,6 +141,7 @@ export function summarize(header, metadata = {}) {
|
|
|
123
141
|
);
|
|
124
142
|
|
|
125
143
|
return {
|
|
144
|
+
summaryVersion: SUMMARY_VERSION,
|
|
126
145
|
specVersion: header.specVersion,
|
|
127
146
|
format: type.format,
|
|
128
147
|
contentType: type.contentType,
|