@torrent-tv/proxy 2.80.0 → 2.80.1

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.
@@ -0,0 +1,156 @@
1
+ /**
2
+ * @file What the download is told when the priority map changes.
3
+ *
4
+ * The map states seconds of film against a number. This is the one place those
5
+ * seconds become bytes, and the one place the map's own scale — as many bands
6
+ * as the film needs — is fitted onto the five levels the register has. Both
7
+ * were written on 2026-09-05 to replace the windows the reads themselves used
8
+ * to declare: fifteen reads on one file were fifteen windows on a piece store
9
+ * holding sixteen pieces, and half of all evictions then took a piece a reader
10
+ * had said it wanted.
11
+ */
12
+
13
+ import test from "node:test";
14
+ import assert from "node:assert/strict";
15
+ import { TorrentPool } from "../services/torrent-pool.js";
16
+ import { demandFor, forgetTorrent } from "../services/download/registry.js";
17
+ import { Urgency } from "../services/demand/index.js";
18
+ import { mapForViewer } from "../services/priority/PriorityMap.js";
19
+
20
+ /** A torrent that is nothing but one file of a known length. */
21
+ function torrentOf({ length = 1_000_000, offset = 0 } = {}) {
22
+ return {
23
+ infoHash: `hash-${Math.random().toString(36).slice(2)}`,
24
+ pieceLength: 1024,
25
+ files: [{ offset, length, name: "film.mkv" }],
26
+ _selections: { _items: [] },
27
+ _select() {},
28
+ _deselect() {},
29
+ critical() {}
30
+ };
31
+ }
32
+
33
+ /** The pool's method under test, called without building a pool. */
34
+ const applyPriorityMap = TorrentPool.prototype.applyPriorityMap;
35
+
36
+ test("seconds of film become bytes of the file", () => {
37
+ const torrent = torrentOf({ length: 1000 });
38
+ try {
39
+ applyPriorityMap.call(null, torrent, 0, [
40
+ { from: 0, to: 100, priority: 5 },
41
+ { from: 100, to: 200, priority: 3 }
42
+ ], 200);
43
+
44
+ const { register } = demandFor(torrent);
45
+ const stated = register.windows().filter((one) => String(one.claimant).startsWith("priority-map:"));
46
+ assert.equal(stated.length, 2);
47
+ const first = stated.find((one) => one.byteStart === 0);
48
+ assert.equal(first.byteEnd, 499, "half the film is half the file");
49
+ const second = stated.find((one) => one.byteStart === 500);
50
+ assert.equal(second.byteEnd, 999, "the last byte of the file, not one past it");
51
+ } finally {
52
+ forgetTorrent(torrent);
53
+ }
54
+ });
55
+
56
+ test("a zone is stated at the level it means, not at the level of its position", () => {
57
+ const torrent = torrentOf();
58
+ try {
59
+ // A viewer 300 s into a 3000 s film: one band behind them that nobody is
60
+ // approaching, then bands of decreasing urgency ahead.
61
+ const zones = mapForViewer({
62
+ atSeconds: 300,
63
+ durationSeconds: 3000,
64
+ allowanceSeconds: 10
65
+ });
66
+ assert.ok(zones.length > 5, "the map should be finer than the register's levels");
67
+
68
+ applyPriorityMap.call(null, torrent, 0, zones, 3000);
69
+ const { register } = demandFor(torrent);
70
+ const stated = register.windows().filter((one) => String(one.claimant).startsWith("priority-map:"));
71
+
72
+ const near = stated.filter((one) => one.urgency === Urgency.NEAR);
73
+ assert.equal(near.length, 1, "exactly one band is where the viewer is");
74
+ assert.equal(near[0].byteStart, Math.floor((300 / 3000) * 1_000_000));
75
+
76
+ const behind = stated.filter((one) => one.urgency === Urgency.BEHIND);
77
+ assert.equal(behind.length, 1, "what nobody is approaching is the one thing wanted last");
78
+ assert.equal(behind[0].byteStart, 0, "and it is the stretch behind the viewer");
79
+
80
+ assert.ok(
81
+ stated.some((one) => one.urgency === Urgency.AHEAD),
82
+ "the lead being built was stated at no level of its own"
83
+ );
84
+ assert.ok(
85
+ stated.every((one) => one.urgency !== Urgency.BLOCKED),
86
+ "the map claimed BLOCKED, which only a reader stopped on those bytes may say"
87
+ );
88
+ } finally {
89
+ forgetTorrent(torrent);
90
+ }
91
+ });
92
+
93
+ test("a viewer who has stopped the picture makes the whole film wanted last", () => {
94
+ const torrent = torrentOf();
95
+ try {
96
+ const zones = mapForViewer({
97
+ atSeconds: 300,
98
+ durationSeconds: 3000,
99
+ allowanceSeconds: 10,
100
+ playing: false
101
+ });
102
+ applyPriorityMap.call(null, torrent, 0, zones, 3000);
103
+
104
+ const { register } = demandFor(torrent);
105
+ const stated = register.windows().filter((one) => String(one.claimant).startsWith("priority-map:"));
106
+ assert.equal(stated.length, 1, "a viewer going nowhere makes one band of the whole film");
107
+ // Wanted last ABSOLUTELY, not relative to this film's own map. The two
108
+ // speculative levels are withheld across every torrent at once while
109
+ // anything urgent is missing anywhere, so this has to lose to a film
110
+ // somebody is actually watching — and judged against itself alone it would
111
+ // be the most urgent thing there is.
112
+ assert.equal(stated[0].urgency, Urgency.BEHIND);
113
+ } finally {
114
+ forgetTorrent(torrent);
115
+ }
116
+ });
117
+
118
+ test("a map with fewer bands than the last one leaves nothing stated behind", () => {
119
+ const torrent = torrentOf();
120
+ try {
121
+ applyPriorityMap.call(null, torrent, 0, [
122
+ { from: 0, to: 100, priority: 5 },
123
+ { from: 100, to: 200, priority: 4 },
124
+ { from: 200, to: 300, priority: 3 }
125
+ ], 300);
126
+ const { register } = demandFor(torrent);
127
+ assert.equal(
128
+ register.windows().filter((one) => String(one.claimant).startsWith("priority-map:")).length,
129
+ 3
130
+ );
131
+
132
+ applyPriorityMap.call(null, torrent, 0, [{ from: 0, to: 300, priority: 5 }], 300);
133
+ assert.equal(
134
+ register.windows().filter((one) => String(one.claimant).startsWith("priority-map:")).length,
135
+ 1,
136
+ "bands the map no longer has went on being asked for"
137
+ );
138
+ } finally {
139
+ forgetTorrent(torrent);
140
+ }
141
+ });
142
+
143
+ test("a file of unknown length or duration is not guessed at", () => {
144
+ const torrent = torrentOf();
145
+ try {
146
+ applyPriorityMap.call(null, torrent, 0, [{ from: 0, to: 100, priority: 5 }], 0);
147
+ applyPriorityMap.call(null, torrent, 7, [{ from: 0, to: 100, priority: 5 }], 300);
148
+ const { register } = demandFor(torrent);
149
+ assert.equal(
150
+ register.windows().filter((one) => String(one.claimant).startsWith("priority-map:")).length,
151
+ 0
152
+ );
153
+ } finally {
154
+ forgetTorrent(torrent);
155
+ }
156
+ });
@@ -10,77 +10,6 @@ import test from "node:test";
10
10
  import assert from "node:assert/strict";
