@torrent-tv/proxy 2.9.80 → 2.9.81

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 CHANGED
@@ -1,3 +1,7 @@
1
+ ## 2.9.81
2
+
3
+ - **New**: The stream route says why a read failed. A body that failed mid-flight was dropped silently — the connection closed with no status and no log line, which from the client looks like the proxy died and from the log like nothing happened; found while probing the route by hand, where every ranged read closed the socket without a word. It now reports the file, the range, how many bytes had been sent, and the error.
4
+
1
5
  ## 2.9.80
2
6
 
3
7
  - **Fix**: A seek backward could hang forever. `prioritizeByteRange` demotes the pieces behind the playhead with `deselect`, which removes them from the download set — and `critical`, which runs right after, only flags pieces that are already selected, so it never puts them back. A seek forward followed by a seek backward therefore left the target pieces wanted by nobody: the encoder waited on data the torrent had been told to stop fetching, while the swarm ran at full speed on pieces nobody needed. The read position is now re-selected whenever it moves back behind what an earlier seek deselected, tracked per file because WebTorrent does not report its own selection back.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@torrent-tv/proxy",
3
- "version": "2.9.80",
3
+ "version": "2.9.81",
4
4
  "description": "Torrent proxy client that exposes webseed-like HTTP stream endpoint.",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "publishConfig": {
@@ -7,6 +7,7 @@
7
7
  */
8
8
 
9
9
  import { parseRange } from "../../utils/parse-range.js";
10
+ import { logger } from "../../utils/logger.js";
10
11
 
11
12
  /**
12
13
  * Resolve source parameters from the query string.
@@ -121,6 +122,7 @@ export async function handleStreamGet(req, reply, { sourceRegistry, torrentPool
121
122
  // being fetched for nobody.
122
123
  reply.raw.once("close", () => fragments.cancel());
123
124
 
125
+ let sent = 0;
124
126
  try {
125
127
  for await (const fragment of fragments) {
126
128
  if (reply.raw.writableEnded || reply.raw.destroyed) {
@@ -130,15 +132,23 @@ export async function handleStreamGet(req, reply, { sourceRegistry, torrentPool
130
132
  await new Promise((resolve, reject) => {
131
133
  reply.raw.write(fragment.bytes, (error) => (error ? reject(error) : resolve()));
132
134
  });
135
+ sent += fragment.bytes.length;
133
136
  // Only now are these bytes gone: the piece can be unpinned, and the
134
137
  // slot it occupies reused. Releasing before this point corrupts the
135
138
  // response silently.
136
139
  fragment.release();
137
140
  }
138
141
  reply.raw.end();
139
- } catch {
142
+ } catch (error) {
140
143
  // The body is already committed by its headers, so there is nothing
141
144
  // useful to send instead — drop the connection and let the client retry.
145
+ // But say why: swallowing this made the route close connections with no
146
+ // status and no trace, which from the client looks like the proxy died
147
+ // and from the log looks like nothing happened at all.
148
+ logger.warn(
149
+ `stream: read of "${file.name}" bytes ${start}-${end} failed after ` +
150
+ `${sent} of ${contentLength} bytes: ${error instanceof Error ? error.message : String(error)}`
151
+ );
142
152
  reply.raw.destroy();
143
153
  } finally {
144
154
  releaseFile();