1
0
mirror of https://github.com/danbee/chess synced 2025-03-04 08:39:06 +00:00
chess/lib/chess_web/channels/game_channel.ex
2023-02-04 21:35:56 -06:00

147 lines
3.2 KiB
Elixir

defmodule ChessWeb.GameChannel do
@moduledoc false
use ChessWeb, :channel
import ChessWeb.GameView, only: [player: 2, opponent: 2]
alias Chess.Board
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: Board.transform(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: Board.transform(game.board),
turn: game.turn,
state: game.state,
moves: MoveList.transform(game.moves)
}
ChessWeb.Endpoint.broadcast("game:#{game.id}", "game:update", payload)
end
end