forked from Foxyz/sync_replay_project
Sessions leave redacted logs; viewers wait for a member relay's source before opening it
Logs: one redaction pass (query strings to names, member tokens,
passwords, cookies, auth headers) for every line; daily files with size
and age caps in the app (hosted server included) and the dedicated
server (--log-dir); swaps, relay channels, per-member /r /m /j outcomes,
server fetches, mpv load errors, yt-dlp runs. Settings > About: Copy
diagnostics, Open logs folder.
Bilibili through someone else: the viewer opened /r/ before the source
dialled in; the server holds that request and mpv gives up after 5 s
("could not be opened"). Viewers now open a member relay once it is
live, the putter starts its source before its own player, and track
sizes are read in parallel.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
572104f49e
commit
4ab37c55cf
25 files changed
+1124
-108
No files matched your search
@@ -1,4 +1,5 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
@@ -169,6 +170,46 @@ void main() {
|
||||
}
|
||||
});
|
||||
|
||||
test('a source that dials in after mpv would have given up (5 s): viewers wait for it, then play',
|
||||
timeout: const Timeout(Duration(minutes: 2)), () async {
|
||||
final file = await _media();
|
||||
final alice = await member('alice');
|
||||
// Bob is a bare client: he puts a file up and starts passing it on
|
||||
// only 7 s later (a slow first upstream read, a slow own player).
|
||||
final ws = await WebSocket.connect('ws://127.0.0.1:${server.boundPort}/sync');
|
||||
final welcome = Completer<Map>();
|
||||
ws.listen((f) {
|
||||
final j = jsonDecode('$f') as Map;
|
||||
if (j['t'] == 'welcome' && !welcome.isCompleted) welcome.complete(j);
|
||||
}, onError: (_) {});
|
||||
ws.add(jsonEncode(const HelloMessage(
|
||||
proto: RelayConstants.protoVersion,
|
||||
secret: 'pw',
|
||||
user: HelloUser(name: 'bob'),
|
||||
media: HelloMedia(name: '', size: 0, duration: 0))
|
||||
.toJson()));
|
||||
final token = (await welcome.future.timeout(const Duration(seconds: 5)))['token'] as String;
|
||||
final size = await File(file).length();
|
||||
ws.add(jsonEncode({
|
||||
't': 'swap',
|
||||
'media': {'name': 'late.mkv', 'size': size, 'duration': 0, 'relay': <String, Object?>{}},
|
||||
}));
|
||||
await _poll(() => stateMediaRelay(alice.serverState.peek()!)?.source.isNotEmpty ?? false, 'relay state');
|
||||
await Future.delayed(const Duration(seconds: 7));
|
||||
expect(alice.playerError.peek(), isEmpty, reason: 'no "could not be opened" while the source is on its way');
|
||||
expect(alice.health.peek().message, contains('waiting for bob'));
|
||||
final src = RelaySource(Uri.parse('ws://127.0.0.1:${server.boundPort}/r/default/$token/source'),
|
||||
RelayMedia.single(FileRelayBytes(File(file))));
|
||||
await src.start();
|
||||
try {
|
||||
await _poll(() => alice.playback.durationSecs > 19, 'alice opened it once the source was up');
|
||||
expect(alice.playerError.peek(), isEmpty);
|
||||
} finally {
|
||||
await src.close();
|
||||
await ws.close();
|
||||
}
|
||||
});
|
||||
|
||||
test('the source drops uncleanly and resumes: it keeps its copy and keeps serving',
|
||||
timeout: const Timeout(Duration(minutes: 2)), () async {
|
||||
final file = await _media();
|
||||
|
||||
Reference in new issue
Block a user