Transports
A transport is a client-side interface that can connect to a comms URI and exchange real-time messages with peers or services.
Clients are free to implement transports as they see fit (as long as they follow the protocol expected by other clients and services), but the recommended design described below has been tested in practice and proven to integrate well with different projects.`
Standard Transports #
There are 5 transport types defined by the protocol:
-
Websocket
(
ws-room
) uses a standard websocket stream. -
LiveKit
(
livekit
) uses the open-source LiveKit framework, based on WebRTC. -
SignedLogin
(
signed-login
) makes a signed HTTPs request to obtain a dynamically assigned transport from a server. -
Offline
(
offline
) is a dummy transport indicates there are no comms in the current environment. -
Simulator
(
simulator
) is a dummy transport with completely custom behavior, mainly for developers to debug their implementations.
Messages sent and received through a transport interface are always the same (see
messages
). Some transports may wrap them in control structures for transmission, but these should be unpacked before crossing the Transport
interface.
Recommended Design #
This is a minimal Transport
interface written in TypeScript:
interface Transport {
// Initialize the Transport with a URI:
constructor(private uriWithConnectionParams: string)
// Open a connection using the URI given in the constructor:
connect(): Promise<void>
// Close the connection:
disconnect(): Promise<void>
// Send an arbitrary payload to the service and all peers:
send(packet: Packet): Promise<void>
// Subscribe to incoming messages from both the service and all peers:
on(event: 'receive', callback: (packet: Packet) => void): void
}
Actual implementations commonly extend this, adding connection/disconnection and join/leave events, non-broadcast sending, stricter typing or language-specific adaptations.
Transport URIs #
The values of uriWithConnectionParams
are always of the form:
<type>:<type connection parameters>
The <type>
corresponds to one listed above, and the format for <type connection parameters>
is dependent on the specific transport. It can be a URL, an opaque token, or any arbitrary data.
The
LiveKit
transport, for example, uses a wss
URL with an access_token
parameter to establish an authenticated connection:
livekit:wss://comms.example.com?access_token=eyJhbGciOiJI...
For comparison, the
Websocket
transport also uses a wss
URL, but without a pre-generated token. It requires an authentication flow once connected.
Creating Transports #
Since each Transport
class will support a particular kind of URI, it’s a good idea to have a factory method that either returns a valid Transport
or fails immediately. For example:
function createTransport(uriWithConnectionParams: string) {
const type = getPrefix(urlWithConnectionParams)
switch (type) {
case 'ws-room': return new WsRoomTransport(uriWithConnectionParams)
case 'livekit': return new LiveKitTransport(uriWithConnectionParams)
// ... other supported implementations...
}
throw new Error(`Unsupported transport type: ${type}`)
}
Clients are not required to implement all standard transports. If they intend to only use a subset of the defined types without aiming to handle all URIs, they are free to reject types they don’t support.
More featured clients, such as a World Explorer, are advised to implement at least the websocket and LiveKit transports, which are currently in use by all major realms.
Learn more #
Head over to a specific transport type section, read about the different message types or check out the [[Comms Demo Station]].