A candidate that accepted the dial and then said nothing kept its slot
for the session, and ten of those blocked every later batch; a link now
closes after a minute of silence. A parent that flaps its level made us
tell the server four messages per flap; moves are now told at most once
a second, the latest one winning. A parent that reports level zero is
its own root from then on, whatever it said before. The wait for a
searcher's control connection runs from the last message queued for it,
not the first. A successful login is pinned to reset the leaf.
Review of the leaf found the seams a stranger on the other end of a D
connection could pull at, and a few that a slow one would.
- A code-93 envelope is unwrapped once, as Nicotine+ does; a frame made
of nothing but envelopes used to recurse once per byte.
- A branch level is validated before it is used: negative levels leave
the candidate unadoptable and the largest one no longer overflows.
- The link reads through the crate's MessageReader, so a frame split
across a read timeout is no longer torn or mistaken for a closed link.
- Every event a link raises carries its link number, so a stale thread
cannot adopt, close or move a newer link to the same user.
- Later branch facts from the parent move our own place and are told to
the server; a fresh login resets the leaf, whose stance is now the one
place the four announcement messages come from.
- Candidates from a later batch join the ones in flight instead of
cancelling them, capped at ten; searches from the parent are budgeted
at fifty a second; a reply queued for a searcher the server cannot
place expires after a minute.
- Truncated frames and half-read PossibleParents entries are dropped
instead of yielding an empty root, a level of zero or a phantom
candidate.
The e2e now has a searcher of its own, so the answer must go to whoever
asked and not to the parent that relayed it.
The distributed search network carries searches from parent to child
over connections whose frames have a one-byte code; the library had no
reader for them. This adds the codec for Search, BranchLevel,
BranchRoot and the embedded envelope, with the identifier check that
keeps malformed frames from being answered, and completes the post-login
stance Nicotine+ sends: HaveNoParent, BranchRoot (ourselves),
BranchLevel 0 and AcceptChildren false, in place of HaveNoParent alone.
server_actor.rs had grown past twelve hundred lines, a fifth of them
tests and a hundred the value types it hands out. The types now live in
server_actor/types.rs and the tests in server_actor/tests.rs, as the
client's already do, and the room and user traffic in handle_message
moves to its own dispatch step beside the wishlist one. No behaviour
changes; the public paths are re-exported as before.