Initial commit: watch-together phases 0-4 + presence hardening, internet-tested
This commit is contained in:
commit
427d851a5b
101 files changed
+11326
No files matched your search
@@ -0,0 +1,159 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:signals/signals_flutter.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
import 'package:sync_relay_server/server.dart';
|
||||
|
||||
import '../sfx/sfx.dart';
|
||||
import '../session/health.dart';
|
||||
import '../session/session_coordinator.dart';
|
||||
import '../widgets/avatar_pipeline.dart';
|
||||
import 'connect_prefs.dart';
|
||||
|
||||
enum AppRoute { welcome, connect, session }
|
||||
|
||||
enum ConnectMode { host, join }
|
||||
|
||||
class ConnectForm {
|
||||
String host;
|
||||
String port;
|
||||
String secret;
|
||||
String name;
|
||||
String avatarPath;
|
||||
String mediaPath;
|
||||
String linkUrl;
|
||||
ConnectForm({
|
||||
this.host = '127.0.0.1',
|
||||
this.port = '8080',
|
||||
this.secret = '',
|
||||
this.name = '',
|
||||
this.avatarPath = '',
|
||||
this.mediaPath = '',
|
||||
this.linkUrl = '',
|
||||
});
|
||||
}
|
||||
|
||||
class SessionState {
|
||||
static final SessionState instance = SessionState._();
|
||||
SessionState._();
|
||||
|
||||
final route = signal(AppRoute.welcome);
|
||||
final connectMode = signal(ConnectMode.host);
|
||||
final status = signal(const HealthStatus(HealthSeverity.info, 'idle'));
|
||||
final room = signal<RoomBroadcast?>(null);
|
||||
final SfxService sfx = const NoopSfxService();
|
||||
late final SessionCoordinator coordinator = SessionCoordinator(sfx: sfx);
|
||||
final lastForm = ConnectForm();
|
||||
RoomServer? _server;
|
||||
|
||||
Future<void> loadForm() async {
|
||||
final box = await openConnectFormBox();
|
||||
lastForm
|
||||
..host = readString(box, connectKeyHost, '127.0.0.1')
|
||||
..port = readString(box, connectKeyPort, '8080')
|
||||
..secret = readString(box, connectKeySecret, '')
|
||||
..name = readString(box, connectKeyName, '')
|
||||
..avatarPath = readString(box, connectKeyAvatarPath, '')
|
||||
..mediaPath = readString(box, connectKeyMediaPath, '')
|
||||
..linkUrl = readString(box, connectKeyLinkUrl, '');
|
||||
}
|
||||
|
||||
Future<void> saveForm() async {
|
||||
final box = connectFormBoxIfOpen() ?? await openConnectFormBox();
|
||||
await box.putAll({
|
||||
connectKeyHost: lastForm.host,
|
||||
connectKeyPort: lastForm.port,
|
||||
connectKeySecret: lastForm.secret,
|
||||
connectKeyName: lastForm.name,
|
||||
connectKeyAvatarPath: lastForm.avatarPath,
|
||||
connectKeyMediaPath: lastForm.mediaPath,
|
||||
connectKeyLinkUrl: lastForm.linkUrl,
|
||||
});
|
||||
}
|
||||
|
||||
Future<String> loadAvatar(String path) => encodeAvatar(path);
|
||||
|
||||
void goConnect(ConnectMode mode) {
|
||||
connectMode.value = mode;
|
||||
route.value = AppRoute.connect;
|
||||
}
|
||||
|
||||
Future<void> host(ConnectParams params, ConnectForm form) async {
|
||||
_rememberForm(form);
|
||||
status.value = const HealthStatus(HealthSeverity.info, 'starting server…');
|
||||
await stopServer();
|
||||
final server = RoomServer(AppConfig(
|
||||
port: params.port,
|
||||
secret: params.secret,
|
||||
name: 'room',
|
||||
mediaPath: params.mediaPath,
|
||||
));
|
||||
try {
|
||||
await server.start();
|
||||
} catch (e, st) {
|
||||
debugPrint('server start failed: $e\n$st');
|
||||
status.value =
|
||||
HealthStatus(HealthSeverity.error, 'cannot bind port ${params.port}: $e');
|
||||
rethrow;
|
||||
}
|
||||
_server = server;
|
||||
status.value =
|
||||
HealthStatus(HealthSeverity.ok, 'hosting on port ${server.boundPort}');
|
||||
await coordinator.connect(ConnectParams(
|
||||
host: '127.0.0.1',
|
||||
port: server.boundPort,
|
||||
secret: params.secret,
|
||||
name: params.name,
|
||||
avatar: params.avatar,
|
||||
linkUrl: params.linkUrl,
|
||||
));
|
||||
route.value = AppRoute.session;
|
||||
try {
|
||||
await saveForm();
|
||||
} catch (e, st) {
|
||||
debugPrint('save connect form failed: $e\n$st');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> join(ConnectParams params, ConnectForm form) async {
|
||||
_rememberForm(form);
|
||||
await coordinator.connect(params);
|
||||
route.value = AppRoute.session;
|
||||
try {
|
||||
await saveForm();
|
||||
} catch (e, st) {
|
||||
debugPrint('save connect form failed: $e\n$st');
|
||||
}
|
||||
}
|
||||
|
||||
void _rememberForm(ConnectForm form) {
|
||||
lastForm
|
||||
..host = form.host
|
||||
..port = form.port
|
||||
..secret = form.secret
|
||||
..name = form.name
|
||||
..avatarPath = form.avatarPath
|
||||
..mediaPath = form.mediaPath
|
||||
..linkUrl = form.linkUrl;
|
||||
}
|
||||
|
||||
Future<void> startHeadless(List<String> args) async {
|
||||
int port = 8080;
|
||||
for (var i = 0; i < args.length - 1; i++) {
|
||||
if (args[i] == '--port') port = int.tryParse(args[i + 1]) ?? port;
|
||||
}
|
||||
_server = RoomServer(AppConfig(port: port, secret: 'change-me', name: 'room'));
|
||||
await _server!.start();
|
||||
}
|
||||
|
||||
Future<void> stopServer() async {
|
||||
await _server?.stop();
|
||||
_server = null;
|
||||
}
|
||||
|
||||
Future<void> leave() async {
|
||||
await coordinator.leave();
|
||||
await stopServer();
|
||||
status.value = const HealthStatus(HealthSeverity.info, 'idle');
|
||||
route.value = AppRoute.connect;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user