Restructure step 3: your server, Invite, version gate, AppGraph
- One server per app run (loopback, no password); Invite attaches an all-interfaces listener to the same server and Stop sharing detaches it (guests told with 4016); members, media and Up next never reset. No solo mode: you're home on your own server unless in a friend's. - Navigation: none / yours / friend; a join passes a version gate on /health first (clear "they/you need to update", update offer). - Invite as a value (host, port, name, password flag, version, fp reserved); addresses filtered (loopback, link-local, 198.18/15, bridges) and ranked; Sharing chip, Copy invite, Stop sharing. - Alone looks like a plain player (alone replaces solo). - AppGraph builds and disposes systems; widgets use AppScope; SessionState deleted; a test caps the remaining singletons. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
629be0d9ed
commit
4d00b7455e
86 files changed
+2993
-2071
No files matched your search
@@ -487,6 +487,24 @@ class ServerHub {
|
||||
changed();
|
||||
}
|
||||
|
||||
/// The hosting app stopped sharing: every member but the host leaves
|
||||
/// now (feed `leave`, reason `closed`), its socket closed with
|
||||
/// [CloseCodes.closed] so its app does not reconnect. Returns how many
|
||||
/// left.
|
||||
int closeGuests() {
|
||||
final guests = [
|
||||
for (final m in engine.members.values)
|
||||
if (!m.host) m.token,
|
||||
];
|
||||
for (final token in guests) {
|
||||
final ws = sockets.remove(token);
|
||||
if (ws != null) unawaited(closeWith(ws, CloseCodes.closed, 'the server stopped sharing'));
|
||||
engine.applyLeave(token, reason: 'closed');
|
||||
}
|
||||
if (guests.isNotEmpty) changed();
|
||||
return guests.length;
|
||||
}
|
||||
|
||||
/// `bye`: [token]'s member leaves now.
|
||||
void bye(String token) {
|
||||
engine.applyLeave(token, reason: 'bye');
|
||||
@@ -953,7 +971,9 @@ void mountSyncRoute(
|
||||
return;
|
||||
}
|
||||
final session = hub.session;
|
||||
if (session.secret.isNotEmpty && hello.secret != session.secret) {
|
||||
// The hosting app's own client (its host key) needs no password: the
|
||||
// password may change while it is connected ([SyncServer.share]).
|
||||
if (session.secret.isNotEmpty && hello.secret != session.secret && !hub.isHostKey(hello.hostKey)) {
|
||||
await refuse(const ErrorFrame(code: ErrCode.secret, message: 'wrong secret', forType: 'hello'),
|
||||
CloseCodes.secret, '${cleanMemberName(hello.user.name)}: wrong secret');
|
||||
return;
|
||||
|
||||
Reference in new issue
Block a user