Current section

Files

Jump to
islands_engine lib islands engine game server.ex
Raw

lib/islands/engine/game/server.ex

defmodule Islands.Engine.Game.Server do
use GenServer, restart: :transient
use PersistConfig
alias __MODULE__
alias __MODULE__.{
AddPlayer,
Error,
GuessCoord,
Info,
PositionAllIslands,
PositionIsland,
SetIslands,
Stop
}
alias Islands.Engine.Game.Tally
alias Islands.Engine.Game
@type from :: GenServer.from()
@type reply :: {:reply, Tally.t(), Game.t()}
@type request :: tuple
@type response :: tuple
@ets Application.get_env(@app, :ets_name)
# @reg Application.get_env(@app, :registry)
@wait 500
@spec start_link({String.t(), String.t(), pid}) :: GenServer.on_start()
def start_link({game_name, player1_name, pid}) do
import GenServer, only: [start_link: 3]
start_link(Server, {game_name, player1_name, pid}, name: via(game_name))
end
# @spec via(String.t()) :: {:via, module, {atom, tuple}}
# def via(game_name), do: {:via, Registry, {@reg, key(game_name)}}
@spec via(String.t()) :: {:global, tuple}
def via(game_name), do: {:global, key(game_name)}
@spec save(Game.t()) :: Game.t()
def save(game) do
:ok = Info.log(:save, {game})
true = :ets.insert(@ets, {key(game.name), game})
game
end
@spec reply(Game.t(), Game.player_id()) :: reply
def reply(game, player_id), do: {:reply, Tally.new(game, player_id), game}
## Private functions
@spec key(String.t()) :: tuple
defp key(game_name), do: {Server, game_name}
@spec game(String.t(), String.t(), pid) :: Game.t()
defp game(game_name, player1_name, pid) do
case :ets.lookup(@ets, key(game_name)) do
[] -> game_name |> Game.new(player1_name, pid) |> save()
[{_key, game}] -> game
end
end
## Callbacks
@spec init({String.t(), String.t(), pid}) :: {:ok, Game.t()}
def init({game_name, player1_name, pid}),
do: {:ok, game(game_name, player1_name, pid)}
@spec handle_call(request, from, Game.t()) :: reply
def handle_call({:add_player, _, _} = request, from, game),
do: AddPlayer.handle_call(request, from, game)
def handle_call({:position_island, _, _, _, _} = request, from, game),
do: PositionIsland.handle_call(request, from, game)
def handle_call({:position_all_islands, _} = request, from, game),
do: PositionAllIslands.handle_call(request, from, game)
def handle_call({:stop, _} = request, from, game),
do: Stop.handle_call(request, from, game)
def handle_call({:set_islands, _} = request, from, game),
do: SetIslands.handle_call(request, from, game)
def handle_call({:guess_coord, _, _, _} = request, from, game),
do: GuessCoord.handle_call(request, from, game)
def handle_call({:tally, player_id}, _from, game), do: reply(game, player_id)
@spec terminate(term, Game.t()) :: :ok
def terminate(:shutdown = reason, game) do
:ok = Info.log(:terminate, {reason, game})
true = :ets.delete(@ets, key(game.name))
# Ensure message logged before exiting...
Process.sleep(@wait)
end
def terminate(reason, game) do
:ok = Error.log(:terminate, {reason, game})
true = :ets.delete(@ets, key(game.name))
# Ensure message logged before exiting...
Process.sleep(@wait)
end
end