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]).
-export([set_webhook/1, wait_handler/2, start_registry/5]).
-export_type([registry/1, registry_message/0, session_settings/1, context/1, bot_instance_message/1, bot_instance/1, hears/0, handler/1, callback_query_filter/0]).
-type registry(VSL) :: {registry,
gleam@dict:dict(binary(), gleam@erlang@process:subject(bot_instance_message(VSL))),
telega@internal@config:config(),
telega@model:user(),
session_settings(VSL),
list(handler(VSL)),
gleam@erlang@process:subject(registry_message()),
gleam@erlang@process:subject(gleam@erlang@process:subject(bot_instance_message(VSL)))}.
-type registry_message() :: {handle_bot_registry_message,
telega@update:update()}.
-type session_settings(VSM) :: {session_settings,
fun((binary(), VSM) -> {ok, VSM} | {error, binary()}),
fun((binary()) -> {ok, VSM} | {error, binary()})}.
-type context(VSN) :: {context,
binary(),
telega@update:update(),
telega@model:user(),
telega@internal@config:config(),
VSN,
gleam@erlang@process:subject(bot_instance_message(VSN))}.
-type bot_instance_message(VSO) :: bot_instance_message_ok |
{bot_instance_message_new,
gleam@erlang@process:subject(bot_instance_message(VSO)),
telega@update:update()} |
{bot_instance_message_wait_handler, handler(VSO)}.
-type bot_instance(VSP) :: {bot_instance,
binary(),
VSP,
telega@internal@config:config(),
list(handler(VSP)),
telega@model:user(),
session_settings(VSP),
gleam@option:option(handler(VSP)),
gleam@erlang@process:subject(bot_instance_message(VSP))}.
-type hears() :: {hear_text, binary()} |
{hear_texts, list(binary())} |
{hear_regex, gleam@regexp:regexp()} |
{hear_regexes, list(gleam@regexp:regexp())}.
-type handler(VSQ) :: {handle_all,
fun((context(VSQ)) -> {ok, VSQ} | {error, binary()})} |
{handle_command,
binary(),
fun((context(VSQ), telega@update:command()) -> {ok, VSQ} |
{error, binary()})} |
{handle_commands,
list(binary()),
fun((context(VSQ), telega@update:command()) -> {ok, VSQ} |
{error, binary()})} |
{handle_text,
fun((context(VSQ), binary()) -> {ok, VSQ} | {error, binary()})} |
{handle_hears,
hears(),
fun((context(VSQ), binary()) -> {ok, VSQ} | {error, binary()})} |
{handle_callback_query,
callback_query_filter(),
fun((context(VSQ), binary(), binary()) -> {ok, VSQ} | {error, binary()})}.
-type callback_query_filter() :: {callback_query_filter, gleam@regexp:regexp()}.
-file("/Users/bondiano/workspace/telega-gleam/src/telega/bot.gleam", 53).
-spec try_send_update(
gleam@erlang@process:subject(bot_instance_message(VTB)),
telega@update:update()
) -> {ok, bot_instance_message(VTB)} |
{error, gleam@erlang@process:call_error(bot_instance_message(VTB))}.
try_send_update(Registry_item, Update) ->
gleam@erlang@process:try_call(
Registry_item,
fun(_capture) -> {bot_instance_message_new, _capture, Update} end,
1000
).
-file("/Users/bondiano/workspace/telega-gleam/src/telega/bot.gleam", 132).
-spec set_webhook(telega@internal@config:config()) -> {ok, boolean()} |
{error, binary()}.
set_webhook(Config) ->
telega@api:set_webhook(
erlang:element(5, Config),
{set_webhook_parameters,
<<<<(erlang:element(2, Config))/binary, "/"/utf8>>/binary,
(erlang:element(3, Config))/binary>>,
none,
none,
none,
none,
{some, erlang:element(4, Config)}}
).
-file("/Users/bondiano/workspace/telega-gleam/src/telega/bot.gleam", 179).
-spec wait_handler(context(VTT), handler(VTT)) -> {ok, VTT} | {error, binary()}.
wait_handler(Ctx, Handler) ->
gleam@erlang@process:send(
erlang:element(7, Ctx),
{bot_instance_message_wait_handler, Handler}
),
{ok, erlang:element(6, Ctx)}.
-file("/Users/bondiano/workspace/telega-gleam/src/telega/bot.gleam", 187).
-spec new_context(bot_instance(VTY), telega@update:update()) -> context(VTY).
new_context(Bot, Update) ->
{context,
erlang:element(2, Bot),
Update,
erlang:element(6, Bot),
erlang:element(4, Bot),
erlang:element(3, Bot),
erlang:element(9, Bot)}.
-file("/Users/bondiano/workspace/telega-gleam/src/telega/bot.gleam", 209).
-spec get_session_key(telega@update:update()) -> {ok, binary()} |
{error, binary()}.
get_session_key(Update) ->
case Update of
{command_update, Chat_id, _, _} ->
{ok, erlang:integer_to_binary(Chat_id)};
{text_update, Chat_id@1, _, _} ->
{ok, erlang:integer_to_binary(Chat_id@1)};
{callback_query_update, From_id, _} ->
{ok, erlang:integer_to_binary(From_id)};
{unknown_update, _} ->
{error,
<<"Unknown update type don't allow to get session key"/utf8>>}
end.
-file("/Users/bondiano/workspace/telega-gleam/src/telega/bot.gleam", 219).
-spec get_session(session_settings(VUD), telega@update:update()) -> {ok, VUD} |
{error, binary()}.
get_session(Session_settings, Update) ->
gleam@result:'try'(
get_session_key(Update),
fun(Key) -> _pipe = (erlang:element(3, Session_settings))(Key),
gleam@result:map_error(
_pipe,
fun(E) ->
<<"Failed to get session:\n "/utf8,
(gleam@string:inspect(E))/binary>>
end
) end
).
-file("/Users/bondiano/workspace/telega-gleam/src/telega/bot.gleam", 349).
-spec hears_check(binary(), hears()) -> boolean().
hears_check(Text, Hear) ->
case Hear of
{hear_text, Str} ->
Text =:= Str;
{hear_texts, Strs} ->
gleam@list:contains(Strs, 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("/Users/bondiano/workspace/telega-gleam/src/telega/bot.gleam", 389).
-spec do_handle(bot_instance(VUR), telega@update:update(), handler(VUR)) -> gleam@option:option({ok,
VUR} |
{error, binary()}).
do_handle(Bot, Update, Handler) ->
case {Handler, Update} of
{{handle_all, Handle}, _} ->
{some, Handle(new_context(Bot, Update))};
{{handle_text, Handle@1}, {text_update, _, Text, _}} ->
{some, Handle@1(new_context(Bot, Update), Text)};
{{handle_hears, Hear, Handle@2}, {text_update, _, Text@1, _}} ->
case hears_check(Text@1, Hear) of
true ->
{some, Handle@2(new_context(Bot, Update), Text@1)};
false ->
none
end;
{{handle_command, Command, Handle@3},
{command_update, _, Update_command, _}} ->
case erlang:element(3, Update_command) =:= Command of
true ->
{some, Handle@3(new_context(Bot, Update), Update_command)};
false ->
none
end;
{{handle_commands, Commands, Handle@4},
{command_update, _, Update_command@1, _}} ->
case gleam@list:contains(
Commands,
erlang:element(3, Update_command@1)
) of
true ->
{some, Handle@4(new_context(Bot, Update), Update_command@1)};
false ->
none
end;
{{handle_callback_query, Filter, Handle@5},
{callback_query_update, _, Raw}} ->
case erlang:element(7, Raw) of
{some, Data} ->
case gleam@regexp:check(erlang:element(2, Filter), Data) of
true ->
{some,
Handle@5(
new_context(Bot, Update),
Data,
erlang:element(2, Raw)
)};
false ->
none
end;
none ->
none
end;
{_, _} ->
none
end.
-file("/Users/bondiano/workspace/telega-gleam/src/telega/bot.gleam", 429).
-spec loop_handlers(
bot_instance(VUX),
telega@update:update(),
list(handler(VUX))
) -> {ok, VUX} | {error, binary()}.
loop_handlers(Bot, Update, Handlers) ->
case Handlers of
[Handler | Rest] ->
case do_handle(Bot, Update, Handler) of
{some, {ok, New_session}} ->
loop_handlers(
begin
_record = Bot,
{bot_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),
erlang:element(9, _record)}
end,
Update,
Rest
);
{some, {error, E}} ->
{error,
<<<<<<"Failed to handle message "/utf8,
(gleam@string:inspect(Update))/binary>>/binary,
":\n"/utf8>>/binary,
E/binary>>};
none ->
loop_handlers(Bot, Update, Rest)
end;
[] ->
(erlang:element(2, erlang:element(7, Bot)))(
erlang:element(2, Bot),
erlang:element(3, Bot)
)
end.
-file("/Users/bondiano/workspace/telega-gleam/src/telega/bot.gleam", 297).
-spec handle_bot_instance_message(bot_instance_message(VUN), bot_instance(VUN)) -> gleam@otp@actor:next(any(), bot_instance(VUN)).
handle_bot_instance_message(Message, Bot) ->
case Message of
{bot_instance_message_new, Client, Message@1} ->
case erlang:element(8, Bot) of
{some, Handler} ->
case do_handle(Bot, Message@1, Handler) of
{some, {ok, New_session}} ->
gleam@otp@actor:send(
Client,
bot_instance_message_ok
),
gleam@otp@actor:continue(
begin
_record = Bot,
{bot_instance,
erlang:element(2, _record),
New_session,
erlang:element(4, _record),
erlang:element(5, _record),
erlang:element(6, _record),
erlang:element(7, _record),
none,
erlang:element(9, _record)}
end
);
{some, {error, E}} ->
telega@log:error(
<<"Failed to handle update:\n"/utf8, E/binary>>
),
{stop, normal};
none ->
gleam@otp@actor:send(
Client,
bot_instance_message_ok
),
gleam@otp@actor:continue(Bot)
end;
none ->
case loop_handlers(Bot, Message@1, erlang:element(5, Bot)) of
{ok, New_session@1} ->
gleam@otp@actor:send(
Client,
bot_instance_message_ok
),
gleam@otp@actor:continue(
begin
_record@1 = Bot,
{bot_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),
erlang:element(8, _record@1),
erlang:element(9, _record@1)}
end
);
{error, E@1} ->
telega@log:error(
<<"Failed to handle update:\n"/utf8,
E@1/binary>>
),
{stop, normal}
end
end;
{bot_instance_message_wait_handler, Handler@1} ->
gleam@otp@actor:continue(
begin
_record@2 = Bot,
{bot_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},
erlang:element(9, _record@2)}
end
);
bot_instance_message_ok ->
gleam@otp@actor:continue(Bot)
end.
-file("/Users/bondiano/workspace/telega-gleam/src/telega/bot.gleam", 229).
-spec start_bot_instance(
registry(VUH),
telega@update:update(),
binary(),
gleam@erlang@process:subject(gleam@erlang@process:subject(bot_instance_message(VUH)))
) -> {ok, gleam@erlang@process:subject(bot_instance_message(VUH))} |
{error, gleam@otp@actor:start_error()}.
start_bot_instance(Registry, Update, Session_key, Parent_subject) ->
gleam@otp@actor:start_spec(
{spec,
fun() ->
Actor_subj = gleam@erlang@process:new_subject(),
gleam@erlang@process:send(Parent_subject, Actor_subj),
Selector = begin
_pipe = gleam_erlang_ffi:new_selector(),
gleam@erlang@process:selecting(
_pipe,
Actor_subj,
fun gleam@function:identity/1
)
end,
case get_session(erlang:element(5, Registry), Update) of
{ok, Session} ->
_pipe@1 = {bot_instance,
Session_key,
Session,
erlang:element(3, Registry),
erlang:element(6, Registry),
erlang:element(4, Registry),
erlang:element(5, Registry),
none,
Actor_subj},
{ready, _pipe@1, Selector};
{error, E} ->
{failed,
<<"Failed to init bot instance:\n"/utf8, E/binary>>}
end
end,
10000,
fun handle_bot_instance_message/2}
).
-file("/Users/bondiano/workspace/telega-gleam/src/telega/bot.gleam", 82).
-spec add_bot_instance(registry(VTH), binary(), telega@update:update()) -> gleam@otp@actor:next(any(), registry(VTH)).
add_bot_instance(Registry, Session_key, Update) ->
Registry_actor = gleam@otp@supervisor:supervisor(
fun(_) ->
start_bot_instance(
Registry,
Update,
Session_key,
erlang:element(8, Registry)
)
end
),
_assert_subject = gleam@otp@supervisor:start(
fun(_capture) -> gleam@otp@supervisor:add(_capture, Registry_actor) end
),
{ok, _} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail,
module => <<"telega/bot"/utf8>>,
function => <<"add_bot_instance"/utf8>>,
line => 97})
end,
Bot_subject_result = begin
_pipe = gleam_erlang_ffi:'receive'(erlang:element(8, Registry), 1000),
gleam@result:map_error(
_pipe,
fun(E) ->
<<"Failed to start bot instance:\n"/utf8,
(gleam@string:inspect(E))/binary>>
end
)
end,
case Bot_subject_result of
{ok, Bot_subject} ->
case try_send_update(Bot_subject, Update) of
{ok, _} ->
gleam@otp@actor:continue(
begin
_record = Registry,
{registry,
gleam@dict:insert(
erlang:element(2, Registry),
Session_key,
Bot_subject
),
erlang:element(3, _record),
erlang:element(4, _record),
erlang:element(5, _record),
erlang:element(6, _record),
erlang:element(7, _record),
erlang:element(8, _record)}
end
);
{error, E@1} ->
telega@log:error(
<<"Failed to send message to bot instance: "/utf8,
(gleam@string:inspect(E@1))/binary>>
),
gleam@otp@actor:continue(Registry)
end;
{error, E@2} ->
telega@log:error(E@2),
gleam@otp@actor:continue(Registry)
end.
-file("/Users/bondiano/workspace/telega-gleam/src/telega/bot.gleam", 57).
-spec handle_registry_message(registry_message(), registry(VTE)) -> gleam@otp@actor:next(any(), registry(VTE)).
handle_registry_message(Message, Registry) ->
case Message of
{handle_bot_registry_message, Message@1} ->
case get_session_key(Message@1) of
{ok, Session_key} ->
case gleam_stdlib:map_get(
erlang:element(2, Registry),
Session_key
) of
{ok, Registry_item} ->
case try_send_update(Registry_item, Message@1) of
{ok, _} ->
gleam@otp@actor:continue(Registry);
{error, _} ->
add_bot_instance(
Registry,
Session_key,
Message@1
)
end;
{error, nil} ->
add_bot_instance(Registry, Session_key, Message@1)
end;
{error, E} ->
telega@log:error(
<<"Failed to get session key: "/utf8,
(gleam@string:inspect(E))/binary>>
),
gleam@otp@actor:continue(Registry)
end
end.
-file("/Users/bondiano/workspace/telega-gleam/src/telega/bot.gleam", 146).
-spec start_registry(
telega@internal@config:config(),
list(handler(VTM)),
session_settings(VTM),
gleam@erlang@process:subject(gleam@erlang@process:subject(registry_message())),
telega@model:user()
) -> {ok, gleam@erlang@process:subject(registry_message())} |
{error, gleam@otp@actor:start_error()}.
start_registry(Config, Handlers, Session_settings, Root_subject, Bot_info) ->
gleam@otp@actor:start_spec(
{spec,
fun() ->
Registry_subject = gleam@erlang@process:new_subject(),
Bot_instances_subject = gleam@erlang@process:new_subject(),
gleam@erlang@process:send(Root_subject, Registry_subject),
Selector = begin
_pipe = gleam_erlang_ffi:new_selector(),
gleam@erlang@process:selecting(
_pipe,
Registry_subject,
fun gleam@function:identity/1
)
end,
_pipe@1 = {registry,
maps:new(),
Config,
Bot_info,
Session_settings,
Handlers,
Registry_subject,
Bot_instances_subject},
{ready, _pipe@1, Selector}
end,
10000,
fun handle_registry_message/2}
).