The connection registry was a flat map from connection id to
connection data, so finding the connections of one profile meant
walking every connection. `on-connect` and `on-disconnect` also
`swap!`ed a whole-map `assoc`/`dissoc`, which is O(n) per connection
churn.
The registry now holds `:connections` and `:by-profile` in the same
atom, so one `swap!` keeps both consistent and a profile lookup is a
single map access. Both maps are updated together by
`register-connection` / `unregister-connection`; a profile whose last
connection leaves is dropped from the index instead of lingering with
an empty set.
Also extracts `close-file-subscription` out of the
`:unsubscribe-file` handler so a revocation can tear a subscription
down through exactly the same path the client uses: announce
`:leave-file`, close the relay channel, purge the bus. Closing the
channel is what stops the `:subscribe-file` go-loop, since `take!` on
a closed channel returns nil.
Adds `connections-for-profile` and `repl-get-connections-for-profile`
so an operator can inspect a profile's connections from the REPL the
same way as for a file or a team.
The new helpers take no `!` suffix: per `mem:clojure/design-rules` the
default is no `!`, and these are neither `app.db` API nor transient
helpers. Existing `!` names such as `mbus/pub!` are legacy and stay
until their own refactor.
The registry stays local to one backend instance. That is documented
on the var: reaching connections owned by another instance has to go
through the message bus, which is what the revocation watcher will do.
Closes#12155
AI-assisted-by: space-bunny-free