When bringUpLink errored — a handshake timeout against a wedged transport,
for instance — Run/RunWithReady returned straight to the caller without
calling shutdown, so the carrier link that had already joined the MUC
was never closed. The result was a ghost participant lingering on
Jicofo/JVB until idle timeout, which the next test in the same room
inherited as stale endpoints in 'bridge open'.
The clue from logs was that failing seichannel runs produced one
'leave-muc handshake ok' instead of two: the server's normal
ctx-cancel path got there cleanly, but the client's bringUpLink
returned early and skipped its defer.
Both paths now register shutdown before the bringUpLink call. shutdown
is nil-safe and idempotent so it works whether or not bringUpLink
actually populated link/session fields. server's wg.Wait moves into
the same defer so wg goroutines spawned by partial setup also drain
before Run returns.
Break CLI backwards compatibility as planned for refactor/universal-carrier:
- Drop -carrier flag; add -auth (auth provider name), -engine (engine
name for -auth none), -url and -token (SFU endpoint + access token for
direct/none auth mode).
- session.Config.Carrier → Auth + Engine + URL + Token.
- session.Gen() is now generic: auth.Get(cfg.Auth).(auth.RoomCreator)
replaces the hard-coded switch on carrier names.
- Register a "none" carrier in builtin (registerDirect) that bypasses
auth and connects directly to any engine with caller-supplied URL+Token.
- auth/telemost.Provider.Issue now accepts a raw room-ID hash in addition
to a full https://telemost.yandex.ru/j/<id> URL.
- Plumb Engine/URL/Token from session.Config through server.Run,
client.Run/RunWithReady, bringUpLink, link.Config, transport.Config, and
carrier.Config so the "none" carrier has access to them end-to-end.
- Update all tests and mobile.go call sites.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace the hand-rolled multiplexer (internal/mux) with xtaci/smux v2
running on top of the existing KCP-reliable vp8channel transport.
- Add internal/muxconn: io.ReadWriteCloser adapter bridging link.Link
(message-oriented) into the byte-stream smux expects; applies AEAD
on every write and inverts it on every received message
- Rewrite client: smux.Client session over muxconn; OpenStream per
SOCKS5 connection; reconnect handler tears down and rebuilds session
- Rewrite server: smux.Server session; AcceptStream loop dispatches
each stream to a proxy handler; tolerates session bounces on reconnect
- Delete internal/mux: all sequence/reorder/buffer logic is now
handled by smux + KCP