#telegram-bot #bot #telegram #command-handler #api-bindings

macro telegram-bot2-macros

telegram-bot2-macros contains all macros used by the telegram-bot2 crate

4 releases

0.1.3 Feb 17, 2023
0.1.2 Feb 17, 2023
0.1.1 Feb 3, 2023
0.1.0 Oct 29, 2022

#12 in #command-handler


Used in telegram-bot2

Custom license

42KB
787 lines

Telegram bot

This crate provides an easy to use framework to build telegram bots. It is still in developpement, you may report bugs or request features on the project repo.

Workflow

The idea behind this framework is similar to rocket webservers. There is a main function that builds a bot using the BotBuilder. Updates are fetched via long polling, then passed to handlers.

Building the bot

The recommended way to build the bot is to create a function annotated with #[bot], returning a BotBuilder.
For more information, see BotBuilder and #[bot]

#[bot]
async fn bot() -> _ {
    BotBuilder::new()
        .interval(Duration::from_secs(0))
        .timeout(5)
        .handlers(handlers![handler])
        .commands(commands![soup])
}

Note: The function does not need an explicit return type, as it is handled by the #[bot] macro

Handlers

Handlers are async functions returning a Result<(), E> where E: Debug (returning an Err will result in the program termination). They may take as many parameters as needed, but they all need to implement the FromUpdate trait (a bunch of implementations is already provided). Specific handlers may take additional parameters

Generic handler

A generic handler is annotated with the #[handler] attribute, and has no specific parameters.

The parameters of the functions are parsed using the FromUpdate trait. If the parsing of any arguments fails, the next handler is tried, until one is successfully parsed.

The macro takes the following parameters:

  • rank(usize): Defaults to 0. The priority of this handler, 0 being the highest (i.e. the first handler the be executed)
  • restrict (list of UpdateType): Defaults to all. The updates that may be passed to the handler
#[handler(rank = 1)]
async fn handler(message: &Message, bot: &Bot) -> Result<(), ()> {
    bot.send_message(SendMessageBuilder::new(ChatId::from(message.chat.id), message.text.clone().unwrap()).build()).await.unwrap();
    Ok(())
}

Command handler

A command handler is annotated with the #[command] macro. It take as parameters the dynamic arguments of the command (see the syntax), and any type implementing FromUpdate

The function's arguments are either extracted from the call (according to the syntax), or parsed with FromUpdate

The macro takes the following parameters:

  • (String): Mandatory. the syntax of the command, as follows: "/command_name [static|<dynamic>]*". Static parameters are constants, while dynamic parameters are parsed from the command and given to the handler with FromStr
#[command("/soup get <id>")]
async fn soup(bot: &Bot, chat: ChatId, id: i64) -> Result<(), ()> {
    bot.send_message(SendMessageBuilder::new(chat, format!("Soup {} requested", id)).build()).await.unwrap();
    Ok(())
}

In this example, the id parameter is parsed from the message, and has to be an i64. A valid call would be "/soup get 10", while "/soup get hi" would not be parsed successfully

Daemons

You can setup daemons that are periodically called in background and can access the BotState. Daemon function are annotated with #[daemon] and require an interval parameter, which specifies the time between two calls (in seconds).

The interval time is the time between calls, it does not starts at the end of the last call. For example, if the interval is set to 60s and the daemon takes 5s to complete, the next call will proceeds 55s after the first one ends. The same daemon cannot be started if it is already running (i.e. a 5s daemon with interval of 1s will start as soon as it ends). The timer is precise at a millisecond order.

The parameters of the function are parsed by the FromDaemon trait, at each call

The macro takes the following parameters:

  • interval (usize): Mandatory. The time (in seconds) between two calls
#[daemon(interval = 5)]
async fn hello(state: &BotState<Mutex<usize>>) {
    let mut lock = state.lock().unwrap();
    *lock += 1;
    println!("Increasing counter to {}", lock);
}

Dependencies

~3.5–5MB
~92K SLoC