@torrent-tv/proxy 2.80.18 → 2.81.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.
Files changed (67) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/docs/encode-architecture.md +51 -2
  3. package/package.json +1 -1
  4. package/research/double-spawn-2026-09-10.md +171 -0
  5. package/services/disk/DiskSpace.js +146 -0
  6. package/services/disk/wire.js +60 -0
  7. package/services/encode/EncodeRun.js +37 -9
  8. package/services/encode/SegmentStore.js +284 -232
  9. package/services/encode/run-command.js +16 -1
  10. package/services/hls-session-manager.js +31 -128
  11. package/services/orchestrators/EncodeOrchestrator.js +52 -38
  12. package/services/piece-store/allowance.js +107 -0
  13. package/services/piece-store/piece-disk-store.js +365 -0
  14. package/services/piece-store/shared-piece-store.js +1549 -1535
  15. package/services/segment-formats/fmp4.js +54 -0
  16. package/services/segment-formats/mpegts.js +54 -0
  17. package/services/torrent-worker/client.js +32 -0
  18. package/services/torrent-worker/pool-adapter.js +15 -0
  19. package/services/torrent-worker/protocol.js +9 -0
  20. package/services/torrent-worker/worker.js +8 -1
  21. package/services/viewer/positions.js +48 -0
  22. package/test/audio-inventory.test.js +176 -176
  23. package/test/auto-quality-step.test.js +514 -514
  24. package/test/concurrent-cost.test.js +138 -138
  25. package/test/coverage-follows-the-disk.test.js +191 -187
  26. package/test/coverage-map.test.js +195 -195
  27. package/test/declared-tracks.test.js +35 -35
  28. package/test/disk-space.test.js +138 -0
  29. package/test/encode-orchestrator.test.js +0 -3
  30. package/test/encode-run.test.js +5 -12
  31. package/test/held-request-width.test.js +155 -155
  32. package/test/helpers/encode-run.js +2 -2
  33. package/test/matroska-blocks.test.js +0 -0
  34. package/test/matroska-cues-track.test.js +192 -192
  35. package/test/mp4-composition-times.test.js +0 -0
  36. package/test/mp4-subtitles.test.js +173 -173
  37. package/test/one-authority.test.js +281 -220
  38. package/test/orchestrator-wired.test.js +199 -195
  39. package/test/packet-witness-ring.test.js +236 -236
  40. package/test/packet-witness.test.js +148 -148
  41. package/test/piece-disk-store.test.js +267 -0
  42. package/test/piece-reader.test.js +4 -4
  43. package/test/piece-store-eviction.test.js +17 -17
  44. package/test/piece-store-reservations.test.js +20 -1
  45. package/test/piece-store-slow-disk.test.js +16 -1
  46. package/test/produced-copy-choice.test.js +258 -358
  47. package/test/read-window.test.js +6 -6
  48. package/test/run-intervals.test.js +100 -100
  49. package/test/seek-landing.test.js +109 -109
  50. package/test/segment-serve-wiring.test.js +8 -9
  51. package/test/segment-store-eviction.test.js +232 -0
  52. package/test/segment-store.test.js +238 -216
  53. package/test/segments-are-shared.test.js +1 -1
  54. package/test/shared-piece-store.test.js +12 -12
  55. package/test/sidecar-naming.test.js +142 -142
  56. package/test/subtitle-cue-framing.test.js +200 -200
  57. package/test/subtitle-cue-walk.test.js +369 -369
  58. package/test/subtitle-defaults.test.js +97 -97
  59. package/test/subtitle-track-numbering.test.js +370 -370
  60. package/test/tail-duplication.test.js +167 -167
  61. package/test/tracks-begin-together.test.js +195 -195
  62. package/test/two-viewers-one-picture.test.js +374 -374
  63. package/test/video-facts.test.js +102 -102
  64. package/test/wedge-certainty.test.js +131 -131
  65. package/services/encode/open-piece.js +0 -135
  66. package/services/piece-store/disk-tier.js +0 -151
  67. package/test/open-piece.test.js +0 -152
@@ -27,7 +27,7 @@ async function makeStore(capacityPieces) {
27
27
  const store = new SharedPieceStore(PIECE, {
28
28
  length: PIECE * 64,
29
29
  memoryBytes: PIECE * capacityPieces,
30
- spillDirectory: directory,
30
+ path: directory,
31
31
  name: "eviction-test"
32
32
  });
33
33
  return { store, directory };
@@ -89,7 +89,7 @@ test("concurrent puts past capacity never hand two pieces the same slot", async
89
89
  );
90
90
  } finally {
91
91
  await store.destroy();
92
- await fs.rm(directory, { recursive: true, force: true });
92
+ await fs.rm(directory, { recursive: true, force: true, maxRetries: 10, retryDelay: 20 });
93
93
  }
