@torrent-tv/proxy 2.104.0 → 2.104.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@torrent-tv/proxy",
3
- "version": "2.104.0",
3
+ "version": "2.104.1",
4
4
  "description": "Torrent proxy client that exposes webseed-like HTTP stream endpoint.",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "repository": {
@@ -494,43 +494,50 @@ async function runCommand(command, params, id) {
494
494
  const statsStartedAt = performance.now();
495
495
  emitWaitTrace(params.sourceKey, "W10", "begin", { startedAt: statsStartedAt,
496
496
  fileIndex: params.fileIndex, forecast: params.forecast === true });
497
- const torrent = await knownTorrent(params.sourceKey);
498
- if (!torrent) {
499
- const whole = wholeSources.fileOf(params.sourceKey, params.fileIndex);
500
- emitWaitTrace(params.sourceKey, "W10", "end", { startedAt: statsStartedAt,
501
- endedAt: performance.now(), outcome: whole ? "whole-file" : "pending", fileIndex: params.fileIndex });
502
- return whole ? wholeFileStats(whole.length) : { pending: true };
503
- }
504
- // What this file's own interruptions demand, measured by the reader in
505
- // this thread. It travels with the stats because the caller asking for
506
- // them is the one that has to decide with them — the browser's smallest
507
- // safe buffer, and the speed a quality step must sustain. Null until a
508
- // second interruption has been seen: one wait shows no interval, and an
509
- // interval invented from one point is exactly what this work removes.
510
- const file = Array.isArray(torrent?.files) ? torrent.files[params.fileIndex] : null;
511
- const forecastAt = performance.now();
512
- const forecast = file && params.forecast === true ? downloadForecastOf(torrent) : null;
513
- const forecastMs = params.forecast === true ? performance.now() - forecastAt : 0;
514
- const stats = pool.getFileStats(torrent, params.fileIndex);
515
- const ranges = [];
516
- if (forecast) for (const [piece, availableAt] of forecast.arrivals) {
517
- const start = piece * torrent.pieceLength;
518
- const end = Math.min(torrent.length, (piece + 1) * torrent.pieceLength);
519
- if (end > start) ranges.push({ start, end, availableAt });
520
- }
521
- emitWaitTrace(params.sourceKey, "W10", "end", { startedAt: statsStartedAt,
522
- endedAt: performance.now(), outcome: "ok", fileIndex: params.fileIndex,
523
- forecast: params.forecast === true });
524
- return {
525
- ...stats,
526
- ...(params.forecast === true ? { downloadForecast: {
527
- measuredAt: forecast?.measuredAt ?? Date.now(), global: true, ranges
528
- } } : {}),
529
- supply: supplyFiguresFor(torrent?.infoHash, file?.name, params.segmentSeconds ?? 4),
530
- // How long this answer waited for the arrival forecast, which the
531
- // caller says beside its own time (ViewerRequests, torrent-tv/meta#178).
532
- forecastMs
497
+ const finishStatsTrace = (outcome, fields = {}) => {
498
+ const endedAt = performance.now();
499
+ emitWaitTrace(params.sourceKey, "W10", "end", { startedAt: statsStartedAt, endedAt,
500
+ durationMs: endedAt - statsStartedAt, outcome, fileIndex: params.fileIndex, ...fields });
533
501
  };
502
+ try {
503
+ const torrent = await knownTorrent(params.sourceKey);
504
+ if (!torrent) {
505
+ const whole = wholeSources.fileOf(params.sourceKey, params.fileIndex);
506
+ finishStatsTrace(whole ? "whole-file" : "pending");
507
+ return whole ? wholeFileStats(whole.length) : { pending: true };
508
+ }
509
+ // What this file's own interruptions demand, measured by the reader in
510
+ // this thread. It travels with the stats because the caller asking for
511
+ // them is the one that has to decide with them — the browser's smallest
512
+ // safe buffer, and the speed a quality step must sustain. Null until a
513
+ // second interruption has been seen: one wait shows no interval, and an
514
+ // interval invented from one point is exactly what this work removes.
515
+ const file = Array.isArray(torrent?.files) ? torrent.files[params.fileIndex] : null;
516
+ const forecastAt = performance.now();
517
+ const forecast = file && params.forecast === true ? downloadForecastOf(torrent) : null;
518
+ const forecastMs = params.forecast === true ? performance.now() - forecastAt : 0;
519
+ const stats = pool.getFileStats(torrent, params.fileIndex);
520
+ const ranges = [];
521
+ if (forecast) for (const [piece, availableAt] of forecast.arrivals) {
522
+ const start = piece * torrent.pieceLength;
523
+ const end = Math.min(torrent.length, (piece + 1) * torrent.pieceLength);
524
+ if (end > start) ranges.push({ start, end, availableAt });
525
+ }
526
+ finishStatsTrace("ok", { forecast: params.forecast === true });
527
+ return {
528
+ ...stats,
529
+ ...(params.forecast === true ? { downloadForecast: {
530
+ measuredAt: forecast?.measuredAt ?? Date.now(), global: true, ranges
531
+ } } : {}),
532
+ supply: supplyFiguresFor(torrent?.infoHash, file?.name, params.segmentSeconds ?? 4),
533
+ // How long this answer waited for the arrival forecast, which the
534
+ // caller says beside its own time (ViewerRequests, torrent-tv/meta#178).
535
+ forecastMs
536
+ };
537
+ } catch (error) {
538
+ finishStatsTrace("error", { error: String(error?.message ?? error) });
539
+ throw error;
540
+ }
534
541
  }
535
542
 
536
543
  case Command.PRIORITY_MAP: {
@@ -544,18 +551,27 @@ async function runCommand(command, params, id) {
544
551
  // Nor may one for a file held whole, which has nothing left to fetch.
545
552
  const torrent = await knownTorrent(params.sourceKey);
546
553
  if (!torrent) {
554
+ emitWaitTrace(params.sourceKey, "W7", "event", { outcome: "source-not-ready", fileIndex: params.fileIndex });
547
555
  return { appliedMs: null, receivedAt, repliedAt: performance.timeOrigin + performance.now() };
548
556
  }
549
557
  // What applying a map costs this thread, told to whoever sent it: every
550
558
  // zone becomes a window of the register and the swarm is told again
551
559
  // (torrent-tv/meta#166).
552
560
  const startedAt = performance.now();
553
- emitWaitTrace(params.sourceKey, "W7", "begin", { fileIndex: params.fileIndex });
554
- ensureArrivalsWired(params.sourceKey, torrent);
555
- pool.applyPriorityMap(torrent, params.fileIndex, zones, params.durationSeconds);
556
- torrent.emit("priority-map-changed", params.fileIndex);
557
- emitWaitTrace(params.sourceKey, "W7", "end", { startedAt, endedAt: performance.now(),
558
- fileIndex: params.fileIndex });
561
+ emitWaitTrace(params.sourceKey, "W7", "begin", { startedAt, fileIndex: params.fileIndex });
562
+ try {
563
+ ensureArrivalsWired(params.sourceKey, torrent);
564
+ pool.applyPriorityMap(torrent, params.fileIndex, zones, params.durationSeconds);
565
+ torrent.emit("priority-map-changed", params.fileIndex);
566
+ const endedAt = performance.now();
567
+ emitWaitTrace(params.sourceKey, "W7", "end", { startedAt, endedAt, durationMs: endedAt - startedAt,
568
+ outcome: "applied", fileIndex: params.fileIndex });
569
+ } catch (error) {
570
+ const endedAt = performance.now();
571
+ emitWaitTrace(params.sourceKey, "W7", "end", { startedAt, endedAt, durationMs: endedAt - startedAt,
572
+ outcome: "error", error: String(error?.message ?? error), fileIndex: params.fileIndex });
573
+ throw error;
574
+ }
559
575
  return { appliedMs: performance.now() - startedAt, receivedAt, repliedAt: performance.timeOrigin + performance.now() };
560
576
  }
561
577