@torrent-tv/proxy 2.83.3 → 2.83.4

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.
@@ -1,91 +0,0 @@
1
- /**
2
- * @file Who is holding which file open.
3
- *
4
- * A claim keeps a file's data from being removed while something is reading it.
5
- * Until 2.9.77 claims were keyed by `sourceKey:fileIndex`, which quietly made
6
- * them **shared**: a second reader of the same file found the key taken and
7
- * added nothing, so the first reader to finish released the claim out from
8
- * under the second. The proxy reads one file from several places at once —
9
- * ffmpeg's input, the keyframe index, the codec probe, a second viewer — so
10
- * this was the normal case, not an edge one.
11
- *
12
- * The fix is not a counter. A counter restores the arithmetic but keeps the
13
- * ambiguity: a release names a file, not a claim, so a duplicate or late
14
- * release still decrements someone else's hold and nothing can detect it. Here
15
- * every claim gets its own identity and a release names exactly that claim —
16
- * so a stray release matches nothing, is reported, and harms no one.
17
- */
18
-
19
- /**
20
- * @typedef {object} FileClaims
21
- * @property {(sourceKey: string, fileIndex: number, release: () => void) => string} open
22
- * @property {(claimId: string) => boolean} close
23
- * @property {() => void} closeAll
24
- * @property {number} size
25
- */
26
-
27
- /**
28
- * Track file claims by identity.
29
- *
30
- * @returns {FileClaims}
31
- */
32
- export function createFileClaims() {
33
- /** Claim id → the function that releases that one claim. */
34
- const claims = new Map();
35
- let counter = 0;
36
-
37
- return {
38
- /**
39
- * Record a new claim and return its identity.
40
- *
41
- * Each call is a distinct claim even for the same file — that is the whole
42
- * point.
43
- *
44
- * @param {string} sourceKey
45
- * @param {number} fileIndex
46
- * @param {() => void} release
47
- * @returns {string}
48
- */
49
- open(sourceKey, fileIndex, release) {
50
- counter += 1;
51
- // The file is in the id purely so a log line reads usefully; matching is
52
- // on the whole string.
53
- const claimId = `${sourceKey}:${fileIndex}:${counter}`;
54
- claims.set(claimId, release);
55
- return claimId;
56
- },
57
-
58
- /**
59
- * Release one claim. Returns false when there was no such claim, which is
60
- * worth logging: it means a release arrived twice, or after teardown.
61
- *
62
- * @param {string} claimId
63
- * @returns {boolean}
64
- */
65
- close(claimId) {
66
- const release = claims.get(claimId);
67
- if (!release) {
68
- return false;
69
- }
70
- claims.delete(claimId);
71
- release();
72
- return true;
73
- },
74
-
75
- /**
76
- * Release everything — the worker is shutting down.
77
- *
78
- * @returns {void}
79
- */
80
- closeAll() {
81
- for (const [, release] of claims) {
82
- release();
83
- }
84
- claims.clear();
85
- },
86
-
87
- get size() {
88
- return claims.size;
89
- }
90
- };
91
- }
@@ -1,64 +0,0 @@
1
- /**
2
- * @file File claims must be held per reader, not per file.
3
- *
4
- * The proxy reads one file from several places at once — ffmpeg's input, the
5
- * keyframe index, the codec probe, a second viewer. Keying claims by file made
6
- * them shared, so the first reader to finish released the hold while the others
7
- * were still reading, and the file's data could then be removed under them.
8
- */
9
-
10
- import test from "node:test";
11
- import assert from "node:assert/strict";
12
- import { createFileClaims } from "../services/torrent-worker/file-claims.js";
13
-
14
- test("two readers of one file hold two claims", () => {
15
- const claims = createFileClaims();
16
- let released = 0;
17
-
18
- const first = claims.open("source", 0, () => (released += 1));
19
- const second = claims.open("source", 0, () => (released += 1));
20
-
21
- assert.notEqual(first, second, "the second reader reused the first one's claim");
22
- assert.equal(claims.size, 2);
23
-
24
- claims.close(first);
25
- assert.equal(released, 1, "closing one claim released more than one hold");
26
- assert.equal(claims.size, 1, "the second reader's claim went with the first");
27
-
28
- claims.close(second);
29
- assert.equal(released, 2);
30
- assert.equal(claims.size, 0);
31
- });
32
-
33
- test("a repeated release affects nothing and reports itself", () => {
34
- const claims = createFileClaims();
35
- let released = 0;
36
- const claimId = claims.open("source", 3, () => (released += 1));
37
-
38
- assert.equal(claims.close(claimId), true);
39
- assert.equal(claims.close(claimId), false, "a second release was accepted as valid");
40
- assert.equal(released, 1, "the hold was released twice");
41
- });
42
-
43
- test("a release naming nothing is rejected rather than guessed at", () => {
44
- const claims = createFileClaims();
45
- let released = 0;
46
- claims.open("source", 0, () => (released += 1));
47
-
48
- assert.equal(claims.close("source:0:999"), false);
49
- assert.equal(released, 0, "an unknown claim released a real hold");
50
- assert.equal(claims.size, 1);
51
- });
52
-
53
- test("teardown releases every outstanding claim", () => {
54
- const claims = createFileClaims();
55
- let released = 0;
56
- claims.open("a", 0, () => (released += 1));
57
- claims.open("a", 1, () => (released += 1));
58
- claims.open("b", 0, () => (released += 1));
59
-
60
- claims.closeAll();
61
-
62
- assert.equal(released, 3);
63
- assert.equal(claims.size, 0);
64
- });