fix: review findings on the protocol work

Correctness:
- A child that stopped reading could freeze the whole client: the relay
  writes under the context lock and the socket was blocking, so one stalled
  peer took every download, upload and API call with it. Child writes now
  have a deadline, and a child that hits it loses its slot.
- Relaying searches to children was gated by the leaf's answer budget, so a
  parent forwarded a fraction of the stream while advertising itself as
  healthy. The budget bounds our own share scan, which is what it was for;
  the tree's stream goes down whole.
- A dropped client kept its listener port for the life of the process, so a
  retried login advertised an ephemeral port nobody was told about. The
  listener is now stopped and the operations thread let go.
- Excluded phrases were compared against a lowercased path without being
  lowercased themselves, so a capitalised phrase never matched. They are
  normalised where they arrive.
- Losing our own operatorship wiped the room's whole operator roster,
  though we are still a member who can see it.
- A brokered ConnectToPeer of type D was logged and dropped; the peer is
  now told, since we never dial out to adopt a child.
- A peer request made with no server connection returned Ok and parked
  forever; it says NotConnected, as its docs always claimed.
- An empty interest was refused locally but still sent, leaving the
  server's list and ours permanently apart.

Simplification:
- Deleted the excluded-phrase helper nothing called, and the field doc that
  promised behaviour it never had.
- The four roster handlers and four standing handlers were eight
  constructors carrying constants their own message code already implies:
  one newtype each, 100 lines less.
- One place registers a search; the phrase list is borrowed, not cloned per
  relayed search.
This commit is contained in:
Michel de Graaf
2026-09-09 18:38:34 +00:00
parent 435ff382d8
commit 6f32a4e090
11 changed files with 294 additions and 194 deletions
+9 -10
View File
@@ -427,16 +427,14 @@ impl ServerActor {
handlers.register_handler(CantConnectToPeerHandler);
handlers.register_handler(RoomMembersHandler);
handlers.register_handler(RoomOperatorsHandler);
handlers.register_handler(RoomRosterChangeHandler::member_added());
handlers.register_handler(RoomRosterChangeHandler::member_removed());
handlers.register_handler(RoomRosterChangeHandler::operator_added());
handlers.register_handler(RoomRosterChangeHandler::operator_removed());
handlers.register_handler(OwnRoomStandingHandler::membership_granted());
handlers.register_handler(OwnRoomStandingHandler::membership_revoked());
handlers
.register_handler(OwnRoomStandingHandler::operatorship_granted());
handlers
.register_handler(OwnRoomStandingHandler::operatorship_revoked());
// Members added/removed (134/135), operators added/removed (143/144).
for code in [134, 135, 143, 144] {
handlers.register_handler(RoomRosterChangeHandler(code));
}
// Our own membership (139/140) and operatorship (145/146).
for code in [139, 140, 145, 146] {
handlers.register_handler(OwnRoomStandingHandler(code));
}
handlers.register_handler(CantCreateRoomHandler);
handlers.register_handler(RoomTickersHandler);
handlers.register_handler(RoomTickerAddedHandler);
@@ -954,6 +952,7 @@ impl ServerActor {
) {
if let Err(e) =
self.client_channel.send(ClientOperation::IncomingSearch {
from_parent: false,
username,
token,
query,