Packages

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
game_server_sdk lib game_server chat.ex
Raw

lib/game_server/chat.ex

defmodule GameServer.Chat do
@moduledoc ~S"""
Context for chat messaging across lobbies, groups, and friend DMs.
## Chat types
* `"lobby"` — messages within a lobby. `chat_ref_id` is the lobby id.
* `"group"` — messages within a group. `chat_ref_id` is the group id.
* `"friend"` — direct messages between two friends. `chat_ref_id` is the
other user's id (each user stores the *other* user's id so queries work
symmetrically).
## PubSub topics
* `"chat:lobby:<id>"` — lobby chat events
* `"chat:group:<id>"` — group chat events
* `"chat:friend:<low>:<high>"` — friend DM events (sorted pair of user ids)
## Hooks
* `before_chat_message/2` — pipeline hook `(user, attrs)` → `{:ok, attrs}` | `{:error, reason}`
* `after_chat_message/1` — fire-and-forget after a message is persisted
**Note:** This is an SDK stub. Calling these functions will raise an error.
The actual implementation runs on the GameServer.
"""
@doc ~S"""
Admin: delete a single message by id.
"""
@spec admin_delete_message(integer()) :: {:ok, GameServer.Chat.Message.t()} | {:error, term()}
def admin_delete_message(_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
{:ok, nil}
_ ->
raise "GameServer.Chat.admin_delete_message/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Delete all chat data (messages + read cursors) for a given conversation.
"""
@spec cleanup_chat(String.t(), integer()) :: :ok
def cleanup_chat(_chat_type, _chat_ref_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
:ok
_ ->
raise "GameServer.Chat.cleanup_chat/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Delete all friend DM messages and read cursors between two users.
Friend messages are stored bidirectionally (each user's messages use
the other's id as chat_ref_id), so both directions must be cleaned up.
"""
@spec cleanup_friend_chat(integer(), integer()) :: :ok
def cleanup_friend_chat(_user_a_id, _user_b_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
:ok
_ ->
raise "GameServer.Chat.cleanup_friend_chat/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Count all messages matching filters (admin).
"""
@spec count_all_messages(map()) :: non_neg_integer()
def count_all_messages(_filters) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
0
_ ->
raise "GameServer.Chat.count_all_messages/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Count total friend DM messages between two users.
"""
@spec count_friend_messages(integer(), integer()) :: non_neg_integer()
def count_friend_messages(_user_a_id, _user_b_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
0
_ ->
raise "GameServer.Chat.count_friend_messages/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Count total messages in a chat conversation.
"""
@spec count_messages(String.t(), integer()) :: non_neg_integer()
def count_messages(_chat_type, _chat_ref_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
0
_ ->
raise "GameServer.Chat.count_messages/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Count messages grouped by chat_type.
Returns a map like `%{"lobby" => 10, "group" => 5, "friend" => 3}`.
"""
@spec count_messages_by_type() :: map()
def count_messages_by_type() do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
%{}
_ ->
raise "GameServer.Chat.count_messages_by_type/0 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Count distinct users who have sent at least one chat message.
"""
@spec count_unique_senders() :: non_neg_integer()
def count_unique_senders() do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
0
_ ->
raise "GameServer.Chat.count_unique_senders/0 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Count unread messages for a user in a specific chat conversation.
Returns 0 if the user has read all messages or has no cursor (all are unread
in which case `count_messages/2` should be used instead).
"""
@spec count_unread(integer(), String.t(), integer()) :: non_neg_integer()
def count_unread(_user_id, _chat_type, _chat_ref_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
0
_ ->
raise "GameServer.Chat.count_unread/3 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Count unread friend DMs between two users for a specific user.
"""
@spec count_unread_friend(integer(), integer()) :: non_neg_integer()
def count_unread_friend(_user_id, _friend_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
0
_ ->
raise "GameServer.Chat.count_unread_friend/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Count unread friend DMs for a user across all friends.
Returns a map of `%{friend_id => unread_count}` for friends that have
at least one unread message.
"""
@spec count_unread_friends_batch(integer(), [integer()]) :: %{required(integer()) => non_neg_integer()}
def count_unread_friends_batch(_user_id, _friend_ids) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
0
_ ->
raise "GameServer.Chat.count_unread_friends_batch/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Count unread messages for a user in multiple group chats.
Returns a map of `%{group_id => unread_count}`.
"""
@spec count_unread_groups_batch(integer(), [integer()]) :: %{required(integer()) => non_neg_integer()}
def count_unread_groups_batch(_user_id, _group_ids) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
0
_ ->
raise "GameServer.Chat.count_unread_groups_batch/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Delete all messages for a given chat conversation.
"""
@spec delete_messages(String.t(), integer()) :: {non_neg_integer(), nil}
def delete_messages(_chat_type, _chat_ref_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
0
_ ->
raise "GameServer.Chat.delete_messages/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Delete a chat message owned by the given user.
Returns `{:error, :not_found}` if the message does not exist or
`{:error, :forbidden}` if the caller is not the sender.
"""
@spec delete_own_message(integer(), integer()) :: {:ok, GameServer.Chat.Message.t()} | {:error, term()}
def delete_own_message(_user_id, _message_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
{:ok, nil}
_ ->
raise "GameServer.Chat.delete_own_message/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Delete all read cursors for a given chat conversation.
"""
@spec delete_read_cursors(String.t(), integer()) :: {non_neg_integer(), nil}
def delete_read_cursors(_chat_type, _chat_ref_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
0
_ ->
raise "GameServer.Chat.delete_read_cursors/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Get a single message by id.
"""
@spec get_message(integer()) :: GameServer.Chat.Message.t() | nil
def get_message(_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
nil
_ ->
raise "GameServer.Chat.get_message/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Get the read cursor for a user in a chat conversation.
Returns `nil` if the user has never opened this conversation.
"""
@spec get_read_cursor(integer(), String.t(), integer()) :: GameServer.Chat.ReadCursor.t() | nil
def get_read_cursor(_user_id, _chat_type, _chat_ref_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
nil
_ ->
raise "GameServer.Chat.get_read_cursor/3 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
List all messages (admin). Supports filters: sender_id, chat_type, chat_ref_id, content.
"""
@spec list_all_messages(
map(),
keyword()
) :: [GameServer.Chat.Message.t()]
def list_all_messages(_filters, _opts) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
[]
_ ->
raise "GameServer.Chat.list_all_messages/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
List friend DM messages between two users.
Convenience wrapper that queries messages in both directions.
## Options
* `:page` — page number (default 1)
* `:page_size` — items per page (default 25)
"""
@spec list_friend_messages(integer(), integer(), keyword()) :: [GameServer.Chat.Message.t()]
def list_friend_messages(_user_a_id, _user_b_id, _opts) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
[]
_ ->
raise "GameServer.Chat.list_friend_messages/3 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
List messages for a chat conversation.
## Options
* `:page` — page number (default 1)
* `:page_size` — items per page (default 25)
Returns a list of `%Message{}` structs ordered by `inserted_at` descending
(newest first).
"""
@spec list_messages(String.t(), integer(), keyword()) :: [GameServer.Chat.Message.t()]
def list_messages(_chat_type, _chat_ref_id, _opts) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
[]
_ ->
raise "GameServer.Chat.list_messages/3 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Mark a chat conversation as read up to a given message id.
Uses an upsert to create or update the read cursor.
"""
@spec mark_read(integer(), String.t(), integer(), integer()) ::
{:ok, GameServer.Chat.ReadCursor.t()} | {:error, term()}
def mark_read(_user_id, _chat_type, _chat_ref_id, _message_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
{:ok, nil}
_ ->
raise "GameServer.Chat.mark_read/4 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Send a chat message.
## Parameters
* `scope` — `%{user: %User{}}` (current_scope)
* `attrs` — map with `"chat_type"`, `"chat_ref_id"`, `"content"`, optional `"metadata"`
## Returns
* `{:ok, %Message{}}` on success
* `{:error, reason}` on failure
The `before_chat_message` hook is called before persistence and can modify
attrs or reject the message. The `after_chat_message` hook fires asynchronously
after the message is persisted.
"""
@spec send_message(map(), map()) :: {:ok, GameServer.Chat.Message.t()} | {:error, term()}
def send_message(_map, _attrs) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
{:ok, nil}
_ ->
raise "GameServer.Chat.send_message/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Subscribe to chat events for a friend DM conversation.
"""
@spec subscribe_friend_chat(integer(), integer()) :: :ok | {:error, term()}
def subscribe_friend_chat(_user_a_id, _user_b_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
:ok
_ ->
raise "GameServer.Chat.subscribe_friend_chat/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Subscribe to chat events for a group.
"""
@spec subscribe_group_chat(integer()) :: :ok | {:error, term()}
def subscribe_group_chat(_group_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
:ok
_ ->
raise "GameServer.Chat.subscribe_group_chat/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Subscribe to chat events for a lobby.
"""
@spec subscribe_lobby_chat(integer()) :: :ok | {:error, term()}
def subscribe_lobby_chat(_lobby_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
:ok
_ ->
raise "GameServer.Chat.subscribe_lobby_chat/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Subscribe to chat events for a party.
"""
@spec subscribe_party_chat(integer()) :: :ok | {:error, term()}
def subscribe_party_chat(_party_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
:ok
_ ->
raise "GameServer.Chat.subscribe_party_chat/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Unsubscribe from friend DM chat events.
"""
@spec unsubscribe_friend_chat(integer(), integer()) :: :ok
def unsubscribe_friend_chat(_user_a_id, _user_b_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
:ok
_ ->
raise "GameServer.Chat.unsubscribe_friend_chat/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Unsubscribe from group chat events.
"""
@spec unsubscribe_group_chat(integer()) :: :ok
def unsubscribe_group_chat(_group_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
:ok
_ ->
raise "GameServer.Chat.unsubscribe_group_chat/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Unsubscribe from lobby chat events.
"""
@spec unsubscribe_lobby_chat(integer()) :: :ok
def unsubscribe_lobby_chat(_lobby_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
:ok
_ ->
raise "GameServer.Chat.unsubscribe_lobby_chat/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Unsubscribe from party chat events.
"""
@spec unsubscribe_party_chat(integer()) :: :ok
def unsubscribe_party_chat(_party_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
:ok
_ ->
raise "GameServer.Chat.unsubscribe_party_chat/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Update a chat message owned by the given user.
Only the `content` and `metadata` fields can be changed. Returns
`{:error, :not_found}` if the message does not exist or
`{:error, :forbidden}` if the caller is not the sender.
"""
@spec update_message(integer(), integer(), map()) ::
{:ok, GameServer.Chat.Message.t()} | {:error, term()}
def update_message(_user_id, _message_id, _attrs) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
{:ok, nil}
_ ->
raise "GameServer.Chat.update_message/3 is a stub - only available at runtime on GameServer"
end
end
end