pmtiles-swarm 0.32.0 → 0.32.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 +37 -0
- package/package.json +2 -2
- package/src/api.js +2 -0
- package/src/library.js +12 -0
- package/src/prewarm.js +19 -5
- package/src/subscriptions.js +4 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,43 @@
|
|
|
7
7
|
### 🐞 Bug fixes
|
|
8
8
|
- _...Add new stuff here..._
|
|
9
9
|
|
|
10
|
+
## 0.32.2
|
|
11
|
+
### ✨ Features and improvements
|
|
12
|
+
- _...Add new stuff here..._
|
|
13
|
+
|
|
14
|
+
### 🐞 Bug fixes
|
|
15
|
+
- **The head warmer no longer skips every archive it was built for.** It decided an archive was done
|
|
16
|
+
by `Boolean(entry.pmtiles?.format)` — "a summary that names a format is one a header was read
|
|
17
|
+
for". That is not what a format means. A feed carries format, zoom range and bounds precisely so a
|
|
18
|
+
subscriber can judge a 698 GiB download before starting one, so a subscribed archive arrives fully
|
|
19
|
+
summarised before a byte of it exists locally. Every one of them was therefore retired on the spot,
|
|
20
|
+
and retired silently: the runner logged "every archive has been summarised; nothing to warm" and
|
|
21
|
+
meant it. The archives most in need of their header were the only ones never offered one, and the
|
|
22
|
+
visible symptom was a readable TileJSON — served from that same feed summary, touching no bytes —
|
|
23
|
+
beside tile reads that failed and previews that came up empty.
|
|
24
|
+
|
|
25
|
+
Entries now record where the summary came from: `summarySource: 'header'` where an archive's own
|
|
26
|
+
header answered, `'feed'` where a subscription was told. An entry written before this has neither,
|
|
27
|
+
and is treated as unread — the self-healing direction, since a local archive re-reads its own
|
|
28
|
+
header off local disk for nothing, while assuming the opposite would leave every existing
|
|
29
|
+
subscription stuck exactly as it is.
|
|
30
|
+
|
|
31
|
+
- _...Add new stuff here..._
|
|
32
|
+
|
|
33
|
+
## 0.32.1
|
|
34
|
+
### ✨ Features and improvements
|
|
35
|
+
- _...Add new stuff here..._
|
|
36
|
+
|
|
37
|
+
### 🐞 Bug fixes
|
|
38
|
+
- **Requires pmtiles-torrent 0.5.1, so the connection indicator and Recheck files actually work.**
|
|
39
|
+
Both features shipped against a dependency range that still allowed 0.4.6, which has neither
|
|
40
|
+
sidecar op. The declared requirement and the declared dependency disagreed, and the symptom was
|
|
41
|
+
a feature that looked built and did nothing: the indicator hid itself, because an engine that
|
|
42
|
+
cannot answer is deliberately not reported as unreachable, so there was nothing to see and
|
|
43
|
+
nothing to explain why.
|
|
44
|
+
|
|
45
|
+
- _...Add new stuff here..._
|
|
46
|
+
|
|
10
47
|
## 0.32.0
|
|
11
48
|
### ✨ Features and improvements
|
|
12
49
|
- _...Add new stuff here..._
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmtiles-swarm",
|
|
3
|
-
"version": "0.32.
|
|
3
|
+
"version": "0.32.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",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"maplibre-gl": "^6.2.0",
|
|
47
47
|
"parse-torrent": "^11.0.24",
|
|
48
48
|
"pmtiles": "^4.4.1",
|
|
49
|
-
"pmtiles-torrent": "^0.
|
|
49
|
+
"pmtiles-torrent": "^0.5.1",
|
|
50
50
|
"webtorrent": "^3.0.21"
|
|
51
51
|
},
|
|
52
52
|
"engines": {
|
package/src/api.js
CHANGED
|
@@ -2168,6 +2168,7 @@ export function createApp({
|
|
|
2168
2168
|
entry = await catalog.put({
|
|
2169
2169
|
infoHash: entry.infoHash,
|
|
2170
2170
|
pmtiles: summary,
|
|
2171
|
+
summarySource: 'header',
|
|
2171
2172
|
});
|
|
2172
2173
|
} catch (error) {
|
|
2173
2174
|
// The content had its say. Record it so this is answered from the
|
|
@@ -2383,6 +2384,7 @@ export function createApp({
|
|
|
2383
2384
|
entry = await catalog.put({
|
|
2384
2385
|
infoHash: entry.infoHash,
|
|
2385
2386
|
pmtiles: summary,
|
|
2387
|
+
summarySource: 'header',
|
|
2386
2388
|
});
|
|
2387
2389
|
}
|
|
2388
2390
|
}
|
package/src/library.js
CHANGED
|
@@ -204,6 +204,10 @@ export class Library {
|
|
|
204
204
|
// The torrent names the file, so the save path is its parent directory.
|
|
205
205
|
savePath: path.dirname(absolute),
|
|
206
206
|
pmtiles: summary,
|
|
207
|
+
// Read out of the archive, not taken from anybody's word for it. The
|
|
208
|
+
// prewarmer needs the difference: a summary that arrived in a feed says
|
|
209
|
+
// nothing about whether the header is on this disk. See prewarm.due().
|
|
210
|
+
summarySource: 'header',
|
|
207
211
|
kind: identified.kind,
|
|
208
212
|
sparse: options.sparse,
|
|
209
213
|
md5: created.md5,
|
|
@@ -747,6 +751,10 @@ export class Library {
|
|
|
747
751
|
buildDate: options.buildDate,
|
|
748
752
|
savePath,
|
|
749
753
|
pmtiles: summary,
|
|
754
|
+
// Read out of the archive, not taken from anybody's word for it. The
|
|
755
|
+
// prewarmer needs the difference: a summary that arrived in a feed says
|
|
756
|
+
// nothing about whether the header is on this disk. See prewarm.due().
|
|
757
|
+
summarySource: 'header',
|
|
750
758
|
kind: identified.kind,
|
|
751
759
|
sparse: options.sparse,
|
|
752
760
|
md5: created.md5,
|
|
@@ -1212,6 +1220,10 @@ export class Library {
|
|
|
1212
1220
|
magnet,
|
|
1213
1221
|
webSeeds: [],
|
|
1214
1222
|
pmtiles: summary,
|
|
1223
|
+
// Read out of the archive, not taken from anybody's word for it. The
|
|
1224
|
+
// prewarmer needs the difference: a summary that arrived in a feed says
|
|
1225
|
+
// nothing about whether the header is on this disk. See prewarm.due().
|
|
1226
|
+
summarySource: 'header',
|
|
1215
1227
|
kind: guessKind(torrent.name ?? ''),
|
|
1216
1228
|
mode: 'mirror',
|
|
1217
1229
|
// The engine's own account of it. It is on disk under its real name
|
package/src/prewarm.js
CHANGED
|
@@ -157,12 +157,23 @@ export class HeadWarmer {
|
|
|
157
157
|
const kind = entry.kind ?? guessKind(entry.name ?? '');
|
|
158
158
|
if (kind !== 'pmtiles') return false;
|
|
159
159
|
|
|
160
|
-
// A summary
|
|
161
|
-
//
|
|
162
|
-
//
|
|
163
|
-
//
|
|
160
|
+
// A summary is only an answer about *this disk* if a header on this disk
|
|
161
|
+
// produced it. `format` was standing in for that and does not mean it.
|
|
162
|
+
//
|
|
163
|
+
// The feed carries format, zoom range and bounds precisely so a subscriber
|
|
164
|
+
// can judge a 698 GiB download before starting one -- so a subscribed
|
|
165
|
+
// archive arrives fully summarised, before a byte of it exists here. Read
|
|
166
|
+
// as "a header was read", that retired every subscribed archive on the spot
|
|
167
|
+
// and did it silently, since as far as this was concerned there was nothing
|
|
168
|
+
// to do. The archives most in need of their header were the only ones never
|
|
169
|
+
// offered one, and the log said "nothing to warm".
|
|
170
|
+
//
|
|
171
|
+
// An entry from before this was recorded has no source, and is treated as
|
|
172
|
+
// unread. That is the self-healing direction: a local archive re-reads its
|
|
173
|
+
// own header off local disk and costs nothing, where the other way round
|
|
174
|
+
// leaves every existing subscription stuck exactly as it was.
|
|
164
175
|
const summary = entry.pmtiles;
|
|
165
|
-
const read = Boolean(summary?.format);
|
|
176
|
+
const read = entry.summarySource === 'header' && Boolean(summary?.format);
|
|
166
177
|
if (read && (summary.format !== 'pbf' || summary.vectorLayers)) {
|
|
167
178
|
return false;
|
|
168
179
|
}
|
|
@@ -257,6 +268,9 @@ export class HeadWarmer {
|
|
|
257
268
|
const stored = await this.#catalog.put({
|
|
258
269
|
infoHash: entry.infoHash,
|
|
259
270
|
pmtiles: { ...entry.pmtiles, ...summary },
|
|
271
|
+
// The whole point of this pass: from here on the entry's summary is
|
|
272
|
+
// one the header answered for, so due() stops choosing it.
|
|
273
|
+
summarySource: 'header',
|
|
260
274
|
});
|
|
261
275
|
// Said accurately, because the two halves arrive separately and the
|
|
262
276
|
// difference matters: the header is at byte zero, while the JSON
|
package/src/subscriptions.js
CHANGED
|
@@ -419,6 +419,10 @@ export class SubscriptionManager {
|
|
|
419
419
|
// with what the archive itself says; this only means the wait is not
|
|
420
420
|
// spent unservable.
|
|
421
421
|
pmtiles: item.pmtiles,
|
|
422
|
+
// Told, not read. The feed carries this so a subscriber can judge a
|
|
423
|
+
// 698 GiB download before starting one, which means it is populated
|
|
424
|
+
// before a single byte exists here.
|
|
425
|
+
summarySource: 'feed',
|
|
422
426
|
};
|
|
423
427
|
|
|
424
428
|
// The .torrent is preferred where there is one: it carries the trackers
|