forked from Foxyz/sync_replay_project
Relay: viewers keep the file size (headers within 4 s, connection: close), retries back off, 412 re-resolves
Two server behaviours left ffmpeg (8.1/9.0) without the file size, after which every seek failed with "size -38" until a reload: - dart:io holds response headers until body bytes exist: a stalled source meant no headers within mpv's 5 s timeout. Relay byte responses are now written on the raw connection, headers with the first bytes or after 4 s, and a swap ends waiting reads with a plain close. - every response closed its socket without saying connection: close, so ffmpeg 8.x reused a dead connection for its next seek (pol's X clips). The server now says it whenever the request asks. A failed pull waits 250 ms doubling to 8 s instead of re-pulling at once (the ~130 ms storm that drew Bilibili's 412/403); 412 counts as an expired URL and re-resolves the page, at most once per 60 s. The app reloads a player once per media when ffmpeg reports the lost size anyway. P37: a read that waits past ffmpeg's retry budget still ends the file early. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5e3834e6ba
commit
e91539d113
17 files changed
+575
-63
No files matched your search
@@ -249,3 +249,23 @@ MimeType _mimeOf(String? contentType) {
|
||||
return MimeType.octetStream;
|
||||
}
|
||||
}
|
||||
|
||||
/// Says `connection: close` on a response to a request that asked for it
|
||||
/// (ffmpeg always does). dart:io closes such a connection after the
|
||||
/// response but, behind relic, without saying so; ffmpeg (8.x) then sends
|
||||
/// its next seek on that dead connection after reading a range to its end
|
||||
/// (an mp4's tail) and the seek fails for good ("size -38").
|
||||
Handler closeWhenAsked(Handler next) => (req) async {
|
||||
final res = await next(req);
|
||||
if (res is! Response) return res;
|
||||
bool asked;
|
||||
try {
|
||||
asked = req.headers.connection?.isClose ?? false;
|
||||
} catch (_) {
|
||||
asked = false;
|
||||
}
|
||||
if (!asked) return res;
|
||||
return res.copyWith(
|
||||
headers: res.headers.transform(
|
||||
(h) => h.connection = const ConnectionHeader.directives([ConnectionHeaderType.close])));
|
||||
};
|
||||
Reference in new issue
Block a user