Current section

Files

Jump to
telega src telega@bot.erl
Raw

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(AMMK, AMML) :: {bot,
gleam@erlang@process:subject(bot_message()),
telega@internal@config:config(),
telega@model@types:user(),
fun((context(AMMK, AMML), AMML) -> {ok, nil} | {error, AMML}),
session_settings(AMMK, AMML),
fun((context(AMMK, AMML), telega@update:update()) -> {ok,
context(AMMK, AMML)} |
{error, AMML}),
telega@internal@registry:registry(chat_instance_message(AMMK, AMML))}.
-opaque bot_message() :: {cancel_conversation_bot_message, binary()} |
{handle_update_bot_message,
telega@update:update(),
gleam@erlang@process:subject(boolean())}.
-opaque chat_instance_message(AMMM, AMMN) :: {handle_new_chat_instance_message,
telega@update:update(),
gleam@erlang@process:subject(boolean())} |
{wait_handler_chat_instance_message,
handler(AMMM, AMMN),
gleam@option:option(handler(AMMM, AMMN)),
gleam@option:option(integer())}.
-type continuation(AMMO, AMMP) :: {continuation,
handler(AMMO, AMMP),
gleam@option:option(handler(AMMO, AMMP)),
gleam@option:option(gleam@time@timestamp:timestamp())}.
-type chat_instance(AMMQ, AMMR) :: {chat_instance,
binary(),
AMMQ,
telega@internal@config:config(),
session_settings(AMMQ, AMMR),
gleam@erlang@process:subject(chat_instance_message(AMMQ, AMMR)),
gleam@option:option(continuation(AMMQ, AMMR)),
fun((context(AMMQ, AMMR), telega@update:update()) -> {ok,
context(AMMQ, AMMR)} |
{error, AMMR}),
fun((context(AMMQ, AMMR), AMMR) -> {ok, nil} | {error, AMMR}),
telega@model@types:user()}.
-type context(AMMS, AMMT) :: {context,
binary(),
telega@update:update(),
telega@internal@config:config(),
AMMS,
gleam@erlang@process:subject(chat_instance_message(AMMS, AMMT)),
gleam@option:option(gleam@time@timestamp:timestamp()),
gleam@option:option(binary()),
telega@model@types:user()}.
-type session_settings(AMMU, AMMV) :: {session_settings,
fun((binary(), AMMU) -> {ok, AMMU} | {error, AMMV}),
fun((binary()) -> {ok, gleam@option:option(AMMU)} | {error, AMMV}),
fun(() -> AMMU)}.
-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(AMMW, AMMX) :: {handle_all,
fun((context(AMMW, AMMX), telega@update:update()) -> {ok,
context(AMMW, AMMX)} |
{error, AMMX})} |
{handle_command,
binary(),
fun((context(AMMW, AMMX), telega@update:command()) -> {ok,
context(AMMW, AMMX)} |
{error, AMMX})} |
{handle_commands,
list(binary()),
fun((context(AMMW, AMMX), telega@update:command()) -> {ok,
context(AMMW, AMMX)} |
{error, AMMX})} |
{handle_text,
fun((context(AMMW, AMMX), binary()) -> {ok, context(AMMW, AMMX)} |
{error, AMMX})} |
{handle_hears,
hears(),
fun((context(AMMW, AMMX), binary()) -> {ok, context(AMMW, AMMX)} |
{error, AMMX})} |
{handle_message,
fun((context(AMMW, AMMX), telega@model@types:message()) -> {ok,
context(AMMW, AMMX)} |
{error, AMMX})} |
{handle_voice,
fun((context(AMMW, AMMX), telega@model@types:voice()) -> {ok,
context(AMMW, AMMX)} |
{error, AMMX})} |
{handle_audio,
fun((context(AMMW, AMMX), telega@model@types:audio()) -> {ok,
context(AMMW, AMMX)} |
{error, AMMX})} |
{handle_video,
fun((context(AMMW, AMMX), telega@model@types:video()) -> {ok,
context(AMMW, AMMX)} |
{error, AMMX})} |
{handle_photos,
fun((context(AMMW, AMMX), list(telega@model@types:photo_size())) -> {ok,
context(AMMW, AMMX)} |
{error, AMMX})} |
{handle_web_app_data,
fun((context(AMMW, AMMX), telega@model@types:web_app_data()) -> {ok,
context(AMMW, AMMX)} |
{error, AMMX})} |
{handle_callback_query,
callback_query_filter(),
fun((context(AMMW, AMMX), binary(), binary()) -> {ok,
context(AMMW, AMMX)} |
{error, AMMX})} |
{handle_chat_member,
fun((context(AMMW, AMMX), telega@model@types:chat_member_updated()) -> {ok,
context(AMMW, AMMX)} |
{error, AMMX})}.
-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", 441).
-spec new_context(chat_instance(AMQC, AMQD), telega@update:update()) -> context(AMQC, AMQD).
new_context(Chat, Update) ->
{context,
erlang:element(2, Chat),
Update,
erlang:element(4, Chat),
erlang:element(3, Chat),
erlang:element(6, Chat),
none,
none,
erlang:element(10, Chat)}.
-file("src/telega/bot.gleam", 472).
-spec next_session(context(AMQJ, AMQK), AMQJ) -> {ok, context(AMQJ, AMQK)} |
{error, AMQK}.
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),
erlang:element(9, Ctx)}}.
-file("src/telega/bot.gleam", 479).
-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", 483).
-spec get_session(session_settings(AMQS, AMQT), telega@update:update()) -> {ok,
gleam@option:option(AMQS)} |
{error, AMQT}.
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", 494).
?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", 588).
?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(AMRC, AMRD),
handler(AMRC, AMRD),
gleam@option:option(handler(AMRC, AMRD)),
gleam@option:option(integer())
) -> {ok, context(AMRC, AMRD)} | {error, AMRD}.
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", 601).
-spec do_handle(
context(ANAI, ANAJ),
telega@update:update(),
handler(ANAI, ANAJ)
) -> gleam@option:option({ok, context(ANAI, ANAJ)} | {error, ANAJ}).
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", 321).
-spec do_handle_continuation(
context(AMPS, AMPT),
continuation(AMPS, AMPT),
telega@update:update(),
gleam@erlang@process:subject(boolean()),
chat_instance(AMPS, AMPT)
) -> gleam@otp@actor:next(chat_instance(AMPS, AMPT), 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),
erlang:element(10, 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),
erlang:element(10, 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", 244).
-spec do_handle_new_chat_instance_message(
context(AMPJ, AMPK),
chat_instance(AMPJ, AMPK),
telega@update:update(),
gleam@erlang@process:subject(boolean())
) -> gleam@otp@actor:next(chat_instance(AMPJ, AMPK), 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),
erlang:element(10, 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),
erlang:element(10, 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", 221).
-spec loop_chat_instance(
chat_instance(AMPD, AMPE),
chat_instance_message(AMPD, AMPE)
) -> gleam@otp@actor:next(chat_instance(AMPD, AMPE), 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),
erlang:element(10, Chat)},
gleam@otp@actor:continue(_pipe@2)
end.
-file("src/telega/bot.gleam", 180).
-spec start_chat_instance(
binary(),
telega@internal@config:config(),
session_settings(AMOU, AMOV),
fun((context(AMOU, AMOV), AMOV) -> {ok, nil} | {error, AMOV}),
fun((context(AMOU, AMOV), telega@update:update()) -> {ok,
context(AMOU, AMOV)} |
{error, AMOV}),
telega@model@types:user()
) -> {ok, gleam@erlang@process:subject(chat_instance_message(AMOU, AMOV))} |
{error, telega@error:telega_error()}.
start_chat_instance(
Key,
Config,
Session_settings,
Catch_handler,
Router_handler,
Bot_info
) ->
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 => 192})
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,
Bot_info},
_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),
erlang:element(4, 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(ANPQ, ANPR), bot_message()) -> gleam@otp@actor:next(bot(ANPQ, ANPR), 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(AMNS, AMNT)),
telega@internal@config:config(),
telega@model@types:user(),
fun((context(AMNS, AMNT), telega@update:update()) -> {ok,
context(AMNS, AMNT)} |
{error, AMNT}),
session_settings(AMNS, AMNT),
fun((context(AMNS, AMNT), AMNT) -> {ok, nil} | {error, AMNT})
) -> {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
).