Skip to content

Releases: tbot-rs/tbot

v0.5.2

31 Mar 15:55
Compare
Choose a tag to compare

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!

v0.5.1

09 Mar 08:54
Compare
Choose a tag to compare

The version 0.5.1 of tbot fixes the wrong assumption that all code blocks have a defined language, which causes parsing errors whenever a code block without a language is received. This fix is a potential breaking change as it changes the type of code blocks' language from String to Option. However, we tested the patch on open-source bots from GitHub and they continue to compile. Even if this patch affects your bot, it points to the erroneous assumption on your side which should be fixed.

This issue was reported in issue #32 and fixed in merge request !171. Refer to them for additional information about the bug.

v0.5

18 Mar 04:24
Compare
Choose a tag to compare

We're happy to announce the release of tbot v0.5!

In this version, tbot has gained support for Bot API v4.6 (#26). This means that
you can now make use of Polls 2.0, as well as get more information about your
bot and the language of code blocks. Unfortunately, this led to a few breaking
changes:

  • The GetMe method now returns a new struct, types::user::Me, which is
    composed of the fields only returned by GetMe and the user field,
    containing the information which is present in all instances of the User
    type;
  • We fixed a bug regarding reply buttons: though type fields of ReplyButton
    are mutually exclusive, tbot didn't prevent one from setting both types at
    the same time. This was fixed in !158, but it did introduce a breaking change.
    Now, all request types are contained in one enum, which you pass to the
    request setter of a reply::Button instance.
  • To support language tags, we had to change the message::entity::Kind::Pre
    variant from a unit one to a tuple. But this one is easy to figure out 😉

Thanks to @uwinx, you can now easily add a handler for several commands using
EventLoop::commands (and edited_commands in case you're interested in this
one) (!161):

let mut bot = tbot::from_env!(..).event_loop();
bot.commands(["start", "help"], |context| { .. });

This version also introduces the Command context, which wraps the underlying
text update, but it also provides you with the command which triggered the
handler. But note that all command handlers now receive the new context, so you
may have to change a few typed out command context types if you ever did so. But
Command dereferences to the underlying context and implements the appropriate
traits, so migrating to the new context won't be hard.

And the last change in this version is this small improvement (!167): if your
bot receives an edited message with an attachment one can't usually edit, you'll
see the update in tbot's message.

We hope you'll like this update! And by the way, we now have
a website, check it out :)

v0.4

18 Mar 04:22
Compare
Choose a tag to compare

Ho-ho-ho! 🎅 tbot v0.4 is coming to town! 🛷

Didn't expect a major release on New Year? Well, we too. Who could've thought that Telegram would release a new Bot API version today? Anyway, we're already ready for it!

Starting this version, you can use rustls with tbot! (!145) For those who don't know what it is, it's a complete TLS implementation in Rust — a bit less of C in your Rust bots :) It's not enabled by default though, so you have to enable it manually in your Cargo.toml:

tbot = { version = "0.4", default-features = false, features = ["rustls"] }

Let's get back to Bot API v4.5. One of the most important changes is MarkdownV2, which lets you strikethrough and underline text, and also nest formatting! (!152) We're going to implement a module to make it easier to work with markup, but for now you can use parameters::Text::MarkdownV2 to forget about the dark past of messing with the markdown parser.

You can now see admins' custom titles and set titles for those admins that your bot promoted (!151). Also, bots now can read the slow mode delay in supergroups (!150) so that you don't spam too much. And how could you live without unique file IDs you can't do anything with? (!149)

Aaand back to tbotitself. We fixed a horrible typo in chat::member::Status::Administrator and in some doc (!147), hopefully the compiler will point that to you if you used this enum and didn't spot the typo yourself. A more important change is that we've adopted is-macro — a crate that generates is_*, expect_* and taking methods (those that try to match on a variant and return Some(T) if successful or None otherwise) for enums (!146, !156). Because of that, some is_* methods changed their names a bit — check the docs if you run into some problems with this. We also boxed a few types in message::Kind, so grab a few stars from the amazing night sky and put them in your code if you need to work with that type (!155).

Have you checkout out the updated readme on our homepage? In that readme, you can find a link to a list of projects that already build upon tbot. Very proud to see that our project is already used in bots with several thousand users 😊

So, it's already 2020 at my place. We wish you a Merry Christmas, we wish you a Merry Christmas, we wish you a Merry Christmas and a Happy New Year! Write all your bots in Rust

v0.3

18 Mar 04:25
Compare
Choose a tag to compare

We're happy to announce tbot v0.3! Here's an overview of what we've prepared
for this release.

In v0.3, tbot has moved to std::future and now supports async/.await!
For example, here's an echo bot implemented using async/.await:

use tbot::prelude::*;

