Skip to content

v0.5.2

Latest
Compare
Choose a tag to compare
@SnejUgal SnejUgal released this 31 Mar 15:55
· 563 commits to master since this release

We've worked hard during the last two weeks, and prepared two big features, a few smaller ones, аnd, of course, we didn't forget about Bot API 4.7. What's even better is that all the new features don't break compatibility, so we're releasing them in version 0.5.2!

Bot API 4.7 (#33)

Let's start with Bot API 4.7 first. Recently, Telegram released a feature everyone's been asking for years — rolling dice in chats. We can't help but support it in tbot, so we've implemented the SendDice method and the dice handler on EventLoop. Telegram now lets bots see and modify the list of their commands, and you can do it with the GetMyCommands and SetMyCommands methods. Lastly, bots now can create animated sticker sets, and the CreateNewStickerSet and AddStickerToSet methods have been updated accordingly.

tbot::state, the stateful event loop (!173)

The next feature is amazing and you might've really wanted it. The new module tbot::state introduces StatefulEventLoop, as well as a couple state stores you'll likely need. To create a stateful event loop, call Bot::stateful_event_loop instead of Bot::event_loop:

let mut bot = tbot::from_env!("BOT_TOKEN").stateful_event_loop(initial_state);

The initial state can be absolutely anything (that you can share between threads), and all handlers will receive the state wrapped in an Arc as their second argument:

use tokio::sync::Mutex;

let mut bot = tbot::from_env!("BOT_TOKEN")
    .stateful_event_loop(Mutex::new(0));

bot.text(|context, counter| async move {
    counter.lock().await += 1;
});

Each method that sets a handler has a corresponding method with the _if postfix, that take a predicate and run the handler if the predicate returns true:

let is_on_second_stage = |context, state| async move {
    state.chats.get(&*context).await.stage == 2
};

bot.text_if(is_on_second_stage, |context, state| async move { .. });

The rest of StatefulEventLoop's API is pretty much the same as the stateless's one, excepts for methods that go from a stateless to a stateful event loop and back or switch the state.

The last thing about state is two state stores tbot provides out of the box: Chats and Messages, which store some state per each chat and message respectively. If you want to learn more, go check out tbot::state's docs. Don't forget to take a look at our new two examples: a questionary (warning: zealotry!) and an anonymous messenger.

tbot::markup, easy and fearless work with markup (!180)

If you ever worked with markup manually, you know it's pretty hard to escape all user input correctly so that it won't break your markup. tbot::markup comes to the rescue, simplifying working with markup and making it fearless. It contains basic formatters like bold and italic, which you then pass to a markup formatter — markdown_v2 or html — which does all the work applying formatters and escaping strings when turned into a string:

use tbot::markup::{bold, italic, markdown_v2};
let message = markdown_v2(bold((
    "*This is <b>old, ",
    italic("and this is bold and italic!"),
))).to_string();
println!("{}", message); // *\*This is <b\>old, _and this is bold and italic\!_*

To learn more, visit tbot::markup's docs.

Miscellaneous

  • Due to how the ChatMethods trait and its methods were defined, you couldn't write a generic handler with the context's trait bound including ChatMethods. because when you'd call a method, the compiler would error saying that the method's input arguments need to live longer than the context. We fixed the lifetimes on the methods (this doesn't break anything, as it shortens inputs' lifetime, you can't use lifetimes on methods and the traits are sealed), but for compatibility we left the lifetime on ChatsMethods and other context traits. (!181)
  • Due to how Cargo handles features, when we introduced the rustls feature, hyper-proxy was downloaded despite the proxy feature being disabled. Instead of using ugly hacks, we decided to make proxy available without enabling the proxy feature. (!183)
  • If you ever need to trace through tbot when debugging something, tbot now logs all method calls and how the event loop handles updates using tracing. To see it, enable tbot's logs on the trace level, see tracing's Readme to learn how to do it. (!176)
  • Previously, tbot's webhook server accepted updates only on / and ignored updates coming to all other URLs. Now, the URL on which tbot accepts updates can be configured with Webhook::accept_updates_on. (!179)
  • We clarified the docs regarding commands with a bot's username (/command@username). As tbot needs to know the bot's username to properly handle such commands in all circumstances, the username needs to be configured explicitly using either EventLoop::username or EventLoop::fetch_username. Now the docs of command and similar handler setters hint to these methods. (#34)
  • If Telegram returns retry_after when tbot polls for updates, tbot will now respect it. (!177)

It's a lot of features for a single update. Stay home and write bots in Rust with tbot!