# 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](https://www.gitlab.com/Thechi2000/telegram-bot2). ## Workflow The idea behind this framework is similar to [rocket](https://www.rocket.rs) 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]` ```rust #[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|]*"`. Static parameters are constants, while dynamic parameters are parsed from the command and given to the handler with `FromStr` ``` #[command("/soup get ")] 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>) { let mut lock = state.lock().unwrap(); *lock += 1; println!("Increasing counter to {}", lock); } ```