Finite State Machine / conversation state management for ExGram Telegram bots.
Quick start
With ExGram.Router (recommended)
defmodule MyBot do
use ExGram.Bot, name: :my_bot
use ExGram.Router
use ExGram.FSM,
storage: ExGram.FSM.Storage.ETS,
flows: [MyBot.RegistrationFlow, MyBot.SettingsFlow],
on_invalid_transition: :log
command("register")
scope do
filter :command, :register
handle &MyBot.Handlers.register/1
end
scope do
filter :fsm_flow, :registration
filter :fsm_state, :get_name
filter :text
handle &MyBot.Handlers.got_name/1
end
scope do
handle &MyBot.Handlers.fallback/1
end
endThe :fsm_flow and :fsm_state filter aliases are registered automatically
when use ExGram.FSM detects that use ExGram.Router was also called. Use them
to scope routes to a specific flow and step.
Without ExGram.Router
Pattern-match on context.extra.fsm directly in handle/2 clauses:
defmodule MyBot do
use ExGram.Bot, name: :my_bot
use ExGram.FSM,
storage: ExGram.FSM.Storage.ETS,
flows: [MyBot.RegistrationFlow]
command("register")
def handle({:command, :register, _}, context) do
context |> start_flow(:registration) |> answer("What's your name?")
end
def handle({:text, name, _}, %{extra: %{fsm: %ExGram.FSM.State{flow: :registration, state: :get_name}}} = context) do
context
|> update_data(%{name: name})
|> transition(:get_email)
|> answer("Got it! What's your email?")
end
def handle(_, context), do: context
endOptions
| Option | Type | Default | Description |
|---|---|---|---|
storage: | module | ExGram.FSM.Storage.ETS | Storage backend |
flows: | list of modules | [] | Flow modules (each using use ExGram.FSM.Flow) |
on_invalid_transition: | atom or {m, f} | :raise | Invalid transition policy |
key: | module | ExGram.FSM.Key.ChatUser | Key adapter (see ExGram.FSM.Key) |
on_invalid_transition policies
| Policy | Behavior |
|---|---|
:raise (default) | Raises ExGram.FSM.TransitionError |
:log | Logs a warning, returns context unchanged |
:ignore | Silent no-op, returns context unchanged |
{Module, :function} | Calls Module.function(context, from, to) |
Imported helpers
use ExGram.FSM automatically imports these functions:
start_flow/2- start a named flow (sets flow + default state + clears data)get_flow/1- read current flow name atomget_state/1- read current state atom within the active flowget_data/1- read current data mapset_state/2- force set state within the active flow (no transition validation)set_state/3- force set flow + state (escape hatch, ignores conflicts)transition/2- set state with validation against the active flow's transitionsupdate_data/2- merge map into FSM dataclear_flow/1- reset flow, state, and data entirely