# Transports

A *transport* is a client-side interface that can connect to a comms URI and exchange real-time messages with peers or services.

{% hint style="info" %}
You can see the comms protocol in action and experiment with it using the open-source [Comms Station](https://decentraland.github.io/comms-station/).
{% endhint %}

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](#recommended) described below has been tested in practice and proven to integrate well with different projects.\`

### Standard Transports <a href="#types" id="types"></a>

There are 5 transport types defined by the protocol:

* [Websocket](https://github.com/decentraland/docs/blob/main/contributor/communications/transport-types/websocket/README.md) (`ws-room`) uses a standard websocket stream.
* [LiveKit](https://github.com/decentraland/docs/blob/main/contributor/communications/transport-types/livekit/README.md) (`livekit`) uses the open-source LiveKit framework, based on WebRTC.
* [SignedLogin](https://github.com/decentraland/docs/blob/main/contributor/communications/transport-types/signed_login/README.md) (`signed-login`) makes a signed HTTPs request to obtain a dynamically assigned transport from a server.
* [Offline](https://github.com/decentraland/docs/blob/main/contributor/communications/transport-types/offline/README.md) (`offline`) is a dummy transport indicates there are no comms in the current environment.
* [Simulator](https://github.com/decentraland/docs/blob/main/contributor/communications/transport-types/simulator/README.md) (`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](https://github.com/decentraland/docs/blob/main/contributor/communications/messages/README.md)). Some transports may wrap them in control structures for transmission, but these should be unpacked before crossing the `Transport` interface.

### Recommended Design <a href="#recommended" id="recommended"></a>

This is a minimal `Transport` interface written in TypeScript:

```ts
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](https://github.com/decentraland/docs/blob/main/contributor/communications/transport-types/livekit/README.md) 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](https://github.com/decentraland/docs/blob/main/contributor/communications/transport-types/websocket/README.md) 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:

```ts
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](https://github.com/decentraland/docs/blob/main/contributor/communications/transport-types/websocket/README.md) and [LiveKit](https://github.com/decentraland/docs/blob/main/contributor/communications/transport-types/livekit/README.md) transports, which are currently in use by all major realms.

### Learn more

Head over to a [specific transport type](#types) section, read about the different [message types](https://github.com/decentraland/docs/blob/main/contributor/communications/messages/README.md) or check out the \[\[Comms Demo Station]].
