internal/carrier and internal/carrier/builtin sat between transports and
engines, wrapping every engine.Session in carrier.Session +
engineByteStream/engineVideoTrack adapters that mechanically proxied every
method. That layer existed solely to translate Capabilities/AddTrack names;
no behaviour lived above engine.
Replace with internal/engine/builtin: a name-keyed registry that calls
auth.Issue and engine.New directly. Transports look up engine.Session via
enginebuiltin.Open, then type-assert engine.VideoTrackCapable for video
transports. A small per-transport engineVideoSession adapter unifies the
reconnect callback signature (engine uses func(*webrtc.DataChannel); the
transports want func()).
Updates:
- internal/engine/builtin/builtin.go: new Register/Open registry + auth
pass-through ("none") + auth-driven factories for jazz/telemost/wbstream/jitsi.
- internal/transport/datachannel/transport.go: uses engine.Session directly
via Capabilities().ByteStream check.
- internal/transport/{seichannel,videochannel,vp8channel}: each gains an
engineVideoSession adapter and routes Connect/Send/Close/AddTrack through
the engine session.
- internal/app/session: imports enginebuiltin; carrier.Available() →
enginebuiltin.Available().
- pkg/olcrtc/olcrtc.go: switches to enginebuiltin.RegisterDefaults.
- internal/carrier and internal/carrier/builtin: deleted.
- Tests rewritten to register a fakeEngineSession (implements engine.Session
+ engine.VideoTrackCapable) through enginebuiltin.Register. The e2e
memoryStream gains the same dual interface so memorySession is gone.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
internal/link and internal/link/direct were a single-implementation
abstraction layer where directLink mechanically proxied every method to
transport.Transport — only Features() lived above transport.Transport,
and even that was a Features() alias. Six layers of plumbing for zero
behavioural value.
Drop the layer entirely:
- muxconn.Conn now takes a transport.Transport directly.
- server.Server and client.Client store transport.Transport, call
transport.New, and expose Features() through transport.Transport's
built-in method.
- server.Config and client.Config lose their Link string field.
- session.Config loses Link + validateLink + ErrLinkRequired/ErrUnsupportedLink.
- config.File and config.Profile lose the link YAML key.
- pkg/olcrtc/tunnel.Config loses Link.
- mobile drops defaultLink, SetLink, and mobileConfig.link.
Two e2e tests that exercised link.New directly are renamed to call
transport.New (TestTransportCreatesAllProviderTransportCombinations and
TestTransportConnectsFastProviderTransportMatrix); behaviour is unchanged.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
transport.Config used to carry a flat union of video+vp8+sei tuning fields
that every transport ignored except its own. Replace with an opaque
transport.Options marker interface and per-transport Options structs
(videochannel.Options, vp8channel.Options, seichannel.Options). Datachannel
keeps an unset Options.
link.Config gains TransportOptions and drops the 16 transport-specific
fields. server.Config and client.Config follow suit. session.Config is
left untouched in this commit — buildTransportOptions packs its existing
flat fields into the typed Options bundle before calling server/client
(session.Config is rebuilt in a later commit when YAML config moves to
typed sections).
Tests that synthesized link/server/client/transport configs are updated
to pass typed Options bundles. The shared e2eTransportOptions helper
replaces three copies of the flat field bundle in e2e/tunnel_test.go.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
handshake and control duplicated the same 4-byte BE length + body framing
with independent ErrFrameTooLarge constants. Centralize in internal/framing
and have both callers delegate. ErrFrameTooLarge is re-exported so existing
errors.Is checks keep working.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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.