GenServer that manages active conversation flows per chat.
Subscribes to PubSub updates and routes them to the correct flow. Sends prompts and error messages back via the Telegram API.
Supervision Tree
Add the Engine before any bots that use flows:
children = [
{Hotline.Poller, []},
{Hotline.Flow.Engine, []},
{MyBot, []}
]Starting Flows
# From a Bot's handle_update/2:
def handle_update(%{message: %{text: "/register", chat: %{id: chat_id}}}, state) do
Hotline.Flow.Engine.start_flow(chat_id, MyBot.Flows.Registration)
{:noreply, state}
endIntegration with Bots
Use handles_update?/1 to skip updates being handled by an active flow:
def handle_update(update, state) do
unless Hotline.Flow.Engine.handles_update?(update) do
# normal handling
end
{:noreply, state}
endTesting
Inject a :sender function to capture messages in tests:
test_pid = self()
sender = fn params, _opts -> send(test_pid, {:sent, params}); {:ok, %{}} end
{:ok, engine} = Engine.start_link(sender: sender, name: :test_engine)
Summary
Functions
Check if a chat has an active flow.
Cancel the active flow for a chat.
Returns a specification to start this module under a supervisor.
Check if an update belongs to a chat with an active flow.
Start a flow for a chat.
Functions
@spec active_flow?(integer(), GenServer.server()) :: boolean()
Check if a chat has an active flow.
@spec cancel_flow(integer(), GenServer.server()) :: :ok | {:error, :no_flow}
Cancel the active flow for a chat.
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec handles_update?(map(), GenServer.server()) :: boolean()
Check if an update belongs to a chat with an active flow.
@spec start_flow(integer(), module(), map(), GenServer.server()) :: :ok | {:error, :flow_active | :flow_start_failed}
Start a flow for a chat.
Returns {:error, :flow_active} if one is already running, or
{:error, :flow_start_failed} if the flow_module raises while starting
(e.g. a module that does not use Hotline.Flow). A failed start never
crashes the Engine, so other chats' in-flight flows are unaffected.