-module(telega@bot). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([cancel_conversation/2, wait_handler/2, next_session/2, get_session/2, update_to_string/1, handle_update/2, start/6]). -export_type([bot/2, bot_message/0, chat_instance_message/2, chat_instance/2, context/2, handler/2, callback_query_filter/0, hears/0, session_settings/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(ANYE, ANYF) :: {bot, gleam@erlang@process:subject(bot_message()), telega@internal@config:config(), telega@model:user(), fun((context(ANYE, ANYF), ANYF) -> {ok, nil} | {error, ANYF}), session_settings(ANYE, ANYF), list(handler(ANYE, ANYF)), gleam@erlang@process:subject(telega@internal@registry:registry_message(chat_instance_message(ANYE, ANYF)))}. -opaque bot_message() :: {cancel_conversation_bot_message, binary()} | {handle_update_bot_message, telega@update:update(), gleam@erlang@process:subject(boolean())}. -opaque chat_instance_message(ANYG, ANYH) :: {handle_new_chat_instance_message, telega@update:update(), list(handler(ANYG, ANYH)), gleam@erlang@process:subject(boolean())} | {wait_handler_chat_instance_message, handler(ANYG, ANYH)}. -type chat_instance(ANYI, ANYJ) :: {chat_instance, binary(), ANYI, telega@internal@config:config(), fun((context(ANYI, ANYJ), ANYJ) -> {ok, nil} | {error, ANYJ}), session_settings(ANYI, ANYJ), gleam@erlang@process:subject(chat_instance_message(ANYI, ANYJ)), gleam@option:option(handler(ANYI, ANYJ))}. -type context(ANYK, ANYL) :: {context, binary(), telega@update:update(), telega@internal@config:config(), ANYK, gleam@erlang@process:subject(chat_instance_message(ANYK, ANYL))}. -type handler(ANYM, ANYN) :: {handle_all, fun((context(ANYM, ANYN)) -> {ok, context(ANYM, ANYN)} | {error, ANYN})} | {handle_command, binary(), fun((context(ANYM, ANYN), telega@update:command()) -> {ok, context(ANYM, ANYN)} | {error, ANYN})} | {handle_commands, list(binary()), fun((context(ANYM, ANYN), telega@update:command()) -> {ok, context(ANYM, ANYN)} | {error, ANYN})} | {handle_text, fun((context(ANYM, ANYN), binary()) -> {ok, context(ANYM, ANYN)} | {error, ANYN})} | {handle_hears, hears(), fun((context(ANYM, ANYN), binary()) -> {ok, context(ANYM, ANYN)} | {error, ANYN})} | {handle_callback_query, callback_query_filter(), fun((context(ANYM, ANYN), binary(), binary()) -> {ok, context(ANYM, ANYN)} | {error, ANYN})}. -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 session_settings(ANYO, ANYP) :: {session_settings, fun((binary(), ANYO) -> {ok, ANYO} | {error, ANYP}), fun((binary()) -> {ok, gleam@option:option(ANYO)} | {error, ANYP}), fun(() -> ANYO)}. -file("src/telega/bot.gleam", 85). ?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", 212). -spec handle_update_chat_instance( gleam@erlang@process:subject(chat_instance_message(AOAI, AOAJ)), telega@update:update(), list(handler(AOAI, AOAJ)), gleam@erlang@process:subject(boolean()) ) -> {ok, nil} | {error, any()}. handle_update_chat_instance(Chat_subject, Update, Handlers, Reply_with) -> _pipe = gleam@otp@actor:send( Chat_subject, {handle_new_chat_instance_message, Update, Handlers, Reply_with} ), {ok, _pipe}. -file("src/telega/bot.gleam", 304). -spec new_context(chat_instance(AOAV, AOAW), telega@update:update()) -> context(AOAV, AOAW). new_context(Chat, Update) -> {context, erlang:element(2, Chat), Update, erlang:element(4, Chat), erlang:element(3, Chat), erlang:element(7, Chat)}. -file("src/telega/bot.gleam", 382). -spec wait_handler(context(AOBF, AOBG), handler(AOBF, AOBG)) -> {ok, context(AOBF, AOBG)} | {error, any()}. wait_handler(Ctx, Handler) -> gleam@erlang@process:send( erlang:element(6, Ctx), {wait_handler_chat_instance_message, Handler} ), {ok, Ctx}. -file("src/telega/bot.gleam", 387). -spec do_handle( context(AOKZ, AOLA), telega@update:update(), handler(AOKZ, AOLA) ) -> gleam@option:option({ok, context(AOKZ, AOLA)} | {error, AOLA}). do_handle(Context, Update, Handler) -> case {Handler, Update} of {{handle_all, Handler@1}, _} -> _pipe = Context, _pipe@1 = Handler@1(_pipe), {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 ); {_, _} -> none end. -file("src/telega/bot.gleam", 407). -spec loop_handlers( chat_instance(AOBP, AOBQ), context(AOLN, AOBQ), any(), telega@update:update(), list(handler(AOLN, AOBQ)) ) -> {ok, AOBP} | {error, AOBQ}. loop_handlers(Chat, Context, Config, Update, Handlers) -> case Handlers of [Handler | Rest] -> case do_handle(Context, Update, Handler) of {some, {ok, {context, _, _, _, New_session, _}}} -> loop_handlers( Chat, begin _record = Context, {context, erlang:element(2, _record), erlang:element(3, _record), erlang:element(4, _record), New_session, erlang:element(6, _record)} end, Config, Update, Rest ); {some, {error, E}} -> {error, E}; none -> loop_handlers(Chat, Context, Config, Update, Rest) end; [] -> (erlang:element(2, erlang:element(6, Chat)))( erlang:element(2, Chat), erlang:element(3, Chat) ) end. -file("src/telega/bot.gleam", 225). -spec loop_chat_instance( chat_instance_message(AOAQ, AOAR), chat_instance(AOAQ, AOAR) ) -> gleam@otp@actor:next(any(), chat_instance(AOAQ, AOAR)). loop_chat_instance(Message, Chat) -> case Message of {handle_new_chat_instance_message, Update, Handlers, Reply_with} -> Context = new_context(Chat, Update), case erlang:element(8, Chat) of none -> case loop_handlers( Chat, Context, erlang:element(4, Chat), Update, Handlers ) of {ok, New_session} -> gleam@otp@actor:send(Reply_with, true), gleam@otp@actor:continue( begin _record = Chat, {chat_instance, erlang:element(2, _record), New_session, erlang:element(4, _record), erlang:element(5, _record), erlang:element(6, _record), erlang:element(7, _record), erlang:element(8, _record)} end ); {error, E} -> case (erlang:element(5, 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 catch handler: "/utf8>>, E@1 ), {stop, normal} end end; {some, Handler} -> case do_handle(Context, Update, Handler) of {some, {ok, {context, _, _, _, New_session@1, _}}} -> gleam@otp@actor:send(Reply_with, true), gleam@otp@actor:continue( begin _record@1 = Chat, {chat_instance, erlang:element(2, _record@1), New_session@1, erlang:element(4, _record@1), erlang:element(5, _record@1), erlang:element(6, _record@1), erlang:element(7, _record@1), none} end ); {some, {error, E@2}} -> case (erlang:element(5, 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 ), {stop, normal} end; none -> gleam@otp@actor:send(Reply_with, true), gleam@otp@actor:continue(Chat) end end; {wait_handler_chat_instance_message, Handler@1} -> gleam@otp@actor:continue( begin _record@2 = Chat, {chat_instance, erlang:element(2, _record@2), erlang:element(3, _record@2), erlang:element(4, _record@2), erlang:element(5, _record@2), erlang:element(6, _record@2), erlang:element(7, _record@2), {some, Handler@1}} end ) end. -file("src/telega/bot.gleam", 445). -spec check_hears(binary(), hears()) -> boolean(). check_hears(Text, Hear) -> case Hear of {hear_text, Str} -> Text =:= Str; {hear_texts, Strings} -> gleam@list:contains(Strings, Text); {hear_regex, Re} -> gleam@regexp:check(Re, Text); {hear_regexes, Regexes} -> gleam@list:any( Regexes, fun(_capture) -> gleam@regexp:check(_capture, Text) end ) end. -file("src/telega/bot.gleam", 356). -spec extract_update_handlers(list(handler(AORU, AORV)), telega@update:update()) -> list(handler(AORU, AORV)). extract_update_handlers(Handlers, Update) -> gleam@list:filter(Handlers, fun(Handler) -> case {Handler, Update} of {{handle_all, _}, _} -> true; {{handle_text, _}, {text_update, _, _, _, _, _}} -> true; {{handle_hears, Hears, _}, {text_update, _, _, Text, _, _}} -> check_hears(Text, Hears); {{handle_command, Command, _}, {command_update, _, _, Update_command, _, _}} -> erlang:element(3, Update_command) =:= Command; {{handle_callback_query, Filter, _}, {callback_query_update, _, _, Query, _}} -> case erlang:element(7, Query) of {some, Data} -> gleam@regexp:check(erlang:element(2, Filter), Data); none -> false end; {_, _} -> false end end). -file("src/telega/bot.gleam", 469). -spec next_session(context(AOSD, AOSE), AOSD) -> {ok, context(AOSD, AOSE)} | {error, any()}. next_session(Ctx, Session) -> {ok, begin _record = Ctx, {context, erlang:element(2, _record), erlang:element(3, _record), erlang:element(4, _record), Session, erlang:element(6, _record)} end}. -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(AOCE, AOCF), telega@update:update()) -> {ok, gleam@option:option(AOCE)} | {error, AOCF}. 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). -spec update_to_string(telega@update:update()) -> binary(). update_to_string(Update) -> case Update of {command_update, _, Chat_id, Command, _, _} -> <<<<<<"command \""/utf8, (erlang:element(3, Command))/binary>>/binary, "\" from "/utf8>>/binary, (erlang:integer_to_binary(Chat_id))/binary>>; {text_update, _, Chat_id@1, Text, _, _} -> <<<<<<"text \""/utf8, Text/binary>>/binary, "\" from "/utf8>>/binary, (erlang:integer_to_binary(Chat_id@1))/binary>>; {callback_query_update, From_id, _, Query, _} -> <<<<<<"callback query "/utf8, (gleam@option:unwrap( erlang:element(7, Query), <<"no data"/utf8>> ))/binary>>/binary, " from "/utf8>>/binary, (erlang:integer_to_binary(From_id))/binary>> end. -file("src/telega/bot.gleam", 504). ?DOC(false). -spec handle_update( gleam@erlang@process:subject(bot_message()), telega@update:update() ) -> {ok, boolean()} | {error, gleam@erlang@process:call_error(any())}. handle_update(Bot_subject, Update) -> gleam@erlang@process:try_call_forever( Bot_subject, fun(_capture) -> {handle_update_bot_message, Update, _capture} end ). -file("src/telega/bot.gleam", 172). -spec start_chat_instance( binary(), telega@internal@config:config(), session_settings(ANZZ, AOAA), fun((context(ANZZ, AOAA), AOAA) -> {ok, nil} | {error, AOAA}) ) -> {ok, gleam@erlang@process:subject(chat_instance_message(ANZZ, AOAA))} | {error, telega@error:telega_error()}. start_chat_instance(Key, Config, Session_settings, Catch_handler) -> _pipe@1 = gleam@otp@actor:start_spec( {spec, fun() -> Self = gleam@erlang@process:new_subject(), Selector = begin _pipe = gleam_erlang_ffi:new_selector(), gleam@erlang@process:selecting( _pipe, Self, fun gleam@function:identity/1 ) end, 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>>), module => <<"telega/bot"/utf8>>, function => <<"start_chat_instance"/utf8>>, line => 188}) end, Chat_instance = {chat_instance, Key, Session@1, Config, Catch_handler, Session_settings, Self, none}, {ready, Chat_instance, Selector} end, 250, fun loop_chat_instance/2} ), gleam@result:map_error( _pipe@1, fun(Error@1) -> {chat_instance_start_error, gleam@string:inspect(Error@1)} end ). -file("src/telega/bot.gleam", 107). -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} -> Handlers = extract_update_handlers(erlang:element(7, Bot), Update), handle_update_chat_instance( Chat_subject, Update, Handlers, Reply_with ); none -> gleam@result:'try'( start_chat_instance( Key, erlang:element(3, Bot), erlang:element(6, Bot), erlang:element(5, Bot) ), fun(Chat_subject@1) -> telega@internal@registry:register( erlang:element(8, Bot), Key, Chat_subject@1 ), Handlers@1 = extract_update_handlers( erlang:element(7, Bot), Update ), handle_update_chat_instance( Chat_subject@1, Update, Handlers@1, Reply_with ) end ) end. -file("src/telega/bot.gleam", 89). -spec bot_loop(bot_message(), bot(AOVT, AOVU)) -> gleam@otp@actor:next(any(), bot(AOVT, AOVU)). bot_loop(Message, Bot) -> 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 ), {stop, normal} 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", 52). -spec start( gleam@erlang@process:subject(telega@internal@registry:registry_message(chat_instance_message(AOWW, AOWX))), telega@internal@config:config(), telega@model:user(), list(handler(AOWW, AOWX)), session_settings(AOWW, AOWX), fun((context(AOWW, AOWX), AOWX) -> {ok, nil} | {error, AOWX}) ) -> {ok, gleam@erlang@process:subject(bot_message())} | {error, telega@error:telega_error()}. start( Registry_subject, Config, Bot_info, Handlers, Session_settings, Catch_handler ) -> _pipe@1 = gleam@otp@actor:start_spec( {spec, fun() -> Self = gleam@erlang@process:new_subject(), Selector = begin _pipe = gleam_erlang_ffi:new_selector(), gleam@erlang@process:selecting( _pipe, Self, fun gleam@function:identity/1 ) end, Bot = {bot, Self, Config, Bot_info, Catch_handler, Session_settings, Handlers, Registry_subject}, {ready, Bot, Selector} end, 500, fun bot_loop/2} ), gleam@result:map_error( _pipe@1, fun(Err) -> {bot_start_error, gleam@string:inspect(Err)} end ).