From 329291a0760f1ee5e342f5fef72f07ee33c10df8 Mon Sep 17 00:00:00 2001 From: Simponic Date: Wed, 1 Feb 2023 22:50:59 -0700 Subject: [PATCH] Finish thread creation --- .env.example | 6 +- config/config.exs | 4 +- lib/chessh/discord/notifier.ex | 139 ++++++++++++------ lib/chessh/ssh/client/game/game.ex | 19 ++- .../20230202004927_add_discord_thread_id.exs | 4 +- 5 files changed, 111 insertions(+), 61 deletions(-) diff --git a/.env.example b/.env.example index 11ca42e..6636fb9 100644 --- a/.env.example +++ b/.env.example @@ -28,6 +28,6 @@ REACT_APP_SSH_PORT=42069 REDIS_HOST=localhost REDIS_PORT=6379 -NEW_GAME_PINGABLE_ROLE_ID=1123232 -NEW_GAME_CHANNEL_WEBHOOK=https://discordapp.com/api/webhooks/ -REMIND_MOVE_CHANNEL_ID= +NEW_GAME_PINGABLE_ROLE_ID=10 +REMIND_MOVE_CHANNEL_ID=91 +NEW_GAME_CHANNEL_ID=91 diff --git a/config/config.exs b/config/config.exs index 2c08a17..5ada6e6 100644 --- a/config/config.exs +++ b/config/config.exs @@ -24,8 +24,8 @@ config :chessh, Web, discord_scope: "identify" config :chessh, DiscordNotifications, - game_move_notif_delay_ms: 3 * 60 * 1000, - game_created_notif_delay_ms: 30 * 1000, + game_move_notif_delay_ms: 10 * 1000, + game_created_notif_delay_ms: 10 * 1000, reschedule_delay: 5 * 1000 config :joken, default_signer: "secret" diff --git a/lib/chessh/discord/notifier.ex b/lib/chessh/discord/notifier.ex index c19495c..02b7c5f 100644 --- a/lib/chessh/discord/notifier.ex +++ b/lib/chessh/discord/notifier.ex @@ -28,7 +28,7 @@ defmodule Chessh.DiscordNotifier do case Hammer.check_rate_inc( :redis, - "discord-webhook-message-rate", + "discord-rate", discord_notification_rate_ms, discord_notification_rate, 1 @@ -65,16 +65,21 @@ defmodule Chessh.DiscordNotifier do status: :continue, discord_thread_id: discord_thread_id } = game -> - if is_nil(discord_thread_id) do - {:ok, game} = - Game.changeset(game, %{ - discord_thread_id: make_private_discord_thread_id(remind_move_channel_id, game) - }) - |> Repo.update() - end - delta_t = NaiveDateTime.diff(NaiveDateTime.utc_now(), last_updated, :millisecond) + game = + if is_nil(discord_thread_id) do + {:ok, game} = + Game.changeset(game, %{ + discord_thread_id: make_private_discord_thread_id(remind_move_channel_id, game) + }) + |> Repo.update() + + game + else + game + end + if delta_t >= min_delta_t do post_discord( game.discord_thread_id, @@ -87,6 +92,26 @@ defmodule Chessh.DiscordNotifier do end end + defp send_notification({:cleanup_thread, game_id}) do + case Repo.get(Game, game_id) |> Repo.preload([:dark_player, :light_player]) do + %Game{ + discord_thread_id: discord_thread_id, + status: status + } = game -> + if !is_nil(discord_thread_id) && status != :continue do + destroy_channel(discord_thread_id) + + Game.changeset(game, %{ + discord_thread_id: nil + }) + |> Repo.update() + end + + _ -> + nil + end + end + defp send_notification({:game_created, game_id}) do [pingable_mention, new_game_channel_id] = Application.get_env(:chessh, DiscordNotifications) @@ -94,9 +119,6 @@ defmodule Chessh.DiscordNotifier do |> Keyword.values() case Repo.get(Game, game_id) do - nil -> - nil - game -> %Game{ dark_player: dark_player, @@ -118,61 +140,80 @@ defmodule Chessh.DiscordNotifier do if message do post_discord(new_game_channel_id, message) end + + nil -> + nil + end + end + + defp make_private_discord_thread_id(channel_id, %Game{ + id: game_id, + dark_player: %Player{discord_id: dark_player_discord_id, username: dark_username}, + light_player: %Player{discord_id: light_player_discord_id, username: light_username} + }) do + case make_discord_api_call( + :post, + "channels/#{channel_id}/threads", + %{ + # Private thread + type: 12, + name: "Game #{game_id} - #{light_username} V #{dark_username}" + } + ) do + {:ok, {_, _, body}} -> + %{"id" => thread_id} = Jason.decode!(body) + + [light_player_discord_id, dark_player_discord_id] + |> Enum.map(fn id -> + make_discord_api_call(:put, 'channels/#{thread_id}/thread-members/#{id}') + end) + + thread_id + + _ -> + nil end end defp post_discord(channel_id, message) do - :httpc.request( - :post, - { - 'https://discord.com/api/channels/#{channel_id}/messages', - [], - 'application/json', - %{content: message} |> Jason.encode!() |> String.to_charlist() - }, - [], - [] - ) + make_discord_api_call(:post, "channels/#{channel_id}/messages", %{content: message}) end - defp make_private_discord_thread_id(channel_id, %Game{ - dark_player: %Player{discord_id: dark_player_discord_id}, - light_player: %Player{discord_id: light_player_discord_id} - }) do - %{"id" => thread_id} = + defp destroy_channel(channel_id) do + make_discord_api_call(:delete, "channels/#{channel_id}") + end + + defp make_discord_api_call(method, route), + do: :httpc.request( - :post, + method, { - 'https://discord.com/api/channels/#{channel_id}/threads', + 'https://discord.com/api/#{route}', + [ + make_authorization_header() + ] + }, + [], + [] + ) + + defp make_discord_api_call(method, route, body), + do: + :httpc.request( + method, + { + 'https://discord.com/api/#{route}', [ make_authorization_header() ], 'application/json', - %{ - # Private thread - type: 12 - } + body |> Jason.encode!() |> String.to_charlist() }, [], [] ) - |> Jason.decode!() - - [light_player_discord_id, dark_player_discord_id] - |> Enum.map(fn id -> - :httpc.request( - :post, - { - 'https://discord.com/api/channels/#{thread_id}/thread-members/#{id}', - [] - } - ) - end) - - thread_id - end defp make_authorization_header() do bot_token = Application.get_env(:chessh, DiscordNotifications)[:discord_bot_token] diff --git a/lib/chessh/ssh/client/game/game.ex b/lib/chessh/ssh/client/game/game.ex index d6b0b5b..6b2ef60 100644 --- a/lib/chessh/ssh/client/game/game.ex +++ b/lib/chessh/ssh/client/game/game.ex @@ -396,7 +396,7 @@ defmodule Chessh.SSH.Client.Game do {:ok, status} -> {:ok, fen} = :binbo.get_fen(binbo_pid) - {:ok, _new_game} = + {:ok, %Game{status: after_move_status}} = game |> Game.changeset( Map.merge( @@ -413,11 +413,18 @@ defmodule Chessh.SSH.Client.Game do :syn.publish(:games, {:game, game_id}, {:new_move, attempted_move}) - GenServer.cast( - :discord_notifier, - {:schedule_notification, {:move_reminder, game_id}, - Application.get_env(:chessh, DiscordNotifications)[:game_move_notif_delay_ms]} - ) + if after_move_status == :continue do + GenServer.cast( + :discord_notifier, + {:schedule_notification, {:move_reminder, game_id}, + Application.get_env(:chessh, DiscordNotifications)[:game_move_notif_delay_ms]} + ) + else + GenServer.cast( + :discord_notifier, + {:schedule_notification, {:cleanup_thread, game_id}, 0} + ) + end _ -> nil diff --git a/priv/repo/migrations/20230202004927_add_discord_thread_id.exs b/priv/repo/migrations/20230202004927_add_discord_thread_id.exs index fadb8f1..8c7c83a 100644 --- a/priv/repo/migrations/20230202004927_add_discord_thread_id.exs +++ b/priv/repo/migrations/20230202004927_add_discord_thread_id.exs @@ -2,6 +2,8 @@ defmodule Chessh.Repo.Migrations.AddDiscordThreadId do use Ecto.Migration def change do - + alter table(:games) do + add(:discord_thread_id, :string, null: true) + end end end