mirror of
https://github.com/danbee/chess
synced 2025-03-04 08:39:06 +00:00
146 lines
3.1 KiB
Elixir
146 lines
3.1 KiB
Elixir
defmodule ChessWeb.GameChannel do
|
|
@moduledoc false
|
|
|
|
use ChessWeb, :channel
|
|
|
|
import ChessWeb.GameView, only: [player: 2, opponent: 2]
|
|
|
|
alias Chess.Emails
|
|
alias Chess.Mailer
|
|
alias Chess.MoveList
|
|
alias Chess.Moves
|
|
alias Chess.Repo.Queries
|
|
alias ChessWeb.Presence
|
|
|
|
def join("game:" <> game_id, _params, socket) do
|
|
send(self(), {:after_join, game_id})
|
|
|
|
{:ok, assign(socket, :game_id, game_id)}
|
|
end
|
|
|
|
def handle_info({:after_join, game_id}, socket) do
|
|
game =
|
|
socket.assigns.user_id
|
|
|> Queries.game_for_info(game_id)
|
|
|
|
payload = %{
|
|
player_id: socket.assigns.user_id,
|
|
opponent_id: opponent(game, socket.assigns.user_id).id,
|
|
player: player(game, socket.assigns.user_id),
|
|
opponent: opponent(game, socket.assigns.user_id).name,
|
|
board: game.board,
|
|
turn: game.turn,
|
|
state: game.state,
|
|
moves: MoveList.transform(game.moves)
|
|
}
|
|
|
|
socket
|
|
|> push("game:update", payload)
|
|
|
|
track_presence(socket)
|
|
|
|
{:noreply, socket}
|
|
end
|
|
|
|
def handle_in("game:move", params, socket) do
|
|
game =
|
|
socket.assigns.user_id
|
|
|> Queries.game_for_info(socket.assigns.game_id)
|
|
|
|
move_params = convert_params(params)
|
|
|
|
game
|
|
|> Moves.make_move(move_params)
|
|
|> case do
|
|
{:ok, _} ->
|
|
update_opponent(socket, game)
|
|
|
|
{:noreply, socket}
|
|
|
|
{:error, :game, changeset, _} ->
|
|
{message, _} = changeset.errors[:board]
|
|
|
|
{:reply, {:error, %{message: message}}, socket}
|
|
end
|
|
end
|
|
|
|
def handle_in(
|
|
"game:get_available_moves",
|
|
%{"square" => [file, rank]},
|
|
socket
|
|
) do
|
|
game =
|
|
socket.assigns.user_id
|
|
|> Queries.game_with_moves(socket.assigns.game_id)
|
|
|
|
moves =
|
|
Moves.available(
|
|
game.board,
|
|
{
|
|
String.to_integer(file),
|
|
String.to_integer(rank)
|
|
},
|
|
game.moves
|
|
)
|
|
|
|
reply = %{
|
|
moves: Enum.map(moves, &Tuple.to_list(&1))
|
|
}
|
|
|
|
{:reply, {:ok, reply}, socket}
|
|
end
|
|
|
|
def update_opponent(socket, game) do
|
|
opponent_id =
|
|
opponent(game, socket.assigns.user_id).id
|
|
|> Integer.to_string()
|
|
|
|
send_update(socket)
|
|
|
|
"game:#{game.id}"
|
|
|> Presence.list()
|
|
|> case do
|
|
%{^opponent_id => _} ->
|
|
nil
|
|
|
|
_ ->
|
|
socket
|
|
|> Emails.opponent_moved_email(game)
|
|
|> Mailer.deliver_later()
|
|
end
|
|
end
|
|
|
|
def track_presence(socket) do
|
|
{:ok, _} =
|
|
Presence.track(socket, socket.assigns.user_id, %{
|
|
user_id: socket.assigns.user_id,
|
|
online_at: inspect(System.system_time(:second))
|
|
})
|
|
|
|
socket
|
|
|> push("presence_state", Presence.list(socket))
|
|
end
|
|
|
|
def convert_params(%{"from" => from, "to" => to}) do
|
|
%{
|
|
"from" => Enum.map(from, &String.to_integer(&1)),
|
|
"to" => Enum.map(to, &String.to_integer(&1))
|
|
}
|
|
end
|
|
|
|
def send_update(socket) do
|
|
game =
|
|
socket.assigns.user_id
|
|
|> Queries.game_with_moves(socket.assigns.game_id)
|
|
|
|
payload = %{
|
|
board: game.board,
|
|
turn: game.turn,
|
|
state: game.state,
|
|
moves: MoveList.transform(game.moves)
|
|
}
|
|
|
|
ChessWeb.Endpoint.broadcast("game:#{game.id}", "game:update", payload)
|
|
end
|
|
end
|