Packages
game_server_sdk
1.0.1087
1.0.1087
1.0.1086
1.0.1084
1.0.1083
1.0.1082
1.0.1079
1.0.1078
1.0.1077
1.0.1076
1.0.1075
1.0.1074
1.0.1073
1.0.1070
1.0.1068
1.0.1067
1.0.1063
1.0.1059
1.0.1058
1.0.1057
1.0.1056
1.0.1055
1.0.1050
1.0.1049
1.0.1048
1.0.1047
1.0.1046
1.0.1044
1.0.1043
1.0.1042
1.0.1041
1.0.1040
1.0.1039
1.0.1038
1.0.1034
1.0.1033
1.0.1029
1.0.1028
1.0.1026
1.0.1025
1.0.1024
1.0.1023
1.0.1022
1.0.1021
1.0.1020
1.0.1019
1.0.1018
1.0.1017
1.0.1016
1.0.1015
1.0.1014
1.0.1013
1.0.1012
1.0.1011
1.0.1009
1.0.1008
1.0.1007
1.0.1006
1.0.1005
1.0.1004
1.0.1003
1.0.1001
1.0.999
1.0.998
1.0.997
1.0.996
1.0.995
1.0.994
1.0.993
1.0.992
1.0.991
1.0.990
1.0.989
1.0.988
1.0.987
1.0.986
1.0.985
1.0.984
1.0.983
1.0.982
1.0.981
1.0.980
1.0.979
1.0.978
1.0.977
1.0.976
1.0.975
1.0.974
1.0.973
1.0.972
1.0.971
1.0.970
1.0.969
1.0.968
1.0.967
1.0.966
1.0.965
1.0.964
1.0.963
1.0.962
1.0.961
1.0.959
1.0.958
1.0.956
1.0.951
1.0.950
1.0.943
1.0.942
1.0.941
1.0.940
1.0.938
1.0.936
1.0.935
1.0.931
1.0.929
1.0.928
1.0.927
1.0.926
1.0.925
1.0.924
1.0.923
1.0.921
1.0.920
1.0.919
1.0.918
1.0.917
1.0.916
1.0.911
1.0.910
1.0.902
1.0.899
1.0.898
1.0.897
1.0.896
1.0.894
1.0.893
1.0.891
1.0.890
1.0.889
1.0.888
1.0.887
1.0.886
1.0.885
1.0.884
1.0.883
1.0.882
1.0.881
1.0.880
1.0.879
1.0.878
1.0.877
1.0.26
1.0.25
1.0.22
1.0.21
1.0.20
1.0.19
1.0.15
1.0.14
1.0.13
1.0.12
1.0.10
1.0.9
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.1.0
SDK for GameServer hooks development. Provides type specs, documentation, and IDE autocomplete for GameServer modules without requiring the full server.
Current section
Files
Jump to
Current section
Files
lib/game_server/signaling.ex
defmodule GameServer.Signaling do
@moduledoc ~S"""
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.
"""
@type config() :: %{
topology: topology(),
host_user_id: user_id() | nil,
late_join: boolean(),
reconnect_timeout: non_neg_integer()
}
@type message_type() :: :offer | :answer | :ice
@type role() :: :host | :user
@type topology() :: :mesh | :star
@type user_id() :: String.t()
@type room_id() :: String.t()
@doc ~S"""
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.
"""
@spec authorize(room_id(), user_id()) :: {:ok, role()} | {:error, :room_not_found | :not_allowed}
def authorize(_room_id, _user_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
{:ok, nil}
_ ->
raise "GameServer.Signaling.authorize/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Sends `payload` to every other peer in the room.
Only the host may broadcast in a star room.
"""
@spec broadcast(room_id(), user_id(), message_type(), map()) ::
:ok | {:error, :room_not_found | :user_not_found | :not_allowed}
def broadcast(_room_id, _from, _type, _payload) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
:ok
_ ->
raise "GameServer.Signaling.broadcast/4 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Tells every connected peer the room is over, so their channels stop.
"""
@spec close(room_id()) :: :ok
def close(_room_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
:ok
_ ->
raise "GameServer.Signaling.close/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
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.
"""
@spec config(room_id()) :: {:ok, config()} | {:error, :room_not_found}
def config(_room_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
if :erlang.phash2(make_ref(), 2) == 0, do: {:error, :room_not_found}, else: {:ok, %{topology: :star, host_user_id: Enum.random([nil, "00000000-0000-0000-0000-000000000000"]), late_join: true, reconnect_timeout: 30_000}}
_ ->
raise "GameServer.Signaling.config/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
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.
"""
@spec configure(
GameServer.Lobbies.Lobby.t() | room_id(),
keyword()
) :: {:ok, GameServer.Lobbies.Lobby.t()} | {:error, term()}
def configure(_room_id, _opts) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
{:ok, %GameServer.Lobbies.Lobby{id: 0, title: "", host_id: nil, hostless: false, max_users: 0, is_hidden: false, is_locked: false, metadata: %{}, inserted_at: ~U[1970-01-01 00:00:00Z], updated_at: ~U[1970-01-01 00:00:00Z]}}
_ ->
raise "GameServer.Signaling.configure/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Whether the lobby has WebRTC enabled.
"""
@spec enabled?(room_id()) :: boolean()
def enabled?(_room_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
:erlang.phash2(make_ref(), 2) == 0
_ ->
raise "GameServer.Signaling.enabled?/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
PubSub topic one peer listens on for messages addressed to it.
"""
@spec inbox(room_id(), user_id()) :: String.t()
def inbox(_room_id, _user_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
""
_ ->
raise "GameServer.Signaling.inbox/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
The role `user_id` is connected with, or `nil`.
"""
@spec peer_role(room_id(), user_id()) :: role() | nil
def peer_role(_room_id, _user_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
nil
_ ->
raise "GameServer.Signaling.peer_role/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
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.
"""
@spec peers(room_id()) :: %{required(user_id()) => role()}
def peers(_room_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
%{}
_ ->
raise "GameServer.Signaling.peers/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Sends `payload` to one peer.
In a star room every exchange must involve the host; in a mesh room any pair
may talk.
"""
@spec relay(room_id(), user_id(), user_id(), message_type(), map()) ::
:ok | {:error, :room_not_found | :user_not_found | :not_allowed}
def relay(_room_id, _from, _to, _type, _payload) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
:ok
_ ->
raise "GameServer.Signaling.relay/5 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
PubSub topic carrying a room's presence.
"""
@spec topic(room_id()) :: String.t()
def topic(_room_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
""
_ ->
raise "GameServer.Signaling.topic/1 is a stub - only available at runtime on GameServer"
end
end
end