94
94
  });
95
95
 
@@ -108,7 +108,7 @@ test("a piece caught mid-spill is waited for, not reported missing", async () =>
108
108
  assert.ok(bytes.equals(pieceOf(0)), "piece 0 came back wrong while being spilled");
109
109
  } finally {
110
110
  await store.destroy();
111
- await fs.rm(directory, { recursive: true, force: true });
111
+ await fs.rm(directory, { recursive: true, force: true, maxRetries: 10, retryDelay: 20 });
112
112
  }
113
113
  });
114
114
 
@@ -129,7 +129,7 @@ test("pinned pieces are never evicted, and the pin count is reported", async ()
129
129
  assert.equal(store.stats().pinned, 0, "unpin is not reflected in the stats");
130
130
  } finally {
131
131
  await store.destroy();
132
- await fs.rm(directory, { recursive: true, force: true });
132
+ await fs.rm(directory, { recursive: true, force: true, maxRetries: 10, retryDelay: 20 });
133
133
  }
134
134
  });
135
135
 
@@ -188,7 +188,7 @@ test("the store says why it spills: what is asked of it, what it had to take, ho
188
188
  assert.equal(store.stats().demand.readers, 0, "a reader that ends stops being counted");
189
189
  } finally {
190
190
  store.destroy(() => undefined);
191
- await fs.rm(directory, { recursive: true, force: true });
191
+ await fs.rm(directory, { recursive: true, force: true, maxRetries: 10, retryDelay: 20 });
192
192
  }
193
193
  });
194
194
 
@@ -226,7 +226,7 @@ test("a piece nobody has declared does not push out one that is being read", asy
226
226
  }
227
227
  } finally {
228
228
  store.destroy(() => undefined);
229
- await fs.rm(directory, { recursive: true, force: true });
229
+ await fs.rm(directory, { recursive: true, force: true, maxRetries: 10, retryDelay: 20 });
230
230
  }
231
231
  });
232
232
 
@@ -245,7 +245,7 @@ test("before any reader has declared anything, an arriving piece still goes to m
245
245
  assert.ok(stats.spills > 0, "the store filled and evicted, as it did before");
246
246
  } finally {
247
247
  store.destroy(() => undefined);
248
- await fs.rm(directory, { recursive: true, force: true });
248
+ await fs.rm(directory, { recursive: true, force: true, maxRetries: 10, retryDelay: 20 });
249
249
  }
250
250
  });
251
251
 
@@ -274,7 +274,7 @@ test("the store asks for what its readers declared, and for a whole window at le
274
274
  assert.equal(store.wantedBytes, 50 * PIECE);
275
275
  } finally {
276
276
  store.destroy(() => undefined);
277
- await fs.rm(directory, { recursive: true, force: true });
277
+ await fs.rm(directory, { recursive: true, force: true, maxRetries: 10, retryDelay: 20 });
278
278
  }
279
279
  });
280
280
 
@@ -300,7 +300,7 @@ test("the floor the ceiling will not fall below is the same union, not the wides
300
300
  );
301
301
  } finally {
302
302
  store.destroy(() => undefined);
303
- await fs.rm(directory, { recursive: true, force: true });
303
+ await fs.rm(directory, { recursive: true, force: true, maxRetries: 10, retryDelay: 20 });
304
304
  }
305
305
  });
306
306
 
@@ -333,7 +333,7 @@ test("a block is re-used instead of a new one being allocated for every piece",
333
333
  }
334
334
  } finally {
335
335
  store.destroy(() => undefined);
336
- await fs.rm(directory, { recursive: true, force: true });
336
+ await fs.rm(directory, { recursive: true, force: true, maxRetries: 10, retryDelay: 20 });
337
337
  }
338
338
  });
339
339
 
@@ -360,7 +360,7 @@ test("a spare block is given up once it has sat longer than the store's own work
360
360
  assert.equal(store.stats().blocksReleased, released);
361
361
  } finally {
362
362
  store.destroy(() => undefined);
363
- await fs.rm(directory, { recursive: true, force: true });
363
+ await fs.rm(directory, { recursive: true, force: true, maxRetries: 10, retryDelay: 20 });
364
364
  }
365
365
  });
366
366
 
@@ -388,7 +388,7 @@ test("evicting a piece the disk already holds costs no second write", async () =
388
388
  assert.ok((await get(store, 0)).equals(pieceOf(0)));
389
389
  } finally {
390
390
  store.destroy(() => undefined);
391
- await fs.rm(directory, { recursive: true, force: true });
391
+ await fs.rm(directory, { recursive: true, force: true, maxRetries: 10, retryDelay: 20 });
392
392
  }
393
393
  });
394
394
 
