pmtiles-swarm 0.54.0 → 0.54.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 +28 -0
- package/docs/configuration.md +20 -0
- package/package.json +1 -1
- package/src/api.js +5 -1
- package/src/catalog.js +14 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,34 @@
|
|
|
7
7
|
### 🐞 Bug fixes
|
|
8
8
|
- _...Add new stuff here..._
|
|
9
9
|
|
|
10
|
+
## 0.54.2
|
|
11
|
+
### ✨ Features and improvements
|
|
12
|
+
- **Written down and tested: a range read is cached exactly as a tile read is**, because it is the
|
|
13
|
+
same read. `serveArchiveFromSwarm` goes through the same acquisition, the same `TorrentSource` and
|
|
14
|
+
therefore the same piece cache, so `tiles.pieceCacheBytes`, `tiles.maxOpenArchives` and
|
|
15
|
+
`tiles.directoryCacheEntries` all bound it unchanged. The two doors warm each other: pulling the
|
|
16
|
+
header over HTTP leaves the tile endpoint warm for free, and a tile already read costs a range
|
|
17
|
+
request nothing. Five tests now hold that in place by counting what actually reaches the swarm —
|
|
18
|
+
including one that shrinks the byte budget to a single piece and watches the eviction happen.
|
|
19
|
+
|
|
20
|
+
### 🐞 Bug fixes
|
|
21
|
+
|
|
22
|
+
## 0.54.1
|
|
23
|
+
### ✨ Features and improvements
|
|
24
|
+
|
|
25
|
+
### 🐞 Bug fixes
|
|
26
|
+
- **The public page offered a download of an archive the node did not hold.** With `publicDownload`
|
|
27
|
+
on, a cache-mode archive got a link labelled **download** that answers `409` — or, with
|
|
28
|
+
`serveArchiveFromSwarm` on, refuses a request carrying no `Range`, which reads as a broken node
|
|
29
|
+
rather than as a deliberate limit. `publicDownload` now needs the file to be here. `serveArchive`
|
|
30
|
+
is deliberately not conditioned that way, since a bounded range can be fetched from the swarm, and
|
|
31
|
+
neither setting is stored as `false` on this account — so both take effect on their own the moment
|
|
32
|
+
a download finishes.
|
|
33
|
+
|
|
34
|
+
- **A range request with no `Range` header answered `411`.** That code is about a missing
|
|
35
|
+
`Content-Length` on the way in; the request here is well formed and it is the state of the resource
|
|
36
|
+
that makes it unanswerable, so it is now a `409` like the other "not here" refusals beside it.
|
|
37
|
+
|
|
10
38
|
## 0.54.0
|
|
11
39
|
### ✨ Features and improvements
|
|
12
40
|
- **`serveArchiveFromSwarm` — a byte range for an archive this node does not hold.** Experimental,
|
package/docs/configuration.md
CHANGED
|
@@ -373,6 +373,17 @@ The response carries the same `ETag` and the same year-long `immutable` caching
|
|
|
373
373
|
complete copy would give, because it is the same content: the infohash names
|
|
374
374
|
those bytes wherever they were read from.
|
|
375
375
|
|
|
376
|
+
**The pieces are cached exactly as a tile read caches them**, because it is the
|
|
377
|
+
same read. A range goes through the same acquisition, the same `TorrentSource`
|
|
378
|
+
and therefore the same piece cache, so `tiles.pieceCacheBytes`,
|
|
379
|
+
`tiles.maxOpenArchives` and `tiles.directoryCacheEntries` all apply to it
|
|
380
|
+
unchanged — and a node tuned for its memory stays tuned when this endpoint is
|
|
381
|
+
used. It also means the two doors warm each other: somebody pulling the header
|
|
382
|
+
over HTTP leaves the tile endpoint warm for free, and a tile already read costs
|
|
383
|
+
a range request nothing. Underneath, in cache mode, the pieces land in
|
|
384
|
+
[`cacheSavePath`](#cachesavepath) the same way, so what a reader asks for over
|
|
385
|
+
HTTP hydrates the partial archive on disk just as a tile request does.
|
|
386
|
+
|
|
376
387
|
**A node cannot be a web seed for an archive it does not hold**, whatever this is
|
|
377
388
|
set to. [`selfWebSeed`](#selfwebseed) is refused on an incomplete archive and
|
|
378
389
|
offered again when the download finishes — answering from the swarm and then
|
|
@@ -464,6 +475,15 @@ is off, whatever the file says. A web seed URL that answers `403` is worse than
|
|
|
464
475
|
web seed, because a client spends its retries on it, and a download link that
|
|
465
476
|
`403`s is worse than no link.
|
|
466
477
|
|
|
478
|
+
**`publicDownload` also needs the file to actually be here.** A cache-mode
|
|
479
|
+
archive is offered no download link, because there is nothing to download: the
|
|
480
|
+
node holds none of it, and a link labelled "download" that answers `409` reads as
|
|
481
|
+
a broken node rather than as a deliberate limit. `serveArchive` is deliberately
|
|
482
|
+
_not_ conditioned that way — a bounded range can be fetched from the swarm, which
|
|
483
|
+
is what [`serveArchiveFromSwarm`](#servearchivefromswarm) is for — and neither
|
|
484
|
+
setting is stored as `false` on that account, so both take effect on their own the
|
|
485
|
+
moment a download finishes.
|
|
486
|
+
|
|
467
487
|
### Per archive, per folder, per source
|
|
468
488
|
|
|
469
489
|
The node's setting is the default. A [watched folder](#watched-folders), a
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmtiles-swarm",
|
|
3
|
-
"version": "0.54.
|
|
3
|
+
"version": "0.54.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
|
@@ -2382,7 +2382,11 @@ export function createApp({
|
|
|
2382
2382
|
const asked = req.headers.range;
|
|
2383
2383
|
if (!asked) {
|
|
2384
2384
|
res.setHeader('accept-ranges', 'bytes');
|
|
2385
|
-
|
|
2385
|
+
// 409 rather than 411. The request is well formed -- 411 is about a
|
|
2386
|
+
// missing Content-Length on the way in -- and what is wrong is the state
|
|
2387
|
+
// of the thing being asked for: the whole file is not here, and fetching
|
|
2388
|
+
// it through the swarm to stream back out is not an answer.
|
|
2389
|
+
return res.status(409).json({
|
|
2386
2390
|
error:
|
|
2387
2391
|
'this node does not hold this archive, so it can only answer a ' +
|
|
2388
2392
|
'byte range. Send a Range header.',
|
package/src/catalog.js
CHANGED
|
@@ -82,12 +82,26 @@ export function normalizeCategories(source) {
|
|
|
82
82
|
*/
|
|
83
83
|
export function publishingFor(entry, config) {
|
|
84
84
|
const serveArchive = entry?.serveArchive ?? config?.serveArchive ?? false;
|
|
85
|
+
// Whether the whole file is here. `serveArchive` does not depend on it —
|
|
86
|
+
// `serveArchiveFromSwarm` exists precisely so a node holding nothing can
|
|
87
|
+
// still answer a bounded range — but a download link does. A link labelled
|
|
88
|
+
// "download" on a public page has to hand over the file, and a cache-mode
|
|
89
|
+
// node cannot: it answers 409, or refuses a request with no Range, which
|
|
90
|
+
// reads as a broken node rather than as a deliberate limit.
|
|
91
|
+
//
|
|
92
|
+
// `selfWebSeed` is guarded separately, in setPublishing, because it has a
|
|
93
|
+
// lifecycle rather than a state: the URL is written into a .torrent and has
|
|
94
|
+
// to be added and withdrawn at the right moments, not merely reported as
|
|
95
|
+
// off. Resolving it to false here would withdraw a published seed the first
|
|
96
|
+
// time an archive was rechecked.
|
|
97
|
+
const held = entry?.complete !== false;
|
|
85
98
|
return {
|
|
86
99
|
serveArchive,
|
|
87
100
|
selfWebSeed:
|
|
88
101
|
serveArchive && (entry?.selfWebSeed ?? config?.selfWebSeed ?? false),
|
|
89
102
|
publicDownload:
|
|
90
103
|
serveArchive &&
|
|
104
|
+
held &&
|
|
91
105
|
(entry?.publicDownload ?? config?.publicDownload ?? false),
|
|
92
106
|
};
|
|
93
107
|
}
|