зеркало из https://github.com/nextcloud/spreed.git
Remove API documentation of standalone signaling server.
Signed-off-by: Joachim Bauch <bauch@struktur.de>
This commit is contained in:
Родитель
8c47c71232
Коммит
3631005abf
|
@ -1,802 +0,0 @@
|
|||
# External signaling API
|
||||
|
||||
This document gives a rough overview on the API version 1.0 of the Spreed
|
||||
signaling server. Clients can use the signaling server to send realtime
|
||||
messages between different users / sessions.
|
||||
|
||||
The API describes the various messages that can be sent by a client or the
|
||||
server to join rooms or distribute events between clients.
|
||||
|
||||
Depending on the server implementation, clients can use WebSockets (preferred)
|
||||
or COMET (i.e. long-polling) requests to communicate with the signaling server.
|
||||
|
||||
For WebSockets, only the API described in this document is necessary. For COMET,
|
||||
an extension to this API is required to identify a (virtual) connection between
|
||||
multiple requests. The payload for COMET is the messages as described below.
|
||||
|
||||
See [Internal signaling API](internal-signaling.md) for the API of the regular PHP backend.
|
||||
|
||||
|
||||
## Request
|
||||
|
||||
{
|
||||
"id": "unique-request-id",
|
||||
"type": "the-request-type",
|
||||
"the-request-type": {
|
||||
...object defining the request...
|
||||
}
|
||||
}
|
||||
|
||||
Example:
|
||||
|
||||
{
|
||||
"id": "123-abc",
|
||||
"type": "samplemessage",
|
||||
"samplemessage": {
|
||||
"foo": "bar",
|
||||
"baz": 1234
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
## Response
|
||||
|
||||
{
|
||||
"id": "unique-request-id-from-request-if-present",
|
||||
"type": "the-response-type",
|
||||
"the-response-type": {
|
||||
...object defining the response...
|
||||
}
|
||||
}
|
||||
|
||||
Example:
|
||||
|
||||
{
|
||||
"id": "123-abc",
|
||||
"type": "sampleresponse",
|
||||
"sampleresponse": {
|
||||
"hello": "world!"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
## Errors
|
||||
|
||||
The server can send error messages as a response to any request the client has
|
||||
sent.
|
||||
|
||||
Message format:
|
||||
|
||||
{
|
||||
"id": "unique-request-id-from-request-if-present",
|
||||
"type": "error",
|
||||
"error": {
|
||||
"code": "the-internal-message-id",
|
||||
"message": "human-readable-error-message",
|
||||
"details": {
|
||||
...optional additional details...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
## Backend requests
|
||||
|
||||
For some messages, the signaling server has to perform a request to the
|
||||
Nextcloud backend (e.g. to validate the user authentication). The backend
|
||||
must be able to verify the request to make sure it is coming from a valid
|
||||
signaling server.
|
||||
|
||||
Also the Nextcloud backend can send requests to the signaling server to notify
|
||||
about events related to a room or user (e.g. a user is no longer invited to
|
||||
a room). Here the signaling server must be able to verify the request to check
|
||||
if it is coming from a valid Nextcloud instance.
|
||||
|
||||
Therefore all backend requests, either from the signaling server or vice versa
|
||||
must contain two additional HTTP headers:
|
||||
|
||||
- `Spreed-Signaling-Random`: Random string of at least 32 bytes.
|
||||
- `Spreed-Signaling-Checksum`: SHA256-HMAC of the random string and the request
|
||||
body, calculated with a shared secret. The shared secret is configured on
|
||||
both sides, so the checksum can be verified.
|
||||
- `Spreed-Signaling-Backend`: Base URL of the Nextcloud server performing the
|
||||
request.
|
||||
|
||||
### Example
|
||||
|
||||
- Request body: `{"type":"auth","auth":{"version":"1.0","params":{"hello":"world"}}}`
|
||||
- Random: `afb6b872ab03e3376b31bf0af601067222ff7990335ca02d327071b73c0119c6`
|
||||
- Shared secret: `MySecretValue`
|
||||
- Calculated checksum: `3c4a69ff328299803ac2879614b707c807b4758cf19450755c60656cac46e3bc`
|
||||
|
||||
|
||||
## Establish connection
|
||||
|
||||
This must be the first request by a newly connected client and is used to
|
||||
authenticate the connection. No other messages can be sent without a successful
|
||||
`hello` handshake.
|
||||
|
||||
Message format (Client -> Server):
|
||||
|
||||
{
|
||||
"id": "unique-request-id",
|
||||
"type": "hello",
|
||||
"hello": {
|
||||
"version": "the-protocol-version-must-be-1.0",
|
||||
"auth": {
|
||||
"url": "the-url-to-the-auth-backend",
|
||||
"params": {
|
||||
...object containing auth params...
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Message format (Server -> Client):
|
||||
|
||||
{
|
||||
"id": "unique-request-id-from-request",
|
||||
"type": "hello",
|
||||
"hello": {
|
||||
"sessionid": "the-unique-session-id",
|
||||
"resumeid": "the-unique-resume-id",
|
||||
"userid": "the-user-id-for-known-users",
|
||||
"version": "the-protocol-version-must-be-1.0",
|
||||
"server": {
|
||||
"features": ["optional", "list, "of", "feature", "ids"],
|
||||
...additional information about the server...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
### Backend validation
|
||||
|
||||
The server validates the connection request against the passed auth backend
|
||||
(needs to make sure the passed url / hostname is in a whitelist). It performs
|
||||
a POST request and passes the provided `params` as JSON payload in the body
|
||||
of the request.
|
||||
|
||||
Message format (Server -> Auth backend):
|
||||
|
||||
{
|
||||
"type": "auth",
|
||||
"auth": {
|
||||
"version": "the-protocol-version-must-be-1.0",
|
||||
"params": {
|
||||
...object containing auth params from hello request...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
If the auth params are valid, the backend returns information about the user
|
||||
that is connecting (as JSON response).
|
||||
|
||||
Message format (Auth backend -> Server):
|
||||
|
||||
{
|
||||
"type": "auth",
|
||||
"auth": {
|
||||
"version": "the-protocol-version-must-be-1.0",
|
||||
"userid": "the-user-id-for-known-users",
|
||||
"user": {
|
||||
...additional data of the user...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Anonymous connections that are not mapped to a user in Nextcloud will have an
|
||||
empty or omitted `userid` field in the response. If the connection can not be
|
||||
authorized, the backend returns an error and the hello request will be rejected.
|
||||
|
||||
|
||||
### Error codes
|
||||
|
||||
- `unsupported-version`: The requested version is not supported.
|
||||
- `auth-failed`: The session could not be authenticated.
|
||||
- `too-many-sessions`: Too many sessions exist for this user id.
|
||||
- `invalid_backend`: The requested backend URL is not supported.
|
||||
- `invalid_client_type`: The [client type](#client-types) is not supported.
|
||||
- `invalid_token`: The passed token is invalid (can happen for
|
||||
[client type `internal`](#client-type-internal)).
|
||||
|
||||
|
||||
### Client types
|
||||
|
||||
In order to support clients with different functionality on the server, an
|
||||
optional `type` can be specified in the `auth` struct when connecting to the
|
||||
server. If no `type` is present, the default value `client` will be used and
|
||||
a regular "user" client is created internally.
|
||||
|
||||
Message format (Client -> Server):
|
||||
|
||||
{
|
||||
"id": "unique-request-id",
|
||||
"type": "hello",
|
||||
"hello": {
|
||||
"version": "the-protocol-version-must-be-1.0",
|
||||
"auth": {
|
||||
"type": "the-client-type",
|
||||
...other attributes depending on the client type...
|
||||
"params": {
|
||||
...object containing auth params...
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
The key `params` is required for all client types, other keys depend on the
|
||||
`type` value.
|
||||
|
||||
|
||||
#### Client type `client` (default)
|
||||
|
||||
For the client type `client` (which is the default if no `type` is given), the
|
||||
URL to the backend server for this client must be given as described above.
|
||||
|
||||
This client type must be supported by all server implementations of the
|
||||
signaling protocol.
|
||||
|
||||
|
||||
#### Client type `internal`
|
||||
|
||||
"Internal" clients are used for connections from internal services where the
|
||||
connection doesn't map to a user (or session) in Nextcloud.
|
||||
|
||||
These clients can skip some internal validations, e.g. they can join any room,
|
||||
even if they have not been invited (which is not possible as the client doesn't
|
||||
map to a user). This client type is not required to be supported by server
|
||||
implementations of the signaling protocol, but some additional services might
|
||||
not work without "internal" clients.
|
||||
|
||||
To authenticate the connection, the `params` struct must contain keys `random`
|
||||
(containing any random string of at least 32 bytes) and `token` containing the
|
||||
SHA-256 HMAC of `random` with a secret that is shared between the signaling
|
||||
server and the service connecting to it.
|
||||
|
||||
|
||||
## Resuming sessions
|
||||
|
||||
If a connection was interrupted for a client, the server may decide to keep the
|
||||
session alive for a short time, so the client can reconnect and resume the
|
||||
session.
|
||||
|
||||
In this case, no complete `hello` handshake is required and a client can use
|
||||
a shorter `hello` request. On success, the session will resume as if no
|
||||
interruption happened, i.e. the client will stay in his room and will get all
|
||||
messages from the time the interruption happened.
|
||||
|
||||
Message format (Client -> Server):
|
||||
|
||||
{
|
||||
"id": "unique-request-id",
|
||||
"type": "hello",
|
||||
"hello": {
|
||||
"version": "the-protocol-version-must-be-1.0",
|
||||
"resumeid": "the-resume-id-from-the-original-hello-response"
|
||||
}
|
||||
}
|
||||
|
||||
Message format (Server -> Client):
|
||||
|
||||
{
|
||||
"id": "unique-request-id-from-request",
|
||||
"type": "hello",
|
||||
"hello": {
|
||||
"sessionid": "the-unique-session-id",
|
||||
"version": "the-protocol-version-must-be-1.0"
|
||||
}
|
||||
}
|
||||
|
||||
If the session is no longer valid (e.g. because the resume was too late), the
|
||||
server will return an error and a normal `hello` handshake has to be performed.
|
||||
|
||||
|
||||
### Error codes
|
||||
|
||||
- `no_such_session`: The session id is no longer valid.
|
||||
|
||||
|
||||
## Releasing sessions
|
||||
|
||||
By default, the signaling server tries to maintain the session so clients can
|
||||
resume it in case of intermittent connection problems.
|
||||
|
||||
To support cases where a client wants to close the connection and release all
|
||||
session data, he can send a `bye` message so the server knows he doesn't need
|
||||
to keep data for resuming.
|
||||
|
||||
Message format (Client -> Server):
|
||||
|
||||
{
|
||||
"id": "unique-request-id",
|
||||
"type": "bye",
|
||||
"bye": {}
|
||||
}
|
||||
|
||||
Message format (Server -> Client):
|
||||
|
||||
{
|
||||
"id": "unique-request-id-from-request",
|
||||
"type": "bye",
|
||||
"bye": {}
|
||||
}
|
||||
|
||||
After the `bye` has been confirmed, the session can no longer be used.
|
||||
|
||||
|
||||
## Join room
|
||||
|
||||
After joining the room through the PHP backend, the room must be changed on the
|
||||
signaling server, too.
|
||||
|
||||
Message format (Client -> Server):
|
||||
|
||||
{
|
||||
"id": "unique-request-id",
|
||||
"type": "room",
|
||||
"room": {
|
||||
"roomid": "the-room-id",
|
||||
"sessionid": "the-nextcloud-session-id"
|
||||
}
|
||||
}
|
||||
|
||||
- The client can ask about joining a room using this request.
|
||||
- The session id received from the PHP backend must be passed as `sessionid`.
|
||||
- The `roomid` can be empty to leave the room.
|
||||
- A session can only be connected to one room, i.e. joining a room will leave
|
||||
the room currently in.
|
||||
|
||||
Message format (Server -> Client):
|
||||
|
||||
{
|
||||
"id": "unique-request-id-from-request",
|
||||
"type": "room",
|
||||
"room": {
|
||||
"roomid": "the-room-id",
|
||||
"properties": {
|
||||
...additional room properties...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- Sent to confirm a request from the client.
|
||||
- The `roomid` will be empty if the client is no longer in a room.
|
||||
- Can be sent without a request if the server moves a client to a room / out of
|
||||
the current room or the properties of a room change.
|
||||
|
||||
|
||||
### Backend validation
|
||||
|
||||
Rooms are managed by the Nextcloud backend, so the signaling server has to
|
||||
verify that a room exists and a user is allowed to join it.
|
||||
|
||||
Message format (Server -> Room backend):
|
||||
|
||||
{
|
||||
"type": "room",
|
||||
"room": {
|
||||
"version": "the-protocol-version-must-be-1.0",
|
||||
"roomid": "the-room-id",
|
||||
"userid": "the-user-id-for-known-users",
|
||||
"sessionid": "the-nextcloud-session-id",
|
||||
"action": "join-or-leave"
|
||||
}
|
||||
}
|
||||
|
||||
The `userid` is empty or omitted for anonymous sessions that don't belong to a
|
||||
user in Nextcloud.
|
||||
|
||||
Message format (Room backend -> Server):
|
||||
|
||||
{
|
||||
"type": "room",
|
||||
"room": {
|
||||
"version": "the-protocol-version-must-be-1.0",
|
||||
"roomid": "the-room-id",
|
||||
"properties": {
|
||||
...additional room properties...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
If the room does not exist or can not be joined by the given (or anonymous)
|
||||
user, the backend returns an error and the room request will be rejected.
|
||||
|
||||
|
||||
### Error codes
|
||||
|
||||
- `no_such_room`: The requested room does not exist or the user is not invited
|
||||
to the room.
|
||||
|
||||
|
||||
## Leave room
|
||||
|
||||
To leave a room, a [join room](#join-room) message must be sent with an empty
|
||||
`roomid` parameter.
|
||||
|
||||
|
||||
## Room events
|
||||
|
||||
When users join or leave a room, the server generates events that are sent to
|
||||
all sessions in that room. Such events are also sent to users joining a room
|
||||
as initial list of users in the room. Multiple user joins/leaves can be batched
|
||||
into one event to reduce the message overhead.
|
||||
|
||||
Message format (Server -> Client, user(s) joined):
|
||||
|
||||
{
|
||||
"type": "event"
|
||||
"event": {
|
||||
"target": "room",
|
||||
"type": "join",
|
||||
"join": [
|
||||
...list of session objects that joined the room...
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Room event session object:
|
||||
|
||||
{
|
||||
"sessionid": "the-unique-session-id",
|
||||
"userid": "the-user-id-for-known-users",
|
||||
"user": {
|
||||
...additional data of the user as received from the auth backend...
|
||||
}
|
||||
}
|
||||
|
||||
Message format (Server -> Client, user(s) left):
|
||||
|
||||
{
|
||||
"type": "event"
|
||||
"event": {
|
||||
"target": "room",
|
||||
"type": "leave",
|
||||
"leave": [
|
||||
...list of session ids that left the room...
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Message format (Server -> Client, user(s) changed):
|
||||
|
||||
{
|
||||
"type": "event"
|
||||
"event": {
|
||||
"target": "room",
|
||||
"type": "change",
|
||||
"change": [
|
||||
...list of sessions that have changed...
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
## Room list events
|
||||
|
||||
When users are invited to rooms or are disinvited from them, they get notified
|
||||
so they can update the list of available rooms.
|
||||
|
||||
Message format (Server -> Client, invited to room):
|
||||
|
||||
{
|
||||
"type": "event"
|
||||
"event": {
|
||||
"target": "roomlist",
|
||||
"type": "invite",
|
||||
"invite": [
|
||||
"roomid": "the-room-id",
|
||||
"properties": [
|
||||
...additional room properties...
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Message format (Server -> Client, disinvited from room):
|
||||
|
||||
{
|
||||
"type": "event"
|
||||
"event": {
|
||||
"target": "roomlist",
|
||||
"type": "disinvite",
|
||||
"disinvite": [
|
||||
"roomid": "the-room-id"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Message format (Server -> Client, room updated):
|
||||
|
||||
{
|
||||
"type": "event"
|
||||
"event": {
|
||||
"target": "roomlist",
|
||||
"type": "update",
|
||||
"update": [
|
||||
"roomid": "the-room-id",
|
||||
"properties": [
|
||||
...additional room properties...
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
## Participants list events
|
||||
|
||||
When the list of participants or flags of a participant in a room changes, an
|
||||
event is triggered by the server so clients can update their UI accordingly or
|
||||
trigger actions like starting calls with other peers.
|
||||
|
||||
Message format (Server -> Client, participants change):
|
||||
|
||||
{
|
||||
"type": "event"
|
||||
"event": {
|
||||
"target": "participants",
|
||||
"type": "update",
|
||||
"update": [
|
||||
"roomid": "the-room-id",
|
||||
"users": [
|
||||
...list of changed participant objects...
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
If a participant has the `inCall` flag set, he has joined the call of the room
|
||||
and a WebRTC peerconnection should be established if the local client is also
|
||||
in the call. In that case the participant information will contain properties
|
||||
for both the signaling session id (`sessionId`) and the Nextcloud session id
|
||||
(`nextcloudSessionId`).
|
||||
|
||||
|
||||
## Room messages
|
||||
|
||||
The server can notify clients about events that happened in a room. Currently
|
||||
such messages are only sent out when chat messages are posted to notify clients
|
||||
they should load the new messages.
|
||||
|
||||
Message format (Server -> Client, chat messages available):
|
||||
|
||||
{
|
||||
"type": "event"
|
||||
"event": {
|
||||
"target": "room",
|
||||
"type": "message",
|
||||
"message": {
|
||||
"roomid": "the-room-id",
|
||||
"data": {
|
||||
"type": "chat",
|
||||
"chat": {
|
||||
"refresh": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
## Sending messages between clients
|
||||
|
||||
Messages between clients are sent realtime and not stored by the server, i.e.
|
||||
they are only delivered if the recipient is currently connected. This also
|
||||
applies to rooms, where only sessions currently in the room will receive the
|
||||
messages, but not if they join at a later time.
|
||||
|
||||
Use this for establishing WebRTC connections between peers, i.e. sending offers,
|
||||
answers and candidates.
|
||||
|
||||
Message format (Client -> Server, to other sessions):
|
||||
|
||||
{
|
||||
"id": "unique-request-id",
|
||||
"type": "message",
|
||||
"message": {
|
||||
"recipient": {
|
||||
"type": "session",
|
||||
"sessionid": "the-session-id-to-send-to"
|
||||
},
|
||||
"data": {
|
||||
...object containing the data to send...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Message format (Client -> Server, to all sessions of a user):
|
||||
|
||||
{
|
||||
"id": "unique-request-id",
|
||||
"type": "message",
|
||||
"message": {
|
||||
"recipient": {
|
||||
"type": "user",
|
||||
"userid": "the-user-id-to-send-to"
|
||||
},
|
||||
"data": {
|
||||
...object containing the data to send...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Message format (Client -> Server, to all sessions in the same room):
|
||||
|
||||
{
|
||||
"id": "unique-request-id",
|
||||
"type": "message",
|
||||
"message": {
|
||||
"recipient": {
|
||||
"type": "room"
|
||||
},
|
||||
"data": {
|
||||
...object containing the data to send...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Message format (Server -> Client, receive message)
|
||||
|
||||
{
|
||||
"type": "message",
|
||||
"message": {
|
||||
"sender": {
|
||||
"type": "the-type-when-sending",
|
||||
"sessionid": "the-session-id-of-the-sender",
|
||||
"userid": "the-user-id-of-the-sender"
|
||||
},
|
||||
"data": {
|
||||
...object containing the data of the message...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- The `userid` is omitted if a message was sent by an anonymous user.
|
||||
|
||||
|
||||
# Internal signaling server API
|
||||
|
||||
The signaling server provides an internal API that can be called from Nextcloud
|
||||
to trigger events from the server side.
|
||||
|
||||
|
||||
## Rooms API
|
||||
|
||||
The base URL for the rooms API is `/api/vi/room/<roomid>`, all requests must be
|
||||
sent as `POST` request with proper checksum headers as described above.
|
||||
|
||||
|
||||
### New users invited to room
|
||||
|
||||
This can be used to notify users that they are now invited to a room.
|
||||
|
||||
Message format (Backend -> Server)
|
||||
|
||||
{
|
||||
"type": "invite"
|
||||
"invite" {
|
||||
"userids": [
|
||||
...list of user ids that are now invited to the room...
|
||||
],
|
||||
"alluserids": [
|
||||
...list of all user ids that invited to the room...
|
||||
],
|
||||
"properties": [
|
||||
...additional room properties...
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
### Users no longer invited to room
|
||||
|
||||
This can be used to notify users that they are no longer invited to a room.
|
||||
|
||||
Message format (Backend -> Server)
|
||||
|
||||
{
|
||||
"type": "disinvite"
|
||||
"disinvite" {
|
||||
"userids": [
|
||||
...list of user ids that are no longer invited to the room...
|
||||
],
|
||||
"alluserids": [
|
||||
...list of all user ids that still invited to the room...
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
### Room updated
|
||||
|
||||
This can be used to notify about changes to a room. The room properties are the
|
||||
same as described in section "Join room" above.
|
||||
|
||||
Message format (Backend -> Server)
|
||||
|
||||
{
|
||||
"type": "update"
|
||||
"update" {
|
||||
"userids": [
|
||||
...list of user ids that are invited to the room...
|
||||
],
|
||||
"properties": [
|
||||
...additional room properties...
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
### Room deleted
|
||||
|
||||
This can be used to notify about a deleted room. All sessions currently
|
||||
connected to the room will leave the room.
|
||||
|
||||
Message format (Backend -> Server)
|
||||
|
||||
{
|
||||
"type": "delete"
|
||||
"delete" {
|
||||
"userids": [
|
||||
...list of user ids that were invited to the room...
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
### Participants changed
|
||||
|
||||
This can be used to notify about changed participants.
|
||||
|
||||
Message format (Backend -> Server)
|
||||
|
||||
{
|
||||
"type": "participants"
|
||||
"participants" {
|
||||
"changed": [
|
||||
...list of users that were changed...
|
||||
],
|
||||
"users": [
|
||||
...list of users in the room...
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
### In call state of participants changed
|
||||
|
||||
This can be used to notify about participants that changed their `inCall` flag.
|
||||
|
||||
Message format (Backend -> Server)
|
||||
|
||||
{
|
||||
"type": "incall"
|
||||
"incall" {
|
||||
"incall": new-incall-state,
|
||||
"changed": [
|
||||
...list of users that were changed...
|
||||
],
|
||||
"users": [
|
||||
...list of users in the room...
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
### Send an arbitrary room message
|
||||
|
||||
This can be used to send arbitrary messages to participants in a room. It is
|
||||
currently used to notify about new chat messages.
|
||||
|
||||
Message format (Backend -> Server)
|
||||
|
||||
{
|
||||
"type": "message"
|
||||
"message" {
|
||||
"data": {
|
||||
...arbitrary object to sent to clients...
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче