#bot #events #handler #event-handling #flow #creation #simplifies

nightly flow-bot

An onebot-11 SDK that simplifies bot creation

1 unstable release

new 0.1.0 Mar 5, 2025

#6 in #simplifies

Download history 110/week @ 2025-02-28

110 downloads per month

AGPL-3.0-only

58KB
1.5K SLoC

An onebot-11 SDK that simplifies bot creation.

Flow-bot is carefully crafted to provide a mechanism similar to that of axum so if you are familiar with axum, you will find it easy to use.

The basic unit of event processing in flow-bot is a handler. A handler is a function that optionally takes BotContext and a BotEvent or any of the extractors as arguments and returns a HandlerControl. Handlers can parse the incoming event and respond to it. The returned value serves as a control flow signal to determine the flow of the event processing which is where the name comes from.

Example

use flow_bot::{
    FlowBotBuilder,
    base::{connect::ReverseConnectionConfig, extract::Message, handler::HandlerControl},
};

async fn on_message(msg: Message) -> HandlerControl {
    println!("{:?}", msg.message);
    HandlerControl::Continue
}

async fn main() {
    let bot = FlowBotBuilder::new(ReverseConnectionConfig {
        target: "ws://localhost:19999".to_string(),
        auth: None,
    })
    .with_state(())
    .with_handler(on_message)
    .build();

    bot.run().await.unwrap();
}

Handlers

Handlers are functions that can be registered to process events. They can be registered using the with_handler method. Commonly, a handler responds to a event by calling methods in ApiExt which is implemented by BotContext to control the bot.

The returned value of a handler is a HandlerControl which determines the flow of the event processing. HandlerControl::Continue means the event will be passed to the next handler, HandlerControl::Block means the event will not be passed to the next handler. HandlerControl::Skip means the event will be passed to the next handler but the event will not be processed by the current handler, used in the case where the event criteria is not met within the handler. It is a crucial difference from many other bot SDKs that we do not provide a matcher machenism to match the event, so that you need to implement the logic in the handler. However, a similar way is mimiced by the extractor mechanism. See the Extractors section below.

Extractors

Extractors work similarly to the extractors in axum. They are functions that can be registered to extract data from the event. They are to extract data from the context and event for the handler to use. To see a full list of predefined extractors, see the extract module.

Using Extractors

It is already shown in the example above how to use the predefined Message extractor which extracts the message from the event. It is also possible to use extractors to match event criteria.

use flow_bot::{
   base::extract::MatchGroupId,handler::HandlerControl
};

async fn on_group_msg(_: MatchGroupId<123>) -> HandlerControl {
   // This handler will only be called when the event is a group message in group 123, otherwise it will be skipped.
   println!("Received message in group 123");
   HandlerControl::Continue
}

Optional Extraction

Extractors can be optional by using the Option type. This is useful when the data is not always present in the event.

Custom Extractors

It is also possible to create custom extractors by implementing the FromEvent trait. This is an async trait that takes the context and event as arguments and returns a result of the extracted data.

States

States are data that can be shared between handlers. They are stored in the context and can be accessed by any handler. States can be added to the bot using the with_state method. States can be any type that implements std::any::Any, Send, and Sync.

In a handler, a state is accessed by using the State extractor.

There can be multiple states in the bot, each with a unique type. If the required state is not present in the context, the handler will be skipped.

Services

Services provide a way to make the bot extendable. They are similar to handlers but take the shape of a struct that implements the Service trait and have their own state. It is made so that the bot can be extended to use services from other crates with ease. Services can be added to the bot using the with_service method.

Dependencies

~8–20MB
~260K SLoC