Current section
Files
Jump to
Current section
Files
lib/telegram_ex.ex
defmodule TelegramEx do
@moduledoc """
Defines a behaviour for Telegram bots and provides the main `use` macro.
`use TelegramEx` sets up callbacks, imports common helpers, registers the bot
child spec, and adds fallback handlers.
## Macro Options
- `:name` (required) - bot identifier used for config lookup and FSM storage
- `:routers` (optional) - router modules tried before the bot module
See [Getting Started](getting-started.md) for setup and supervision examples,
and [Effects](effects.md) for builder pipeline error handling.
"""
alias TelegramEx.Types
@typedoc """
Context map passed to all handlers.
Contains bot token, FSM state/data, and builder request data.
"""
@type context :: %{
required(:token) => String.t(),
required(:state) => atom() | nil,
required(:data) => term(),
optional(:message_thread_id) => integer(),
optional(:payload) => map(),
optional(:chat_id) => integer(),
optional(:method) => String.t(),
optional(:format) => :json | :multipart
}
@typedoc """
Return value from handlers.
Builder pipelines return `TelegramEx.Effect` values. The server converts them
to ordinary handler results before applying FSM transitions or logging errors.
"""
@type handler_result ::
:ok
| :pass
| TelegramEx.Effect.t()
| {:transition, new_state :: atom()}
| {:transition, new_state :: atom(), data :: term()}
| {:stay, data :: term()}
| {:error, reason :: term()}
@doc """
Callback invoked when a message is received.
Return a `t:handler_result/0`. See [Getting Started](getting-started.md)
for handler examples.
"""
@callback handle_message(message :: Types.Message.t(), context :: context()) ::
handler_result()
@doc """
Callback invoked when a callback query (inline button press) is received.
Return a `t:handler_result/0`. See
[Messages and Media](messages-and-media.md) for callback examples.
"""
@callback handle_callback(callback :: Types.CallbackQuery.t(), context :: context()) ::
handler_result()
defmacro __using__(opts) do
quote do
@behaviour TelegramEx
import TelegramEx
import TelegramEx.FSM, only: [defstate: 2]
import TelegramEx.Command, only: [defcommand: 3]
alias TelegramEx.{API, Config, FSM}
alias TelegramEx.Builder.{
Contact,
Document,
Location,
Message,
Photo,
Poll,
Sticker,
Video,
Voice
}
@bot_name Keyword.fetch!(unquote(opts), :name)
@routers Keyword.get(unquote(opts), :routers, [])
Module.register_attribute(__MODULE__, :commands, accumulate: true)
def child_spec(_) do
%{
id: __MODULE__,
start: {TelegramEx.Server, :start_link, [__MODULE__, @bot_name, @routers]},
type: :worker
}
end
@before_compile TelegramEx
end
end
defmacro __before_compile__(env) do
commands =
env.module
|> Module.get_attribute(:commands)
|> Enum.reverse()
quote do
def __commands__, do: unquote(Macro.escape(commands))
def __routers__, do: @routers
def handle_message(_message, _ctx), do: :ok
def handle_callback(_callback, _ctx), do: :ok
end
end
end