Skip to content

Commit

Permalink
Add optional get_chat callback to Telegram.ChatBot (#177)
Browse files Browse the repository at this point in the history
  • Loading branch information
lnr0626 authored Oct 21, 2024
1 parent e3d1977 commit a05fa2a
Show file tree
Hide file tree
Showing 7 changed files with 350 additions and 79 deletions.
15 changes: 15 additions & 0 deletions lib/bot/chat_bot/chat/chat.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
defmodule Telegram.ChatBot.Chat do
@moduledoc """
A struct that represents a chat extracted from a Telegram update.
Currently the only required field is `id`, any other data you may want to pass to
`c:Telegram.ChatBot.init/1` should be included under the `metadata` field.
"""

@type t() :: %__MODULE__{
id: String.t(),
metadata: map() | nil
}

@enforce_keys [:id]
defstruct [:metadata] ++ @enforce_keys
end
50 changes: 30 additions & 20 deletions lib/bot/chat_bot/chat/session/server.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Telegram.Bot.ChatBot.Chat.Session.Server do

use GenServer, restart: :transient
require Logger
alias Telegram.Bot.{ChatBot.Chat, Utils}
alias Telegram.Bot.ChatBot.Chat
alias Telegram.{ChatBot, Types}

defmodule State do
Expand All @@ -13,21 +13,21 @@ defmodule Telegram.Bot.ChatBot.Chat.Session.Server do
defstruct @enforce_keys
end

@spec start_link({ChatBot.t(), Types.token(), ChatBot.chat()}) :: GenServer.on_start()
def start_link({chatbot_behaviour, token, %{"id" => chat_id} = chat}) do
@spec start_link({ChatBot.t(), Types.token(), ChatBot.Chat.t(), nil | term()}) :: GenServer.on_start()
def start_link({chatbot_behaviour, token, chat, bot_state}) do
GenServer.start_link(
__MODULE__,
{chatbot_behaviour, token, chat},
name: Chat.Registry.via(token, chat_id)
{chatbot_behaviour, token, chat, bot_state},
name: Chat.Registry.via(token, chat.id)
)
end

@spec resume(ChatBot.t(), Types.token(), String.t(), term()) :: :ok | {:error, :already_started | :max_children}
def resume(chatbot_behaviour, token, chat_id, state) do
chat = %{"resume" => :resume, "id" => chat_id, "state" => state}
def resume(chatbot_behaviour, token, chat_id, bot_state) do
chat = %Telegram.ChatBot.Chat{id: chat_id}

with {:lookup, {:error, :not_found}} <- {:lookup, Chat.Registry.lookup(token, chat_id)},
{:start, {:ok, _server}} <- {:start, start_chat_session_server(chatbot_behaviour, token, chat)} do
{:start, {:ok, _server}} <- {:start, start_chat_session_server(chatbot_behaviour, token, chat, bot_state)} do
:ok
else
# coveralls-ignore-start
Expand All @@ -42,12 +42,12 @@ defmodule Telegram.Bot.ChatBot.Chat.Session.Server do

@spec handle_update(ChatBot.t(), Types.token(), Types.update()) :: :ok
def handle_update(chatbot_behaviour, token, update) do
with {:get_chat, {:ok, chat}} <- {:get_chat, Utils.get_chat(update)},
with {:get_chat, {:ok, chat}} <- {:get_chat, get_chat(chatbot_behaviour, update)},
{:get_chat_session_server, {:ok, server}} <-
{:get_chat_session_server, get_chat_session_server(chatbot_behaviour, token, chat)} do
GenServer.cast(server, {:handle_update, update})
else
{:get_chat, nil} ->
{:get_chat, :ignore} ->
Logger.info("Dropped update without chat #{inspect(update)}", bot: chatbot_behaviour, token: token)

{:get_chat_session_server, {:error, :max_children}} ->
Expand All @@ -58,10 +58,10 @@ defmodule Telegram.Bot.ChatBot.Chat.Session.Server do
end

@impl GenServer
def init({chatbot_behaviour, token, %{"resume" => :resume, "id" => chat_id, "state" => bot_state}}) do
Logger.metadata(bot: chatbot_behaviour, chat_id: chat_id)
def init({chatbot_behaviour, token, %Telegram.ChatBot.Chat{} = chat, bot_state}) when bot_state != nil do
Logger.metadata(bot: chatbot_behaviour, chat_id: chat.id)

state = %State{token: token, chatbot_behaviour: chatbot_behaviour, chat_id: chat_id, bot_state: bot_state}
state = %State{token: token, chatbot_behaviour: chatbot_behaviour, chat_id: chat.id, bot_state: bot_state}

case chatbot_behaviour.handle_resume(bot_state) do
{:ok, bot_state} ->
Expand All @@ -74,10 +74,10 @@ defmodule Telegram.Bot.ChatBot.Chat.Session.Server do
end
end

def init({chatbot_behaviour, token, %{"id" => chat_id} = chat}) do
Logger.metadata(bot: chatbot_behaviour, chat_id: chat_id)
def init({chatbot_behaviour, token, %Telegram.ChatBot.Chat{} = chat, nil}) do
Logger.metadata(bot: chatbot_behaviour, chat_id: chat.id)

state = %State{token: token, chatbot_behaviour: chatbot_behaviour, chat_id: chat_id, bot_state: nil}
state = %State{token: token, chatbot_behaviour: chatbot_behaviour, chat_id: chat.id, bot_state: nil}

chatbot_behaviour.init(chat)
|> case do
Expand All @@ -92,6 +92,7 @@ defmodule Telegram.Bot.ChatBot.Chat.Session.Server do
@impl GenServer
def handle_cast({:handle_update, update}, %State{} = state) do
res = state.chatbot_behaviour.handle_update(update, state.token, state.bot_state)

handle_callback_result(res, state)
end

Expand All @@ -109,8 +110,17 @@ defmodule Telegram.Bot.ChatBot.Chat.Session.Server do
handle_callback_result(res, state)
end

defp get_chat_session_server(chatbot_behaviour, token, %{"id" => chat_id} = chat) do
Chat.Registry.lookup(token, chat_id)
defp get_chat(chatbot_behaviour, update) do
[update_type] =
update
|> Map.drop(["update_id"])
|> Map.keys()

chatbot_behaviour.get_chat(update_type, Map.get(update, update_type))
end

defp get_chat_session_server(chatbot_behaviour, token, %Telegram.ChatBot.Chat{} = chat) do
Chat.Registry.lookup(token, chat.id)
|> case do
{:ok, _server} = ok ->
ok
Expand All @@ -120,8 +130,8 @@ defmodule Telegram.Bot.ChatBot.Chat.Session.Server do
end
end

defp start_chat_session_server(chatbot_behaviour, token, chat) do
child_spec = {__MODULE__, {chatbot_behaviour, token, chat}}
defp start_chat_session_server(chatbot_behaviour, token, %Telegram.ChatBot.Chat{} = chat, bot_state \\ nil) do
child_spec = {__MODULE__, {chatbot_behaviour, token, chat, bot_state}}

Chat.Session.Supervisor.start_child(child_spec, token)
|> case do
Expand Down
17 changes: 0 additions & 17 deletions lib/bot/utils.ex
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,4 @@ defmodule Telegram.Bot.Utils do
nil
end
end

@doc """
Get the "chat" field in an Update object, if present
"""
@spec get_chat(Types.update()) :: {:ok, map()} | nil
def get_chat(update) do
Enum.find_value(update, fn
{_update_type, %{"chat" => %{"id" => _} = chat}} ->
{:ok, chat}

{_update_type, %{"message" => %{"chat" => %{"id" => _} = chat}} = _chat} ->
{:ok, chat}

_ ->
nil
end)
end
end
Loading

0 comments on commit a05fa2a

Please sign in to comment.