Current section

Files

Jump to
telega src telega.erl
Raw

src/telega.erl

-module(telega).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/telega.gleam").
-export([get_bot_subject_internal/1, get_client_internal/1, is_webhook_path/2, is_secret_token_valid/2, get_api_config/1, new/4, new_for_polling/1, with_router/2, with_session_settings/2, with_catch_handler/2, set_drop_pending_updates/2, set_max_connections/2, set_ip_address/2, set_allowed_updates/2, set_certificate/2, set_api_client/2, with_polling_config/4, with_polling_on_stop/2, with_chat_config/4, with_nil_session/1, init_for_polling/1, init_for_polling_nil_session/1, init/1, handle_update/2, get_me/1, get_session/1, log_context/3, log_info/2, log_error/2, wait_any/4, wait_command/5, wait_commands/5, wait_text/4, wait_hears/5, wait_message/4, wait_callback_query/5, wait_audio/4, wait_video/4, wait_voice/4, wait_photos/4, wait_number/6, wait_email/4, wait_choice/5, wait_for/5, start_polling_default/1, shutdown/1, get_supervisor_pid/1]).
-export_type([telega/2, telega_builder/2]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-opaque telega(AIQU, AIQV) :: {telega,
telega@internal@config:config(),
telega@model@types:user(),
gleam@erlang@process:subject(telega@bot:bot_message()),
gleam@erlang@process:pid_()} |
{gleam_phantom, AIQU, AIQV}.
-opaque telega_builder(AIQW, AIQX) :: {telega_builder,
telega@internal@config:config(),
gleam@option:option(telega@router:router(AIQW, AIQX)),
gleam@option:option(telega@bot:session_settings(AIQW, AIQX)),
gleam@option:option(fun((telega@bot:context(AIQW, AIQX), AIQX) -> {ok,
nil} |
{error, AIQX})),
gleam@option:option(gleam@erlang@process:subject(telega@bot:bot_message())),
gleam@option:option(telega@client:telegram_client()),
gleam@option:option(boolean()),
gleam@option:option(integer()),
gleam@option:option(binary()),
gleam@option:option(list(binary())),
gleam@option:option(telega@model@types:file()),
gleam@option:option(integer()),
gleam@option:option(integer()),
gleam@option:option(integer()),
gleam@option:option(fun((telega@error:telega_error()) -> nil)),
gleam@option:option(integer()),
gleam@option:option(integer()),
gleam@option:option(integer())}.
-file("src/telega.gleam", 65).
?DOC(false).
-spec get_bot_subject_internal(telega(any(), any())) -> gleam@erlang@process:subject(telega@bot:bot_message()).
get_bot_subject_internal(Telega) ->
erlang:element(4, Telega).
-file("src/telega.gleam", 71).
?DOC(false).
-spec get_client_internal(telega(any(), any())) -> telega@client:telegram_client().
get_client_internal(Telega) ->
erlang:element(5, erlang:element(2, Telega)).
-file("src/telega.gleam", 80).
?DOC(
" Check if a path is the webhook path for the bot.\n"
"\n"
" Useful if you plan to implement own adapter.\n"
).
-spec is_webhook_path(telega(any(), any()), binary()) -> boolean().
is_webhook_path(Telega, Path) ->
erlang:element(3, erlang:element(2, Telega)) =:= Path.
-file("src/telega.gleam", 87).
?DOC(
" Check if a secret token is valid.\n"
"\n"
" Useful if you plan to implement own adapter.\n"
).
-spec is_secret_token_valid(telega(any(), any()), binary()) -> boolean().
is_secret_token_valid(Telega, Token) ->
erlang:element(4, erlang:element(2, Telega)) =:= Token.
-file("src/telega.gleam", 92).
?DOC(" Helper to get the config for API requests.\n").
-spec get_api_config(telega(any(), any())) -> telega@client:telegram_client().
get_api_config(Telega) ->
erlang:element(5, erlang:element(2, Telega)).
-file("src/telega.gleam", 99).
?DOC(
" Create a new Telega instance.\n"
"\n"
" Requires an `api_client` created by an adapter package like `telega_httpc` or `telega_hackney`.\n"
).
-spec new(
telega@client:telegram_client(),
binary(),
binary(),
gleam@option:option(binary())
) -> telega_builder(any(), any()).
new(Api_client, Server_url, Webhook_path, Secret_token) ->
Url = telega@internal@utils:normalize_url(Server_url),
Webhook_path@1 = telega@internal@utils:normalize_webhook_path(Webhook_path),
{telega_builder,
telega@internal@config:new(
Api_client,
Url,
Webhook_path@1,
Secret_token
),
none,
none,
none,
none,
none,
none,
none,
none,
none,
none,
none,
none,
none,
none,
none,
none,
none}.
-file("src/telega.gleam", 134).
?DOC(
" Create a new Telega instance optimized for long polling.\n"
"\n"
" Requires an `api_client` created by an adapter package like `telega_httpc` or `telega_hackney`.\n"
" This is a convenience function for polling bots that don't need webhook configuration.\n"
).
-spec new_for_polling(telega@client:telegram_client()) -> telega_builder(any(), any()).
new_for_polling(Api_client) ->
{telega_builder,
telega@internal@config:new(
Api_client,
<<"https://api.telegram.org"/utf8>>,
<<"/webhook"/utf8>>,
none
),
none,
none,
none,
none,
none,
none,
none,
none,
none,
none,
none,
none,
none,
none,
none,
none,
none}.
-file("src/telega.gleam", 165).
?DOC(
" Set the router for handling updates.\n"
" This is the primary way to handle updates - use router.new() to create a router\n"
" and configure it with command handlers, text handlers, middleware, etc.\n"
).
-spec with_router(telega_builder(AIRY, AIRZ), telega@router:router(AIRY, AIRZ)) -> telega_builder(AIRY, AIRZ).
with_router(Builder, Router) ->
{telega_builder,
erlang:element(2, Builder),
{some, Router},
erlang:element(4, Builder),
erlang:element(5, Builder),
erlang:element(6, Builder),
erlang:element(7, Builder),
erlang:element(8, Builder),
erlang:element(9, Builder),
erlang:element(10, Builder),
erlang:element(11, Builder),
erlang:element(12, Builder),
erlang:element(13, Builder),
erlang:element(14, Builder),
erlang:element(15, Builder),
erlang:element(16, Builder),
erlang:element(17, Builder),
erlang:element(18, Builder),
erlang:element(19, Builder)}.
-file("src/telega.gleam", 173).
?DOC(" Set session settings for the bot.\n").
-spec with_session_settings(
telega_builder(AISG, AISH),
telega@bot:session_settings(AISG, AISH)
) -> telega_builder(AISG, AISH).
with_session_settings(Builder, Session_settings) ->
{telega_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
{some, Session_settings},
erlang:element(5, Builder),
erlang:element(6, Builder),
erlang:element(7, Builder),
erlang:element(8, Builder),
erlang:element(9, Builder),
erlang:element(10, Builder),
erlang:element(11, Builder),
erlang:element(12, Builder),
erlang:element(13, Builder),
erlang:element(14, Builder),
erlang:element(15, Builder),
erlang:element(16, Builder),
erlang:element(17, Builder),
erlang:element(18, Builder),
erlang:element(19, Builder)}.
-file("src/telega.gleam", 182).
?DOC(
" Set catch handler for system errors (like session persistence failures) and [conversation](/docs/conversation) errors.\n"
" This is different from router's catch handler which handles route errors.\n"
).
-spec with_catch_handler(
telega_builder(AISO, AISP),
fun((telega@bot:context(AISO, AISP), AISP) -> {ok, nil} | {error, AISP})
) -> telega_builder(AISO, AISP).
with_catch_handler(Builder, Catch_handler) ->
{telega_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
erlang:element(4, Builder),
{some, Catch_handler},
erlang:element(6, Builder),
erlang:element(7, Builder),
erlang:element(8, Builder),
erlang:element(9, Builder),
erlang:element(10, Builder),
erlang:element(11, Builder),
erlang:element(12, Builder),
erlang:element(13, Builder),
erlang:element(14, Builder),
erlang:element(15, Builder),
erlang:element(16, Builder),
erlang:element(17, Builder),
erlang:element(18, Builder),
erlang:element(19, Builder)}.
-file("src/telega.gleam", 190).
?DOC(" Set whether to drop pending updates.\n").
-spec set_drop_pending_updates(telega_builder(AISW, AISX), boolean()) -> telega_builder(AISW, AISX).
set_drop_pending_updates(Builder, Drop) ->
{telega_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
erlang:element(4, Builder),
erlang:element(5, Builder),
erlang:element(6, Builder),
erlang:element(7, Builder),
{some, Drop},
erlang:element(9, Builder),
erlang:element(10, Builder),
erlang:element(11, Builder),
erlang:element(12, Builder),
erlang:element(13, Builder),
erlang:element(14, Builder),
erlang:element(15, Builder),
erlang:element(16, Builder),
erlang:element(17, Builder),
erlang:element(18, Builder),
erlang:element(19, Builder)}.
-file("src/telega.gleam", 198).
?DOC(" Set max connections for webhook.\n").
-spec set_max_connections(telega_builder(AITC, AITD), integer()) -> telega_builder(AITC, AITD).
set_max_connections(Builder, Max) ->
{telega_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
erlang:element(4, Builder),
erlang:element(5, Builder),
erlang:element(6, Builder),
erlang:element(7, Builder),
erlang:element(8, Builder),
{some, Max},
erlang:element(10, Builder),
erlang:element(11, Builder),
erlang:element(12, Builder),
erlang:element(13, Builder),
erlang:element(14, Builder),
erlang:element(15, Builder),
erlang:element(16, Builder),
erlang:element(17, Builder),
erlang:element(18, Builder),
erlang:element(19, Builder)}.
-file("src/telega.gleam", 206).
?DOC(" Set IP address for webhook.\n").
-spec set_ip_address(telega_builder(AITI, AITJ), binary()) -> telega_builder(AITI, AITJ).
set_ip_address(Builder, Ip) ->
{telega_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
erlang:element(4, Builder),
erlang:element(5, Builder),
erlang:element(6, Builder),
erlang:element(7, Builder),
erlang:element(8, Builder),
erlang:element(9, Builder),
{some, Ip},
erlang:element(11, Builder),
erlang:element(12, Builder),
erlang:element(13, Builder),
erlang:element(14, Builder),
erlang:element(15, Builder),
erlang:element(16, Builder),
erlang:element(17, Builder),
erlang:element(18, Builder),
erlang:element(19, Builder)}.
-file("src/telega.gleam", 214).
?DOC(" Set allowed updates for webhook.\n").
-spec set_allowed_updates(telega_builder(AITO, AITP), list(binary())) -> telega_builder(AITO, AITP).
set_allowed_updates(Builder, Updates) ->
{telega_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
erlang:element(4, Builder),
erlang:element(5, Builder),
erlang:element(6, Builder),
erlang:element(7, Builder),
erlang:element(8, Builder),
erlang:element(9, Builder),
erlang:element(10, Builder),
{some, Updates},
erlang:element(12, Builder),
erlang:element(13, Builder),
erlang:element(14, Builder),
erlang:element(15, Builder),
erlang:element(16, Builder),
erlang:element(17, Builder),
erlang:element(18, Builder),
erlang:element(19, Builder)}.
-file("src/telega.gleam", 222).
?DOC(" Set certificate for webhook.\n").
-spec set_certificate(telega_builder(AITV, AITW), telega@model@types:file()) -> telega_builder(AITV, AITW).
set_certificate(Builder, Cert) ->
{telega_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
erlang:element(4, Builder),
erlang:element(5, Builder),
erlang:element(6, Builder),
erlang:element(7, Builder),
erlang:element(8, Builder),
erlang:element(9, Builder),
erlang:element(10, Builder),
erlang:element(11, Builder),
{some, Cert},
erlang:element(13, Builder),
erlang:element(14, Builder),
erlang:element(15, Builder),
erlang:element(16, Builder),
erlang:element(17, Builder),
erlang:element(18, Builder),
erlang:element(19, Builder)}.
-file("src/telega.gleam", 230).
?DOC(" Set a custom API client.\n").
-spec set_api_client(
telega_builder(AIUB, AIUC),
telega@client:telegram_client()
) -> telega_builder(AIUB, AIUC).
set_api_client(Builder, Client) ->
{telega_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
erlang:element(4, Builder),
erlang:element(5, Builder),
erlang:element(6, Builder),
{some, Client},
erlang:element(8, Builder),
erlang:element(9, Builder),
erlang:element(10, Builder),
erlang:element(11, Builder),
erlang:element(12, Builder),
erlang:element(13, Builder),
erlang:element(14, Builder),
erlang:element(15, Builder),
erlang:element(16, Builder),
erlang:element(17, Builder),
erlang:element(18, Builder),
erlang:element(19, Builder)}.
-file("src/telega.gleam", 238).
?DOC(" Set polling configuration for the supervised polling worker.\n").
-spec with_polling_config(
telega_builder(AIUH, AIUI),
integer(),
integer(),
integer()
) -> telega_builder(AIUH, AIUI).
with_polling_config(Builder, Timeout, Limit, Poll_interval) ->
{telega_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
erlang:element(4, Builder),
erlang:element(5, Builder),
erlang:element(6, Builder),
erlang:element(7, Builder),
erlang:element(8, Builder),
erlang:element(9, Builder),
erlang:element(10, Builder),
erlang:element(11, Builder),
erlang:element(12, Builder),
{some, Timeout},
{some, Limit},
{some, Poll_interval},
erlang:element(16, Builder),
erlang:element(17, Builder),
erlang:element(18, Builder),
erlang:element(19, Builder)}.
-file("src/telega.gleam", 253).
?DOC(" Set a callback for when polling stops due to errors.\n").
-spec with_polling_on_stop(
telega_builder(AIUN, AIUO),
fun((telega@error:telega_error()) -> nil)
) -> telega_builder(AIUN, AIUO).
with_polling_on_stop(Builder, On_stop) ->
{telega_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
erlang:element(4, Builder),
erlang:element(5, Builder),
erlang:element(6, Builder),
erlang:element(7, Builder),
erlang:element(8, Builder),
erlang:element(9, Builder),
erlang:element(10, Builder),
erlang:element(11, Builder),
erlang:element(12, Builder),
erlang:element(13, Builder),
erlang:element(14, Builder),
erlang:element(15, Builder),
{some, On_stop},
erlang:element(17, Builder),
erlang:element(18, Builder),
erlang:element(19, Builder)}.
-file("src/telega.gleam", 265).
?DOC(
" Configure the chat instance factory supervisor.\n"
"\n"
" - `restart_tolerance_intensity` — max restarts within the period (default: 5)\n"
" - `restart_tolerance_period` — period in seconds (default: 10)\n"
" - `init_timeout` — chat instance init timeout in ms (default: 10 000)\n"
).
-spec with_chat_config(
telega_builder(AIUT, AIUU),
integer(),
integer(),
integer()
) -> telega_builder(AIUT, AIUU).
with_chat_config(Builder, Intensity, Period, Timeout) ->
{telega_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
erlang:element(4, Builder),
erlang:element(5, Builder),
erlang:element(6, Builder),
erlang:element(7, Builder),
erlang:element(8, Builder),
erlang:element(9, Builder),
erlang:element(10, Builder),
erlang:element(11, Builder),
erlang:element(12, Builder),
erlang:element(13, Builder),
erlang:element(14, Builder),
erlang:element(15, Builder),
erlang:element(16, Builder),
{some, Intensity},
{some, Period},
{some, Timeout}}.
-file("src/telega.gleam", 280).
?DOC(" Set nil session for the bot.\n").
-spec with_nil_session(telega_builder(nil, AIUZ)) -> telega_builder(nil, AIUZ).
with_nil_session(Builder) ->
_pipe = Builder,
with_session_settings(
_pipe,
{session_settings,
fun(_, _) -> {ok, nil} end,
fun(_) -> {ok, none} end,
fun() -> nil end}
).
-file("src/telega.gleam", 1018).
-spec build_chat_factory_spec(telega_builder(any(), any())) -> {gleam@otp@supervision:child_specification(gleam@otp@factory_supervisor:supervisor(telega@bot:chat_instance_args(AKEO, AKEP), gleam@erlang@process:subject(telega@bot:chat_instance_message(AKEO, AKEP)))),
gleam@erlang@process:name(gleam@otp@factory_supervisor:message(telega@bot:chat_instance_args(AKEO, AKEP), gleam@erlang@process:subject(telega@bot:chat_instance_message(AKEO, AKEP))))}.
build_chat_factory_spec(Builder) ->
Intensity = gleam@option:unwrap(erlang:element(17, Builder), 5),
Period = gleam@option:unwrap(erlang:element(18, Builder), 10),
Timeout = gleam@option:unwrap(erlang:element(19, Builder), 10000),
Name = gleam_erlang_ffi:new_name(<<"telega_chat_factory"/utf8>>),
Spec = begin
_pipe = gleam@otp@factory_supervisor:worker_child(
fun telega@bot:start_chat_instance/1
),
_pipe@1 = gleam@otp@factory_supervisor:named(_pipe, Name),
_pipe@2 = gleam@otp@factory_supervisor:restart_strategy(
_pipe@1,
transient
),
_pipe@3 = gleam@otp@factory_supervisor:restart_tolerance(
_pipe@2,
Intensity,
Period
),
_pipe@4 = gleam@otp@factory_supervisor:timeout(_pipe@3, Timeout),
gleam@otp@factory_supervisor:supervised(_pipe@4)
end,
{Spec, Name}.
-file("src/telega.gleam", 1046).
-spec generate_registry_name(binary()) -> binary().
generate_registry_name(Token) ->
_pipe = Token,
_pipe@1 = gleam@string:slice(_pipe, 0, 8),
gleam@string:append(
_pipe@1,
<<"_"/utf8,
(erlang:integer_to_binary(gleam@int:random(1000000)))/binary>>
).
-file("src/telega.gleam", 387).
?DOC(
" Initialize the bot for long polling with a supervision tree.\n"
" Includes a supervised polling worker that auto-starts.\n"
).
-spec init_for_polling(telega_builder(AIVT, AIVU)) -> {ok, telega(AIVT, AIVU)} |
{error, telega@error:telega_error()}.
init_for_polling(Builder) ->
Api_client = gleam@option:unwrap(
erlang:element(7, Builder),
erlang:element(5, erlang:element(2, Builder))
),
gleam@result:'try'(
begin
_pipe = telega@api:get_me(Api_client),
gleam@result:map_error(_pipe, fun(Err) -> case Err of
{telegram_api_error, 404, _} ->
{telegram_api_error,
404,
<<"Bot not found. Please check that your BOT_TOKEN is valid and the bot exists. Get a valid token from @BotFather on Telegram."/utf8>>};
{telegram_api_error, 401, _} ->
{telegram_api_error,
401,
<<"Unauthorized. Your bot token is invalid. Please get a valid token from @BotFather on Telegram."/utf8>>};
_ ->
Err
end end)
end,
fun(Bot_info) ->
Session_settings = gleam@option:to_result(
erlang:element(4, Builder),
no_session_settings_error
),
gleam@result:'try'(
Session_settings,
fun(Session_settings@1) ->
Router = gleam@option:to_result(
erlang:element(3, Builder),
{actor_error,
<<"Router is required. Use with_router() to set a router."/utf8>>}
),
gleam@result:'try'(
Router,
fun(Router@1) ->
Router_handler = fun(Ctx, Upd) ->
telega@router:handle(Router@1, Ctx, Upd)
end,
Catch_handler = gleam@option:unwrap(
erlang:element(5, Builder),
fun(_, Err@1) -> {error, Err@1} end
),
Config = begin
_record = erlang:element(2, Builder),
{config,
erlang:element(2, _record),
erlang:element(3, _record),
erlang:element(4, _record),
Api_client}
end,
Registry_name = generate_registry_name(
telega@client:get_token(
erlang:element(5, Config)
)
),
gleam@result:'try'(
telega@internal@registry:start(Registry_name),
fun(Registry) ->
{Chat_factory_spec, Chat_factory_name} = build_chat_factory_spec(
Builder
),
Bot_name = gleam_erlang_ffi:new_name(
<<"telega_bot"/utf8>>
),
Bot_subject = gleam@erlang@process:named_subject(
Bot_name
),
Chat_factory_ref = gleam@otp@factory_supervisor:get_by_name(
Chat_factory_name
),
Bot_spec = begin
_pipe@1 = gleam@otp@supervision:worker(
fun() ->
telega@bot:start(
Registry,
Config,
Bot_info,
Router_handler,
Session_settings@1,
Catch_handler,
Chat_factory_ref,
{some, Bot_name}
)
end
),
gleam@otp@supervision:restart(
_pipe@1,
permanent
)
end,
Polling_timeout = gleam@option:unwrap(
erlang:element(13, Builder),
30
),
Polling_limit = gleam@option:unwrap(
erlang:element(14, Builder),
100
),
Polling_interval = gleam@option:unwrap(
erlang:element(15, Builder),
1000
),
Allowed_updates = gleam@option:unwrap(
erlang:element(11, Builder),
[]
),
Polling_spec = telega@polling:supervised(
Api_client,
Bot_subject,
Polling_timeout,
Polling_limit,
Allowed_updates,
Polling_interval,
erlang:element(16, Builder)
),
gleam@result:'try'(
begin
_pipe@2 = gleam@otp@static_supervisor:new(
one_for_one
),
_pipe@3 = gleam@otp@static_supervisor:add(
_pipe@2,
Chat_factory_spec
),
_pipe@4 = gleam@otp@static_supervisor:add(
_pipe@3,
Bot_spec
),
_pipe@5 = gleam@otp@static_supervisor:add(
_pipe@4,
Polling_spec
),
_pipe@6 = gleam@otp@static_supervisor:start(
_pipe@5
),
gleam@result:map_error(
_pipe@6,
fun(Field@0) -> {supervisor_start_error, Field@0} end
)
end,
fun(Sup_started) ->
{ok,
{telega,
Config,
Bot_info,
Bot_subject,
erlang:element(
2,
Sup_started
)}}
end
)
end
)
end
)
end
)
end
).
-file("src/telega.gleam", 294).
?DOC(" Initialize the bot for long polling with nil session.\n").
-spec init_for_polling_nil_session(telega_builder(nil, AIVE)) -> {ok,
telega(nil, AIVE)} |
{error, telega@error:telega_error()}.
init_for_polling_nil_session(Builder) ->
_pipe = Builder,
_pipe@1 = with_session_settings(
_pipe,
{session_settings,
fun(_, _) -> {ok, nil} end,
fun(_) -> {ok, none} end,
fun() -> nil end}
),
init_for_polling(_pipe@1).
-file("src/telega.gleam", 309).
?DOC(" Initialize the bot for webhook mode with a supervision tree.\n").
-spec init(telega_builder(AIVL, AIVM)) -> {ok, telega(AIVL, AIVM)} |
{error, telega@error:telega_error()}.
init(Builder) ->
Api_client = gleam@option:unwrap(
erlang:element(7, Builder),
erlang:element(5, erlang:element(2, Builder))
),
gleam@result:'try'(
telega@api:set_webhook(
Api_client,
{set_webhook_parameters,
<<<<(erlang:element(2, erlang:element(2, Builder)))/binary,
"/"/utf8>>/binary,
(erlang:element(3, erlang:element(2, Builder)))/binary>>,
erlang:element(12, Builder),
erlang:element(9, Builder),
erlang:element(10, Builder),
erlang:element(11, Builder),
erlang:element(8, Builder),
{some, erlang:element(4, erlang:element(2, Builder))}}
),
fun(Is_ok) ->
gleam@bool:guard(
not Is_ok,
{error, set_webhook_error},
fun() ->
gleam@result:'try'(
telega@api:get_me(Api_client),
fun(Bot_info) ->
Session_settings = gleam@option:to_result(
erlang:element(4, Builder),
no_session_settings_error
),
gleam@result:'try'(
Session_settings,
fun(Session_settings@1) ->
Router = gleam@option:to_result(
erlang:element(3, Builder),
{router_error,
<<"Router is required. Use with_router() to set a router."/utf8>>}
),
gleam@result:'try'(
Router,
fun(Router@1) ->
Router_handler = fun(Ctx, Upd) ->
telega@router:handle(
Router@1,
Ctx,
Upd
)
end,
Catch_handler = gleam@option:unwrap(
erlang:element(5, Builder),
fun(_, Err) -> {error, Err} end
),
Config = begin
_record = erlang:element(
2,
Builder
),
{config,
erlang:element(2, _record),
erlang:element(3, _record),
erlang:element(4, _record),
Api_client}
end,
Registry_name = generate_registry_name(
telega@client:get_token(
erlang:element(5, Config)
)
),
gleam@result:'try'(
telega@internal@registry:start(
Registry_name
),
fun(Registry) ->
{Chat_factory_spec,
Chat_factory_name} = build_chat_factory_spec(
Builder
),
Bot_name = gleam_erlang_ffi:new_name(
<<"telega_bot"/utf8>>
),
Bot_subject = gleam@erlang@process:named_subject(
Bot_name
),
Chat_factory_ref = gleam@otp@factory_supervisor:get_by_name(
Chat_factory_name
),
Bot_spec = begin
_pipe = gleam@otp@supervision:worker(
fun() ->
telega@bot:start(
Registry,
Config,
Bot_info,
Router_handler,
Session_settings@1,
Catch_handler,
Chat_factory_ref,
{some,
Bot_name}
)
end
),
gleam@otp@supervision:restart(
_pipe,
permanent
)
end,
gleam@result:'try'(
begin
_pipe@1 = gleam@otp@static_supervisor:new(
one_for_one
),
_pipe@2 = gleam@otp@static_supervisor:add(
_pipe@1,
Chat_factory_spec
),
_pipe@3 = gleam@otp@static_supervisor:add(
_pipe@2,
Bot_spec
),
_pipe@4 = gleam@otp@static_supervisor:start(
_pipe@3
),
gleam@result:map_error(
_pipe@4,
fun(Field@0) -> {supervisor_start_error, Field@0} end
)
end,
fun(Sup_started) ->
{ok,
{telega,
Config,
Bot_info,
Bot_subject,
erlang:element(
2,
Sup_started
)}}
end
)
end
)
end
)
end
)
end
)
end
)
end
).
-file("src/telega.gleam", 485).
?DOC(
" Handle an update.\n"
"\n"
" This function is useful when you want to handle updates in your own way.\n"
).
-spec handle_update(telega(any(), any()), telega@model@types:update()) -> boolean().
handle_update(Telega, Raw_update) ->
Update = telega@update:raw_to_update(Raw_update),
telega@bot:handle_update(erlang:element(4, Telega), Update).
-file("src/telega.gleam", 494).
?DOC(" Get the bot's information.\n").
-spec get_me(telega(any(), any())) -> telega@model@types:user().
get_me(Telega) ->
erlang:element(3, Telega).
-file("src/telega.gleam", 499).
?DOC(" Get session for the current context.\n").
-spec get_session(telega@bot:context(AIWJ, any())) -> AIWJ.
get_session(Ctx) ->
erlang:element(5, Ctx).
-file("src/telega.gleam", 504).
?DOC(" Add logging context to the current context.\n").
-spec log_context(
telega@bot:context(AIWN, AIWO),
binary(),
fun((telega@bot:context(AIWN, AIWO)) -> {ok, telega@bot:context(AIWN, AIWO)} |
{error, AIWO})
) -> {ok, telega@bot:context(AIWN, AIWO)} | {error, AIWO}.
log_context(Ctx, Prefix, Fun) ->
Ctx_with_log = {context,
erlang:element(2, Ctx),
erlang:element(3, Ctx),
erlang:element(4, Ctx),
erlang:element(5, Ctx),
erlang:element(6, Ctx),
erlang:element(7, Ctx),
{some, Prefix},
erlang:element(9, Ctx)},
Fun(Ctx_with_log).
-file("src/telega.gleam", 514).
?DOC(" Context helpers for logging\n").
-spec log_info(telega@bot:context(any(), any()), binary()) -> nil.
log_info(Ctx, Message) ->
case erlang:element(8, Ctx) of
{some, Prefix} ->
telega@internal@log:info_d(Prefix, Message);
none ->
telega@internal@log:info(Message)
end.
-file("src/telega.gleam", 521).
-spec log_error(telega@bot:context(any(), any()), binary()) -> nil.
log_error(Ctx, Message) ->
case erlang:element(8, Ctx) of
{some, Prefix} ->
telega@internal@log:error_d(Prefix, Message);
none ->
telega@internal@log:error(Message)
end.
-file("src/telega.gleam", 532).
?DOC(
" Pauses the current chat actor's handler and waits for any update.\n"
" Other chats and users continue to be handled concurrently.\n"
"\n"
" See [conversation](/docs/conversation)\n"
).
-spec wait_any(
telega@bot:context(AIXL, AIXM),
gleam@option:option(telega@bot:handler(AIXL, AIXM)),
gleam@option:option(integer()),
fun((telega@bot:context(AIXL, AIXM), telega@update:update()) -> {ok,
telega@bot:context(AIXL, AIXM)} |
{error, AIXM})
) -> {ok, telega@bot:context(AIXL, AIXM)} | {error, AIXM}.
wait_any(Ctx, Handle_else, Timeout, Handler) ->
telega@bot:wait_handler(Ctx, {handle_all, Handler}, Handle_else, Timeout).
-file("src/telega.gleam", 551).
?DOC(
" Pauses the current chat actor's handler and waits for a specific command.\n"
" Other chats and users continue to be handled concurrently.\n"
"\n"
" See [conversation](/docs/conversation)\n"
).
-spec wait_command(
telega@bot:context(AIYD, AIYE),
binary(),
gleam@option:option(telega@bot:handler(AIYD, AIYE)),
gleam@option:option(integer()),
fun((telega@bot:context(AIYD, AIYE), telega@update:command()) -> {ok,
telega@bot:context(AIYD, AIYE)} |
{error, AIYE})
) -> {ok, telega@bot:context(AIYD, AIYE)} | {error, AIYE}.
wait_command(Ctx, Command, Handle_else, Timeout, Continue) ->
telega@bot:wait_handler(
Ctx,
{handle_command, Command, Continue},
Handle_else,
Timeout
).
-file("src/telega.gleam", 571).
?DOC(
" Pauses the current chat actor's handler and waits for one of the specified commands.\n"
" Other chats and users continue to be handled concurrently.\n"
"\n"
" See [conversation](/docs/conversation)\n"
).
-spec wait_commands(
telega@bot:context(AIYV, AIYW),
list(binary()),
gleam@option:option(telega@bot:handler(AIYV, AIYW)),
gleam@option:option(integer()),
fun((telega@bot:context(AIYV, AIYW), telega@update:command()) -> {ok,
telega@bot:context(AIYV, AIYW)} |
{error, AIYW})
) -> {ok, telega@bot:context(AIYV, AIYW)} | {error, AIYW}.
wait_commands(Ctx, Commands, Handle_else, Timeout, Continue) ->
telega@bot:wait_handler(
Ctx,
{handle_commands, Commands, Continue},
Handle_else,
Timeout
).
-file("src/telega.gleam", 591).
?DOC(
" Pauses the current chat actor's handler and waits for a text message.\n"
" Other chats and users continue to be handled concurrently.\n"
"\n"
" See [conversation](/docs/conversation)\n"
).
-spec wait_text(
telega@bot:context(AIZO, AIZP),
gleam@option:option(telega@bot:handler(AIZO, AIZP)),
gleam@option:option(integer()),
fun((telega@bot:context(AIZO, AIZP), binary()) -> {ok,
telega@bot:context(AIZO, AIZP)} |
{error, AIZP})
) -> {ok, telega@bot:context(AIZO, AIZP)} | {error, AIZP}.
wait_text(Ctx, Handle_else, Timeout, Continue) ->
telega@bot:wait_handler(Ctx, {handle_text, Continue}, Handle_else, Timeout).
-file("src/telega.gleam", 610).
?DOC(
" Pauses the current chat actor's handler and waits for a message that matches the given `Hears`.\n"
" Other chats and users continue to be handled concurrently.\n"
"\n"
" See [conversation](/docs/conversation)\n"
).
-spec wait_hears(
telega@bot:context(AJAG, AJAH),
telega@bot:hears(),
gleam@option:option(telega@bot:handler(AJAG, AJAH)),
gleam@option:option(integer()),
fun((telega@bot:context(AJAG, AJAH), binary()) -> {ok,
telega@bot:context(AJAG, AJAH)} |
{error, AJAH})
) -> {ok, telega@bot:context(AJAG, AJAH)} | {error, AJAH}.
wait_hears(Ctx, Hears, Handle_else, Timeout, Continue) ->
telega@bot:wait_handler(
Ctx,
{handle_hears, Hears, Continue},
Handle_else,
Timeout
).
-file("src/telega.gleam", 630).
?DOC(
" Pauses the current chat actor's handler and waits for any message.\n"
" Other chats and users continue to be handled concurrently.\n"
"\n"
" See [conversation](/docs/conversation)\n"
).
-spec wait_message(
telega@bot:context(AJAY, AJAZ),
gleam@option:option(telega@bot:handler(AJAY, AJAZ)),
gleam@option:option(integer()),
fun((telega@bot:context(AJAY, AJAZ), telega@model@types:message()) -> {ok,
telega@bot:context(AJAY, AJAZ)} |
{error, AJAZ})
) -> {ok, telega@bot:context(AJAY, AJAZ)} | {error, AJAZ}.
wait_message(Ctx, Handle_else, Timeout, Continue) ->
telega@bot:wait_handler(
Ctx,
{handle_message, Continue},
Handle_else,
Timeout
).
-file("src/telega.gleam", 649).
?DOC(
" Pauses the current chat actor's handler and waits for a callback query.\n"
" Other chats and users continue to be handled concurrently.\n"
"\n"
" See [conversation](/docs/conversation)\n"
).
-spec wait_callback_query(
telega@bot:context(AJBQ, AJBR),
gleam@option:option(telega@bot:callback_query_filter()),
gleam@option:option(telega@bot:handler(AJBQ, AJBR)),
gleam@option:option(integer()),
fun((telega@bot:context(AJBQ, AJBR), binary(), binary()) -> {ok,
telega@bot:context(AJBQ, AJBR)} |
{error, AJBR})
) -> {ok, telega@bot:context(AJBQ, AJBR)} | {error, AJBR}.
wait_callback_query(Ctx, Filter, Handle_else, Timeout, Continue) ->
Default_re@1 = case gleam@regexp:from_string(<<".*"/utf8>>) of
{ok, Default_re} -> Default_re;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"telega"/utf8>>,
function => <<"wait_callback_query"/utf8>>,
line => 657,
value => _assert_fail,
start => 20337,
'end' => 20389,
pattern_start => 20348,
pattern_end => 20362})
end,
Filter_value = gleam@option:unwrap(
Filter,
{callback_query_filter, Default_re@1}
),
telega@bot:wait_handler(
Ctx,
{handle_callback_query, Filter_value, Continue},
Handle_else,
Timeout
).
-file("src/telega.gleam", 672).
?DOC(
" Pauses the current chat actor's handler and waits for an audio message.\n"
" Other chats and users continue to be handled concurrently.\n"
"\n"
" See [conversation](/docs/conversation)\n"
).
-spec wait_audio(
telega@bot:context(AJCJ, AJCK),
gleam@option:option(telega@bot:handler(AJCJ, AJCK)),
gleam@option:option(integer()),
fun((telega@bot:context(AJCJ, AJCK), telega@model@types:audio()) -> {ok,
telega@bot:context(AJCJ, AJCK)} |
{error, AJCK})
) -> {ok, telega@bot:context(AJCJ, AJCK)} | {error, AJCK}.
wait_audio(Ctx, Handle_else, Timeout, Continue) ->
telega@bot:wait_handler(Ctx, {handle_audio, Continue}, Handle_else, Timeout).
-file("src/telega.gleam", 691).
?DOC(
" Pauses the current chat actor's handler and waits for a video message.\n"
" Other chats and users continue to be handled concurrently.\n"
"\n"
" See [conversation](/docs/conversation)\n"
).
-spec wait_video(
telega@bot:context(AJDB, AJDC),
gleam@option:option(telega@bot:handler(AJDB, AJDC)),
gleam@option:option(integer()),
fun((telega@bot:context(AJDB, AJDC), telega@model@types:video()) -> {ok,
telega@bot:context(AJDB, AJDC)} |
{error, AJDC})
) -> {ok, telega@bot:context(AJDB, AJDC)} | {error, AJDC}.
wait_video(Ctx, Handle_else, Timeout, Continue) ->
telega@bot:wait_handler(Ctx, {handle_video, Continue}, Handle_else, Timeout).
-file("src/telega.gleam", 710).
?DOC(
" Pauses the current chat actor's handler and waits for a voice message.\n"
" Other chats and users continue to be handled concurrently.\n"
"\n"
" See [conversation](/docs/conversation)\n"
).
-spec wait_voice(
telega@bot:context(AJDT, AJDU),
gleam@option:option(telega@bot:handler(AJDT, AJDU)),
gleam@option:option(integer()),
fun((telega@bot:context(AJDT, AJDU), telega@model@types:voice()) -> {ok,
telega@bot:context(AJDT, AJDU)} |
{error, AJDU})
) -> {ok, telega@bot:context(AJDT, AJDU)} | {error, AJDU}.
wait_voice(Ctx, Handle_else, Timeout, Continue) ->
telega@bot:wait_handler(Ctx, {handle_voice, Continue}, Handle_else, Timeout).
-file("src/telega.gleam", 729).
?DOC(
" Pauses the current chat actor's handler and waits for photos.\n"
" Other chats and users continue to be handled concurrently.\n"
"\n"
" See [conversation](/docs/conversation)\n"
).
-spec wait_photos(
telega@bot:context(AJEL, AJEM),
gleam@option:option(telega@bot:handler(AJEL, AJEM)),
gleam@option:option(integer()),
fun((telega@bot:context(AJEL, AJEM), list(telega@model@types:photo_size())) -> {ok,
telega@bot:context(AJEL, AJEM)} |
{error, AJEM})
) -> {ok, telega@bot:context(AJEL, AJEM)} | {error, AJEM}.
wait_photos(Ctx, Handle_else, Timeout, Continue) ->
telega@bot:wait_handler(
Ctx,
{handle_photos, Continue},
Handle_else,
Timeout
).
-file("src/telega.gleam", 767).
?DOC(
" Wait for a number with validation.\n"
"\n"
" This function waits for user to send text that can be parsed as an integer,\n"
" with optional min/max validation.\n"
"\n"
" If validation fails and `or` handler is provided, it will be called.\n"
" Otherwise, the function will keep waiting for valid input.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" use ctx, age <- wait_number(\n"
" ctx,\n"
" min: Some(0),\n"
" max: Some(120),\n"
" or: Some(bot.HandleText(fn(ctx, invalid) {\n"
" reply.with_text(ctx, \"Please enter age between 0 and 120\")\n"
" })),\n"
" timeout: None,\n"
" )\n"
" ```\n"
"\n"
" See [conversation](/docs/conversation)\n"
).
-spec wait_number(
telega@bot:context(AJFE, AJFF),
gleam@option:option(integer()),
gleam@option:option(integer()),
gleam@option:option(telega@bot:handler(AJFE, AJFF)),
gleam@option:option(integer()),
fun((telega@bot:context(AJFE, AJFF), integer()) -> {ok,
telega@bot:context(AJFE, AJFF)} |
{error, AJFF})
) -> {ok, telega@bot:context(AJFE, AJFF)} | {error, AJFF}.
wait_number(Ctx, Min, Max, Handle_else, Timeout, Continue) ->
Validation_handler = {handle_text,
fun(Ctx@1, Text) -> case gleam_stdlib:parse_int(Text) of
{ok, Number} ->
Min_ok = case Min of
{some, Min_val} ->
Number >= Min_val;
none ->
true
end,
Max_ok = case Max of
{some, Max_val} ->
Number =< Max_val;
none ->
true
end,
case Min_ok andalso Max_ok of
true ->
Continue(Ctx@1, Number);
false ->
wait_number(
Ctx@1,
Min,
Max,
Handle_else,
Timeout,
Continue
)
end;
{error, _} ->
wait_number(Ctx@1, Min, Max, Handle_else, Timeout, Continue)
end end},
telega@bot:wait_handler(Ctx, Validation_handler, Handle_else, Timeout).
-file("src/telega.gleam", 826).
?DOC(
" Wait for email with validation.\n"
"\n"
" This function waits for user to send text that matches email pattern.\n"
"\n"
" If validation fails and `or` handler is provided, it will be called.\n"
" Otherwise, the function will keep waiting for valid input.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" use ctx, email <- wait_email(\n"
" ctx,\n"
" or: Some(bot.HandleText(fn(ctx, invalid) {\n"
" reply.with_text(ctx, \"Invalid email format. Try again.\")\n"
" })),\n"
" timeout: None,\n"
" )\n"
" ```\n"
"\n"
" See [conversation](/docs/conversation)\n"
).
-spec wait_email(
telega@bot:context(AJFY, AJFZ),
gleam@option:option(telega@bot:handler(AJFY, AJFZ)),
gleam@option:option(integer()),
fun((telega@bot:context(AJFY, AJFZ), binary()) -> {ok,
telega@bot:context(AJFY, AJFZ)} |
{error, AJFZ})
) -> {ok, telega@bot:context(AJFY, AJFZ)} | {error, AJFZ}.
wait_email(Ctx, Handle_else, Timeout, Continue) ->
Email_pattern = <<"^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$"/utf8>>,
Validation_handler = {handle_text,
fun(Ctx@1, Text) -> case gleam@regexp:from_string(Email_pattern) of
{ok, Re} ->
case gleam@regexp:check(Re, Text) of
true ->
Continue(Ctx@1, Text);
false ->
wait_email(Ctx@1, Handle_else, Timeout, Continue)
end;
{error, _} ->
Continue(Ctx@1, Text)
end end},
telega@bot:wait_handler(Ctx, Validation_handler, Handle_else, Timeout).
-file("src/telega.gleam", 1053).
-spec list_at(list(AJIV), integer()) -> {ok, AJIV} | {error, nil}.
list_at(List, Index) ->
case {List, Index} of
{[], _} ->
{error, nil};
{[Head | _], 0} ->
{ok, Head};
{[_ | Tail], N} ->
list_at(Tail, N - 1)
end.
-file("src/telega.gleam", 871).
?DOC(
" Wait for user choice from inline keyboard.\n"
"\n"
" This function creates an inline keyboard with provided options\n"
" and waits for user to select one.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" use ctx, color <- wait_choice(\n"
" ctx,\n"
" [\n"
" #(\"🔴 Red\", Red),\n"
" #(\"🔵 Blue\", Blue),\n"
" #(\"🟢 Green\", Green),\n"
" ],\n"
" or: None,\n"
" timeout: None,\n"
" )\n"
" ```\n"
"\n"
" See [conversation](/docs/conversation)\n"
).
-spec wait_choice(
telega@bot:context(AJGQ, AJGR),
list({binary(), AJGU}),
gleam@option:option(telega@bot:handler(AJGQ, AJGR)),
gleam@option:option(integer()),
fun((telega@bot:context(AJGQ, AJGR), AJGU) -> {ok,
telega@bot:context(AJGQ, AJGR)} |
{error, AJGR})
) -> {ok, telega@bot:context(AJGQ, AJGR)} | {error, AJGR}.
wait_choice(Ctx, Options, Handle_else, Timeout, Continue) ->
Buttons = begin
_pipe = Options,
gleam@list:index_map(
_pipe,
fun(Opt, Idx) ->
{Label, _} = Opt,
Callback_data = erlang:integer_to_binary(Idx),
{inline_keyboard_button,
Label,
none,
none,
none,
{some, Callback_data},
none,
none,
none,
none,
none,
none,
none,
none}
end
)
end,
Keyboard = {inline_keyboard_markup, [Buttons]},
Send_params = {send_message_parameters,
none,
{int, erlang:element(3, erlang:element(3, Ctx))},
none,
<<""/utf8>>,
none,
none,
none,
none,
none,
none,
none,
none,
{some, {send_message_reply_inline_keyboard_markup_parameters, Keyboard}}},
_ = telega@api:send_message(
erlang:element(5, erlang:element(4, Ctx)),
Send_params
),
wait_callback_query(
Ctx,
none,
Handle_else,
Timeout,
fun(Ctx@1, Data, _) -> case gleam_stdlib:parse_int(Data) of
{ok, Idx@1} ->
case list_at(Options, Idx@1) of
{ok, {_, Value}} ->
Continue(Ctx@1, Value);
{error, _} ->
wait_choice(
Ctx@1,
Options,
Handle_else,
Timeout,
Continue
)
end;
{error, _} ->
wait_choice(Ctx@1, Options, Handle_else, Timeout, Continue)
end end
).
-file("src/telega.gleam", 969).
?DOC(
" Wait for update matching custom filter.\n"
"\n"
" This function waits for any update that passes the provided filter function.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" use ctx, photo_update <- wait_for(\n"
" ctx,\n"
" filter: fn(upd) {\n"
" case upd {\n"
" update.PhotoUpdate(..) -> True\n"
" _ -> False\n"
" }\n"
" },\n"
" or: Some(bot.HandleAll(fn(ctx, wrong_update) {\n"
" reply.with_text(ctx, \"Please send a photo\")\n"
" })),\n"
" timeout: Some(60_000),\n"
" )\n"
" ```\n"
"\n"
" See [conversation](/docs/conversation)\n"
).
-spec wait_for(
telega@bot:context(AJHK, AJHL),
fun((telega@update:update()) -> boolean()),
gleam@option:option(telega@bot:handler(AJHK, AJHL)),
gleam@option:option(integer()),
fun((telega@bot:context(AJHK, AJHL), telega@update:update()) -> {ok,
telega@bot:context(AJHK, AJHL)} |
{error, AJHL})
) -> {ok, telega@bot:context(AJHK, AJHL)} | {error, AJHL}.
wait_for(Ctx, Filter, Handle_else, Timeout, Continue) ->
Filter_handler = {handle_all, fun(Ctx@1, Upd) -> case Filter(Upd) of
true ->
Continue(Ctx@1, Upd);
false ->
wait_for(Ctx@1, Filter, Handle_else, Timeout, Continue)
end end},
telega@bot:wait_handler(Ctx, Filter_handler, Handle_else, Timeout).
-file("src/telega.gleam", 990).
?DOC(
" Start polling with default configuration for a Telega instance.\n"
" This is useful when you want to manually start polling outside the supervision tree.\n"
).
-spec start_polling_default(telega(any(), any())) -> {ok,
telega@polling:poller()} |
{error, telega@error:telega_error()}.
start_polling_default(Telega) ->
telega@polling:start_polling_default(
erlang:element(5, erlang:element(2, Telega)),
erlang:element(4, Telega)
).
-file("src/telega.gleam", 1001).
?DOC(
" Graceful shutdown — stops supervisor, cascading to all children.\n"
" Children are stopped in reverse start order: polling → bot → chat_factory.\n"
).
-spec shutdown(telega(any(), any())) -> nil.
shutdown(Telega) ->
gleam@erlang@process:send_abnormal_exit(
erlang:element(5, Telega),
erlang:binary_to_atom(<<"shutdown"/utf8>>)
).
-file("src/telega.gleam", 1006).
?DOC(" Get the supervisor PID for the running bot instance.\n").
-spec get_supervisor_pid(telega(any(), any())) -> gleam@erlang@process:pid_().
get_supervisor_pid(Telega) ->
erlang:element(5, Telega).