@torrent-tv/proxy 2.80.12 → 2.80.13
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 +9 -0
- package/docs/download-architecture.md +23 -0
- package/docs/encode-architecture.md +30 -0
- package/package.json +1 -1
- package/routes/stream/get.js +324 -300
- package/routes/transcode/session-file/get.js +22 -2
- package/services/encode/SegmentDemand.js +34 -0
- package/services/hls-session-manager.js +14 -16
- package/services/orchestrators/EncodeOrchestrator.js +735 -726
- package/services/priority/WaitLedger.js +142 -0
- package/services/torrent-pool.js +38 -1
- package/services/torrent-worker/client.js +27 -12
- package/test/wait-ledger.test.js +100 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
## 2.80.13
|
|
2
|
+
|
|
3
|
+
- **New**: Whether the priority map is being served IN ITS OWN ORDER is measured, for both things that read it. Until now the map's ranks were built, published, and then thrown away by everyone who acted on them — a map read backwards would have looked identical in every line this proxy writes. The measure is one wait recorded against the rank the map gave the thing waited for at the moment it was asked for, on one scale for both layers (`services/priority/WaitLedger.js`, `SegmentDemand.rankOf`, eight checks). The encoding's own state line carries `served[now N wait(s) median Xms worst Yms, soon …, later …]` and each `[hold]` line names the band it belonged to; a band that never waited prints `none` rather than a zero, because silence is not a good result. Read: long waits at `now` mean the urgent zone is not being served first, long waits lower down with none at `now` mean the zones are the wrong width.
|
|
4
|
+
- **New**: What the swarm is ACTUALLY TOLD is said out loud, on change, per level: `the swarm is told, for "film.mkv": NEAR 1 zone(s) 42MB, AHEAD 4 zone(s) 310MB, TAIL 1 zone(s) 1900MB (7 band(s) of the map, over 1218s of film)`. `applyPriorityMap` was silent — that the map had been built was visible in the encoding's line, that the download had received it was visible nowhere, and a whole field session carried not one line about it. Per level rather than per zone, because the register has five levels against the map's however-many bands and the fit between them is the one thing there that can be wrong.
|
|
5
|
+
- **Fix**: A read that ends SHORTER than the `Content-Length` already sent says so, loudly. The header is committed before the first byte and the reader's `close()` ends the iteration with no accounting, so only the `fail()` path was ever logged: a client could receive a truncated body with no way to know it, and ffmpeg's mp4 demuxer — which holds the sample table and asks for samples past what arrived — then parses at wrong offsets. That is exactly the `Invalid NAL unit size (negative)` and `missing picture in access unit` seen 2138 times in one field session on a COPIED picture, where no encoder touches a frame. A single clean read of the same file through the same route produced none, and four concurrent ones produced none; what the field session also had was a piece store whose readers wanted every piece it could hold and 100 of 1395 evictions taking a piece a reader had declared.
|
|
6
|
+
- **Fix**: The reads that feed ffmpeg are failed when the torrent thread dies. Both death handlers walked the ordinary reads and left `#fragmentReaders` untouched — which is what `/stream` uses for an encoder — so an encoder's input neither ended nor errored, it went quiet. Field 2026-08-31, three times: the thread died, both ffmpeg runs stayed alive and stopped producing (167 `holding segment-00085.mp4 … encoder alive` lines), and the viewer was left on a spinner that never ended. Recorded as open since then.
|
|
7
|
+
- **Chore**: `hls-session-manager.js` is 2 lines shorter: the zone walk it did by hand is one call to the map that owns ranks, and the explanation of what an empty map means moved to `SegmentDemand.rankOf`, which is the thing it is about.
|
|
8
|
+
- **Chore**: Both architecture documents gain the measurement and how to read it.
|
|
9
|
+
|
|
1
10
|
## 2.80.12
|
|
2
11
|
|
|
3
12
|
- **Chore**: The predicate that decides whether an output is the one somebody is consuming asks each layer only for what it owns. Written first as `LiveOutputs.watchedBy(session, viewer)`, it had the output layer reading a viewer's fields — a coupling in the wrong direction, however plain the values. It is `supersededBy(session, stepOnScreen)` now, taking a plain id: which step is on somebody's screen belongs to the person, which output a step supersedes belongs to the film's shape, and the one place that legitimately holds both puts them together.
|
|
@@ -72,6 +72,29 @@ wanted, and two thirds of reads came back from disk.
|
|
|
72
72
|
**The background fill** states one file at a time — a soundtrack pulled whole
|
|
73
73
|
once the cushion is full, and no further.
|
|
74
74
|
|
|
75
|
+
## Whether the map reaches the swarm, and in what shape
|
|
76
|
+
|
|
77
|
+
Applied in silence until 2026-09-08: that the map had been BUILT was visible in
|
|
78
|
+
the encoding's own line, that the download had received it was visible nowhere,
|
|
79
|
+
and a whole field session carried not one line about it. Said now on change, per
|
|
80
|
+
LEVEL rather than per zone — the register has five levels and the map has as many
|
|
81
|
+
bands as the film needs, and the fit between the two is the one thing here that
|
|
82
|
+
could be wrong:
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
torrent-pool: the swarm is told, for "film.mkv": NEAR 1 zone(s) 42MB,
|
|
86
|
+
AHEAD 4 zone(s) 310MB, TAIL 1 zone(s) 1900MB (7 band(s) of the map, over 1218s of film)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
In megabytes, because that is what a swarm delivers. `NEAR` absent while
|
|
90
|
+
somebody is watching means the map is not arriving; every band landing in one
|
|
91
|
+
level means the fit has collapsed.
|
|
92
|
+
|
|
93
|
+
Beside it, where the waits fell: the reader records each wait against the level
|
|
94
|
+
the map put its piece in, and the `supply` line carries the table. Long waits at
|
|
95
|
+
`blocked` mean the urgent zone is too narrow; long waits further out mean the
|
|
96
|
+
lead is.
|
|
97
|
+
|
|
75
98
|
## The five levels
|
|
76
99
|
|
|
77
100
|
| level | what it is | stated |
|
|
@@ -136,6 +136,36 @@ one-segment backoff are gone — a second debounce on a signal the browser had
|
|
|
136
136
|
already debounced, and every millisecond of it was dead time in front of the
|
|
137
137
|
viewer.
|
|
138
138
|
|
|
139
|
+
## Whether the map is being served in its own order
|
|
140
|
+
|
|
141
|
+
The zones say what matters most. What the viewer actually waited for is measured
|
|
142
|
+
where a viewer measurably waits — the one place in the proxy that holds a
|
|
143
|
+
request for a named segment — and recorded against the rank the map gave that
|
|
144
|
+
segment **at the moment it was asked for**. It reaches the `encode:` state line
|
|
145
|
+
as `served[...]`:
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
served[now 42 wait(s) median 180ms worst 1900ms, soon 6 wait(s) median 90ms worst 240ms, later none]
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Read it like this:
|
|
152
|
+
|
|
153
|
+
| what it says | what is wrong |
|
|
154
|
+
|---|---|
|
|
155
|
+
| long waits at `now` | the urgent zone is not being served first — a fault in whoever acts on the map |
|
|
156
|
+
| long waits at `soon`/`later`, none at `now` | the zones are the wrong width: the urgent one too narrow, so the viewer reaches material only ranked "soon" |
|
|
157
|
+
| `now none` while the viewer is watching | nothing was ever urgent — the map is not reaching this output |
|
|
158
|
+
| a band reading `none` | silence, not a zero, and it is printed as `none` so it cannot be read as "no waits, all good" |
|
|
159
|
+
|
|
160
|
+
Ranks are collapsed into three bands because the map's own scale is as long as
|
|
161
|
+
the film needs — a hundred ranks on a long file — and a hundred-row table says
|
|
162
|
+
nothing a reader can hold. The width of `soon` is a tenth of the top rank, which
|
|
163
|
+
is the map's own shape (its zones widen geometrically) rather than a threshold
|
|
164
|
+
chosen for the table.
|
|
165
|
+
|
|
166
|
+
The download half is measured the same way and on the same scale, so the two are
|
|
167
|
+
comparable: `download-architecture.md`.
|
|
168
|
+
|
|
139
169
|
## What is checked
|
|
140
170
|
|
|
141
171
|
`test/one-authority.test.js` holds the shape: one caller of `#startEncodeRun`,
|