@torrent-tv/proxy 2.99.7 → 2.99.9
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
|
@@ -94,19 +94,20 @@ export async function futureDownload(entries, { now = Date.now(), findStore = pi
|
|
|
94
94
|
continue;
|
|
95
95
|
}
|
|
96
96
|
const remaining = piece?.missing;
|
|
97
|
-
const
|
|
97
|
+
const holders = [];
|
|
98
|
+
for (const wire of torrent.wires ?? []) {
|
|
98
99
|
// Only a peer that can be asked for it now: one choking us is asked for
|
|
99
100
|
// nothing outside the pieces it allows, whatever it carried before.
|
|
100
|
-
if (wire.destroyed || !wire.peerPieces?.get(index) || !mayAsk(wire, index))
|
|
101
|
+
if (wire.destroyed || !wire.peerPieces?.get(index) || !mayAsk(wire, index)) continue;
|
|
101
102
|
// What it carried with its queue kept full, where it has been seen so:
|
|
102
103
|
// its speed while our selection gave it little measures our asking
|
|
103
104
|
// (`SelectionLimit`, torrent-tv/meta#178).
|
|
104
105
|
const rate = Number(limit?.capacityOf?.(wire) ?? wire.downloadSpeed?.());
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
pending.push({ arrivals, index, ...band,
|
|
108
|
-
Number.isSafeInteger(remaining) && remaining > 0 && remaining <= piece.length &&
|
|
109
|
-
? remaining
|
|
106
|
+
if (Number.isFinite(rate) && rate > 0) holders.push({ wire, rate });
|
|
107
|
+
}
|
|
108
|
+
pending.push({ arrivals, index, ...band, holders, remaining:
|
|
109
|
+
Number.isSafeInteger(remaining) && remaining > 0 && remaining <= piece.length && holders.length > 0
|
|
110
|
+
? remaining : null });
|
|
110
111
|
if (++steps % 256 === 0) {
|
|
111
112
|
await nextTurn();
|
|
112
113
|
if (!isCurrent()) return new Map();
|
|
@@ -120,15 +121,62 @@ export async function futureDownload(entries, { now = Date.now(), findStore = pi
|
|
|
120
121
|
// before it have. Charged the whole band's end instead, a band of many
|
|
121
122
|
// segments — the map states one per stretch of a level since 2.97.27 — would
|
|
122
123
|
// put its nearest piece at its farthest piece's time (torrent-tv/meta#178).
|
|
124
|
+
//
|
|
125
|
+
// AND IN PARALLEL WHERE THE PEERS DIFFER. A piece is brought by the peers
|
|
126
|
+
// holding it, each from when it has brought what was asked of it before, and
|
|
127
|
+
// no sooner than the measured supply of every peer that holds a piece still
|
|
128
|
+
// to come carries all the bytes ahead of it. Summed one piece after another
|
|
129
|
+
// at its own holders' speed, a two-hour film whose far pieces each had a few
|
|
130
|
+
// unchoked holders was forecast to arrive in 127 838 s at 2.33 MB/s, and a
|
|
131
|
+
// seek was held for 39 s on it (r49, torrent-tv/meta#178). One holder for
|
|
132
|
+
// every piece gives the sum it was; a piece nobody can be asked for still
|
|
133
|
+
// leaves every piece after it unknown.
|
|
123
134
|
pending.sort((left, right) => compareBands(left, right) || left.index - right.index);
|
|
124
|
-
|
|
125
|
-
for (const {
|
|
126
|
-
|
|
127
|
-
|
|
135
|
+
const supply = new Map();
|
|
136
|
+
for (const { holders } of pending) for (const { wire, rate } of holders) supply.set(wire, rate);
|
|
137
|
+
const total = [...supply.values()].reduce((sum, rate) => sum + rate, 0);
|
|
138
|
+
const freeAt = new Map();
|
|
139
|
+
let ahead = 0;
|
|
140
|
+
let known = true;
|
|
141
|
+
for (const { arrivals, index, holders, remaining } of pending) {
|
|
142
|
+
if (!known || remaining === null || !(total > 0)) {
|
|
143
|
+
known = false;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
ahead += remaining;
|
|
147
|
+
const finish = Math.max(sharedFinish(holders, freeAt, remaining, now), now + ahead / total * 1000);
|
|
148
|
+
for (const { wire } of holders) freeAt.set(wire, Math.max(freeAt.get(wire) ?? now, finish));
|
|
149
|
+
arrivals.set(index, finish);
|
|
128
150
|
}
|
|
129
151
|
return isCurrent() ? forecasts : new Map();
|
|
130
152
|
}
|
|
131
153
|
|
|
154
|
+
/**
|
|
155
|
+
* When peers bringing `bytes` together finish: each starts when it is free
|
|
156
|
+
* and brings at its own rate, so the finish is where their combined bytes
|
|
157
|
+
* reach `bytes` (the earliest of them working alone at first, more joining as
|
|
158
|
+
* they come free).
|
|
159
|
+
*
|
|
160
|
+
* @param {Array<{ wire: object, rate: number }>} holders - Bytes per second.
|
|
161
|
+
* @param {Map<object, number>} freeAt - Milliseconds.
|
|
162
|
+
* @param {number} bytes
|
|
163
|
+
* @param {number} now - Milliseconds.
|
|
164
|
+
* @returns {number} Milliseconds.
|
|
165
|
+
*/
|
|
166
|
+
function sharedFinish(holders, freeAt, bytes, now) {
|
|
167
|
+
const starts = holders.map(({ wire, rate }) => ({ at: Math.max(now, freeAt.get(wire) ?? now), rate }))
|
|
168
|
+
.sort((left, right) => left.at - right.at);
|
|
169
|
+
let rate = 0;
|
|
170
|
+
let weighted = 0;
|
|
171
|
+
for (let index = 0; index < starts.length; index++) {
|
|
172
|
+
rate += starts[index].rate;
|
|
173
|
+
weighted += starts[index].rate * starts[index].at;
|
|
174
|
+
const finish = (bytes * 1000 + weighted) / rate;
|
|
175
|
+
if (index === starts.length - 1 || finish <= starts[index + 1].at) return finish;
|
|
176
|
+
}
|
|
177
|
+
return now;
|
|
178
|
+
}
|
|
179
|
+
|
|
132
180
|
/**
|
|
133
181
|
* Whether this peer can be asked for this piece now: it is not choking us, or
|
|
134
182
|
* it allows this piece while it does (BEP 6, WebTorrent 2.8.5 `_updateWire`).
|
|
@@ -313,6 +313,14 @@ export function createTunnelClient({
|
|
|
313
313
|
signalRoutes.delete(sessionId);
|
|
314
314
|
}
|
|
315
315
|
}
|
|
316
|
+
// Closed because this proxy is stopping (`disconnect`), which clears the
|
|
317
|
+
// connection before its close arrives. Read as a handover, a stopping
|
|
318
|
+
// proxy said a replacement carried its tunnel while viewers found no
|
|
319
|
+
// proxy at all (r48, torrent-tv/meta#178).
|
|
320
|
+
if (stopped) {
|
|
321
|
+
log(`Tunnel closed (code=${event.code}): this proxy is stopping.`);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
316
324
|
// A connection this one replaced. The server closes it as soon as the
|
|
317
325
|
// replacement registers, which is the whole point of renewing early —
|
|
318
326
|
// there is nothing to report and nothing to reconnect, because the tunnel
|