Interface ISubscriptionTransport
A listener that turns connections into links: the built-in TCP transport, the ASP.NET Core adapter, or a test fake.
public interface ISubscriptionTransport
Remarks
A transport owns bytes on a wire; the engine owns the protocol and the session. That split is the whole point of this seam
(design/Subscriptions/04-transport.md § 1). A transport accepts, negotiates TLS, frames messages, checks the origin and runs the receive loop. It
never decodes a HELLO, never decides who is admitted, never tracks a session and never writes a byte the engine did not hand it.
What a transport must do. Call Accept(ISubscriptionLink, in LinkInfo) once per connection, with a link that is already usable; deliver each complete client-to-server message to OnMessage(ReadOnlySpan<byte>), one at a time and in order; deliver exactly one OnClosed(ushort, Exception) when the link ends, whoever ended it. Message boundaries are the transport's: WebSocket has them natively, TCP adds a length prefix inside its own link, and the engine never parses a byte stream.
What a transport must not do. It must not reorder messages, coalesce two into one, split one into two, hold a
ReadOnlySpan<T> handed to OnMessage(ReadOnlySpan<byte>) past that call, or call into one connection from two threads
at once. It must not interpret a message's contents: a version mismatch is settled by the subprotocol or the preamble it owns
(design/Subscriptions/03-wire-protocol.md § 10), never by reading a message body.
This interface is not IDisposable on purpose: stopping a listener drains connections, which is asynchronous, and a synchronous
Dispose would either block a shutdown path or lie about having finished.
Methods
Start(ISubscriptionAcceptor)
Begins listening, handing every connection to acceptor.
void Start(ISubscriptionAcceptor acceptor)
Parameters
acceptorISubscriptionAcceptorThe engine's acceptor. It is the only engine surface a transport ever calls into to create a connection.
Remarks
Called once, from the runtime's start path. A transport that cannot bind throws here, where the failure reaches the host as a start failure rather than as a server that is running and unreachable.
StopAsync()
Stops listening and closes what is still connected.
ValueTask StopAsync()
Returns
- ValueTask
A task that completes when no link remains and no receive loop is running.
Remarks
Every live link is closed with GoingAway and each connection is told through OnClosed(ushort, Exception), so a transport that returns without doing so leaves session rows the engine will never reclaim.