@torrent-tv/proxy 2.98.5 → 2.98.6
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/package.json
CHANGED
package/server.js
CHANGED
|
@@ -200,7 +200,7 @@ export async function startProxyServer({
|
|
|
200
200
|
// The ONE forward reference here, and it is safe by construction: this fires
|
|
201
201
|
// only once the worker thread is up and a piece has verified, which is long
|
|
202
202
|
// after the declarations below have run.
|
|
203
|
-
onPiecesArrived: ({ sourceKey, fileIndexes }) => {
|
|
203
|
+
onPiecesArrived: ({ sourceKey, fileIndexes, arrived }) => {
|
|
204
204
|
for (const fileIndex of fileIndexes) {
|
|
205
205
|
mediaReads.bytesChanged(sourceKey, fileIndex);
|
|
206
206
|
probeReads.bytesChanged(sourceKey, fileIndex);
|
|
@@ -211,7 +211,9 @@ export async function startProxyServer({
|
|
|
211
211
|
// is read again now; nothing was recorded for that wait.
|
|
212
212
|
keyframeTables.readAgainIfUnanswered({ sourceKey, fileIndex, logName: String(fileIndex) });
|
|
213
213
|
}
|
|
214
|
-
|
|
214
|
+
// Which bytes arrived, when the event names them: an input waiting for
|
|
215
|
+
// named bytes is tried again only when some of them have come.
|
|
216
|
+
outputParts.encodeInputs?.bytesChanged(Array.isArray(arrived) ? { sourceKey, ranges: arrived } : null);
|
|
215
217
|
}
|
|
216
218
|
});
|
|
217
219
|
const selectedPort = await getPort({
|
|
@@ -259,10 +259,27 @@ export class EncodeInputs {
|
|
|
259
259
|
return this.take(output, from, to);
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
-
|
|
262
|
+
/**
|
|
263
|
+
* Bytes of a source changed: every waiting input is tried again, except one
|
|
264
|
+
* that waits for named bytes none of which have come. Tried at every piece
|
|
265
|
+
* of the file, a seek's input was prepared 28 times in 8.5 s on Home
|
|
266
|
+
* Assistant, each time asking the torrent thread which ranges it holds
|
|
267
|
+
* (171 ms on average), and the try that found its bytes could start only
|
|
268
|
+
* after the one in flight (r34, torrent-tv/meta#178).
|
|
269
|
+
*
|
|
270
|
+
* @param {{ sourceKey: string, ranges: Array<{ fileIndex: number, start: number, end: number }> } | null} [arrived] -
|
|
271
|
+
* The bytes that arrived, inclusive, when the event names them.
|
|
272
|
+
*/
|
|
273
|
+
bytesChanged(arrived = null) {
|
|
263
274
|
this.#revision++;
|
|
264
275
|
for (const request of this.#requests.values()) {
|
|
265
|
-
if (
|
|
276
|
+
if (request.pending || request.result?.kind === "result" || request.result?.kind === "terminal") continue;
|
|
277
|
+
if (arrived && request.result?.kind === "needs-bytes" && !awaitedIn(request.result, arrived)) {
|
|
278
|
+
// Nothing it waits for has come: it stands as tried at this revision.
|
|
279
|
+
request.revision = this.#revision;
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
this.#prepare(request);
|
|
266
283
|
}
|
|
267
284
|
}
|
|
268
285
|
|
|
@@ -486,7 +503,9 @@ export class EncodeInputs {
|
|
|
486
503
|
// found pieces missing, and the run was refused for good (torrent-tv/meta#178).
|
|
487
504
|
if (this.#heldRanges !== null && !await this.#present(chosen.sources, held, request.timing)) {
|
|
488
505
|
const [first] = chosen.sources;
|
|
489
|
-
return { kind: "needs-bytes", sourceKey: first.sourceKey, fileIndex: first.fileIndex, ranges: first.input.ranges
|
|
506
|
+
return { kind: "needs-bytes", sourceKey: first.sourceKey, fileIndex: first.fileIndex, ranges: first.input.ranges,
|
|
507
|
+
// Every source of the stretch, so the bytes of any of them wake it.
|
|
508
|
+
awaiting: chosen.sources.map(source => ({ sourceKey: source.sourceKey, fileIndex: source.fileIndex, ranges: source.input.ranges })) };
|
|
490
509
|
}
|
|
491
510
|
if (this.#requests.get(request.key) !== request) return undefined;
|
|
492
511
|
this.#wanted.set(request.key, { wanted: chosen.bytes, required: chosen.bytes });
|
|
@@ -527,6 +546,21 @@ export class EncodeInputs {
|
|
|
527
546
|
}
|
|
528
547
|
}
|
|
529
548
|
|
|
549
|
+
/**
|
|
550
|
+
* Whether some of the bytes an input waits for are among those that arrived.
|
|
551
|
+
*
|
|
552
|
+
* @param {{ sourceKey: string, fileIndex: number, ranges: Array<[number, number]>,
|
|
553
|
+
* awaiting?: Array<{ sourceKey: string, fileIndex: number, ranges: Array<[number, number]> }> }} waiting
|
|
554
|
+
* @param {{ sourceKey: string, ranges: Array<{ fileIndex: number, start: number, end: number }> }} arrived
|
|
555
|
+
* @returns {boolean}
|
|
556
|
+
*/
|
|
557
|
+
function awaitedIn(waiting, arrived) {
|
|
558
|
+
const sources = waiting.awaiting ?? [waiting];
|
|
559
|
+
return sources.some(source => source.sourceKey === arrived.sourceKey && Array.isArray(source.ranges) &&
|
|
560
|
+
arrived.ranges.some(range => range.fileIndex === source.fileIndex &&
|
|
561
|
+
source.ranges.some(([start, end]) => range.start <= end && range.end >= start)));
|
|
562
|
+
}
|
|
563
|
+
|
|
530
564
|
/**
|
|
531
565
|
* Where a request has spent its time since it was asked, as one clause of its
|
|
532
566
|
* log line. The resolutions include the reads of the file they made, and those
|
|
@@ -1300,6 +1300,7 @@ export class TorrentPool {
|
|
|
1300
1300
|
// depend on facts that are gone by the time it is said.
|
|
1301
1301
|
if (Array.isArray(zones) && zones.length === 0) {
|
|
1302
1302
|
withdrawPriorityMap(torrent, fileIndex);
|
|
1303
|
+
reconcileAll();
|
|
1303
1304
|
// The ends of the file go with it. They are kept for as long as the file
|
|
1304
1305
|
// is open, and this is what says it is not.
|
|
1305
1306
|
// And this may have been the last thing anybody wanted of this torrent.
|
|
@@ -1346,6 +1347,11 @@ export class TorrentPool {
|
|
|
1346
1347
|
// Bands the map no longer has: a viewer moved on, and what they had wanted
|
|
1347
1348
|
// is not wanted by anybody now.
|
|
1348
1349
|
withdrawPriorityMap(torrent, fileIndex, ordered.length);
|
|
1350
|
+
// THE SWARM IS TOLD WHEN THE MAP IS APPLIED, not at the next piece verified
|
|
1351
|
+
// or the pool's timer: on Home Assistant a seek's map was applied and the
|
|
1352
|
+
// swarm went on fetching the old first class for 1.16 s, until the next
|
|
1353
|
+
// piece happened to be verified (r34, torrent-tv/meta#178).
|
|
1354
|
+
reconcileAll();
|
|
1349
1355
|
// WHAT THE SWARM WAS ACTUALLY TOLD, said on change and never on a timer.
|
|
1350
1356
|
// The map was applied in silence: that it had been BUILT was visible in the
|
|
1351
1357
|
// encoding's own line, and that the download had received it was visible
|
|
@@ -254,7 +254,8 @@ export class TorrentWorkerClient {
|
|
|
254
254
|
this.#onPiecesArrived({
|
|
255
255
|
sourceKey: message.sourceKey,
|
|
256
256
|
fileIndexes: Array.isArray(message.fileIndexes) ? message.fileIndexes : [],
|
|
257
|
-
...(typeof message.reason === "string" ? { reason: message.reason } : {})
|
|
257
|
+
...(typeof message.reason === "string" ? { reason: message.reason } : {}),
|
|
258
|
+
...(Array.isArray(message.arrived) ? { arrived: message.arrived } : {})
|
|
258
259
|
});
|
|
259
260
|
break;
|
|
260
261
|
default:
|
|
@@ -881,12 +881,36 @@ function describePieceBuffers() {
|
|
|
881
881
|
* @param {object} torrent
|
|
882
882
|
* @returns {void}
|
|
883
883
|
*/
|
|
884
|
-
function announceArrivals(sourceKey, torrent, reason = "verified") {
|
|
884
|
+
function announceArrivals(sourceKey, torrent, reason = "verified", piece = null) {
|
|
885
885
|
const fileIndexes = [...demandFor(torrent).register.files()];
|
|
886
886
|
if (fileIndexes.length === 0) {
|
|
887
887
|
return;
|
|
888
888
|
}
|
|
889
|
-
parentPort.postMessage({ type: Event.PIECES_CHANGED, sourceKey, fileIndexes, reason
|
|
889
|
+
parentPort.postMessage({ type: Event.PIECES_CHANGED, sourceKey, fileIndexes, reason,
|
|
890
|
+
...(Number.isSafeInteger(piece) ? { arrived: bytesOfPiece(torrent, piece) } : {}) });
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
/**
|
|
894
|
+
* The bytes of one piece, as each file it covers counts them: what a reader
|
|
895
|
+
* waiting for named bytes compares against, so a piece of another part of the
|
|
896
|
+
* file wakes nobody (torrent-tv/meta#178).
|
|
897
|
+
*
|
|
898
|
+
* @param {object} torrent
|
|
899
|
+
* @param {number} piece
|
|
900
|
+
* @returns {Array<{ fileIndex: number, start: number, end: number }>} Inclusive.
|
|
901
|
+
*/
|
|
902
|
+
function bytesOfPiece(torrent, piece) {
|
|
903
|
+
const pieceLength = Number(torrent.pieceLength);
|
|
904
|
+
const length = Number(torrent.length);
|
|
905
|
+
if (!(pieceLength > 0) || !(length > 0)) return [];
|
|
906
|
+
const start = piece * pieceLength;
|
|
907
|
+
const end = Math.min(length, start + pieceLength) - 1;
|
|
908
|
+
const arrived = [];
|
|
909
|
+
(torrent.files ?? []).forEach((file, fileIndex) => {
|
|
910
|
+
const from = Math.max(start, file.offset), to = Math.min(end, file.offset + file.length - 1);
|
|
911
|
+
if (to >= from) arrived.push({ fileIndex, start: from - file.offset, end: to - file.offset });
|
|
912
|
+
});
|
|
913
|
+
return arrived;
|
|
890
914
|
}
|
|
891
915
|
|
|
892
916
|
|
|
@@ -917,7 +941,7 @@ function ensureArrivalsWired(sourceKey, torrent) {
|
|
|
917
941
|
}
|
|
918
942
|
arrivalsWired.add(torrent);
|
|
919
943
|
holdingsChanged();
|
|
920
|
-
torrent.on("verified", () => announceArrivals(sourceKey, torrent));
|
|
944
|
+
torrent.on("verified", (piece) => announceArrivals(sourceKey, torrent, "verified", piece));
|
|
921
945
|
torrent.on("piece-withdrawn", () => announceArrivals(sourceKey, torrent, "withdrawn"));
|
|
922
946
|
torrent.once("close", () => {
|
|
923
947
|
if (resolvedTorrents.get(sourceKey) !== torrent) return;
|