Discord threads #16
@ -28,6 +28,6 @@ REACT_APP_SSH_PORT=42069
|
|||||||
REDIS_HOST=localhost
|
REDIS_HOST=localhost
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
|
|
||||||
NEW_GAME_PINGABLE_ROLE_ID=1123232
|
NEW_GAME_PINGABLE_ROLE_ID=10
|
||||||
NEW_GAME_CHANNEL_WEBHOOK=https://discordapp.com/api/webhooks/
|
REMIND_MOVE_CHANNEL_ID=91
|
||||||
REMIND_MOVE_CHANNEL_ID=
|
NEW_GAME_CHANNEL_ID=91
|
||||||
|
@ -24,8 +24,8 @@ config :chessh, Web,
|
|||||||
discord_scope: "identify"
|
discord_scope: "identify"
|
||||||
|
|
||||||
config :chessh, DiscordNotifications,
|
config :chessh, DiscordNotifications,
|
||||||
game_move_notif_delay_ms: 3 * 60 * 1000,
|
game_move_notif_delay_ms: 10 * 1000,
|
||||||
game_created_notif_delay_ms: 30 * 1000,
|
game_created_notif_delay_ms: 10 * 1000,
|
||||||
reschedule_delay: 5 * 1000
|
reschedule_delay: 5 * 1000
|
||||||
|
|
||||||
config :joken, default_signer: "secret"
|
config :joken, default_signer: "secret"
|
||||||
|
@ -28,7 +28,7 @@ defmodule Chessh.DiscordNotifier do
|
|||||||
|
|
||||||
case Hammer.check_rate_inc(
|
case Hammer.check_rate_inc(
|
||||||
:redis,
|
:redis,
|
||||||
"discord-webhook-message-rate",
|
"discord-rate",
|
||||||
discord_notification_rate_ms,
|
discord_notification_rate_ms,
|
||||||
discord_notification_rate,
|
discord_notification_rate,
|
||||||
1
|
1
|
||||||
@ -65,15 +65,20 @@ defmodule Chessh.DiscordNotifier do
|
|||||||
status: :continue,
|
status: :continue,
|
||||||
discord_thread_id: discord_thread_id
|
discord_thread_id: discord_thread_id
|
||||||
} = game ->
|
} = game ->
|
||||||
|
delta_t = NaiveDateTime.diff(NaiveDateTime.utc_now(), last_updated, :millisecond)
|
||||||
|
|
||||||
|
game =
|
||||||
if is_nil(discord_thread_id) do
|
if is_nil(discord_thread_id) do
|
||||||
{:ok, game} =
|
{:ok, game} =
|
||||||
Game.changeset(game, %{
|
Game.changeset(game, %{
|
||||||
discord_thread_id: make_private_discord_thread_id(remind_move_channel_id, game)
|
discord_thread_id: make_private_discord_thread_id(remind_move_channel_id, game)
|
||||||
})
|
})
|
||||||
|> Repo.update()
|
|> Repo.update()
|
||||||
end
|
|
||||||
|
|
||||||
delta_t = NaiveDateTime.diff(NaiveDateTime.utc_now(), last_updated, :millisecond)
|
game
|
||||||
|
else
|
||||||
|
game
|
||||||
|
end
|
||||||
|
|
||||||
if delta_t >= min_delta_t do
|
if delta_t >= min_delta_t do
|
||||||
post_discord(
|
post_discord(
|
||||||
@ -87,6 +92,26 @@ defmodule Chessh.DiscordNotifier do
|
|||||||
end
|
end
|
||||||
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
|
defp send_notification({:game_created, game_id}) do
|
||||||
[pingable_mention, new_game_channel_id] =
|
[pingable_mention, new_game_channel_id] =
|
||||||
Application.get_env(:chessh, DiscordNotifications)
|
Application.get_env(:chessh, DiscordNotifications)
|
||||||
@ -94,9 +119,6 @@ defmodule Chessh.DiscordNotifier do
|
|||||||
|> Keyword.values()
|
|> Keyword.values()
|
||||||
|
|
||||||
case Repo.get(Game, game_id) do
|
case Repo.get(Game, game_id) do
|
||||||
nil ->
|
|
||||||
nil
|
|
||||||
|
|
||||||
game ->
|
game ->
|
||||||
%Game{
|
%Game{
|
||||||
dark_player: dark_player,
|
dark_player: dark_player,
|
||||||
@ -118,61 +140,80 @@ defmodule Chessh.DiscordNotifier do
|
|||||||
if message do
|
if message do
|
||||||
post_discord(new_game_channel_id, message)
|
post_discord(new_game_channel_id, message)
|
||||||
end
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
defp post_discord(channel_id, message) do
|
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(
|
:httpc.request(
|
||||||
:post,
|
method,
|
||||||
{
|
{
|
||||||
'https://discord.com/api/channels/#{channel_id}/messages',
|
'https://discord.com/api/#{route}',
|
||||||
[],
|
[
|
||||||
'application/json',
|
make_authorization_header()
|
||||||
%{content: message} |> Jason.encode!() |> String.to_charlist()
|
]
|
||||||
},
|
},
|
||||||
[],
|
[],
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
end
|
|
||||||
|
|
||||||
defp make_private_discord_thread_id(channel_id, %Game{
|
defp make_discord_api_call(method, route, body),
|
||||||
dark_player: %Player{discord_id: dark_player_discord_id},
|
do:
|
||||||
light_player: %Player{discord_id: light_player_discord_id}
|
|
||||||
}) do
|
|
||||||
%{"id" => thread_id} =
|
|
||||||
:httpc.request(
|
:httpc.request(
|
||||||
:post,
|
method,
|
||||||
{
|
{
|
||||||
'https://discord.com/api/channels/#{channel_id}/threads',
|
'https://discord.com/api/#{route}',
|
||||||
[
|
[
|
||||||
make_authorization_header()
|
make_authorization_header()
|
||||||
],
|
],
|
||||||
'application/json',
|
'application/json',
|
||||||
%{
|
body
|
||||||
# Private thread
|
|
||||||
type: 12
|
|
||||||
}
|
|
||||||
|> Jason.encode!()
|
|> Jason.encode!()
|
||||||
|> String.to_charlist()
|
|> 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
|
defp make_authorization_header() do
|
||||||
bot_token = Application.get_env(:chessh, DiscordNotifications)[:discord_bot_token]
|
bot_token = Application.get_env(:chessh, DiscordNotifications)[:discord_bot_token]
|
||||||
|
@ -396,7 +396,7 @@ defmodule Chessh.SSH.Client.Game do
|
|||||||
{:ok, status} ->
|
{:ok, status} ->
|
||||||
{:ok, fen} = :binbo.get_fen(binbo_pid)
|
{:ok, fen} = :binbo.get_fen(binbo_pid)
|
||||||
|
|
||||||
{:ok, _new_game} =
|
{:ok, %Game{status: after_move_status}} =
|
||||||
game
|
game
|
||||||
|> Game.changeset(
|
|> Game.changeset(
|
||||||
Map.merge(
|
Map.merge(
|
||||||
@ -413,11 +413,18 @@ defmodule Chessh.SSH.Client.Game do
|
|||||||
|
|
||||||
:syn.publish(:games, {:game, game_id}, {:new_move, attempted_move})
|
:syn.publish(:games, {:game, game_id}, {:new_move, attempted_move})
|
||||||
|
|
||||||
|
if after_move_status == :continue do
|
||||||
GenServer.cast(
|
GenServer.cast(
|
||||||
:discord_notifier,
|
:discord_notifier,
|
||||||
{:schedule_notification, {:move_reminder, game_id},
|
{:schedule_notification, {:move_reminder, game_id},
|
||||||
Application.get_env(:chessh, DiscordNotifications)[:game_move_notif_delay_ms]}
|
Application.get_env(:chessh, DiscordNotifications)[:game_move_notif_delay_ms]}
|
||||||
)
|
)
|
||||||
|
else
|
||||||
|
GenServer.cast(
|
||||||
|
:discord_notifier,
|
||||||
|
{:schedule_notification, {:cleanup_thread, game_id}, 0}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
nil
|
nil
|
||||||
|
@ -2,6 +2,8 @@ defmodule Chessh.Repo.Migrations.AddDiscordThreadId do
|
|||||||
use Ecto.Migration
|
use Ecto.Migration
|
||||||
|
|
||||||
def change do
|
def change do
|
||||||
|
alter table(:games) do
|
||||||
|
add(:discord_thread_id, :string, null: true)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user