GameServer.Signaling (game_server_sdk v1.0.1087)

Copy Markdown View Source

WebRTC signaling: who is in a room, and relaying offers between them.

A "room" is a lobby. There is no room record and no room process — the configuration lives in the lobby's own webrtc_* columns, membership lives in GameServer.Presence, and relayed messages travel over Phoenix.PubSub. All three are cluster-wide, so a peer on one node can signal a peer on another.

That is the reason for this shape. The previous version kept rooms in a GenServer registered under a plain local name, so a room created on one node did not exist on any other, and every player whose socket landed elsewhere failed to join with :room_not_found.

Configuration

Read from the lobby, never mirrored:

Signaling.configure(lobby, enabled: true, topology: :star)

Held in server-owned lobbies.webrtc_* columns, written only by configure/2. It lived in metadata once, which was wrong twice over: that map is replaced wholesale by any writer, so a game storing match state wiped it, and the lobby host can PATCH it, so a player could flip the topology and hand everyone the right to broadcast. The star host is always lobby.host_id and is not settable.

Topology

  • :mesh — any peer may signal any other.
  • :star — every exchange must involve the host, and only the host may broadcast.

Note: This is an SDK stub. Calling these functions will raise an error. The actual implementation runs on the GameServer.

Summary

Functions

The role user_id may join with, or {:error, :not_allowed}.

Sends payload to every other peer in the room.

Tells every connected peer the room is over, so their channels stop.

The room's configuration, derived from the lobby.

Turns signaling on or off for a lobby, and sets how it behaves.

Whether the lobby has WebRTC enabled.

PubSub topic one peer listens on for messages addressed to it.

The role user_id is connected with, or nil.

Everyone currently connected to the room, as %{user_id => role}.

Sends payload to one peer.

PubSub topic carrying a room's presence.

Types

config()

@type config() :: %{
  topology: topology(),
  host_user_id: user_id() | nil,
  late_join: boolean(),
  reconnect_timeout: non_neg_integer()
}

message_type()

@type message_type() :: :offer | :answer | :ice

role()

@type role() :: :host | :user

room_id()

@type room_id() :: String.t()

topology()

@type topology() :: :mesh | :star

user_id()

@type user_id() :: String.t()

Functions

authorize(room_id, user_id)

@spec authorize(room_id(), user_id()) ::
  {:ok, role()} | {:error, :room_not_found | :not_allowed}

The role user_id may join with, or {:error, :not_allowed}.

Membership comes from the lobby. late_join decides whether a non-member may connect at all; the host of a star room is whoever the lobby says it is.

broadcast(room_id, from, type, payload)

@spec broadcast(room_id(), user_id(), message_type(), map()) ::
  :ok | {:error, :room_not_found | :user_not_found | :not_allowed}

Sends payload to every other peer in the room.

Only the host may broadcast in a star room.

close(room_id)

@spec close(room_id()) :: :ok

Tells every connected peer the room is over, so their channels stop.

config(room_id)

@spec config(room_id()) :: {:ok, config()} | {:error, :room_not_found}

The room's configuration, derived from the lobby.

{:error, :room_not_found} when the lobby is gone or WebRTC is not enabled on it — deliberately indistinguishable to a caller.

configure(room_id, opts)

@spec configure(
  GameServer.Lobbies.Lobby.t() | room_id(),
  keyword()
) :: {:ok, GameServer.Lobbies.Lobby.t()} | {:error, term()}

Turns signaling on or off for a lobby, and sets how it behaves.

The only writer of the webrtc_* columns. Options: :enabled, :topology (:star | :mesh), :late_join, :reconnect_timeout.

Deliberately not part of the lobby changeset — a client PATCH must not be able to reach any of it. The star host is not settable at all; it is always the lobby host.

enabled?(room_id)

@spec enabled?(room_id()) :: boolean()

Whether the lobby has WebRTC enabled.

inbox(room_id, user_id)

@spec inbox(room_id(), user_id()) :: String.t()

PubSub topic one peer listens on for messages addressed to it.

peer_role(room_id, user_id)

@spec peer_role(room_id(), user_id()) :: role() | nil

The role user_id is connected with, or nil.

peers(room_id)

@spec peers(room_id()) :: %{required(user_id()) => role()}

Everyone currently connected to the room, as %{user_id => role}.

The role is computed from the lobby on every read rather than read back from the presence meta it was tracked with. Otherwise a host change leaves the new host tracked as :user and the old one still holding :host until they happen to reconnect.

relay(room_id, from, to, type, payload)

@spec relay(room_id(), user_id(), user_id(), message_type(), map()) ::
  :ok | {:error, :room_not_found | :user_not_found | :not_allowed}

Sends payload to one peer.

In a star room every exchange must involve the host; in a mesh room any pair may talk.

topic(room_id)

@spec topic(room_id()) :: String.t()

PubSub topic carrying a room's presence.