@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.
- package/CHANGELOG.md +22 -0
- package/docs/encode-architecture.md +51 -2
- package/package.json +1 -1
- package/research/double-spawn-2026-09-10.md +171 -0
- package/services/disk/DiskSpace.js +146 -0
- package/services/disk/wire.js +60 -0
- package/services/encode/EncodeRun.js +37 -9
- package/services/encode/SegmentStore.js +284 -232
- package/services/encode/run-command.js +16 -1
- package/services/hls-session-manager.js +31 -128
- package/services/orchestrators/EncodeOrchestrator.js +52 -38
- package/services/piece-store/allowance.js +107 -0
- package/services/piece-store/piece-disk-store.js +365 -0
- package/services/piece-store/shared-piece-store.js +1549 -1535
- package/services/segment-formats/fmp4.js +54 -0
- package/services/segment-formats/mpegts.js +54 -0
- package/services/torrent-worker/client.js +32 -0
- package/services/torrent-worker/pool-adapter.js +15 -0
- package/services/torrent-worker/protocol.js +9 -0
- package/services/torrent-worker/worker.js +8 -1
- package/services/viewer/positions.js +48 -0
- package/test/audio-inventory.test.js +176 -176
- package/test/auto-quality-step.test.js +514 -514
- package/test/concurrent-cost.test.js +138 -138
- package/test/coverage-follows-the-disk.test.js +191 -187
- package/test/coverage-map.test.js +195 -195
- package/test/declared-tracks.test.js +35 -35
- package/test/disk-space.test.js +138 -0
- package/test/encode-orchestrator.test.js +0 -3
- package/test/encode-run.test.js +5 -12
- package/test/held-request-width.test.js +155 -155
- package/test/helpers/encode-run.js +2 -2
- package/test/matroska-blocks.test.js +0 -0
- package/test/matroska-cues-track.test.js +192 -192
- package/test/mp4-composition-times.test.js +0 -0
- package/test/mp4-subtitles.test.js +173 -173
- package/test/one-authority.test.js +281 -220
- package/test/orchestrator-wired.test.js +199 -195
- package/test/packet-witness-ring.test.js +236 -236
- package/test/packet-witness.test.js +148 -148
- package/test/piece-disk-store.test.js +267 -0
- package/test/piece-reader.test.js +4 -4
- package/test/piece-store-eviction.test.js +17 -17
- package/test/piece-store-reservations.test.js +20 -1
- package/test/piece-store-slow-disk.test.js +16 -1
- package/test/produced-copy-choice.test.js +258 -358
- package/test/read-window.test.js +6 -6
- package/test/run-intervals.test.js +100 -100
- package/test/seek-landing.test.js +109 -109
- package/test/segment-serve-wiring.test.js +8 -9
- package/test/segment-store-eviction.test.js +232 -0
- package/test/segment-store.test.js +238 -216
- package/test/segments-are-shared.test.js +1 -1
- package/test/shared-piece-store.test.js +12 -12
- package/test/sidecar-naming.test.js +142 -142
- package/test/subtitle-cue-framing.test.js +200 -200
- package/test/subtitle-cue-walk.test.js +369 -369
- package/test/subtitle-defaults.test.js +97 -97
- package/test/subtitle-track-numbering.test.js +370 -370
- package/test/tail-duplication.test.js +167 -167
- package/test/tracks-begin-together.test.js +195 -195
- package/test/two-viewers-one-picture.test.js +374 -374
- package/test/video-facts.test.js +102 -102
- package/test/wedge-certainty.test.js +131 -131
- package/services/encode/open-piece.js +0 -135
- package/services/piece-store/disk-tier.js +0 -151
- 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
|
-
|
|
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
|
-
// `
|
|
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
|
});
|