ferogram-fsm 0.3.8

FSM state management for ferogram bots
Documentation

ferogram-fsm

FSM state management for ferogram bots.

Crates.io Telegram Channel docs.rs License: MIT OR Apache-2.0

Handles state storage and context for multi-step bot conversations. Used by ferogram's dispatcher when you register FSM handlers.

ferogram re-exports everything from here. Existing code needs no changes.

Installation

[dependencies]
ferogram-fsm = "0.3.8"

What it does

  • StateStorage trait so you can plug in any backend
  • MemoryStorage built-in (in-process, no persistence)
  • StateContext for reading, writing, and transitioning state per user/chat
  • StateKey for scoping state by user ID, chat ID, or both
  • FsmState trait that your state enum implements

Usage

Define a state enum and implement FsmState on it (or use #[derive(FsmState)] from ferogram-derive):

use ferogram_fsm::{FsmState, MemoryStorage, StateContext};
use std::sync::Arc;

#[derive(Clone, Debug, PartialEq)]
enum Order {
    Item,
    Quantity,
    Confirm,
}

impl FsmState for Order {
    fn as_key(&self) -> String {
        match self {
            Order::Item => "Item".into(),
            Order::Quantity => "Quantity".into(),
            Order::Confirm => "Confirm".into(),
        }
    }

    fn from_key(key: &str) -> Option<Self> {
        match key {
            "Item" => Some(Order::Item),
            "Quantity" => Some(Order::Quantity),
            "Confirm" => Some(Order::Confirm),
            _ => None,
        }
    }
}

Use StateContext to read, write, and move between states:

async fn handle(ctx: StateContext) {
    // Read stored data
    let item = ctx.get_data("item").await.unwrap_or_default();

    // Store data
    ctx.set_data("item", "Widget").await.ok();

    // Move to next state
    ctx.transition(Order::Quantity).await.ok();

    // Clear everything and exit the FSM
    ctx.finish().await.ok();
}

Custom storage

If you need persistence, implement StateStorage for Redis, SQL, or whatever backend you prefer:

use ferogram_fsm::{StateStorage, StorageError};

struct RedisStorage { /* ... */ }

#[async_trait::async_trait]
impl StateStorage for RedisStorage {
    async fn get_state(&self, key: &str) -> Result<Option<String>, StorageError> { todo!() }
    async fn set_state(&self, key: &str, state: &str) -> Result<(), StorageError> { todo!() }
    async fn del_state(&self, key: &str) -> Result<(), StorageError> { todo!() }
    async fn get_data(&self, key: &str, field: &str) -> Result<Option<String>, StorageError> { todo!() }
    async fn set_data(&self, key: &str, field: &str, value: &str) -> Result<(), StorageError> { todo!() }
    async fn clear(&self, key: &str) -> Result<(), StorageError> { todo!() }
}

Stack position

ferogram
└ ferogram-fsm  <-- here

License

MIT or Apache-2.0, at your option. See LICENSE-MIT and LICENSE-APACHE.

Ankit Chaubey - github.com/ankit-chaubey