ODIN Gateway
This ODIN gateway server is written in Deno. It regulates access by spreading ODIN clients over available ODIN servers based on current and future usage. It also performs basic checks on customer license conditions.
sequenceDiagram
participant Client
participant Gateway
participant Server
Server ->> Gateway: sfu.GridConfig RPC
activate Gateway
Gateway -->> Server: Receive recommended settings
deactivate Gateway
loop every n seconds
Server ->> Gateway: sfu.Report RPC
activate Gateway
Gateway -->> Server: Receive enqueued tasks
deactivate Gateway
end
autonumber 1
Client ->> Gateway: Connect RPC
activate Gateway
Gateway -->> Client: Receive signed room token
deactivate Gateway
Client ->> Server: Join Room
Setup Development Environment
The following prerequisites are necessary to start development:
Configuration
The gateway is configured using a TypeScript configuration file (config.ts). In addition, the following optional command-line arguments are available to enforce specific options:
Option | Description |
---|---|
--host | The IP address to listen on |
--port | The TCP port number to listen on |
--ssl | Enable HTTPS |
--certificate | The certificate file to use |
--privatekey | The private key file to use |
Note: For local testing, using mkcert is recommended.
Importing Customer Keys
Instead of providing a static list of customer keys in the gateway configuration file, you can also write your own custom import function, which needs to return a Promise<Customer[]>
value.
customerApi: {
updateFunction: myFunction, // async function returning a list of customers
updateInterval: 300, // interval in seconds
},
This function can be used to either fetch your customer keys from a RESTful API or a reload file on disk. Here’s an example:
async function myFunction(): Promise<Customer[]> {
try {
const response = await fetch("https://domain.tld/api/customer-keys");
if (response.status !== 200) {
throw "something went wrong";
}
return await response.json();
} catch (_e) {
// handle error
}
return [];
}
How to Start
# start a HTTP server on port 7000
deno run --unstable --allow-net --import-map=imports.json main.ts
# start a HTTPS server on port 7000
deno run --unstable --allow-net --allow-read=. --import-map=imports.json main.ts --ssl
Note: If you don’t want to install Deno on the target system, you can also compile the scripts into a self-containing executable. Click here for details.
Public API
Authentication
Authentication for the public API is done using a Bearer
token signed with an ODIN access key. When specified, the audience claim (aud) in the token must be set to gateway
. The payload of a decoded JWT looks like this:
{
"rid": "foo",
"uid": "bar",
"aud": "gateway",
"sub": "connect",
"exp": 1669852860,
"nbf": 1669852800
}
For details on generating tokens, please refer to @4players/odin-tokens.
RPC Methods
To use any of the following methods, the JWT used to authorize must have its name listed in the subject claim (sub).
Connect
Authorizes ODIN clients to access the room specified in the Bearer
token and responds with a new JWT signed with the gateway master key, which can be used to join a room on an attached ODIN server.
curl --request POST \
--url http://localhost:7000/ \
--header 'Authorization: Bearer ${JWT}' \
--header 'Content-Type: application/json' \
--data '{
"jsonrpc": "2.0",
"method": "Connect",
"params": {},
"id": 1
}'
RoomClose
Closes the specified room (if available) and prevents it from being joined again until ban_time
is expired.
curl --request POST \
--url http://localhost:7000/ \
--header 'Authorization: Bearer ${JWT}' \
--header 'Content-Type: application/json' \
--data '{
"jsonrpc": "2.0",
"method": "RoomClose",
"params": {
"room_id": "${ROOM_ID}",
"ban_time": ${OPTIONAL_TIME_IN_SECONDS},
},
"id": 1
}'
RoomUpdate
Updates the global user data of the specified room using the given user_data
byte array.
curl --request POST \
--url https://localhost:7000/ \
--header 'Authorization: Bearer ${JWT}' \
--header 'Content-Type: application/json' \
--data '{
"jsonrpc": "2.0",
"method": "RoomUpdate",
"params": {
"room_id": "${ROOM_ID}",
"user_data": ${ARRAY_OF_BYTES}
},
"id": 1
}'
RoomBanClient
Kicks all clients matching the specified user_id
from the specified room and prevents them from joining again until ban_time
is expired.
curl --request POST \
--url http://localhost:7000/ \
--header 'Authorization: Bearer ${JWT}' \
--header 'Content-Type: application/json' \
--data '{
"jsonrpc": "2.0",
"method": "RoomBanClient",
"params": {
"room_id": "${ROOM_ID}",
"user_id": "${PEER_USER_ID}",
"ban_time": ${OPTIONAL_TIME_IN_SECONDS},
},
"id": 1
}'
RoomSendMessage
Sends arbitrary data to all clients matching the specified user_id
in the specified room.
curl --request POST \
--url https://localhost:7000/ \
--header 'Authorization: Bearer ${JWT}' \
--header 'Content-Type: application/json' \
--data '{
"jsonrpc": "2.0",
"method": "RoomSendMessage",
"params": {
"room_id": "${ROOM_ID}",
"user_id": "${PEER_USER_ID}",
"message": ${ARRAY_OF_BYTES}
},
"id": 1
}'