Current section
Files
Jump to
Current section
Files
src/telega@bot.erl
-module(telega@bot).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/telega/bot.gleam").
-export([cancel_conversation/2, next_session/2, get_session/2, handle_update/2, wait_handler/4, start/6]).
-export_type([bot/2, bot_message/0, chat_instance_message/2, continuation/2, chat_instance/2, context/2, session_settings/2, callback_query_filter/0, hears/0, handler/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 bot(AMDC, AMDD) :: {bot,
gleam@erlang@process:subject(bot_message()),
telega@internal@config:config(),
telega@model@types:user(),
fun((context(AMDC, AMDD), AMDD) -> {ok, nil} | {error, AMDD}),
session_settings(AMDC, AMDD),
fun((context(AMDC, AMDD), telega@update:update()) -> {ok,
context(AMDC, AMDD)} |
{error, AMDD}),
telega@internal@registry:registry(chat_instance_message(AMDC, AMDD))}.
-opaque bot_message() :: {cancel_conversation_bot_message, binary()} |
{handle_update_bot_message,
telega@update:update(),
gleam@erlang@process:subject(boolean())}.
-opaque chat_instance_message(AMDE, AMDF) :: {handle_new_chat_instance_message,
telega@update:update(),
gleam@erlang@process:subject(boolean())} |
{wait_handler_chat_instance_message,
handler(AMDE, AMDF),
gleam@option:option(handler(AMDE, AMDF)),
gleam@option:option(integer())}.
-type continuation(AMDG, AMDH) :: {continuation,
handler(AMDG, AMDH),
gleam@option:option(handler(AMDG, AMDH)),
gleam@option:option(gleam@time@timestamp:timestamp())}.
-type chat_instance(AMDI, AMDJ) :: {chat_instance,
binary(),
AMDI,
telega@internal@config:config(),
session_settings(AMDI, AMDJ),
gleam@erlang@process:subject(chat_instance_message(AMDI, AMDJ)),
gleam@option:option(continuation(AMDI, AMDJ)),
fun((context(AMDI, AMDJ), telega@update:update()) -> {ok,
context(AMDI, AMDJ)} |
{error, AMDJ}),
fun((context(AMDI, AMDJ), AMDJ) -> {ok, nil} | {error, AMDJ})}.
-type context(AMDK, AMDL) :: {context,
binary(),
telega@update:update(),
telega@internal@config:config(),
AMDK,
gleam@erlang@process:subject(chat_instance_message(AMDK, AMDL)),
gleam@option:option(gleam@time@timestamp:timestamp()),
gleam@option:option(binary())}.
-type session_settings(AMDM, AMDN) :: {session_settings,
fun((binary(), AMDM) -> {ok, AMDM} | {error, AMDN}),
fun((binary()) -> {ok, gleam@option:option(AMDM)} | {error, AMDN}),
fun(() -> AMDM)}.
-type callback_query_filter() :: {callback_query_filter, gleam@regexp:regexp()}.
-type hears() :: {hear_text, binary()} |
{hear_texts, list(binary())} |
{hear_regex, gleam@regexp:regexp()} |
{hear_regexes, list(gleam@regexp:regexp())}.
-type handler(AMDO, AMDP) :: {handle_all,
fun((context(AMDO, AMDP), telega@update:update()) -> {ok,
context(AMDO, AMDP)} |
{error, AMDP})} |
{handle_command,
binary(),
fun((context(AMDO, AMDP), telega@update:command()) -> {ok,
context(AMDO, AMDP)} |
{error, AMDP})} |
{handle_commands,
list(binary()),
fun((context(AMDO, AMDP), telega@update:command()) -> {ok,
context(AMDO, AMDP)} |
{error, AMDP})} |
{handle_text,
fun((context(AMDO, AMDP), binary()) -> {ok, context(AMDO, AMDP)} |
{error, AMDP})} |
{handle_hears,
hears(),
fun((context(AMDO, AMDP), binary()) -> {ok, context(AMDO, AMDP)} |
{error, AMDP})} |
{handle_message,
fun((context(AMDO, AMDP), telega@model@types:message()) -> {ok,
context(AMDO, AMDP)} |
{error, AMDP})} |
{handle_voice,
fun((context(AMDO, AMDP), telega@model@types:voice()) -> {ok,
context(AMDO, AMDP)} |
{error, AMDP})} |
{handle_audio,
fun((context(AMDO, AMDP), telega@model@types:audio()) -> {ok,
context(AMDO, AMDP)} |
{error, AMDP})} |
{handle_video,
fun((context(AMDO, AMDP), telega@model@types:video()) -> {ok,
context(AMDO, AMDP)} |
{error, AMDP})} |
{handle_photos,
fun((context(AMDO, AMDP), list(telega@model@types:photo_size())) -> {ok,
context(AMDO, AMDP)} |
{error, AMDP})} |
{handle_web_app_data,
fun((context(AMDO, AMDP), telega@model@types:web_app_data()) -> {ok,
context(AMDO, AMDP)} |
{error, AMDP})} |
{handle_callback_query,
callback_query_filter(),
fun((context(AMDO, AMDP), binary(), binary()) -> {ok,
context(AMDO, AMDP)} |
{error, AMDP})} |
{handle_chat_member,
fun((context(AMDO, AMDP), telega@model@types:chat_member_updated()) -> {ok,
context(AMDO, AMDP)} |
{error, AMDP})}.
-file("src/telega/bot.gleam", 88).
?DOC(" Stops waiting for any handler for specific key (chat_id)\n").
-spec cancel_conversation(bot(any(), any()), binary()) -> nil.
cancel_conversation(Bot, Key) ->
gleam@otp@actor:send(
erlang:element(2, Bot),
{cancel_conversation_bot_message, Key}
).
-file("src/telega/bot.gleam", 436).
-spec new_context(chat_instance(AMGU, AMGV), telega@update:update()) -> context(AMGU, AMGV).
new_context(Chat, Update) ->
{context,
erlang:element(2, Chat),
Update,
erlang:element(4, Chat),
erlang:element(3, Chat),
erlang:element(6, Chat),
none,
none}.
-file("src/telega/bot.gleam", 466).
-spec next_session(context(AMHB, AMHC), AMHB) -> {ok, context(AMHB, AMHC)} |
{error, AMHC}.
next_session(Ctx, Session) ->
{ok,
{context,
erlang:element(2, Ctx),
erlang:element(3, Ctx),
erlang:element(4, Ctx),
Session,
erlang:element(6, Ctx),
erlang:element(7, Ctx),
erlang:element(8, Ctx)}}.
-file("src/telega/bot.gleam", 473).
-spec build_session_key(telega@update:update()) -> binary().
build_session_key(Update) ->
<<<<(erlang:integer_to_binary(erlang:element(3, Update)))/binary, ":"/utf8>>/binary,
(erlang:integer_to_binary(erlang:element(2, Update)))/binary>>.
-file("src/telega/bot.gleam", 477).
-spec get_session(session_settings(AMHK, AMHL), telega@update:update()) -> {ok,
gleam@option:option(AMHK)} |
{error, AMHL}.
get_session(Session_settings, Update) ->
_pipe = Update,
_pipe@1 = build_session_key(_pipe),
(erlang:element(3, Session_settings))(_pipe@1).
-file("src/telega/bot.gleam", 488).
?DOC(false).
-spec handle_update(
gleam@erlang@process:subject(bot_message()),
telega@update:update()
) -> boolean().
handle_update(Bot_subject, Update) ->
gleam@erlang@process:call_forever(
Bot_subject,
fun(_capture) -> {handle_update_bot_message, Update, _capture} end
).
-file("src/telega/bot.gleam", 582).
?DOC(
" Pass any handler to start waiting\n"
"\n"
" `or` - calls if there are any other updates\n"
" `timeout` - the conversation will be canceled after this timeout\n"
).
-spec wait_handler(
context(AMHU, AMHV),
handler(AMHU, AMHV),
gleam@option:option(handler(AMHU, AMHV)),
gleam@option:option(integer())
) -> {ok, context(AMHU, AMHV)} | {error, AMHV}.
wait_handler(Ctx, Handler, Handle_else, Timeout) ->
gleam@otp@actor:send(
erlang:element(6, Ctx),
{wait_handler_chat_instance_message, Handler, Handle_else, Timeout}
),
{ok, Ctx}.
-file("src/telega/bot.gleam", 595).
-spec do_handle(
context(AMQW, AMQX),
telega@update:update(),
handler(AMQW, AMQX)
) -> gleam@option:option({ok, context(AMQW, AMQX)} | {error, AMQX}).
do_handle(Context, Update, Handler) ->
case {Handler, Update} of
{{handle_all, Handler@1}, _} ->
_pipe = Context,
_pipe@1 = Handler@1(_pipe, Update),
{some, _pipe@1};
{{handle_text, Handler@2}, {text_update, _, _, Text, _, _}} ->
_pipe@2 = Context,
_pipe@3 = Handler@2(_pipe@2, Text),
{some, _pipe@3};
{{handle_hears, _, Handler@3}, {text_update, _, _, Text@1, _, _}} ->
_pipe@4 = Context,
_pipe@5 = Handler@3(_pipe@4, Text@1),
{some, _pipe@5};
{{handle_command, _, Handler@4},
{command_update, _, _, Update_command, _, _}} ->
_pipe@6 = Context,
_pipe@7 = Handler@4(_pipe@6, Update_command),
{some, _pipe@7};
{{handle_commands, _, Handler@5},
{command_update, _, _, Update_command@1, _, _}} ->
_pipe@8 = Context,
_pipe@9 = Handler@5(_pipe@8, Update_command@1),
{some, _pipe@9};
{{handle_callback_query, _, Handler@6},
{callback_query_update, _, _, Query, _}} ->
gleam@option:map(
erlang:element(7, Query),
fun(Data) ->
Handler@6(Context, Data, erlang:element(2, Query))
end
);
{{handle_message, Handler@7}, {message_update, _, _, Message, _}} ->
_pipe@10 = Context,
_pipe@11 = Handler@7(_pipe@10, Message),
{some, _pipe@11};
{{handle_chat_member, Handler@8},
{chat_member_update, _, _, Chat_member_updated, _}} ->
_pipe@12 = Context,
_pipe@13 = Handler@8(_pipe@12, Chat_member_updated),
{some, _pipe@13};
{{handle_voice, Handler@9}, {voice_update, _, _, Voice, _, _}} ->
_pipe@14 = Context,
_pipe@15 = Handler@9(_pipe@14, Voice),
{some, _pipe@15};
{{handle_audio, Handler@10}, {audio_update, _, _, Audio, _, _}} ->
_pipe@16 = Context,
_pipe@17 = Handler@10(_pipe@16, Audio),
{some, _pipe@17};
{{handle_video, Handler@11}, {video_update, _, _, Video, _, _}} ->
_pipe@18 = Context,
_pipe@19 = Handler@11(_pipe@18, Video),
{some, _pipe@19};
{{handle_web_app_data, Handler@12},
{web_app_update, _, _, Web_app_data, _, _}} ->
_pipe@20 = Context,
_pipe@21 = Handler@12(_pipe@20, Web_app_data),
{some, _pipe@21};
{_, _} ->
none
end.
-file("src/telega/bot.gleam", 317).
-spec do_handle_continuation(
context(AMGK, AMGL),
continuation(AMGK, AMGL),
telega@update:update(),
gleam@erlang@process:subject(boolean()),
chat_instance(AMGK, AMGL)
) -> gleam@otp@actor:next(chat_instance(AMGK, AMGL), any()).
do_handle_continuation(Context, Continuation, Update, Reply_with, Chat) ->
case do_handle(Context, Update, erlang:element(2, Continuation)) of
{some, {ok, {context, _, _, _, New_session, _, _, _}}} ->
case (erlang:element(2, erlang:element(5, Chat)))(
erlang:element(2, Chat),
New_session
) of
{ok, Persisted_session} ->
gleam@otp@actor:send(Reply_with, true),
gleam@otp@actor:continue(
{chat_instance,
erlang:element(2, Chat),
Persisted_session,
erlang:element(4, Chat),
erlang:element(5, Chat),
erlang:element(6, Chat),
none,
erlang:element(8, Chat),
erlang:element(9, Chat)}
);
{error, E} ->
case (erlang:element(9, Chat))(Context, E) of
{ok, _} ->
gleam@otp@actor:send(Reply_with, false),
gleam@otp@actor:continue(Chat);
{error, E@1} ->
telega@internal@log:error_d(
<<"Error in session persistence after continuation: "/utf8>>,
E@1
),
gleam@otp@actor:stop()
end
end;
{some, {error, E@2}} ->
case (erlang:element(9, Chat))(Context, E@2) of
{ok, _} ->
gleam@otp@actor:send(Reply_with, false),
gleam@otp@actor:continue(Chat);
{error, E@3} ->
telega@internal@log:error_d(
<<"Error in catch handler: "/utf8>>,
E@3
),
gleam@otp@actor:stop()
end;
none ->
case erlang:element(3, Continuation) of
{some, Handler} ->
case do_handle(Context, Update, Handler) of
{some, {ok, {context, _, _, _, New_session@1, _, _, _}}} ->
case (erlang:element(2, erlang:element(5, Chat)))(
erlang:element(2, Chat),
New_session@1
) of
{ok, Persisted_session@1} ->
gleam@otp@actor:send(Reply_with, true),
gleam@otp@actor:continue(
{chat_instance,
erlang:element(2, Chat),
Persisted_session@1,
erlang:element(4, Chat),
erlang:element(5, Chat),
erlang:element(6, Chat),
erlang:element(7, Chat),
erlang:element(8, Chat),
erlang:element(9, Chat)}
);
{error, E@4} ->
case (erlang:element(9, Chat))(Context, E@4) of
{ok, _} ->
gleam@otp@actor:send(
Reply_with,
false
),
gleam@otp@actor:continue(Chat);
{error, E@5} ->
telega@internal@log:error_d(
<<"Error in session persistence after handle_else: "/utf8>>,
E@5
),
gleam@otp@actor:stop()
end
end;
{some, {error, E@6}} ->
case (erlang:element(9, Chat))(Context, E@6) of
{ok, _} ->
gleam@otp@actor:send(Reply_with, false),
gleam@otp@actor:continue(Chat);
{error, E@7} ->
telega@internal@log:error_d(
<<"Error in catch else handler: "/utf8>>,
E@7
),
gleam@otp@actor:stop()
end;
none ->
gleam@otp@actor:send(Reply_with, false),
gleam@otp@actor:continue(Chat)
end;
none ->
gleam@otp@actor:send(Reply_with, false),
gleam@otp@actor:continue(Chat)
end
end.
-file("src/telega/bot.gleam", 240).
-spec do_handle_new_chat_instance_message(
context(AMGB, AMGC),
chat_instance(AMGB, AMGC),
telega@update:update(),
gleam@erlang@process:subject(boolean())
) -> gleam@otp@actor:next(chat_instance(AMGB, AMGC), any()).
do_handle_new_chat_instance_message(Context, Chat, Update, Reply_with) ->
case erlang:element(7, Chat) of
{some, Continuation} ->
case erlang:element(4, Continuation) of
{some, Ttl} ->
case gleam@time@timestamp:compare(
Ttl,
gleam@time@timestamp:system_time()
) of
lt ->
do_handle_new_chat_instance_message(
Context,
{chat_instance,
erlang:element(2, Chat),
erlang:element(3, Chat),
erlang:element(4, Chat),
erlang:element(5, Chat),
erlang:element(6, Chat),
none,
erlang:element(8, Chat),
erlang:element(9, Chat)},
Update,
Reply_with
);
_ ->
do_handle_continuation(
Context,
Continuation,
Update,
Reply_with,
Chat
)
end;
none ->
do_handle_continuation(
Context,
Continuation,
Update,
Reply_with,
Chat
)
end;
none ->
case (erlang:element(8, Chat))(Context, Update) of
{ok, {context, _, _, _, New_session, _, _, _}} ->
case (erlang:element(2, erlang:element(5, Chat)))(
erlang:element(2, Chat),
New_session
) of
{ok, Persisted_session} ->
gleam@otp@actor:send(Reply_with, true),
gleam@otp@actor:continue(
{chat_instance,
erlang:element(2, Chat),
Persisted_session,
erlang:element(4, Chat),
erlang:element(5, Chat),
erlang:element(6, Chat),
erlang:element(7, Chat),
erlang:element(8, Chat),
erlang:element(9, Chat)}
);
{error, E} ->
case (erlang:element(9, Chat))(Context, E) of
{ok, _} ->
gleam@otp@actor:send(Reply_with, false),
gleam@otp@actor:continue(Chat);
{error, E@1} ->
telega@internal@log:error_d(
<<"Error in session persistence: "/utf8>>,
E@1
),
gleam@otp@actor:stop()
end
end;
{error, E@2} ->
case (erlang:element(9, Chat))(Context, E@2) of
{ok, _} ->
gleam@otp@actor:send(Reply_with, false),
gleam@otp@actor:continue(Chat);
{error, E@3} ->
telega@internal@log:error_d(
<<"Error in catch handler: "/utf8>>,
E@3
),
gleam@otp@actor:stop()
end
end
end.
-file("src/telega/bot.gleam", 217).
-spec loop_chat_instance(
chat_instance(AMFV, AMFW),
chat_instance_message(AMFV, AMFW)
) -> gleam@otp@actor:next(chat_instance(AMFV, AMFW), any()).
loop_chat_instance(Chat, Message) ->
case Message of
{handle_new_chat_instance_message, Update, Reply_with} ->
do_handle_new_chat_instance_message(
new_context(Chat, Update),
Chat,
Update,
Reply_with
);
{wait_handler_chat_instance_message, Handler, Handle_else, Timeout} ->
_pipe@2 = {chat_instance,
erlang:element(2, Chat),
erlang:element(3, Chat),
erlang:element(4, Chat),
erlang:element(5, Chat),
erlang:element(6, Chat),
begin
_pipe@1 = {continuation,
Handler,
Handle_else,
begin
gleam@option:map(
Timeout,
fun(Timeout@1) ->
_pipe = gleam@time@timestamp:system_time(),
gleam@time@timestamp:add(
_pipe,
gleam@time@duration:seconds(Timeout@1)
)
end
)
end},
{some, _pipe@1}
end,
erlang:element(8, Chat),
erlang:element(9, Chat)},
gleam@otp@actor:continue(_pipe@2)
end.
-file("src/telega/bot.gleam", 178).
-spec start_chat_instance(
binary(),
telega@internal@config:config(),
session_settings(AMFM, AMFN),
fun((context(AMFM, AMFN), AMFN) -> {ok, nil} | {error, AMFN}),
fun((context(AMFM, AMFN), telega@update:update()) -> {ok,
context(AMFM, AMFN)} |
{error, AMFN})
) -> {ok, gleam@erlang@process:subject(chat_instance_message(AMFM, AMFN))} |
{error, telega@error:telega_error()}.
start_chat_instance(
Key,
Config,
Session_settings,
Catch_handler,
Router_handler
) ->
Session@1 = case (erlang:element(3, Session_settings))(Key) of
{ok, {some, Session}} ->
Session;
{ok, none} ->
(erlang:element(4, Session_settings))();
{error, Error} ->
erlang:error(#{gleam_error => panic,
message => (<<"Failed to get session: "/utf8,
(gleam@string:inspect(Error))/binary>>),
file => <<?FILEPATH/utf8>>,
module => <<"telega/bot"/utf8>>,
function => <<"start_chat_instance"/utf8>>,
line => 189})
end,
gleam@result:'try'(
begin
_pipe@2 = gleam@otp@actor:new_with_initialiser(
10,
fun(Subject) ->
Chat_instance = {chat_instance,
Key,
Session@1,
Config,
Session_settings,
Subject,
none,
Router_handler,
Catch_handler},
_pipe = gleam@otp@actor:initialised(Chat_instance),
_pipe@1 = gleam@otp@actor:returning(_pipe, Subject),
{ok, _pipe@1}
end
),
_pipe@3 = gleam@otp@actor:on_message(
_pipe@2,
fun loop_chat_instance/2
),
_pipe@4 = gleam@otp@actor:start(_pipe@3),
gleam@result:map_error(
_pipe@4,
fun(Field@0) -> {chat_instance_start_error, Field@0} end
)
end,
fun(Started) -> {ok, erlang:element(3, Started)} end
).
-file("src/telega/bot.gleam", 110).
-spec handle_update_bot_message(
bot(any(), any()),
telega@update:update(),
gleam@erlang@process:subject(boolean())
) -> {ok, nil} | {error, telega@error:telega_error()}.
handle_update_bot_message(Bot, Update, Reply_with) ->
Key = build_session_key(Update),
case telega@internal@registry:get(erlang:element(8, Bot), Key) of
{some, Chat_subject} ->
_pipe = gleam@otp@actor:send(
Chat_subject,
{handle_new_chat_instance_message, Update, Reply_with}
),
{ok, _pipe};
none ->
gleam@result:'try'(
start_chat_instance(
Key,
erlang:element(3, Bot),
erlang:element(6, Bot),
erlang:element(5, Bot),
erlang:element(7, Bot)
),
fun(Subject) ->
telega@internal@registry:register(
erlang:element(8, Bot),
Key,
Subject
),
_pipe@1 = gleam@otp@actor:send(
Subject,
{handle_new_chat_instance_message, Update, Reply_with}
),
{ok, _pipe@1}
end
)
end.
-file("src/telega/bot.gleam", 92).
-spec bot_loop(bot(ANFS, ANFT), bot_message()) -> gleam@otp@actor:next(bot(ANFS, ANFT), any()).
bot_loop(Bot, Message) ->
case Message of
{handle_update_bot_message, Update, Reply_with} ->
case handle_update_bot_message(Bot, Update, Reply_with) of
{ok, _} ->
gleam@otp@actor:continue(Bot);
{error, Error} ->
telega@internal@log:error_d(
<<"Error in handler: "/utf8>>,
Error
),
gleam@otp@actor:stop()
end;
{cancel_conversation_bot_message, Key} ->
telega@internal@registry:unregister(erlang:element(8, Bot), Key),
gleam@otp@actor:continue(Bot)
end.
-file("src/telega/bot.gleam", 60).
-spec start(
telega@internal@registry:registry(chat_instance_message(AMEK, AMEL)),
telega@internal@config:config(),
telega@model@types:user(),
fun((context(AMEK, AMEL), telega@update:update()) -> {ok,
context(AMEK, AMEL)} |
{error, AMEL}),
session_settings(AMEK, AMEL),
fun((context(AMEK, AMEL), AMEL) -> {ok, nil} | {error, AMEL})
) -> {ok, gleam@erlang@process:subject(bot_message())} |
{error, telega@error:telega_error()}.
start(
Registry,
Config,
Bot_info,
Router_handler,
Session_settings,
Catch_handler
) ->
Self = gleam@erlang@process:new_subject(),
Bot = {bot,
Self,
Config,
Bot_info,
Catch_handler,
Session_settings,
Router_handler,
Registry},
_pipe = gleam@otp@actor:new(Bot),
_pipe@1 = gleam@otp@actor:on_message(_pipe, fun bot_loop/2),
_pipe@2 = gleam@otp@actor:start(_pipe@1),
_pipe@3 = gleam@result:map(
_pipe@2,
fun(Started) -> erlang:element(3, Started) end
),
gleam@result:map_error(
_pipe@3,
fun(Field@0) -> {bot_start_error, Field@0} end
).