pmtiles-swarm 0.37.2 → 0.37.3

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 CHANGED
@@ -7,6 +7,25 @@
7
7
  ### 🐞 Bug fixes
8
8
  - _...Add new stuff here..._
9
9
 
10
+ ## 0.37.3
11
+ ### ✨ Features and improvements
12
+
13
+ ### 🐞 Bug fixes
14
+ - **An archive fetched from a URL is now hashed the same way one already on disk is.** `creator` was
15
+ passed on the local path and nowhere else, so every archive a schedule ever built was hashed
16
+ inside this process — the one serving tiles and the console — rather than in the sidecar's
17
+ one-shot hasher. Four things followed from that one omission: the hash competed with serving,
18
+ it could not be cancelled (`create-torrent` takes no signal, so the add's AbortController reached
19
+ the download and stopped there), it reported nothing while it ran, and it produced a v1 torrent
20
+ rather than a hybrid. An archive arriving from a feed got a lesser torrent, built the slower way,
21
+ than the same file added by path.
22
+ - **A fetched archive now says when it has stopped downloading and started hashing.** The remote
23
+ add's progress callback dropped the `phase` the hasher reports, and its entry carried no phase at
24
+ all, so `runningAdds()` called it `fetching` from beginning to end. With the byte counts equal at
25
+ that point, the row sat at 100% "fetching" for the whole hash — which reads as a transfer that
26
+ completed and then hung, and was reported as exactly that. The bar now hands over to the hash and
27
+ fills again as pieces are read.
28
+
10
29
  ## 0.37.2
11
30
  ### ✨ Features and improvements
12
31
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmtiles-swarm",
3
- "version": "0.37.2",
3
+ "version": "0.37.3",
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/library.js CHANGED
@@ -311,20 +311,7 @@ export class Library {
311
311
  comment: options.comment,
312
312
  md5: options.md5 ?? this.#config.md5,
313
313
  signal: controller.signal,
314
- // Pieces in, bytes out. The console draws one progress bar for adds and
315
- // labels it in bytes, and a piece count means nothing beside a download
316
- // measured in gigabytes — so it is converted here, where the file size
317
- // is known, rather than teaching the console a second unit. Accurate to
318
- // within one piece, which at 4 MiB against a planet archive is four
319
- // parts in a million.
320
- onHashProgress: ({ piece, pieces }) => {
321
- const state = this.#running.get(requested);
322
- if (!state || !pieces || !size) return;
323
- state.received = Math.min(
324
- size,
325
- Math.round(((piece + 1) / pieces) * size),
326
- );
327
- },
314
+ onHashProgress: this.#hashProgress(requested),
328
315
  });
329
316
 
330
317
  return await this.#register(created, {
@@ -352,6 +339,28 @@ export class Library {
352
339
  }
353
340
  }
354
341
 
342
+ /**
343
+ * Reports a hash's progress as bytes, which is what the console draws.
344
+ *
345
+ * Pieces are what a hasher counts; the adds list has one bar and labels it in
346
+ * bytes, and a piece count means nothing beside a download measured in
347
+ * gigabytes. Converted here, where the size is known, rather than teaching
348
+ * the console a second unit. Accurate to within one piece — at 4 MiB against
349
+ * a planet archive, four parts in a million.
350
+ * @param {string} key - How the add is registered in #running.
351
+ * @returns {Function} - An onHashProgress callback.
352
+ */
353
+ #hashProgress(key) {
354
+ return ({ piece, pieces }) => {
355
+ const state = this.#running.get(key);
356
+ if (!state || !pieces || !state.total) return;
357
+ state.received = Math.min(
358
+ state.total,
359
+ Math.round(((piece + 1) / pieces) * state.total),
360
+ );
361
+ };
362
+ }
363
+
355
364
  /**
356
365
  * Turns a caller's choice of location into a directory, and checks it.
357
366
  *
@@ -884,8 +893,33 @@ export class Library {
884
893
  fetchAttempts: this.#config.fetchAttempts,
885
894
  fetchRetryDelayMs: (this.#config.fetchRetrySeconds ?? 5) * 1000,
886
895
  signal: controller.signal,
887
- onProgress: ({ received, total, done }) => {
896
+ // The same hasher a local add gets, which this route never asked for.
897
+ //
898
+ // Without it the hash ran in this process -- the one serving tiles and
899
+ // the console -- for every archive a schedule ever built, could not be
900
+ // cancelled because create-torrent takes no signal, reported nothing
901
+ // while it ran, and produced a v1 torrent rather than a hybrid. So an
902
+ // archive arriving from a feed got a lesser torrent, built the slower
903
+ // way, than the same file added by path.
904
+ creator: this.#creator(),
905
+ onHashProgress: this.#hashProgress(url),
906
+ onProgress: ({ phase, received, total, done }) => {
888
907
  const state = this.#running.get(url);
908
+ if (phase === 'hashing') {
909
+ // The transfer is over and a different job has started, measured
910
+ // in the same units. Handing the bar over rather than leaving it
911
+ // at 100%: a finished download that sits at 100% for the length of
912
+ // a 128 GiB hash reads as one that completed and then hung, which
913
+ // is how it was reported.
914
+ if (state) {
915
+ Object.assign(state, {
916
+ phase: 'hashing',
917
+ received: undefined,
918
+ total,
919
+ });
920
+ }
921
+ return;
922
+ }
889
923
  if (state) Object.assign(state, { received, total });
890
924
  const pct = total ? ((received / total) * 100).toFixed(1) : '?';
891
925
  console.log(