@@ -411,7 +411,7 @@ test("a store whose readers have gone asks for nothing, one that never had them
411
411
  assert.ok(store.wantedBytes < opening, "a store with no readers left asks for nothing");
412
412
  } finally {
413
413
  store.destroy(() => undefined);
414
- await fs.rm(directory, { recursive: true, force: true });
414
+ await fs.rm(directory, { recursive: true, force: true, maxRetries: 10, retryDelay: 20 });
415
415
  }
416
416
  });
417
417
 
@@ -434,7 +434,7 @@ test("the allowance is never cut below one reader's whole window", async () => {
434
434
  assert.equal(obeyed.belowAWindow, false);
435
435
  } finally {
436
436
  store.destroy(() => undefined);
437
- await fs.rm(directory, { recursive: true, force: true });
437
+ await fs.rm(directory, { recursive: true, force: true, maxRetries: 10, retryDelay: 20 });
438
438
  }
439
439
  });
440
440
 
@@ -478,7 +478,7 @@ test("the pool stays the size it is allowed to be, however many pieces pass thro
478
478
  }
479
479
  } finally {
480
480
  store.destroy(() => undefined);
481
- await fs.rm(directory, { recursive: true, force: true });
481
+ await fs.rm(directory, { recursive: true, force: true, maxRetries: 10, retryDelay: 20 });
482
482
  }
483
483
  });
484
484
 
@@ -512,7 +512,7 @@ test("a piece wanted later than the one it would displace goes to disk instead",
512
512
  }
513
513
  } finally {
514
514
  store.destroy(() => undefined);
515
- await fs.rm(directory, { recursive: true, force: true });
515
+ await fs.rm(directory, { recursive: true, force: true, maxRetries: 10, retryDelay: 20 });
516
516
  }
517
517
  });
518
518
 
@@ -542,6 +542,6 @@ test("a piece the map wants more displaces one it wants less, however far away i
542
542
  assert.ok((await get(store, 95)).equals(pieceOf(95)));
543
543
  } finally {
544
544
  store.destroy(() => undefined);
545
- await fs.rm(directory, { recursive: true, force: true });
545
+ await fs.rm(directory, { recursive: true, force: true, maxRetries: 10, retryDelay: 20 });
546
546
  }
547
547
  });
@@ -39,6 +39,25 @@ function makeDisk({ failWrite = false, failRead = false, holdWrites = false } =
39
39
  get size() {
40
40
  return stored.size;
41
41
  },
42
+ get bytes() {
43
+ let total = 0;
44
+ for (const value of stored.values()) {
45
+ total += value.length;
46
+ }
47
+ return total;
48
+ },
49
+ get path() {
50
+ return ".";
51
+ },
52
+ get allowanceBytes() {
53
+ return null;
54
+ },
55
+ reviseAllowance() {
56
+ return null;
57
+ },
58
+ stats() {
59
+ return { pieces: stored.size, bytes: this.bytes, allowanceBytes: null, evictions: 0 };
60
+ },
42
61
  has(index) {
43
62
  return stored.has(index);
44
63
  },
@@ -247,7 +266,7 @@ test("a piece written back to memory is not resurrected on disk by its own spill
247
266
 
248
267
  // The swarm hands piece 0 back while that write is still going. The store
249
268
  // must drop the disk copy AFTER the write has recorded it, not before —
250
- // `DiskTier.write` adds the index on completion, so an early forget is
269
+ // `PieceDiskStore.write` adds the index on completion, so an early forget is
251
270
  // undone and the next read of piece 0 comes back from before the rewrite.
252
271
  let settled = false;
253
272
  const rewritten = put(store, 0);
@@ -55,6 +55,21 @@ function heldDisk() {
55
55
  get size() {
56
56
  return stored.size;
57
57
  },
58
+ get bytes() {
59
+ return 0;
60
+ },
61
+ get path() {
62
+ return ".";
63
+ },
64
+ get allowanceBytes() {
65
+ return null;
66
+ },
67
+ reviseAllowance() {
68
+ return null;
69
+ },
70
+ stats() {
71
+ return { pieces: stored.size, bytes: 0, allowanceBytes: null, evictions: 0 };
72
+ },
58
73
  has: (index) => stored.has(index),
59
74
  forget: (index) => stored.delete(index),
60
75
  write(index) {
@@ -139,6 +154,6 @@ test("memory in use never runs past the allowance while the disk is behind", asy
139
154
  assert.ok(store.stats().blocksInUse <= capacity + 1, "the pool did not settle");
140
155
  } finally {
141
156
  store.destroy(() => undefined);
142
- await fs.rm(directory, { recursive: true, force: true });
157
+ await fs.rm(directory, { recursive: true, force: true, maxRetries: 10, retryDelay: 20 });
143
158
  }
144
159
  });