summaryrefslogtreecommitdiff
path: root/lib/chessh/discord
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chessh/discord')
-rw-r--r--lib/chessh/discord/notifier.ex140
1 files changed, 117 insertions, 23 deletions
diff --git a/lib/chessh/discord/notifier.ex b/lib/chessh/discord/notifier.ex
index 6d7bd46..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
@@ -50,9 +50,9 @@ defmodule Chessh.DiscordNotifier do
end
defp send_notification({:move_reminder, game_id}) do
- [min_delta_t, discord_game_move_notif_webhook] =
+ [min_delta_t, remind_move_channel_id] =
Application.get_env(:chessh, DiscordNotifications)
- |> Keyword.take([:game_move_notif_delay_ms, :discord_game_move_notif_webhook])
+ |> Keyword.take([:game_move_notif_delay_ms, :remind_move_channel_id])
|> Keyword.values()
case Repo.get(Game, game_id) |> Repo.preload([:dark_player, :light_player]) do
@@ -62,13 +62,27 @@ defmodule Chessh.DiscordNotifier do
turn: turn,
updated_at: last_updated,
moves: move_count,
- status: :continue
- } ->
+ status: :continue,
+ discord_thread_id: discord_thread_id
+ } = game ->
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(
- discord_game_move_notif_webhook,
+ game.discord_thread_id,
"<@#{if turn == :light, do: light_player_discord_id, else: dark_player_discord_id}> it is your move in Game #{game_id} (move #{move_count})."
)
end
@@ -78,16 +92,33 @@ 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, discord_game_created_notif_webhook] =
+ [pingable_mention, new_game_channel_id] =
Application.get_env(:chessh, DiscordNotifications)
- |> Keyword.take([:looking_for_games_role_mention, :discord_new_game_notif_webhook])
+ |> Keyword.take([:looking_for_games_role_mention, :new_game_channel_id])
|> Keyword.values()
case Repo.get(Game, game_id) do
- nil ->
- nil
-
game ->
%Game{
dark_player: dark_player,
@@ -107,22 +138,85 @@ defmodule Chessh.DiscordNotifier do
end
if message do
- post_discord(discord_game_created_notif_webhook, message)
+ 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(webhook, message) do
- :httpc.request(
- :post,
- {
- String.to_charlist(webhook),
+ defp post_discord(channel_id, message) do
+ make_discord_api_call(:post, "channels/#{channel_id}/messages", %{content: message})
+ end
+
+ 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(
+ method,
+ {
+ 'https://discord.com/api/#{route}',
+ [
+ make_authorization_header()
+ ]
+ },
[],
- 'application/json',
- %{content: message} |> Jason.encode!() |> String.to_charlist()
- },
- [],
- []
- )
+ []
+ )
+
+ defp make_discord_api_call(method, route, body),
+ do:
+ :httpc.request(
+ method,
+ {
+ 'https://discord.com/api/#{route}',
+ [
+ make_authorization_header()
+ ],
+ 'application/json',
+ body
+ |> Jason.encode!()
+ |> String.to_charlist()
+ },
+ [],
+ []
+ )
+
+ defp make_authorization_header() do
+ bot_token = Application.get_env(:chessh, DiscordNotifications)[:discord_bot_token]
+ {'Authorization', 'Bot #{bot_token}'}
end
end