mirror of
https://github.com/teloxide/teloxide.git
synced 2024-12-22 06:25:10 +01:00
Refactor
This commit is contained in:
parent
c9f811a311
commit
42e2f3fb42
14 changed files with 164 additions and 130 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -3,7 +3,7 @@
|
|||
Cargo.lock
|
||||
.idea/
|
||||
.vscode/
|
||||
examples/target
|
||||
examples/ping_pong_bot/target
|
||||
examples/dialogue_bot/target
|
||||
examples/multiple_handlers_bot/target
|
||||
examples/multiple_handlers_bot/target
|
||||
examples/commands_bot/target
|
|
@ -14,7 +14,6 @@ tokio-util = { version = "0.2.0", features = ["full"] }
|
|||
|
||||
reqwest = { version = "0.10", features = ["json", "stream", "native-tls-vendored"] }
|
||||
log = "0.4.8"
|
||||
pretty_env_logger = "0.4.0"
|
||||
bytes = "0.5.3"
|
||||
mime = "0.3.16"
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "admin_bot"
|
||||
name = "commands_bot"
|
||||
version = "0.1.0"
|
||||
authors = ["p0lunin <dmytro.polunin@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
@ -9,6 +9,7 @@ edition = "2018"
|
|||
[dependencies]
|
||||
log = "0.4.8"
|
||||
tokio = "0.2.9"
|
||||
pretty_env_logger = "0.4.0"
|
||||
teloxide = { path = "../../" }
|
||||
|
||||
[profile.release]
|
|
@ -1,15 +1,19 @@
|
|||
use teloxide::prelude::*;
|
||||
use teloxide::utils::command::BotCommand;
|
||||
use teloxide::types::ChatPermissions;
|
||||
use teloxide::{
|
||||
prelude::*, types::ChatPermissions, utils::command::BotCommand,
|
||||
};
|
||||
|
||||
// Declare type of handler context
|
||||
type Ctx = DispatcherHandlerCtx<Message>;
|
||||
|
||||
// Derive trait which allow to parse text with command into enum
|
||||
// (rename = "lowercase") means that names of variants of enum will be lowercase before parsing
|
||||
// `description` will be add before description of command when you call Command::descriptions()
|
||||
// (rename = "lowercase") means that names of variants of enum will be lowercase
|
||||
// before parsing `description` will be add before description of command when
|
||||
// you call Command::descriptions()
|
||||
#[derive(BotCommand)]
|
||||
#[command(rename = "lowercase", description = "Use commands in format /%command% %num% %unit%")]
|
||||
#[command(
|
||||
rename = "lowercase",
|
||||
description = "Use commands in format /%command% %num% %unit%"
|
||||
)]
|
||||
enum Command {
|
||||
#[command(description = "kick user from chat.")]
|
||||
Kick,
|
||||
|
@ -24,10 +28,10 @@ enum Command {
|
|||
// Calculate time of restrict user.
|
||||
fn calc_restrict_time(num: i32, unit: &str) -> Result<i32, &str> {
|
||||
match unit {
|
||||
"h"|"hours" => Ok(num * 3600),
|
||||
"m"|"minutes" => Ok(num * 60),
|
||||
"s"|"seconds" => Ok(num),
|
||||
_ => Err("Allowed units: h, m, s")
|
||||
"h" | "hours" => Ok(num * 3600),
|
||||
"m" | "minutes" => Ok(num * 60),
|
||||
"s" | "seconds" => Ok(num),
|
||||
_ => Err("Allowed units: h, m, s"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,7 +43,7 @@ fn parse_args(args: Vec<&str>) -> Result<(i32, &str), &str> {
|
|||
};
|
||||
let unit = match args.get(1) {
|
||||
Some(s) => s,
|
||||
None => return Err("Use command in format /%command% %num% %unit%")
|
||||
None => return Err("Use command in format /%command% %num% %unit%"),
|
||||
};
|
||||
|
||||
match num.parse::<i32>() {
|
||||
|
@ -60,12 +64,14 @@ async fn mute_user(ctx: &Ctx, args: Vec<&str>) -> Result<(), RequestError> {
|
|||
Some(mes) => match parse_time_restrict(args) {
|
||||
// Mute user temporarily...
|
||||
Ok(time) => {
|
||||
ctx.bot.restrict_chat_member(
|
||||
ctx.bot
|
||||
.restrict_chat_member(
|
||||
ctx.update.chat_id(),
|
||||
// Sender of message cannot be only in messages from channels
|
||||
// so we can use unwrap()
|
||||
// Sender of message cannot be only in messages from
|
||||
// channels so we can use
|
||||
// unwrap()
|
||||
mes.from().unwrap().id,
|
||||
ChatPermissions::default()
|
||||
ChatPermissions::default(),
|
||||
)
|
||||
.until_date(ctx.update.date + time)
|
||||
.send()
|
||||
|
@ -73,18 +79,21 @@ async fn mute_user(ctx: &Ctx, args: Vec<&str>) -> Result<(), RequestError> {
|
|||
}
|
||||
// ...or permanently
|
||||
Err(msg) => {
|
||||
ctx.bot.restrict_chat_member(
|
||||
ctx.bot
|
||||
.restrict_chat_member(
|
||||
ctx.update.chat_id(),
|
||||
mes.from().unwrap().id,
|
||||
ChatPermissions::default()
|
||||
ChatPermissions::default(),
|
||||
)
|
||||
.send()
|
||||
.await?;
|
||||
}
|
||||
},
|
||||
None => {
|
||||
ctx.reply_to("Use this command in reply to another message").send().await?;
|
||||
},
|
||||
ctx.reply_to("Use this command in reply to another message")
|
||||
.send()
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -94,13 +103,15 @@ async fn kick_user(ctx: &Ctx) -> Result<(), RequestError> {
|
|||
match ctx.update.reply_to_message() {
|
||||
Some(mes) => {
|
||||
// `unban_chat_member` will also kick user from group chat
|
||||
ctx.bot.unban_chat_member(
|
||||
ctx.update.chat_id(),
|
||||
mes.from().unwrap().id
|
||||
).send().await?;
|
||||
},
|
||||
ctx.bot
|
||||
.unban_chat_member(ctx.update.chat_id(), mes.from().unwrap().id)
|
||||
.send()
|
||||
.await?;
|
||||
}
|
||||
None => {
|
||||
ctx.reply_to("Use this command in reply to another message").send().await?;
|
||||
ctx.reply_to("Use this command in reply to another message")
|
||||
.send()
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
@ -112,27 +123,31 @@ async fn ban_user(ctx: &Ctx, args: Vec<&str>) -> Result<(), RequestError> {
|
|||
Some(mes) => match parse_time_restrict(args) {
|
||||
// Mute user temporarily...
|
||||
Ok(time) => {
|
||||
ctx.bot.kick_chat_member(
|
||||
ctx.update.chat_id(),
|
||||
mes.from().unwrap().id
|
||||
)
|
||||
ctx.bot
|
||||
.kick_chat_member(
|
||||
ctx.update.chat_id(),
|
||||
mes.from().unwrap().id,
|
||||
)
|
||||
.until_date(ctx.update.date + time)
|
||||
.send()
|
||||
.await?;
|
||||
}
|
||||
// ...or permanently
|
||||
Err(msg) => {
|
||||
ctx.bot.kick_chat_member(
|
||||
ctx.update.chat_id(),
|
||||
mes.from().unwrap().id
|
||||
)
|
||||
ctx.bot
|
||||
.kick_chat_member(
|
||||
ctx.update.chat_id(),
|
||||
mes.from().unwrap().id,
|
||||
)
|
||||
.send()
|
||||
.await?;
|
||||
},
|
||||
}
|
||||
},
|
||||
None => {
|
||||
ctx.reply_to("Use this command in reply to another message").send().await?;
|
||||
},
|
||||
ctx.reply_to("Use this command in reply to another message")
|
||||
.send()
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -140,8 +155,9 @@ async fn ban_user(ctx: &Ctx, args: Vec<&str>) -> Result<(), RequestError> {
|
|||
// Handle all messages
|
||||
async fn handle_command(ctx: Ctx) -> Result<(), RequestError> {
|
||||
// If message not from group stop handled.
|
||||
// NOTE: in this case we have only one `message_handler`. If you have more, return
|
||||
// DispatcherHandlerResult::next() so that the following handlers can receive this message!
|
||||
// NOTE: in this case we have only one `message_handler`. If you have more,
|
||||
// return DispatcherHandlerResult::next() so that the following handlers
|
||||
// can receive this message!
|
||||
if ctx.update.chat.is_group() {
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -150,7 +166,7 @@ async fn handle_command(ctx: Ctx) -> Result<(), RequestError> {
|
|||
// Parse text into command with args
|
||||
let (command, args): (Command, Vec<&str>) = match Command::parse(text) {
|
||||
Some(tuple) => tuple,
|
||||
None => return Ok(())
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
match command {
|
||||
|
@ -178,7 +194,11 @@ async fn handle_command(ctx: Ctx) -> Result<(), RequestError> {
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let bot = Bot::from_env().enable_logging(crate_name!()).build();
|
||||
teloxide::enable_logging!();
|
||||
log::info!("Starting commands_bot!");
|
||||
|
||||
let bot = Bot::from_env();
|
||||
|
||||
Dispatcher::new(bot)
|
||||
.message_handler(&handle_command)
|
||||
.dispatch()
|
|
@ -9,6 +9,7 @@ edition = "2018"
|
|||
[dependencies]
|
||||
log = "0.4.8"
|
||||
tokio = "0.2.9"
|
||||
pretty_env_logger = "0.4.0"
|
||||
smart-default = "0.6.0"
|
||||
parse-display = "0.1.1"
|
||||
teloxide = { path = "../../" }
|
||||
|
|
|
@ -177,9 +177,11 @@ async fn main() {
|
|||
}
|
||||
|
||||
async fn run() {
|
||||
let bot = Bot::from_env().enable_logging(crate_name!()).build();
|
||||
teloxide::enable_logging!();
|
||||
log::info!("Starting dialogue_bot!");
|
||||
|
||||
let bot = Bot::from_env();
|
||||
|
||||
Dispatcher::new(bot)
|
||||
.message_handler(&DialogueDispatcher::new(|ctx| async move {
|
||||
handle_message(ctx)
|
||||
|
|
|
@ -9,4 +9,5 @@ edition = "2018"
|
|||
[dependencies]
|
||||
log = "0.4.8"
|
||||
tokio = "0.2.9"
|
||||
pretty_env_logger = "0.4.0"
|
||||
teloxide = { path = "../../" }
|
|
@ -6,9 +6,11 @@ async fn main() {
|
|||
}
|
||||
|
||||
async fn run() {
|
||||
let bot = Bot::from_env().enable_logging(crate_name!()).build();
|
||||
teloxide::enable_logging!();
|
||||
log::info!("Starting multiple_handlers_bot!");
|
||||
|
||||
let bot = Bot::from_env();
|
||||
|
||||
// Create a dispatcher with multiple handlers of different types. This will
|
||||
// print One! and Two! on every incoming UpdateKind::Message.
|
||||
Dispatcher::<RequestError>::new(bot)
|
||||
|
|
|
@ -9,6 +9,7 @@ edition = "2018"
|
|||
[dependencies]
|
||||
log = "0.4.8"
|
||||
tokio = "0.2.9"
|
||||
pretty_env_logger = "0.4.0"
|
||||
teloxide = { path = "../../" }
|
||||
|
||||
[profile.release]
|
||||
|
|
|
@ -6,9 +6,11 @@ async fn main() {
|
|||
}
|
||||
|
||||
async fn run() {
|
||||
let bot = Bot::from_env().enable_logging(crate_name!()).build();
|
||||
teloxide::enable_logging!();
|
||||
log::info!("Starting ping_pong_bot!");
|
||||
|
||||
let bot = Bot::from_env();
|
||||
|
||||
// Create a dispatcher with a single message handler that answers "pong" to
|
||||
// each incoming message.
|
||||
Dispatcher::<RequestError>::new(bot)
|
||||
|
|
109
src/bot/mod.rs
109
src/bot/mod.rs
|
@ -1,5 +1,3 @@
|
|||
use log::LevelFilter;
|
||||
use pretty_env_logger::env_logger::WriteStyle;
|
||||
use reqwest::Client;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -14,92 +12,57 @@ pub struct Bot {
|
|||
}
|
||||
|
||||
impl Bot {
|
||||
/// Returns [`BotBuilder`] from the `TELOXIDE_TOKEN` environmental variable
|
||||
/// (a bot's token).
|
||||
/// Creates a new `Bot` with the `TELOXIDE_TOKEN` environmental variable (a
|
||||
/// bot's token) and the default [`reqwest::Client`].
|
||||
///
|
||||
/// # Panics
|
||||
/// If cannot get the `TELOXIDE_TOKEN` environmental variable.
|
||||
///
|
||||
/// [`BotBuilder`]: crate::BotBuilder
|
||||
pub fn from_env() -> BotBuilder {
|
||||
BotBuilder {
|
||||
token: std::env::var("TELOXIDE_TOKEN")
|
||||
/// [`reqwest::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html
|
||||
pub fn from_env() -> Arc<Self> {
|
||||
Self::new(
|
||||
std::env::var("TELOXIDE_TOKEN")
|
||||
.expect("Cannot get the TELOXIDE_TOKEN env variable"),
|
||||
client: None,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns [`BotBuilder`] with the specified token.
|
||||
/// Creates a new `Bot` with the `TELOXIDE_TOKEN` environmental variable (a
|
||||
/// bot's token) and your [`reqwest::Client`].
|
||||
///
|
||||
/// [`BotBuilder`]: crate::BotBuilder
|
||||
pub fn new<S>(token: S) -> BotBuilder
|
||||
/// # Panics
|
||||
/// If cannot get the `TELOXIDE_TOKEN` environmental variable.
|
||||
///
|
||||
/// [`reqwest::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html
|
||||
pub fn from_env_with_client(client: Client) -> Arc<Self> {
|
||||
Self::with_client(
|
||||
std::env::var("TELOXIDE_TOKEN")
|
||||
.expect("Cannot get the TELOXIDE_TOKEN env variable"),
|
||||
client,
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a new `Bot` with the specified token and the default
|
||||
/// [`reqwest::Client`].
|
||||
///
|
||||
/// [`reqwest::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html
|
||||
pub fn new<S>(token: S) -> Arc<Self>
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
BotBuilder {
|
||||
token: token.into(),
|
||||
client: None,
|
||||
}
|
||||
Self::with_client(token, Client::new())
|
||||
}
|
||||
}
|
||||
|
||||
/// Used to build [`Bot`].
|
||||
///
|
||||
/// [`Bot`]: crate::Bot
|
||||
pub struct BotBuilder {
|
||||
token: String,
|
||||
client: Option<Client>,
|
||||
}
|
||||
|
||||
impl BotBuilder {
|
||||
/// Sets your custom [`reqwest::Client`] (teloxide will make all requests
|
||||
/// using it).
|
||||
/// Creates a new `Bot` with the specified token and your
|
||||
/// [`reqwest::Client`].
|
||||
///
|
||||
/// [`reqwest::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html
|
||||
pub fn client(mut self, client: Client) -> Self {
|
||||
self.client = Some(client);
|
||||
self
|
||||
}
|
||||
|
||||
/// Enables logging through [pretty-env-logger].
|
||||
///
|
||||
/// A logger will **only** print errors from teloxide and **all** logs from
|
||||
/// your program.
|
||||
///
|
||||
/// [pretty-env-logger]: https://crates.io/crates/pretty_env_logger
|
||||
pub fn enable_logging(self, crate_name: &'static str) -> Self {
|
||||
Self::enable_logging_with_filter(self, crate_name, LevelFilter::Trace)
|
||||
}
|
||||
|
||||
/// Enables logging through [pretty-env-logger].
|
||||
///
|
||||
/// A logger will **only** print errors from teloxide and restrict logs from
|
||||
/// your program by the specified filter.
|
||||
///
|
||||
/// [pretty-env-logger]: https://crates.io/crates/pretty_env_logger
|
||||
pub fn enable_logging_with_filter(
|
||||
self,
|
||||
crate_name: &'static str,
|
||||
filter: LevelFilter,
|
||||
) -> Self {
|
||||
pretty_env_logger::formatted_builder()
|
||||
.write_style(WriteStyle::Auto)
|
||||
.filter(Some(crate_name), filter)
|
||||
.filter(Some("teloxide"), LevelFilter::Error)
|
||||
.init();
|
||||
self
|
||||
}
|
||||
|
||||
/// Builds [`Bot`].
|
||||
///
|
||||
/// Sets the default [`request::Client`] if you haven't specified yours.
|
||||
///
|
||||
/// [`request::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html
|
||||
/// [`Bot`]: crate::Bot
|
||||
pub fn build(self) -> Arc<Bot> {
|
||||
Arc::new(Bot {
|
||||
token: self.token,
|
||||
client: self.client.unwrap_or(Client::new()),
|
||||
pub fn with_client<S>(token: S, client: Client) -> Arc<Self>
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
Arc::new(Self {
|
||||
token: token.into(),
|
||||
client,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
11
src/lib.rs
11
src/lib.rs
|
@ -4,7 +4,7 @@
|
|||
)]
|
||||
#![allow(clippy::match_bool)]
|
||||
|
||||
pub use bot::{Bot, BotBuilder};
|
||||
pub use bot::Bot;
|
||||
pub use errors::{ApiErrorKind, DownloadError, RequestError};
|
||||
|
||||
mod errors;
|
||||
|
@ -12,17 +12,10 @@ mod net;
|
|||
|
||||
mod bot;
|
||||
pub mod dispatching;
|
||||
mod logging;
|
||||
pub mod prelude;
|
||||
pub mod requests;
|
||||
pub mod types;
|
||||
pub mod utils;
|
||||
|
||||
extern crate teloxide_macros;
|
||||
|
||||
/// Expands to a name of your crate.
|
||||
#[macro_export]
|
||||
macro_rules! crate_name {
|
||||
() => {
|
||||
env!("CARGO_PKG_NAME")
|
||||
};
|
||||
}
|
||||
|
|
50
src/logging.rs
Normal file
50
src/logging.rs
Normal file
|
@ -0,0 +1,50 @@
|
|||
/// Enables logging through [pretty-env-logger].
|
||||
///
|
||||
/// A logger will **only** print errors from teloxide and **all** logs from
|
||||
/// your program.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// teloxide::enable_logging!();
|
||||
/// ```
|
||||
///
|
||||
/// # Note
|
||||
/// Calling this macro **is not mandatory**; you can setup if your own logger if
|
||||
/// you want.
|
||||
///
|
||||
/// [pretty-env-logger]: https://crates.io/crates/pretty_env_logger
|
||||
#[macro_export]
|
||||
macro_rules! enable_logging {
|
||||
() => {
|
||||
teloxide::enable_logging_with_filter!(log::LevelFilter::Trace);
|
||||
};
|
||||
}
|
||||
|
||||
/// Enables logging through [pretty-env-logger].
|
||||
///
|
||||
/// A logger will **only** print errors from teloxide and restrict logs from
|
||||
/// your program by the specified filter.
|
||||
///
|
||||
/// # Example
|
||||
/// Allow printing all logs from your program up to [`LevelFilter::Debug`] (i.e.
|
||||
/// do not print traces):
|
||||
///
|
||||
/// ```
|
||||
/// teloxide::enable_logging_with_filter!(log::LevelFilter::Debug);
|
||||
/// ```
|
||||
///
|
||||
/// # Note
|
||||
/// Calling this macro **is not mandatory**; you can setup if your own logger if
|
||||
/// you want.
|
||||
///
|
||||
/// [pretty-env-logger]: https://crates.io/crates/pretty_env_logger
|
||||
#[macro_export]
|
||||
macro_rules! enable_logging_with_filter {
|
||||
($filter:expr) => {
|
||||
pretty_env_logger::formatted_builder()
|
||||
.write_style(pretty_env_logger::env_logger::WriteStyle::Auto)
|
||||
.filter(Some(env!("CARGO_PKG_NAME")), $filter)
|
||||
.filter(Some("teloxide"), log::LevelFilter::Error)
|
||||
.init();
|
||||
};
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
//! Commonly used items.
|
||||
|
||||
pub use crate::{
|
||||
crate_name,
|
||||
dispatching::{
|
||||
dialogue::{
|
||||
exit, next, DialogueDispatcher, DialogueHandlerCtx, DialogueStage,
|
||||
|
|
Loading…
Reference in a new issue