async fn main() {
    let mut bot = tbot::from_env!("BOT_TOKEN").event_loop();

    bot.text(|context| {
        async move {
            let echo = &context.text.value;
            let call_result = context.send_message(echo).call().await;

            if let Err(err) = call_result {
                dbg!(err);
            }
        }
    });

    bot.polling().start().await.unwrap();
}

Also, you must appreciate the getMe example:

async fn main() -> Result<(), tbot::errors::MethodCall> {
    let bot = tbot::from_env!("BOT_TOKEN");

    let me = bot.get_me().call().await?;
    dbg!(me);

    Ok(())
}

tbot v0.3 introduces contexts::fields, a module that contains traits for
specific contexts fields. It may sound complicated, but what it actually means
is that you can now write handlers generic over contexts. Here's an example
of a handler that you can use for both just-sent photos and edited ones:

use std::sync::Arc;
use tbot::{contexts::fields::Photo, connectors::Connector};

async fn handle_photo<Ctx, Cnn: Connector>(context: Arc<Ctx>)
where
    Ctx: Photo<Cnn>,
    Cnn: Connector,
{
    let photo = context.photo();
    // ..
}

// ..

bot.photo(handle_photo);
bot.edited_photo(handle_photo);

Though tbot has had webhook support since the first version, it could only
listen over HTTP, while Telegram sent updates over HTTPS only. Because of that,
you would have to use nginx to use webhooks with tbot. Now tbot can natively
listen to updates over HTTPS! If you had this:

bot.webhook(URL, PORT).start();

you can turn it into this:

use tbot::event_loop::webhook::https::Identity;

let identity = Identity::from_pkcs12(
    include_bytes!("path/to/identity.p12"),
    env!("IDENTITY_PASSWORD"),
).unwrap();
bot.webhook(URL, PORT)
    .certificate(include_str!("path/to/public/key/cert.pem"))
    .https(identity)
    .start()
    .await
    .unwrap();

Still, nginx is useful if you want to host several bots on one domain/IP
address or to distribute load between servers, and tbot continues to support
webhook over HTTP.

Another important change in this release is that handlers cannot be mutating
anymore, meaning that you no longer can write this:

let mut id = 0;
bot.inline(move |_| {
    id += 1;
    // ..
});

Instead, you should use a Mutex (or similar) if you need to have some global
state, which scales better with time:

use tokio::sync::Mutex;
use std::sync::Arc;

let id = Arc::new(Mutex::new(0));
bot.inline(move |_| {
    let id = Arc::clone(&id);
    async move {
        id.lock().await += 1;
    }
});
  • tbot::bot! was renamed to tbot::from_env! to better reflect what it does
    (!107);
  • Most types are annotated with #[non_exhaustive] (leading to MSRV 1.40)
    (!133);
  • Input types became #[must_use], as well as methods returning any type
    (for they're all pure) (!134, !137, !138);
  • types::parameters::Updates was renamed to types::parameters::UpdateKind
    (!141);
  • A missing method ChatMethods::pin_chat_message was added (!111);
  • A trait Connector was introduced to simplify writing code generic over
    connectors (!118);
  • Method docs were updated to describe what each method does, so you no longer
    need to refer to Bots API docs (!115);
  • is_* methods were added for enums where they were accidentially missing
    (!140);
  • The Token type is no longer public: it was only used once in public code
    where this additional type safety is not actually needed. It is still used
    internally to allow debugging methods without revealing your token (!124).

We hope you enjoy this huge update!

v0.2.2

18 Mar 04:28
Compare
Choose a tag to compare

v0.2.2 fixes compilation error with serde >= 1.0.101, along with fixing wrong field names serialized in ypes::inline_query::result::{Gif, Mpeg4Gif}.

v0.2

18 Mar 04:37
Compare
Choose a tag to compare

tbot v0.2 brings several improvements, including:

  • Bot API v4.4 is now fully supported;
  • Reduced panics and added a warning when an update handler panicked.

Also, v0.2 has a few breaking changes. You can find a list of merged changes with descriptions of breaking changes here.

v0.1.2

18 Mar 04:35
Compare
Choose a tag to compare

The v0.1.2 release of tbot minimizes the breaking change caused by Bot API v4.4. The cause of the breaking change is Message.sticker reused for animated stickers, which use tgs instead of webp, yet old code will still see the animated stickers as plain ones. tbot addresses this by adding a separate handler for animated stickers while the old handlers for stickers won't be fired.

Also, this release adds the is_animated field to types::sticker::Set. In the v0.2 release, this field will be instead replaced with an enum of sticker set kinds.

v0.1.1

18 Mar 04:33
Compare
Choose a tag to compare

The v0.1.1 release includes a bug fix of wrong parse mode serialization in multipart (!93).

v0.1

18 Mar 04:34
Compare
Choose a tag to compare

The initial release of tbot.