summaryrefslogtreecommitdiff
path: root/lib/chessh/schema/player_session.ex
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chessh/schema/player_session.ex')
-rw-r--r--lib/chessh/schema/player_session.ex52
1 files changed, 49 insertions, 3 deletions
diff --git a/lib/chessh/schema/player_session.ex b/lib/chessh/schema/player_session.ex
index 84f15ee..ce3fc1f 100644
--- a/lib/chessh/schema/player_session.ex
+++ b/lib/chessh/schema/player_session.ex
@@ -1,10 +1,12 @@
defmodule Chessh.PlayerSession do
- alias Chessh.Repo
+ alias Chessh.{Repo, Player, PlayerSession, Utils}
use Ecto.Schema
import Ecto.{Query, Changeset}
+ require Logger
schema "player_sessions" do
- field(:login, :utc_datetime)
+ field(:process, :string)
+ field(:login, :utc_datetime_usec)
belongs_to(:node, Chessh.Node, type: :string)
belongs_to(:player, Chessh.Player)
@@ -17,7 +19,7 @@ defmodule Chessh.PlayerSession do
def concurrent_sessions(player) do
Repo.aggregate(
- from(p in Chessh.PlayerSession,
+ from(p in PlayerSession,
where: p.player_id == ^player.id
),
:count
@@ -31,4 +33,48 @@ defmodule Chessh.PlayerSession do
)
)
end
+
+ def player_within_concurrent_sessions_and_satisfies(username, auth_fn) do
+ max_sessions =
+ Application.get_env(:chessh, RateLimits)
+ |> Keyword.get(:max_concurrent_user_sessions)
+
+ Repo.transaction(fn ->
+ case Repo.one(
+ from(p in Player,
+ where: p.username == ^String.Chars.to_string(username),
+ lock: "FOR UPDATE"
+ )
+ ) do
+ nil ->
+ Logger.error("Player with username #{username} does not exist")
+ send(self(), {:authed, false})
+
+ player ->
+ authed =
+ auth_fn.(player) &&
+ PlayerSession.concurrent_sessions(player) < max_sessions
+
+ Repo.insert(%PlayerSession{
+ login: DateTime.utc_now(),
+ node_id: System.fetch_env!("NODE_ID"),
+ player: player,
+ # TODO: This PID may be wrong - need to determine if this PID is shared with disconnectfun
+ process: Utils.pid_to_str(self())
+ })
+
+ player
+ |> Player.authentications_changeset(%{authentications: player.authentications + 1})
+ |> Repo.update()
+
+ send(self(), {:authed, authed})
+ end
+ end)
+
+ receive do
+ {:authed, authed} -> authed
+ after
+ 3_000 -> false
+ end
+ end
end