Current section
Files
Jump to
Current section
Files
src/telega@flow@registry.erl
-module(telega@flow@registry).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/telega/flow/registry.gleam").
-export([new_registry/0, register_with_data/4, register/3, register_callable/2, with_callback_filter/3, with_orphan_callback_handler/3, register_cancel_command_with/3, register_cancel_command/2, cancel_user_flows/3, cancel_flow_instance/2, call_flow/4, apply_to_router/2, to_handler/1]).
-export_type([flow_registry/3]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(" FlowRegistry and router integration.\n").
-opaque flow_registry(BFDX, BFDY, BFDZ) :: {flow_registry,
list({telega@flow@types:flow_trigger(),
telega@flow@types:flow(gleam@dynamic:dynamic_(), BFDX, BFDY, BFDZ),
gleam@dict:dict(binary(), binary())}),
gleam@dict:dict(binary(), telega@flow@types:flow(gleam@dynamic:dynamic_(), BFDX, BFDY, BFDZ)),
gleam@dict:dict(binary(), fun((binary()) -> boolean())),
list({fun((binary()) -> boolean()),
fun((telega@bot:context(BFDX, BFDY, BFDZ), binary()) -> {ok,
telega@bot:context(BFDX, BFDY, BFDZ)} |
{error, BFDY})}),
list({binary(),
fun((telega@bot:context(BFDX, BFDY, BFDZ), list(binary())) -> {ok,
telega@bot:context(BFDX, BFDY, BFDZ)} |
{error, BFDY})})}.
-file("src/telega/flow/registry.gleam", 57).
?DOC(" Create a new empty flow registry\n").
-spec new_registry() -> flow_registry(any(), any(), any()).
new_registry() ->
{flow_registry, [], maps:new(), maps:new(), [], []}.
-file("src/telega/flow/registry.gleam", 786).
-spec unsafe_coerce(any()) -> any().
unsafe_coerce(Value) ->
telega@internal@coerce:unsafe_coerce(Value).
-file("src/telega/flow/registry.gleam", 77).
?DOC(" Add a flow to the registry with a trigger and initial data\n").
-spec register_with_data(
flow_registry(BFEU, BFEV, BFEW),
telega@flow@types:flow_trigger(),
telega@flow@types:flow(any(), BFEU, BFEV, BFEW),
gleam@dict:dict(binary(), binary())
) -> flow_registry(BFEU, BFEV, BFEW).
register_with_data(Registry, Trigger, Flow, Initial_data) ->
Coerced_flow = unsafe_coerce(Flow),
{flow_registry,
lists:append(
erlang:element(2, Registry),
[{Trigger, Coerced_flow, Initial_data}]
),
gleam@dict:insert(
erlang:element(3, Registry),
erlang:element(2, Flow),
Coerced_flow
),
erlang:element(4, Registry),
erlang:element(5, Registry),
erlang:element(6, Registry)}.
-file("src/telega/flow/registry.gleam", 68).
?DOC(" Add a flow to the registry with a trigger\n").
-spec register(
flow_registry(BFEG, BFEH, BFEI),
telega@flow@types:flow_trigger(),
telega@flow@types:flow(any(), BFEG, BFEH, BFEI)
) -> flow_registry(BFEG, BFEH, BFEI).
register(Registry, Trigger, Flow) ->
register_with_data(Registry, Trigger, Flow, maps:new()).
-file("src/telega/flow/registry.gleam", 92).
?DOC(" Register a flow without a trigger (for calling from handlers)\n").
-spec register_callable(
flow_registry(BFFK, BFFL, BFFM),
telega@flow@types:flow(any(), BFFK, BFFL, BFFM)
) -> flow_registry(BFFK, BFFL, BFFM).
register_callable(Registry, Flow) ->
Coerced_flow = unsafe_coerce(Flow),
{flow_registry,
erlang:element(2, Registry),
gleam@dict:insert(
erlang:element(3, Registry),
erlang:element(2, Flow),
Coerced_flow
),
erlang:element(4, Registry),
erlang:element(5, Registry),
erlang:element(6, Registry)}.
-file("src/telega/flow/registry.gleam", 109).
?DOC(
" Restrict a registered flow's callback auto-resume to payloads accepted by\n"
" `filter`. Auto-resume normally delivers a callback to the first waiting\n"
" flow regardless of payload; with a filter, a press that belongs to another\n"
" flow's keyboard skips this one and reaches its real target. Used by the\n"
" dialog engine, whose payloads are self-identifying (`dlg:<dialog_id>:...`).\n"
).
-spec with_callback_filter(
flow_registry(BFFY, BFFZ, BFGA),
binary(),
fun((binary()) -> boolean())
) -> flow_registry(BFFY, BFFZ, BFGA).
with_callback_filter(Registry, Flow_name, Filter) ->
{flow_registry,
erlang:element(2, Registry),
erlang:element(3, Registry),
gleam@dict:insert(erlang:element(4, Registry), Flow_name, Filter),
erlang:element(5, Registry),
erlang:element(6, Registry)}.
-file("src/telega/flow/registry.gleam", 125).
?DOC(
" Handle callback payloads that no waiting flow consumed. Handlers are\n"
" tried in registration order; the first whose `matches` accepts the raw\n"
" payload runs. Used by dialogs to answer presses on messages of already\n"
" finished dialogs (otherwise the spinner hangs and the press is silently\n"
" swallowed by the registry's catch-all route).\n"
).
-spec with_orphan_callback_handler(
flow_registry(BFGH, BFGI, BFGJ),
fun((binary()) -> boolean()),
fun((telega@bot:context(BFGH, BFGI, BFGJ), binary()) -> {ok,
telega@bot:context(BFGH, BFGI, BFGJ)} |
{error, BFGI})
) -> flow_registry(BFGH, BFGI, BFGJ).
with_orphan_callback_handler(Registry, Matches, Handler) ->
{flow_registry,
erlang:element(2, Registry),
erlang:element(3, Registry),
erlang:element(4, Registry),
lists:append(erlang:element(5, Registry), [{Matches, Handler}]),
erlang:element(6, Registry)}.
-file("src/telega/flow/registry.gleam", 150).
?DOC(" Register a cancel command with a custom callback\n").
-spec register_cancel_command_with(
flow_registry(BFHH, BFHI, BFHJ),
binary(),
fun((telega@bot:context(BFHH, BFHI, BFHJ), list(binary())) -> {ok,
telega@bot:context(BFHH, BFHI, BFHJ)} |
{error, BFHI})
) -> flow_registry(BFHH, BFHI, BFHJ).
register_cancel_command_with(Registry, Command, On_cancel) ->
{flow_registry,
erlang:element(2, Registry),
erlang:element(3, Registry),
erlang:element(4, Registry),
erlang:element(5, Registry),
lists:append(erlang:element(6, Registry), [{Command, On_cancel}])}.
-file("src/telega/flow/registry.gleam", 140).
?DOC(" Register a cancel command that cancels all active flows for the user\n").
-spec register_cancel_command(flow_registry(BFGY, BFGZ, BFHA), binary()) -> flow_registry(BFGY, BFGZ, BFHA).
register_cancel_command(Registry, Command) ->
register_cancel_command_with(
Registry,
Command,
fun(Ctx, _) -> {ok, Ctx} end
).
-file("src/telega/flow/registry.gleam", 165).
?DOC(" Cancel all flows for a user in a chat\n").
-spec cancel_user_flows(flow_registry(any(), BFIA, any()), integer(), integer()) -> {ok,
list(binary())} |
{error, BFIA}.
cancel_user_flows(Registry, User_id, Chat_id) ->
Flows = maps:values(erlang:element(3, Registry)),
gleam@list:try_fold(
Flows,
[],
fun(Acc, Flow) ->
Flow_id = telega@flow@storage:generate_id(
User_id,
Chat_id,
erlang:element(2, Flow)
),
case (erlang:element(3, erlang:element(7, Flow)))(Flow_id) of
{ok, {some, _}} ->
case (erlang:element(4, erlang:element(7, Flow)))(Flow_id) of
{ok, _} ->
{ok, [Flow_id | Acc]};
{error, Err} ->
{error, Err}
end;
{ok, none} ->
{ok, Acc};
{error, Err@1} ->
{error, Err@1}
end
end
).
-file("src/telega/flow/registry.gleam", 187).
?DOC(" Cancel a specific flow instance by ID\n").
-spec cancel_flow_instance(flow_registry(any(), BFIJ, any()), binary()) -> {ok,
boolean()} |
{error, BFIJ}.
cancel_flow_instance(Registry, Flow_id) ->
Flows = maps:values(erlang:element(3, Registry)),
Found = gleam@list:fold(Flows, false, fun(Acc, Flow) -> case Acc of
true ->
true;
false ->
case (erlang:element(3, erlang:element(7, Flow)))(Flow_id) of
{ok, {some, _}} ->
_ = (erlang:element(4, erlang:element(7, Flow)))(
Flow_id
),
true;
_ ->
false
end
end end),
{ok, Found}.
-file("src/telega/flow/registry.gleam", 293).
-spec start(
telega@flow@types:flow(any(), BFKJ, BFKK, BFKL),
gleam@dict:dict(binary(), binary()),
telega@bot:context(BFKJ, BFKK, BFKL)
) -> {ok, telega@bot:context(BFKJ, BFKK, BFKL)} | {error, BFKK}.
start(Flow, Initial_data, Ctx) ->
{From_id, Chat_id} = telega@flow@engine:extract_ids_from_context(Ctx),
telega@flow@engine:start_or_resume(
Flow,
Ctx,
From_id,
Chat_id,
Initial_data
).
-file("src/telega/flow/registry.gleam", 210).
?DOC(" Call a registered flow from any handler\n").
-spec call_flow(
telega@bot:context(BFIQ, BFIR, BFIS),
flow_registry(BFIQ, BFIR, BFIS),
binary(),
gleam@dict:dict(binary(), binary())
) -> {ok, telega@bot:context(BFIQ, BFIR, BFIS)} | {error, BFIR}.
call_flow(Ctx, Registry, Flow_name, Initial_data) ->
case gleam_stdlib:map_get(erlang:element(3, Registry), Flow_name) of
{ok, Found_flow} ->
start(Found_flow, Initial_data, Ctx);
{error, _} ->
{ok, Ctx}
end.
-file("src/telega/flow/registry.gleam", 354).
?DOC(
" Check if instance is expired, run timeout/exit hooks if so, delete and return True.\n"
" Returns False if not expired.\n"
).
-spec run_timeout_and_cleanup(
telega@flow@types:flow(gleam@dynamic:dynamic_(), BFMH, BFMI, BFMJ),
telega@bot:context(BFMH, BFMI, BFMJ),
telega@flow@types:flow_instance()
) -> {boolean(), {ok, telega@bot:context(BFMH, BFMI, BFMJ)} | {error, BFMI}}.
run_timeout_and_cleanup(Flow, Ctx, Inst) ->
case telega@flow@instance:is_expired(Inst, erlang:element(17, Flow)) of
true ->
telega@flow@engine:emit_flow_event(
<<"timeout"/utf8>>,
Inst,
[{<<"count"/utf8>>, 1}]
),
Ctx_result = case erlang:element(18, Flow) of
{some, Timeout_fn} ->
case Timeout_fn(Ctx, Inst) of
{ok, New_ctx} ->
case erlang:element(16, Flow) of
{some, Exit_fn} ->
Exit_fn(New_ctx, Inst);
none ->
{ok, New_ctx}
end;
{error, Err} ->
{error, Err}
end;
none ->
case erlang:element(16, Flow) of
{some, Exit_fn@1} ->
Exit_fn@1(Ctx, Inst);
none ->
{ok, Ctx}
end
end,
_ = (erlang:element(4, erlang:element(7, Flow)))(
erlang:element(2, Inst)
),
{true, Ctx_result};
false ->
{false, {ok, Ctx}}
end.
-file("src/telega/flow/registry.gleam", 734).
-spec auto_resume_command_handler(flow_registry(BFQR, BFQS, BFQT)) -> fun((telega@bot:context(BFQR, BFQS, BFQT), telega@update:update()) -> {ok,
telega@bot:context(BFQR, BFQS, BFQT)} |
{error, BFQS}).
auto_resume_command_handler(Registry) ->
fun(Ctx, Upd) -> case Upd of
{command_update, _, _, Command, _, _} ->
{User_id, Chat_id} = telega@flow@engine:extract_ids_from_context(
Ctx
),
Flows = maps:values(erlang:element(3, Registry)),
Payload = gleam@option:unwrap(
erlang:element(4, Command),
<<""/utf8>>
),
Result = gleam@list:fold(
Flows,
none,
fun(Acc, Flow) -> case Acc of
{some, _} ->
Acc;
none ->
Flow_id = telega@flow@storage:generate_id(
User_id,
Chat_id,
erlang:element(2, Flow)
),
case (erlang:element(3, erlang:element(7, Flow)))(
Flow_id
) of
{ok, {some, Inst}} when erlang:element(
8,
Inst
) =/= none ->
case run_timeout_and_cleanup(
Flow,
Ctx,
Inst
) of
{true, _} ->
none;
{false, _} ->
Data = maps:from_list(
[{<<"__wait_result"/utf8>>,
<<<<<<"command:"/utf8,
(erlang:element(
3,
Command
))/binary>>/binary,
":"/utf8>>/binary,
Payload/binary>>},
{<<"command"/utf8>>,
erlang:element(
3,
Command
)},
{<<"command_payload"/utf8>>,
Payload}]
),
_pipe = telega@flow@engine:resume_with_instance(
Flow,
Ctx,
Inst,
{some, Data}
),
{some, _pipe}
end;
_ ->
none
end
end end
),
case Result of
{some, Res} ->
Res;
none ->
{ok, Ctx}
end;
_ ->
{ok, Ctx}
end end.
-file("src/telega/flow/registry.gleam", 671).
-spec auto_resume_location_handler(flow_registry(BFQD, BFQE, BFQF)) -> fun((telega@bot:context(BFQD, BFQE, BFQF), telega@update:update()) -> {ok,
telega@bot:context(BFQD, BFQE, BFQF)} |
{error, BFQE}).
auto_resume_location_handler(Registry) ->
fun(Ctx, Upd) -> case Upd of
{message_update, _, _, Message, _} ->
case erlang:element(62, Message) of
{some, Location} ->
{User_id, Chat_id} = telega@flow@engine:extract_ids_from_context(
Ctx
),
Flows = maps:values(erlang:element(3, Registry)),
Lat_str = gleam_stdlib:float_to_string(
erlang:element(2, Location)
),
Lng_str = gleam_stdlib:float_to_string(
erlang:element(3, Location)
),
Result = gleam@list:fold(
Flows,
none,
fun(Acc, Flow) -> case Acc of
{some, _} ->
Acc;
none ->
Flow_id = telega@flow@storage:generate_id(
User_id,
Chat_id,
erlang:element(2, Flow)
),
case (erlang:element(
3,
erlang:element(7, Flow)
))(Flow_id) of
{ok, {some, Inst}} when erlang:element(
8,
Inst
) =/= none ->
case run_timeout_and_cleanup(
Flow,
Ctx,
Inst
) of
{true, _} ->
none;
{false, _} ->
Data = maps:from_list(
[{<<"__wait_result"/utf8>>,
<<<<<<"location:"/utf8,
Lat_str/binary>>/binary,
","/utf8>>/binary,
Lng_str/binary>>},
{<<"__location_lat"/utf8>>,
Lat_str},
{<<"__location_lng"/utf8>>,
Lng_str}]
),
_pipe = telega@flow@engine:resume_with_instance(
Flow,
Ctx,
Inst,
{some, Data}
),
{some, _pipe}
end;
_ ->
none
end
end end
),
case Result of
{some, Res} ->
Res;
none ->
{ok, Ctx}
end;
none ->
{ok, Ctx}
end;
_ ->
{ok, Ctx}
end end.
-file("src/telega/flow/registry.gleam", 629).
-spec auto_resume_audio_handler(flow_registry(BFPP, BFPQ, BFPR)) -> fun((telega@bot:context(BFPP, BFPQ, BFPR), telega@model@types:audio()) -> {ok,
telega@bot:context(BFPP, BFPQ, BFPR)} |
{error, BFPQ}).
auto_resume_audio_handler(Registry) ->
fun(Ctx, Audio) ->
{User_id, Chat_id} = telega@flow@engine:extract_ids_from_context(Ctx),
Flows = maps:values(erlang:element(3, Registry)),
Result = gleam@list:fold(Flows, none, fun(Acc, Flow) -> case Acc of
{some, _} ->
Acc;
none ->
Flow_id = telega@flow@storage:generate_id(
User_id,
Chat_id,
erlang:element(2, Flow)
),
case (erlang:element(3, erlang:element(7, Flow)))(
Flow_id
) of
{ok, {some, Inst}} when erlang:element(8, Inst) =/= none ->
case run_timeout_and_cleanup(Flow, Ctx, Inst) of
{true, _} ->
none;
{false, _} ->
Data = maps:from_list(
[{<<"__wait_result"/utf8>>,
<<"audio:"/utf8,
(erlang:element(
2,
Audio
))/binary>>},
{<<"__audio_file_id"/utf8>>,
erlang:element(2, Audio)}]
),
_pipe = telega@flow@engine:resume_with_instance(
Flow,
Ctx,
Inst,
{some, Data}
),
{some, _pipe}
end;
_ ->
none
end
end end),
case Result of
{some, Res} ->
Res;
none ->
{ok, Ctx}
end
end.
-file("src/telega/flow/registry.gleam", 587).
-spec auto_resume_voice_handler(flow_registry(BFPB, BFPC, BFPD)) -> fun((telega@bot:context(BFPB, BFPC, BFPD), telega@model@types:voice()) -> {ok,
telega@bot:context(BFPB, BFPC, BFPD)} |
{error, BFPC}).
auto_resume_voice_handler(Registry) ->
fun(Ctx, Voice) ->
{User_id, Chat_id} = telega@flow@engine:extract_ids_from_context(Ctx),
Flows = maps:values(erlang:element(3, Registry)),
Result = gleam@list:fold(Flows, none, fun(Acc, Flow) -> case Acc of
{some, _} ->
Acc;
none ->
Flow_id = telega@flow@storage:generate_id(
User_id,
Chat_id,
erlang:element(2, Flow)
),
case (erlang:element(3, erlang:element(7, Flow)))(
Flow_id
) of
{ok, {some, Inst}} when erlang:element(8, Inst) =/= none ->
case run_timeout_and_cleanup(Flow, Ctx, Inst) of
{true, _} ->
none;
{false, _} ->
Data = maps:from_list(
[{<<"__wait_result"/utf8>>,
<<"voice:"/utf8,
(erlang:element(
2,
Voice
))/binary>>},
{<<"__voice_file_id"/utf8>>,
erlang:element(2, Voice)}]
),
_pipe = telega@flow@engine:resume_with_instance(
Flow,
Ctx,
Inst,
{some, Data}
),
{some, _pipe}
end;
_ ->
none
end
end end),
case Result of
{some, Res} ->
Res;
none ->
{ok, Ctx}
end
end.
-file("src/telega/flow/registry.gleam", 545).
-spec auto_resume_video_handler(flow_registry(BFON, BFOO, BFOP)) -> fun((telega@bot:context(BFON, BFOO, BFOP), telega@model@types:video()) -> {ok,
telega@bot:context(BFON, BFOO, BFOP)} |
{error, BFOO}).
auto_resume_video_handler(Registry) ->
fun(Ctx, Video) ->
{User_id, Chat_id} = telega@flow@engine:extract_ids_from_context(Ctx),
Flows = maps:values(erlang:element(3, Registry)),
Result = gleam@list:fold(Flows, none, fun(Acc, Flow) -> case Acc of
{some, _} ->
Acc;
none ->
Flow_id = telega@flow@storage:generate_id(
User_id,
Chat_id,
erlang:element(2, Flow)
),
case (erlang:element(3, erlang:element(7, Flow)))(
Flow_id
) of
{ok, {some, Inst}} when erlang:element(8, Inst) =/= none ->
case run_timeout_and_cleanup(Flow, Ctx, Inst) of
{true, _} ->
none;
{false, _} ->
Data = maps:from_list(
[{<<"__wait_result"/utf8>>,
<<"video:"/utf8,
(erlang:element(
2,
Video
))/binary>>},
{<<"__video_file_id"/utf8>>,
erlang:element(2, Video)}]
),
_pipe = telega@flow@engine:resume_with_instance(
Flow,
Ctx,
Inst,
{some, Data}
),
{some, _pipe}
end;
_ ->
none
end
end end),
case Result of
{some, Res} ->
Res;
none ->
{ok, Ctx}
end
end.
-file("src/telega/flow/registry.gleam", 501).
-spec auto_resume_photo_handler(flow_registry(BFNY, BFNZ, BFOA)) -> fun((telega@bot:context(BFNY, BFNZ, BFOA), list(telega@model@types:photo_size())) -> {ok,
telega@bot:context(BFNY, BFNZ, BFOA)} |
{error, BFNZ}).
auto_resume_photo_handler(Registry) ->
fun(Ctx, Photos) ->
{User_id, Chat_id} = telega@flow@engine:extract_ids_from_context(Ctx),
Flows = maps:values(erlang:element(3, Registry)),
File_ids = gleam@list:map(Photos, fun(P) -> erlang:element(2, P) end),
File_ids_str = gleam@string:join(File_ids, <<","/utf8>>),
Result = gleam@list:fold(Flows, none, fun(Acc, Flow) -> case Acc of
{some, _} ->
Acc;
none ->
Flow_id = telega@flow@storage:generate_id(
User_id,
Chat_id,
erlang:element(2, Flow)
),
case (erlang:element(3, erlang:element(7, Flow)))(
Flow_id
) of
{ok, {some, Inst}} when erlang:element(8, Inst) =/= none ->
case run_timeout_and_cleanup(Flow, Ctx, Inst) of
{true, _} ->
none;
{false, _} ->
Data = maps:from_list(
[{<<"__wait_result"/utf8>>,
<<"photo:"/utf8,
File_ids_str/binary>>},
{<<"__photos"/utf8>>,
File_ids_str}]
),
_pipe = telega@flow@engine:resume_with_instance(
Flow,
Ctx,
Inst,
{some, Data}
),
{some, _pipe}
end;
_ ->
none
end
end end),
case Result of
{some, Res} ->
Res;
none ->
{ok, Ctx}
end
end.
-file("src/telega/flow/registry.gleam", 431).
-spec auto_resume_callback_handler(flow_registry(BFNK, BFNL, BFNM)) -> fun((telega@bot:context(BFNK, BFNL, BFNM), binary(), binary()) -> {ok,
telega@bot:context(BFNK, BFNL, BFNM)} |
{error, BFNL}).
auto_resume_callback_handler(Registry) ->
fun(Ctx, _, Data) ->
{User_id, Chat_id} = telega@flow@engine:extract_ids_from_context(Ctx),
Flows = maps:values(erlang:element(3, Registry)),
Result = gleam@list:fold(Flows, none, fun(Acc, Flow) -> case Acc of
{some, _} ->
Acc;
none ->
Accepts = case gleam_stdlib:map_get(
erlang:element(4, Registry),
erlang:element(2, Flow)
) of
{ok, Filter} ->
Filter(Data);
{error, _} ->
true
end,
case Accepts of
false ->
none;
true ->
Flow_id = telega@flow@storage:generate_id(
User_id,
Chat_id,
erlang:element(2, Flow)
),
case (erlang:element(3, erlang:element(7, Flow)))(
Flow_id
) of
{ok, {some, Inst}} when erlang:element(
8,
Inst
) =/= none ->
case run_timeout_and_cleanup(
Flow,
Ctx,
Inst
) of
{true, _} ->
none;
{false, _} ->
Wait_result_value = telega@flow@instance:encode_callback_wait_result(
Data
),
Callback_data = maps:from_list(
[{<<"callback_data"/utf8>>,
Data},
{<<"__wait_result"/utf8>>,
Wait_result_value}]
),
_pipe = telega@flow@engine:resume_with_instance(
Flow,
Ctx,
Inst,
{some, Callback_data}
),
{some, _pipe}
end;
_ ->
none
end
end
end end),
case Result of
{some, Res} ->
Res;
none ->
case gleam@list:find(
erlang:element(5, Registry),
fun(Entry) -> (erlang:element(1, Entry))(Data) end
) of
{ok, {_, Handler}} ->
Handler(Ctx, Data);
{error, _} ->
{ok, Ctx}
end
end
end.
-file("src/telega/flow/registry.gleam", 385).
-spec auto_resume_handler(flow_registry(BFMW, BFMX, BFMY)) -> fun((telega@bot:context(BFMW, BFMX, BFMY), binary()) -> {ok,
telega@bot:context(BFMW, BFMX, BFMY)} |
{error, BFMX}).
auto_resume_handler(Registry) ->
fun(Ctx, Text) ->
{User_id, Chat_id} = telega@flow@engine:extract_ids_from_context(Ctx),
Flows = maps:values(erlang:element(3, Registry)),
Result = gleam@list:fold(Flows, none, fun(Acc, Flow) -> case Acc of
{some, _} ->
Acc;
none ->
Flow_id = telega@flow@storage:generate_id(
User_id,
Chat_id,
erlang:element(2, Flow)
),
case (erlang:element(3, erlang:element(7, Flow)))(
Flow_id
) of
{ok, {some, Inst}} when erlang:element(8, Inst) =/= none ->
case run_timeout_and_cleanup(Flow, Ctx, Inst) of
{true, _} ->
none;
{false, _} ->
Data = maps:from_list(
[{<<"user_input"/utf8>>, Text},
{<<"__wait_result"/utf8>>,
telega@flow@instance:encode_text_wait_result(
Text
)}]
),
_pipe = telega@flow@engine:resume_with_instance(
Flow,
Ctx,
Inst,
{some, Data}
),
{some, _pipe}
end;
_ ->
none
end
end end),
case Result of
{some, Res} ->
Res;
none ->
{ok, Ctx}
end
end.
-file("src/telega/flow/registry.gleam", 302).
-spec to_handler_with_data(
telega@flow@types:flow(any(), BFLB, BFLC, BFLD),
gleam@dict:dict(binary(), binary())
) -> fun((telega@bot:context(BFLB, BFLC, BFLD), telega@update:command()) -> {ok,
telega@bot:context(BFLB, BFLC, BFLD)} |
{error, BFLC}).
to_handler_with_data(Flow, Initial_data) ->
fun(Ctx, _) -> start(Flow, Initial_data, Ctx) end.
-file("src/telega/flow/registry.gleam", 310).
-spec add_flow_route(
telega@router:router(BFLS, BFLT, BFLU),
telega@flow@types:flow_trigger(),
telega@flow@types:flow(gleam@dynamic:dynamic_(), BFLS, BFLT, BFLU),
gleam@dict:dict(binary(), binary())
) -> telega@router:router(BFLS, BFLT, BFLU).
add_flow_route(Router, Trigger, Flow, Initial_data) ->
case Trigger of
{on_command, Command} ->
telega@router:on_command(
Router,
Command,
to_handler_with_data(Flow, Initial_data)
);
{on_text, Pattern} ->
telega@router:on_text(
Router,
Pattern,
fun(Ctx, _) -> start(Flow, Initial_data, Ctx) end
);
{on_callback, Pattern@1} ->
telega@router:on_callback(
Router,
Pattern@1,
fun(Ctx@1, _, _) -> start(Flow, Initial_data, Ctx@1) end
);
{on_filtered, Filter} ->
telega@router:on_filtered(
Router,
Filter,
fun(Ctx@2, _) -> start(Flow, Initial_data, Ctx@2) end
);
on_photo ->
telega@router:on_photo(
Router,
fun(Ctx@3, _) -> start(Flow, Initial_data, Ctx@3) end
);
on_video ->
telega@router:on_video(
Router,
fun(Ctx@4, _) -> start(Flow, Initial_data, Ctx@4) end
);
on_audio ->
telega@router:on_audio(
Router,
fun(Ctx@5, _) -> start(Flow, Initial_data, Ctx@5) end
);
on_voice ->
telega@router:on_voice(
Router,
fun(Ctx@6, _) -> start(Flow, Initial_data, Ctx@6) end
);
on_any_text ->
telega@router:on_any_text(
Router,
fun(Ctx@7, _) -> start(Flow, Initial_data, Ctx@7) end
)
end.
-file("src/telega/flow/registry.gleam", 223).
?DOC(" Apply all registered flows to a router\n").
-spec apply_to_router(
telega@router:router(BFJG, BFJH, BFJI),
flow_registry(BFJG, BFJH, BFJI)
) -> telega@router:router(BFJG, BFJH, BFJI).
apply_to_router(Router, Registry) ->
Router_with_flows = gleam@list:fold(
erlang:element(2, Registry),
Router,
fun(Router@1, Flow_entry) ->
{Trigger, Flow, Initial_data} = Flow_entry,
add_flow_route(Router@1, Trigger, Flow, Initial_data)
end
),
Router_with_cancel = gleam@list:fold(
erlang:element(6, Registry),
Router_with_flows,
fun(R, Cancel_entry) ->
{Command, On_cancel} = Cancel_entry,
telega@router:on_command(
R,
Command,
fun(Ctx, _) ->
case cancel_user_flows(
Registry,
erlang:element(2, erlang:element(3, Ctx)),
erlang:element(3, erlang:element(3, Ctx))
) of
{ok, Cancelled} ->
On_cancel(Ctx, Cancelled);
{error, _} ->
{ok, Ctx}
end
end
)
end
),
case maps:size(erlang:element(3, Registry)) of
0 ->
Router_with_cancel;
_ ->
_pipe = Router_with_cancel,
_pipe@1 = telega@router:on_any_text(
_pipe,
auto_resume_handler(Registry)
),
_pipe@2 = telega@router:on_callback(
_pipe@1,
{prefix, <<""/utf8>>},
auto_resume_callback_handler(Registry)
),
_pipe@3 = telega@router:on_photo(
_pipe@2,
auto_resume_photo_handler(Registry)
),
_pipe@4 = telega@router:on_video(
_pipe@3,
auto_resume_video_handler(Registry)
),
_pipe@5 = telega@router:on_voice(
_pipe@4,
auto_resume_voice_handler(Registry)
),
_pipe@6 = telega@router:on_audio(
_pipe@5,
auto_resume_audio_handler(Registry)
),
_pipe@7 = telega@router:on_filtered(
_pipe@6,
telega@router:filter(
<<"has_location"/utf8>>,
fun(Upd) -> case Upd of
{message_update, _, _, Message, _} ->
gleam@option:is_some(
erlang:element(62, Message)
);
_ ->
false
end end
),
auto_resume_location_handler(Registry)
),
telega@router:on_filtered(
_pipe@7,
telega@router:filter(
<<"is_command"/utf8>>,
fun(Upd@1) -> case Upd@1 of
{command_update, _, _, _, _, _} ->
true;
_ ->
false
end end
),
auto_resume_command_handler(Registry)
)
end.
-file("src/telega/flow/registry.gleam", 286).
?DOC(" Create a router handler that starts a flow\n").
-spec to_handler(telega@flow@types:flow(any(), BFJT, BFJU, BFJV)) -> fun((telega@bot:context(BFJT, BFJU, BFJV), telega@update:command()) -> {ok,
telega@bot:context(BFJT, BFJU, BFJV)} |
{error, BFJU}).
to_handler(Flow) ->
fun(Ctx, _) -> start(Flow, maps:new(), Ctx) end.