11
11
  import { mapForViewer, mergeMaps, inWorkingOrder } from "../services/priority/PriorityMap.js";
12
12
 
13
- test("a viewer's own position is the most urgent thing there is", () => {
14
- const map = mapForViewer({
15
- atSeconds: 100,
16
- durationSeconds: 1000,
17
- allowanceSeconds: 8,
18
- encodeSpeedX: 2
19
- });
20
-
21
- assert.equal(map[0].from, 100);
22
- assert.equal(map[0].to, 108, "above realtime, only the measured allowance");
23
- for (const zone of map.slice(1)) {
24
- assert.ok(zone.priority < map[0].priority);
25
- }
26
- });
27
-
28
- test("a machine that cannot keep up needs more encoders, not a longer first zone", () => {
29
- // An encoder starting where the viewer stands stays ahead of them for
30
- // `held x s / (1 - s)`, so the SLOWER the machine the shorter that is — and
31
- // the film is held by more encoders rather than by one working further.
32
- const slow = mapForViewer({
33
- atSeconds: 0,
34
- durationSeconds: 1000,
35
- allowanceSeconds: 10,
36
- encodeSpeedX: 0.25
37
- });
38
- const quicker = mapForViewer({
39
- atSeconds: 0,
40
- durationSeconds: 1000,
41
- allowanceSeconds: 10,
42
- encodeSpeedX: 0.5
43
- });
44
-
45
- assert.ok(
46
- slow[0].to - slow[0].from < quicker[0].to - quicker[0].from,
47
- "the slower machine holds the viewer for less"
48
- );
49
- assert.ok(slow.length > quicker.length, "so more encoders are needed to hold the film");
50
- });
51
-
52
- test("the first zone is exactly what one encoder can hold", () => {
53
- // `held x s / (1 - s)`: ten seconds held at half speed is ten seconds held,
54
- // and the encoder is caught exactly there. A longer first zone would stall
55
- // the viewer inside it; a shorter one would start the next encoder nearer,
56
- // where its own bound is tighter.
57
- const map = mapForViewer({
58
- atSeconds: 0,
59
- durationSeconds: 100,
60
- allowanceSeconds: 10,
61
- encodeSpeedX: 0.5
62
- });
63
-
64
- assert.equal(map[0].to, 10);
65
- assert.equal(map[1].to, 30, "the next holds three times as long, because they arrive later");
66
- assert.equal(map[2].to, 70);
67
- });
68
-
69
- test("a viewer holding nothing is told the whole of it is urgent", () => {
70
- // With nothing held, no partition holds them: the first encoder stays ahead
71
- // for zero seconds. Slicing the film into equal slivers would pretend
72
- // otherwise.
73
- const map = mapForViewer({
74
- atSeconds: 0,
75
- durationSeconds: 1000,
76
- allowanceSeconds: 0,
77
- encodeSpeedX: 0.25
78
- });
79
-
80
- assert.equal(map.length, 1);
81
- assert.equal(map[0].to, 1000);
82
- });
83
-
84
13
  test("the rest of the track is still wanted, and wanted last", () => {
85
14
  const map = mapForViewer({ atSeconds: 0, durationSeconds: 1000, allowanceSeconds: 4, encodeSpeedX: 2 });
86
15
 
@@ -93,12 +22,6 @@ test("the rest of the track is still wanted, and wanted last", () => {
93
22
  }
94
23
  });
95
24
 
96
- test("nothing is measured yet: the middle zone is left out rather than invented", () => {
97
- const map = mapForViewer({ atSeconds: 0, durationSeconds: 100, allowanceSeconds: 4, encodeSpeedX: 0 });
98
-
99
- assert.equal(map.length, 2, "what must be ready, and the rest");
100
- });
101
-
102
25
  test("two viewers merge to the highest priority per second, with no overlaps", () => {
103
26
  const first = mapForViewer({ atSeconds: 0, durationSeconds: 1000, allowanceSeconds: 8, encodeSpeedX: 2 });
104
27
  const second = mapForViewer({ atSeconds: 500, durationSeconds: 1000, allowanceSeconds: 8, encodeSpeedX: 2 });
@@ -137,3 +60,53 @@ test("within one priority the earliest film goes first — that is where somebod
137
60
 
138
61
  assert.deepEqual(order.map((zone) => zone.from), [0, 100, 900]);
139
62
  });
63
+
64
+ test("the nearer a viewer is to a second, the higher its number", () => {
65
+ // The number is a reading of how far they still have to travel, and nothing
66
+ // else. That is what makes two viewers comparable at all.
67
+ const map = mapForViewer({ atSeconds: 300, durationSeconds: 3000, allowanceSeconds: 10 });
68
+ const ahead = map.filter((zone) => zone.from >= 300);
69
+
70
+ assert.equal(ahead[0].from, 300, "it starts where they are");
71
+ assert.equal(ahead[0].to, 310, "and the first band is the measured allowance");
72
+ for (let index = 1; index < ahead.length; index += 1) {
73
+ assert.ok(ahead[index].priority < ahead[index - 1].priority, "further off is less urgent");
74
+ }
75
+ });
76
+
77
+ test("the bands widen, so any film is described by a handful of them", () => {
78
+ // Near the viewer the difference between now and ten seconds away decides
79
+ // what is made first; twenty minutes out it changes nothing.
80
+ const map = mapForViewer({ atSeconds: 0, durationSeconds: 3000, allowanceSeconds: 10 });
81
+
82
+ assert.ok(map.length <= 12, `a fifty-minute film in ${map.length} bands`);
83
+ assert.equal(map[0].to - map[0].from, 10);
84
+ assert.equal(map[1].to - map[1].from, 20);
85
+ assert.equal(map[2].to - map[2].from, 40);
86
+ });
87
+
88
+ test("what is behind a viewer is wanted, and wanted last", () => {
89
+ const map = mapForViewer({ atSeconds: 300, durationSeconds: 3000, allowanceSeconds: 10 });
90
+ const behind = map.find((zone) => zone.from === 0);
91
+
92
+ assert.ok(behind, "it is still in the map");
93
+ assert.equal(behind.to, 300);
94
+ assert.ok(
95
+ map.filter((zone) => zone.from >= 300).every((zone) => zone.priority > behind.priority),
96
+ "and everything anybody is approaching outranks it"
97
+ );
98
+ });
99
+
100
+ test("a viewer who has stopped the picture is going nowhere", () => {
101
+ // Nothing is nearer to them than anything else, so nothing in the film is
102
+ // wanted sooner than the rest — and the work goes to whoever is watching.
103
+ const map = mapForViewer({
104
+ atSeconds: 300,
105
+ durationSeconds: 3000,
106
+ allowanceSeconds: 10,
107
+ playing: false
108
+ });
109
+
110
+ assert.equal(map.length, 1);
111
+ assert.deepEqual({ from: map[0].from, to: map[0].to }, { from: 0, to: 3000 });
112
+ });
@@ -8,9 +8,17 @@
8
8
  * seeks. Nothing after that could outrank it: measured on a 4.7 GB film, a seek
9
9
  * to 89.1% waited 93 s while the swarm fetched 2.47 GB in file order.
10
10
  *
11
- * Now a read holds a moving window and returns it when it ends. These tests pin
12
- * the three properties that matter: the claim is bounded, it is given back, and
13
- * several readers add up instead of overwriting each other.
11
+ * Now a read claims only the piece it is STOPPED on, and gives it back when it
12
+ * ends. What should be downloaded ahead of a viewer is the priority map's
13
+ * answer, stated once for the whole file by the side that knows where the
14
+ * viewers are; a read is consumption, not a forecast. Fifteen reads on one file
15
+ * used to declare fifteen windows on a piece store holding sixteen pieces, and
16
+ * half of all evictions then took a piece a reader had declared (field
17
+ * 2026-09-05).
18
+ *
19
+ * These tests pin what is left: a read that is not stopped claims nothing, a
20
+ * read that is stopped claims the pieces it is waiting for and nothing beyond
21
+ * them, and every claim is given back.
14
22
  */
15
23
 
16
24
  import test from "node:test";
@@ -119,12 +127,13 @@ test("the window is bounded and clamped to the end of the read", () => {
119
127
  );
120
128
  });
121
129
 
122
- test("an open-ended read does not claim the whole file at once", async () => {
123
- // 8000 pieces of 1 KB far more than the 32 MB window, so a read to the end
124
- // of the file is exactly the ffmpeg case.
130
+ test("a read that is not stopped claims nothing", async () => {
131
+ // 8000 pieces of 1 KB, every one of them present, and the read asks as ffmpeg
132
+ // does: to the last byte of the file. Nothing is missing, so this read is
133
+ // waiting for nothing, so it wants nothing of the swarm — what lies ahead of
134
+ // it belongs to the priority map.
125
135
  const { torrent, store, directory } = await recordingTorrent({ pieceCount: 8000 });
126
136
  try {
127
- // Read only the first two pieces, but ask as ffmpeg does: to the last byte.
128
137
  const iterator = readFragments({
129
138
  torrent,
130
139
  fileIndex: 0,
@@ -136,15 +145,11 @@ test("an open-ended read does not claim the whole file at once", async () => {
136
145
  const first = await iterator.next();
137
146
  first.value.release();
138
147
 
139
- const selects = torrent.calls.filter((entry) => entry.call === "select");
140
- assert.ok(selects.length >= 1, "the reader claimed nothing");
141
- const claimed = selects[0].to - selects[0].from + 1;
142
- assert.equal(
143
- claimed,
144
- WINDOW_PIECES,
145
- `the reader claimed ${claimed} pieces of the file instead of its window`
148
+ assert.deepEqual(
149
+ torrent.held,
150
+ [],
151
+ "the read declared a window of its own, which is the forecast that has to come from the map"
146
152
  );
147
- assert.equal(selects[0].stream, true, "the claim must be a stream selection, so it can be counted");
148
153
 
149
154
  await iterator.return();
150
155
  } finally {
@@ -187,35 +192,47 @@ test("an abandoned read leaves nothing selected", async () => {
187
192
  }
188
193
  });
189
194
 
190
- test("two readers add up, and one leaving takes only its own", async () => {
191
- const { torrent, store, directory } = await recordingTorrent({ pieceCount: 8000 });
195
+ test("two stopped readers add up, and one leaving takes only its own", async () => {
196
+ // Nothing has arrived yet, so both readers are stopped on their first piece
197
+ // and each states it. Two claims, each withdrawn on its own.
198
+ let arrived = false;
199
+ const { torrent, store, directory } = await recordingTorrent({
200
+ pieceCount: 8000,
201
+ present: () => arrived
202
+ });
192
203
  try {
193
204
  const head = readFragments({
194
205
  torrent, fileIndex: 0, start: 0, end: 8000 * PIECE - 1,
195
- cancellation: { isCancelled: () => false }
206
+ cancellation: { isCancelled: () => false },
207
+ windowBytes: WINDOW_PIECES * PIECE
196
208
  });
197
209
  const tail = readFragments({
198
210
  torrent, fileIndex: 0, start: 4000 * PIECE, end: 8000 * PIECE - 1,
199
- cancellation: { isCancelled: () => false }
211
+ cancellation: { isCancelled: () => false },
212
+ windowBytes: WINDOW_PIECES * PIECE
200
213
  });
201
- (await head.next()).value.release();
202
- (await tail.next()).value.release();
214
+ const headPending = head.next();
215
+ const tailPending = tail.next();
216
+ await new Promise((resolve) => setImmediate(resolve));
203
217
 
204
- // Not a count: each reader states several bands by level, and two readers
205
- // wanting the same pieces are one instruction. What matters is that both
206
- // are represented and that leaving removes only what leaving should.
207
218
  const pieceOf = (range) => Number(range.split("-")[0]);
208
219
  const held = [...torrent.held];
209
- assert.ok(held.some((range) => pieceOf(range) < 4000), "the head reader holds nothing");
210
- assert.ok(held.some((range) => pieceOf(range) >= 4000), "the tail reader holds nothing");
220
+ assert.ok(held.some((range) => pieceOf(range) < 4000), "the head reader claimed nothing");
221
+ assert.ok(held.some((range) => pieceOf(range) >= 4000), "the tail reader claimed nothing");
222
+
223
+ // Let both through to a yield, so ending them runs their `finally` at once.
224
+ arrived = true;
225
+ torrent.emit("verified", 0);
226
+ torrent.emit("verified", 4000);
227
+ (await headPending).value.release();
228
+ (await tailPending).value.release();
211
229
 
212
230
  await tail.return();
213
231
  const after = [...torrent.held];
214
232
  assert.ok(
215
- after.some((range) => pieceOf(range) < 4000),
216
- "the head reader's window went with the tail reader"
233
+ after.every((range) => pieceOf(range) < 4000),
234
+ "the tail reader left its claim behind"
217
235
  );
218
- assert.ok(after.length < held.length, "the tail reader took nothing away when it left");
219
236
 
220
237
  await head.return();
221
238
  assert.deepEqual(torrent.held, [], "the last reader left something behind");
@@ -1,140 +0,0 @@
1
- /**
2
- * @file Claiming what a reader wants in four bands instead of one.
3
- *
4
- * Until now a reader claimed one band at one urgency, and WebTorrent's own
5
- * whole-file selection sat under it at priority 0 — so "what the viewer reaches
6
- * in seconds" and "the rest of the film" were indistinguishable to the picker.
7
- * The bands separate them, and their widths come from what has been measured
8
- * about this file on this swarm rather than from numbers chosen here.
9
- */
10
-
11
- import test from "node:test";
12
- import assert from "node:assert/strict";
13
- import { bandWidthsFrom, bandsFrom, sameBands } from "../services/torrent-worker/piece-reader.js";
14
- import { Urgency } from "../services/demand/Urgency.js";
15
-
16
- const PIECE = 8 * 1024 * 1024;
17
-
18
- test("the urgent band is the one being read, and the lead bands come behind it in order", () => {
19
- const bands = bandsFrom({
20
- urgent: { from: 100, to: 103 },
21
- pieceIndex: 100,
22
- firstPiece: 0,
23
- lastPiece: 1000,
24
- widths: { near: 5, far: 20 }
25
- });
26
-
27
- assert.deepEqual(
28
- bands,
29
- [
30
- { from: 100, to: 103, urgency: Urgency.NEAR },
31
- { from: 104, to: 108, urgency: Urgency.AHEAD },
32
- { from: 109, to: 128, urgency: Urgency.AHEAD }
33
- ],
34
- "no gap, no overlap, and each band strictly less urgent than the one in front"
35
- );
36
- });
37
-
38
- test("no band is speculative while the reader is still walking the file", () => {
39
- const bands = bandsFrom({
40
- urgent: { from: 0, to: 1 },
41
- pieceIndex: 0,
42
- firstPiece: 0,
43
- lastPiece: 100,
44
- widths: { near: 2, far: 2 }
45
- });
46
-
47
- assert.ok(
48
- bands.every((band) => band.urgency <= Urgency.AHEAD),
49
- "a band at 0 would be indistinguishable from the background fill of the whole torrent"
50
- );
51
- });
52
-
53
- test("what was never downloaded behind the viewer is not asked for until the lead reaches the end", () => {
54
- const stillFilling = bandsFrom({
55
- urgent: { from: 50, to: 52 },
56
- pieceIndex: 50,
57
- firstPiece: 0,
58
- lastPiece: 1000,
59
- widths: { near: 4, far: 8 }
60
- });
61
- assert.equal(
62
- stillFilling.length,
63
- 3,
64
- "the film ahead is not covered yet, so the past must not compete with it"
65
- );
66
-
67
- const covered = bandsFrom({
68
- urgent: { from: 50, to: 52 },
69
- pieceIndex: 50,
70
- firstPiece: 0,
71
- lastPiece: 60,
72
- widths: { near: 4, far: 8 }
73
- });
74
- assert.deepEqual(
75
- covered[covered.length - 1],
76
- { from: 0, to: 49, urgency: Urgency.BEHIND },
77
- "once there is nothing left ahead, the gap behind the viewer is worth filling"
78
- );
79
- });
80
-
81
- test("a swarm with no surplus produces no far band, because there is nothing to get ahead with", () => {
82
- const widths = bandWidthsFrom({
83
- worstWaitSec: 2,
84
- medianIntervalSec: 10,
85
- downloadBytesPerSec: 1_000_000,
86
- consumeBytesPerSec: 1_000_000,
87
- pieceLength: PIECE,
88
- basePieces: 4
89
- });
90
-
91
- assert.equal(widths.far, 0, "download rate equals consumption, so no lead can be built");
92
- assert.equal(widths.measured, true);
93
- });
94
-
95
- test("the near band covers the worst interruption this reader has actually met", () => {
96
- // 4 s of a film eaten at 2 MB/s is 8 MB, which is one piece here.
97
- const widths = bandWidthsFrom({
98
- worstWaitSec: 4,
99
- medianIntervalSec: 30,
100
- downloadBytesPerSec: 3_000_000,
101
- consumeBytesPerSec: 2_000_000,
102
- pieceLength: PIECE,
103
- basePieces: 4
104
- });
105
-
106
- assert.equal(widths.near, 1, "worst wait × consumption, in pieces");
107
- // A surplus of 1 MB/s held for 30 s is 30 MB, which is four pieces here.
108
- assert.equal(widths.far, 4, "surplus × the interval it usually runs for, in pieces");
109
- });
110
-
111
- test("with nothing measured yet both lead bands fall back to the reader's own window", () => {
112
- const widths = bandWidthsFrom({
113
- worstWaitSec: null,
114
- medianIntervalSec: null,
115
- downloadBytesPerSec: 5_000_000,
116
- consumeBytesPerSec: 0,
117
- pieceLength: PIECE,
118
- basePieces: 6
119
- });
120
-
121
- assert.deepEqual(widths, { near: 6, far: 6, measured: false });
122
- });
123
-
124
- test("an unchanged claim is recognised, so it is not released and re-made on every read", () => {
125
- const bands = [
126
- { from: 1, to: 2, urgency: Urgency.NEAR },
127
- { from: 3, to: 9, urgency: Urgency.AHEAD }
128
- ];
129
-
130
- assert.equal(sameBands(bands, [...bands.map((band) => ({ ...band }))]), true);
131
- assert.equal(sameBands(bands, [{ from: 1, to: 2, urgency: Urgency.NEAR }]), false);
132
- assert.equal(
133
- sameBands(bands, [
134
- { from: 1, to: 2, urgency: Urgency.NEAR },
135
- { from: 3, to: 9, urgency: Urgency.BEHIND }
136
- ]),
137
- false,
138
- "the same range at another urgency is a different claim"
139
- );
140
- });