toptl-teloxide

Teloxide plugin for TOP.TL — autopost bot stats, gate handlers behind votes, and handle vote webhooks.
Install
[dependencies]
toptl-teloxide = "0.1"
teloxide = "0.13"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
Built on the toptl SDK.
Quick start
use std::time::Duration;
use teloxide::prelude::*;
use toptl::TopTL;
use toptl_teloxide::{record_update, TopTLPlugin};
#[tokio::main]
async fn main() {
let bot = Bot::from_env();
let client = TopTL::new("toptl_xxx");
let plugin = TopTLPlugin::new(client, "mybot");
plugin.start(Duration::from_secs(30 * 60));
let plugin_clone = plugin.clone();
teloxide::repl(bot, move |msg: Message, bot: Bot| {
let plugin = plugin_clone.clone();
async move {
record_update(&plugin, &msg).await;
bot.send_message(msg.chat.id, "hi").await?;
Ok::<_, teloxide::RequestError>(())
}
})
.await;
}
plugin.start(...) spawns a background task that flushes unique user/group/channel counts every interval. record_update(...) ingests one incoming message so the counters stay current.
Vote gating
async fn premium(msg: Message, bot: Bot, plugin: TopTLPlugin) -> ResponseResult<()> {
if let Some(user) = &msg.from {
if !plugin.has_voted(user.id.0 as i64).await {
bot.send_message(msg.chat.id, "Vote first: https://top.tl/mybot").await?;
return Ok(());
}
}
bot.send_message(msg.chat.id, "Thanks for voting!").await?;
Ok(())
}
has_voted is fail-open — network or auth errors count as "not voted" and log, never crash your handler.
Manual flush
Useful from a shutdown hook:
plugin.post_now().await?;
License
MIT — see LICENSE.