Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tachyon system/serverStats #586

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions lib/teiserver/player.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,27 @@ defmodule Teiserver.Player do
alias Teiserver.Data.Types, as: T
alias Teiserver.{Player, Matchmaking}

@doc """
Returns the pid of the session registered with a given user id
"""
@spec lookup_session(T.userid()) :: pid() | nil
defdelegate lookup_session(user_id), to: Player.SessionRegistry, as: :lookup

@doc """
Returns the pid of the connection registered with a given user id
"""
@spec lookup_connection(T.userid()) :: pid() | nil
def lookup_connection(user_id) do
Player.Registry.lookup(user_id)
end
defdelegate lookup_connection(user_id), to: Player.Registry, as: :lookup

@spec connection_via_tuple(T.userid()) :: GenServer.name()
def connection_via_tuple(user_id) do
Player.Registry.via_tuple(user_id)
end
defdelegate connection_via_tuple(user_id), to: Player.Registry, as: :via_tuple

@doc """
To be used when a process is interested in the presence of a given player.
"""
@spec monitor_session(T.userid()) :: reference() | nil
def monitor_session(user_id) do
pid = Player.SessionRegistry.lookup(user_id)
pid = lookup_connection(user_id)

if is_nil(pid) do
nil
Expand Down
6 changes: 5 additions & 1 deletion lib/teiserver/player/session_registry.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ defmodule Teiserver.Player.SessionRegistry do
end

@doc """
how to reach a given session
How to reach a given session
"""
@spec via_tuple(T.userid()) :: GenServer.name()
def via_tuple(user_id) do
Expand All @@ -35,4 +35,8 @@ defmodule Teiserver.Player.SessionRegistry do
start: {__MODULE__, :start_link, []}
)
end

def count() do
Horde.Registry.count(__MODULE__)
end
end
6 changes: 6 additions & 0 deletions lib/teiserver/player/tachyon_handler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,12 @@ defmodule Teiserver.Player.TachyonHandler do
{:stop, :normal, state}
end

def handle_command("system/serverStats" = cmd_id, "request", _message_id, _message, state) do
user_count = Teiserver.Player.SessionRegistry.count()

{:response, cmd_id, %{userCount: user_count}, state}
end

def handle_command("matchmaking/list" = cmd_id, "request", message_id, _message, state) do
queues =
Matchmaking.list_queues()
Expand Down
17 changes: 17 additions & 0 deletions priv/tachyon/schema/system/serverStats/request.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"$id": "https://schema.beyondallreason.dev/tachyon/system/serverStats/request.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "SystemServerStatsRequest",
"tachyon": {
"source": "user",
"target": "server",
"scopes": ["tachyon.lobby"]
},
"type": "object",
"properties": {
"type": { "const": "request" },
"messageId": { "type": "string" },
"commandId": { "const": "system/serverStats" }
},
"required": ["type", "messageId", "commandId"]
}
47 changes: 47 additions & 0 deletions priv/tachyon/schema/system/serverStats/response.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"title": "SystemServerStatsResponse",
"tachyon": {
"source": "server",
"target": "user",
"scopes": ["tachyon.lobby"]
},
"anyOf": [
{
"title": "SystemServerStatsOkResponse",
"type": "object",
"properties": {
"type": { "const": "response" },
"messageId": { "type": "string" },
"commandId": { "const": "system/serverStats" },
"status": { "const": "success" },
"data": {
"title": "SystemServerStatsOkResponseData",
"type": "object",
"properties": { "userCount": { "type": "integer" } },
"required": ["userCount"]
}
},
"required": ["type", "messageId", "commandId", "status", "data"]
},
{
"title": "SystemServerStatsFailResponse",
"type": "object",
"properties": {
"type": { "const": "response" },
"messageId": { "type": "string" },
"commandId": { "const": "system/serverStats" },
"status": { "const": "failed" },
"reason": {
"enum": [
"internal_error",
"unauthorized",
"invalid_request",
"command_unimplemented"
]
},
"details": { "type": "string" }
},
"required": ["type", "messageId", "commandId", "status", "reason"]
}
]
}
23 changes: 22 additions & 1 deletion test/support/tachyon.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
defmodule Teiserver.Support.Tachyon do
alias WebsocketSyncClient, as: WSC
alias Teiserver.OAuthFixtures
alias Teiserver.Player

def setup_client(_context), do: setup_client()

Expand Down Expand Up @@ -29,7 +30,20 @@ defmodule Teiserver.Support.Tachyon do
{:ok, _user_updated} = recv_message(client)
end

ExUnit.Callbacks.on_exit(fn -> WSC.disconnect(client) end)
ExUnit.Callbacks.on_exit(fn ->
WSC.disconnect(client)

case Player.lookup_session(token.owner_id) do
nil -> :ok
pid -> Process.exit(pid, :test_cleanup)
end

poll_until(
fn -> Player.lookup_session(token.owner_id) end,
fn x -> is_nil(x) end
)
end)

client
end

Expand Down Expand Up @@ -226,6 +240,13 @@ defmodule Teiserver.Support.Tachyon do
resp
end

def server_stats!(client) do
req = request("system/serverStats")
:ok = WSC.send_message(client, {:text, req |> Jason.encode!()})
{:ok, resp} = recv_message(client)
resp
end

@doc """
Run the given function `f` until `pred` returns true on its result.
Waits `wait` ms between each tries. Raise an error if `pred` returns false
Expand Down
41 changes: 41 additions & 0 deletions test/teiserver_web/tachyon/system_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
defmodule TeiserverWeb.Tachyon.SystemTest do
use TeiserverWeb.ConnCase
alias Teiserver.Support.Tachyon
alias Teiserver.OAuthFixtures

describe "server stats" do
defp setup_app(_context) do
owner = Central.Helpers.GeneralTestLib.make_user(%{"data" => %{"roles" => ["Verified"]}})

app =
OAuthFixtures.app_attrs(owner.id)
|> Map.put(:uid, UUID.uuid4())
|> OAuthFixtures.create_app()

{:ok, app: app}
end

defp setup_user(app) do
user = Central.Helpers.GeneralTestLib.make_user(%{"data" => %{"roles" => ["Verified"]}})
token = OAuthFixtures.token_attrs(user.id, app) |> OAuthFixtures.create_token()
client = Tachyon.connect(token)
{:ok, %{user: user, token: token, client: client}}
end

setup [:setup_app]

test "works", %{app: app} do
{:ok, %{client: client1}} = setup_user(app)
{:ok, %{client: client2}} = setup_user(app)

assert %{"data" => %{"userCount" => 2}} = Tachyon.server_stats!(client1)
assert %{"data" => %{"userCount" => 2}} = Tachyon.server_stats!(client2)

Tachyon.disconnect!(client2)

Tachyon.poll_until(fn -> Tachyon.server_stats!(client1) end, fn data ->
data["data"]["userCount"] == 1
end)
end
end
end
Loading