pmtiles-swarm 0.43.0 β 0.45.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/CHANGELOG.md +31 -0
- package/docs/publishing.md +16 -0
- package/docs/running-as-a-service.md +46 -0
- package/package.json +2 -2
- package/src/web/index.html +54 -22
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,37 @@
|
|
|
7
7
|
### π Bug fixes
|
|
8
8
|
- _...Add new stuff here..._
|
|
9
9
|
|
|
10
|
+
## 0.45.0
|
|
11
|
+
### β¨ Features and improvements
|
|
12
|
+
- **Requires pmtiles-torrent 0.9.1**, which stops the sidecar rewriting resume data that has not
|
|
13
|
+
changed. A hybrid torrent carries a merkle tree of 32 bytes per 16 KiB block in its resume data β
|
|
14
|
+
a few hundred megabytes for a 128 GiB archive β and it was being restaged, fsynced and renamed
|
|
15
|
+
every five minutes for every archive at once, to record that nothing had moved. It also gives each
|
|
16
|
+
torrent its own share of the save budget instead of five seconds for the whole library, which is
|
|
17
|
+
why a node with four archives persisted two of them and a different two next time.
|
|
18
|
+
- **Running as a service documents a newer libtorrent than the distribution ships.** `apt` gives you
|
|
19
|
+
whatever your release froze on, `pip install` into the system Python is refused under PEP 668, and
|
|
20
|
+
`--break-system-packages` is not the way round it. A virtualenv plus the existing
|
|
21
|
+
`libtorrent.python` key is, reversibly and without touching apt. The upgrade section now also says
|
|
22
|
+
that libtorrent is a third thing an update never moves, and how to check which one the service
|
|
23
|
+
actually imports.
|
|
24
|
+
|
|
25
|
+
### π Bug fixes
|
|
26
|
+
|
|
27
|
+
## 0.44.0
|
|
28
|
+
### β¨ Features and improvements
|
|
29
|
+
- **Web seeds are added where they are listed.** The **HTTP sources** tab now has a field and an Add
|
|
30
|
+
button under the list, so adding one shows what is already there and what the addition did. It
|
|
31
|
+
replaces the **Add web seed** button in Actions, which opened a `prompt()` a long way from the list
|
|
32
|
+
it changed β one way to do this rather than two.
|
|
33
|
+
|
|
34
|
+
The tab now also says why this is safe on a published archive: `url-list` sits outside the info
|
|
35
|
+
dictionary, so the infohash is unchanged and every magnet and peer already relying on it keeps
|
|
36
|
+
working. The result distinguishes "added" from "the engine has taken it", which are different
|
|
37
|
+
claims and the second is the one that matters.
|
|
38
|
+
|
|
39
|
+
### π Bug fixes
|
|
40
|
+
|
|
10
41
|
## 0.43.0
|
|
11
42
|
### β¨ Features and improvements
|
|
12
43
|
- **Six detail tabs are now five, and the two bars that matter lead the General tab.** How much of an
|
package/docs/publishing.md
CHANGED
|
@@ -151,6 +151,22 @@ Adding from a **local path** never publishes a seed unless you ask: a web seed
|
|
|
151
151
|
appears only when `webSeedBase` is set, and `publishDir` moves the file without
|
|
152
152
|
implying one.
|
|
153
153
|
|
|
154
|
+
### Adding one later
|
|
155
|
+
|
|
156
|
+
An archive already in circulation can be given a web seed at any time, from the
|
|
157
|
+
**HTTP sources** tab of its details or with
|
|
158
|
+
`POST /api/torrents/<infohash>/webseeds`. This is safe on a published torrent:
|
|
159
|
+
`url-list` sits outside the info dictionary, so the infohash does not change and
|
|
160
|
+
every magnet, tracker and peer already relying on it keeps working.
|
|
161
|
+
|
|
162
|
+
The URL has to serve the whole archive, byte for byte, under the name the torrent
|
|
163
|
+
gives it. A seed that answers with anything else is not a faster path to the
|
|
164
|
+
data β peers will fetch from it, fail the piece hash, and fall back to the swarm
|
|
165
|
+
having wasted the transfer.
|
|
166
|
+
|
|
167
|
+
Worth doing whenever an archive gets a public home after the fact: a swarm with
|
|
168
|
+
one web seed starts cold in seconds rather than waiting for a peer to appear.
|
|
169
|
+
|
|
154
170
|
## Building from a feed of source data
|
|
155
171
|
|
|
156
172
|
Subscribing is not only for finished archives. The OpenStreetMap project
|
|
@@ -553,6 +553,36 @@ rather than exiting. Name the interpreter explicitly when the service user's
|
|
|
553
553
|
{ "libtorrent": { "python": "/usr/bin/python3" } }
|
|
554
554
|
```
|
|
555
555
|
|
|
556
|
+
### A newer libtorrent than the distribution ships
|
|
557
|
+
|
|
558
|
+
`apt` gives you whatever your release froze on, which on Ubuntu 24.04 is
|
|
559
|
+
libtorrent 2.0.x. `pip install libtorrent` into the system Python is refused β
|
|
560
|
+
`externally-managed-environment`, because apt owns that Python β and
|
|
561
|
+
`--break-system-packages` is not the way round it.
|
|
562
|
+
|
|
563
|
+
Give the service account a virtualenv instead and point the sidecar at it. The
|
|
564
|
+
same `python` key does the work, so nothing else changes:
|
|
565
|
+
|
|
566
|
+
```sh
|
|
567
|
+
sudo -u pmtiles-swarm python3 -m venv /var/lib/pmtiles-swarm/venv
|
|
568
|
+
sudo -u pmtiles-swarm /var/lib/pmtiles-swarm/venv/bin/pip install libtorrent
|
|
569
|
+
sudo -u pmtiles-swarm /var/lib/pmtiles-swarm/venv/bin/python -c "import libtorrent; print(libtorrent.__version__)"
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
```json
|
|
573
|
+
{ "libtorrent": { "python": "/var/lib/pmtiles-swarm/venv/bin/python" } }
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
Reversible in one line: delete the key and the node is back on the distribution
|
|
577
|
+
package, with no uninstall and nothing done to apt. `ReadWritePaths` already
|
|
578
|
+
covers `/var/lib/pmtiles-swarm`, so the venv needs no unit change β put it
|
|
579
|
+
anywhere else and it does.
|
|
580
|
+
|
|
581
|
+
Worth doing for a node seeding very large hybrid archives, where v2 support has
|
|
582
|
+
had the most work since 2.0. Change one thing at a time, though: take a version
|
|
583
|
+
of the node first, confirm what it did, then move libtorrent, so a difference in
|
|
584
|
+
behaviour has one candidate rather than two.
|
|
585
|
+
|
|
556
586
|
## Ports
|
|
557
587
|
|
|
558
588
|
Five listeners, and only the peer ports want a firewall rule. See
|
|
@@ -615,6 +645,22 @@ sudo -u pmtiles-swarm -H npm ls --prefix /var/lib/pmtiles-swarm --depth 1 \
|
|
|
615
645
|
pmtiles-swarm pmtiles-torrent
|
|
616
646
|
```
|
|
617
647
|
|
|
648
|
+
**libtorrent itself is a third thing, and an update never touches it.** The
|
|
649
|
+
sidecar is Python that ships with the package; libtorrent is the binding it
|
|
650
|
+
imports, which came from `apt` or from a virtualenv you made. Neither moves when
|
|
651
|
+
the node does:
|
|
652
|
+
|
|
653
|
+
```sh
|
|
654
|
+
sudo -u pmtiles-swarm python3 -c "import libtorrent; print(libtorrent.__version__)"
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
Run that against whatever `libtorrent.python` names, not your login shell's
|
|
658
|
+
Python β they are frequently different interpreters, and the one that matters is
|
|
659
|
+
the one the service uses. See
|
|
660
|
+
[a newer libtorrent than the distribution ships](#a-newer-libtorrent-than-the-distribution-ships)
|
|
661
|
+
for moving it, and move it on its own: a node upgrade and a libtorrent upgrade in
|
|
662
|
+
one restart leaves two candidates for whatever happens next.
|
|
663
|
+
|
|
618
664
|
An install runs the dependency install scripts again, so check WebRTC survived
|
|
619
665
|
it β see [the allowScripts warning](#the-allowscripts-warning):
|
|
620
666
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmtiles-swarm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.45.0",
|
|
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.9.
|
|
49
|
+
"pmtiles-torrent": "^0.9.1",
|
|
50
50
|
"webtorrent": "^3.0.21"
|
|
51
51
|
},
|
|
52
52
|
"engines": {
|
package/src/web/index.html
CHANGED
|
@@ -1728,12 +1728,63 @@
|
|
|
1728
1728
|
if (name === 'sources') {
|
|
1729
1729
|
const seeds = entry.webSeeds ?? [];
|
|
1730
1730
|
pane.innerHTML =
|
|
1731
|
-
table(
|
|
1732
|
-
|
|
1731
|
+
table(
|
|
1732
|
+
['URL'],
|
|
1733
|
+
seeds.map((url) => [escapeHtml(url)]),
|
|
1734
|
+
) +
|
|
1735
|
+
`<div style="display:flex; gap:0.4rem; margin-top:0.75rem">
|
|
1736
|
+
<input
|
|
1737
|
+
id="seed-url"
|
|
1738
|
+
class="grow"
|
|
1739
|
+
placeholder="https://example.org/${escapeHtml(entry.name)}"
|
|
1740
|
+
spellcheck="false"
|
|
1741
|
+
/>
|
|
1742
|
+
<button id="seed-add">Add</button>
|
|
1743
|
+
</div>
|
|
1744
|
+
<div class="sub" style="margin-top:0.5rem">
|
|
1733
1745
|
A web seed serves the archive over plain HTTP, which is what
|
|
1734
1746
|
makes it usable before it has peers β and the difference
|
|
1735
|
-
between a cold tile taking tens of seconds and under one.
|
|
1747
|
+
between a cold tile taking tens of seconds and under one. One
|
|
1748
|
+
can be added at any time: <code>url-list</code> sits outside
|
|
1749
|
+
the info dictionary, so the infohash is unchanged and every
|
|
1750
|
+
magnet and peer already relying on it keeps working. The URL
|
|
1751
|
+
must serve the whole archive, byte for byte, under the name
|
|
1752
|
+
the torrent gives it.
|
|
1736
1753
|
</div>`;
|
|
1754
|
+
|
|
1755
|
+
// Attached here rather than in the panel, because this pane is
|
|
1756
|
+
// rebuilt whenever it is shown and the handler has to survive that.
|
|
1757
|
+
// Safe: sources is not one of the panes the refresh redraws.
|
|
1758
|
+
const add = async () => {
|
|
1759
|
+
const url = pane.querySelector('#seed-url').value.trim();
|
|
1760
|
+
if (!url) return;
|
|
1761
|
+
const button = pane.querySelector('#seed-add');
|
|
1762
|
+
button.disabled = true;
|
|
1763
|
+
try {
|
|
1764
|
+
const result = await api(
|
|
1765
|
+
`/api/torrents/${infoHash}/webseeds`,
|
|
1766
|
+
{ method: 'POST', body: { webSeeds: [url] } },
|
|
1767
|
+
);
|
|
1768
|
+
// "Added" and "the engine is using it" are different claims,
|
|
1769
|
+
// and the second is the one somebody adding a seed wants.
|
|
1770
|
+
toast(
|
|
1771
|
+
result.live
|
|
1772
|
+
? 'web seed added and live'
|
|
1773
|
+
: 'web seed added; the engine has not taken it yet',
|
|
1774
|
+
);
|
|
1775
|
+
renderDetail(infoHash);
|
|
1776
|
+
} catch (error) {
|
|
1777
|
+
toast(error.message);
|
|
1778
|
+
button.disabled = false;
|
|
1779
|
+
}
|
|
1780
|
+
};
|
|
1781
|
+
|
|
1782
|
+
pane.querySelector('#seed-add').onclick = add;
|
|
1783
|
+
pane.querySelector('#seed-url').onkeydown = (event) => {
|
|
1784
|
+
// Enter, because a single field with a button beside it is a
|
|
1785
|
+
// form in everything but name.
|
|
1786
|
+
if (event.key === 'Enter') add();
|
|
1787
|
+
};
|
|
1737
1788
|
return;
|
|
1738
1789
|
}
|
|
1739
1790
|
|
|
@@ -1976,7 +2027,6 @@
|
|
|
1976
2027
|
<div class="actions">
|
|
1977
2028
|
${servable ? '<button id="warm">Warm region</button>' : ''}
|
|
1978
2029
|
<button id="set-location">Set locationβ¦</button>
|
|
1979
|
-
<button id="add-seed">Add web seed</button>
|
|
1980
2030
|
<button id="clear-cache" ${mode === 'cache' ? '' : 'disabled title="only cache-mode archives have a cache to clear"'}>Clear cache</button>
|
|
1981
2031
|
<button id="recheck" title="Hash the files on disk again and believe the result. For an archive that reads 0% next to a file that is plainly there, or one that claims to be complete and is not β every other figure comes from something written down earlier, and this is the only thing that goes and looks.">Recheck files</button>
|
|
1982
2032
|
<button id="pause">${entry.paused ? 'Resume' : 'Pause'}</button>
|
|
@@ -2248,24 +2298,6 @@
|
|
|
2248
2298
|
};
|
|
2249
2299
|
};
|
|
2250
2300
|
|
|
2251
|
-
$('add-seed').onclick = async () => {
|
|
2252
|
-
const url = window.prompt(
|
|
2253
|
-
'Web seed URL (adding one does not change the infohash):',
|
|
2254
|
-
`https://example.org/${entry.name}`,
|
|
2255
|
-
);
|
|
2256
|
-
if (!url) return;
|
|
2257
|
-
try {
|
|
2258
|
-
const result = await api(`/api/torrents/${infoHash}/webseeds`, {
|
|
2259
|
-
method: 'POST',
|
|
2260
|
-
body: { webSeeds: [url] },
|
|
2261
|
-
});
|
|
2262
|
-
toast(result.live ? 'web seed added and live' : 'web seed added');
|
|
2263
|
-
renderDetail(infoHash);
|
|
2264
|
-
} catch (error) {
|
|
2265
|
-
toast(error.message);
|
|
2266
|
-
}
|
|
2267
|
-
};
|
|
2268
|
-
|
|
2269
2301
|
$('clear-cache').onclick = async () => {
|
|
2270
2302
|
if (!window.confirm('Discard this archiveβs cached pieces?')) return;
|
|
2271
2303
|
try {
|