mirror of
https://github.com/TheFunny/TelegramTwitterMediaBot.git
synced 2026-09-23 23:32:05 +00:00
rust refactor
This commit is contained in:
@@ -4,3 +4,10 @@ cert/
|
|||||||
data/
|
data/
|
||||||
docker-compose.yml
|
docker-compose.yml
|
||||||
utils/x.py
|
utils/x.py
|
||||||
|
|
||||||
|
.env
|
||||||
|
|
||||||
|
|
||||||
|
# Added by cargo
|
||||||
|
|
||||||
|
/target
|
||||||
|
|||||||
Generated
+2023
File diff suppressed because it is too large
Load Diff
+12
@@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "TelegramXMediaBot"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
dotenv = "0.15.0"
|
||||||
|
log = "0.4.22"
|
||||||
|
pretty_env_logger = "0.5.0"
|
||||||
|
teloxide = { version = "0.13.0", features = ["webhooks-axum", "macros"] }
|
||||||
|
tokio = { version = "1.40.0", features = ["rt-multi-thread", "macros"] }
|
||||||
|
url = "2.5.2"
|
||||||
+153
@@ -0,0 +1,153 @@
|
|||||||
|
use teloxide::types::{Message, Recipient, ReplyParameters};
|
||||||
|
use teloxide::utils::command::BotCommands;
|
||||||
|
use teloxide::{prelude::*, RequestError};
|
||||||
|
|
||||||
|
#[derive(BotCommands, Clone)]
|
||||||
|
#[command(rename_rule = "snake_case", description = "")]
|
||||||
|
enum Command {
|
||||||
|
#[command(description = "")]
|
||||||
|
Start,
|
||||||
|
#[command(description = "")]
|
||||||
|
Help,
|
||||||
|
#[command(description = "", parse_with = "split")]
|
||||||
|
SetForwardChannel(String),
|
||||||
|
#[command(description = "")]
|
||||||
|
RemoveForwardChannel,
|
||||||
|
#[command(description = "")]
|
||||||
|
EditBeforeForward,
|
||||||
|
#[command(description = "", parse_with = "split")]
|
||||||
|
SetTemplate(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn reply<T>(bot: Bot, message: Message, text: T) -> Result<Message, RequestError>
|
||||||
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
{
|
||||||
|
bot.send_message(message.chat.id, text)
|
||||||
|
.reply_parameters(ReplyParameters::new(message.id).allow_sending_without_reply())
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SetForwardChannelError {
|
||||||
|
EmptyParameter,
|
||||||
|
NotChannel,
|
||||||
|
NotAdmin,
|
||||||
|
NotBotAdmin(RequestError),
|
||||||
|
NotBotCanPost,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_forward_channel_handler(
|
||||||
|
bot: &Bot,
|
||||||
|
message: &Message,
|
||||||
|
channel: String,
|
||||||
|
) -> Result<String, SetForwardChannelError> {
|
||||||
|
if channel.is_empty() {
|
||||||
|
return Err(SetForwardChannelError::EmptyParameter);
|
||||||
|
}
|
||||||
|
let channel = match channel.parse::<i64>() {
|
||||||
|
Ok(id) => Recipient::Id(ChatId(id)),
|
||||||
|
Err(_) => Recipient::ChannelUsername(channel),
|
||||||
|
};
|
||||||
|
log::info!(
|
||||||
|
"Set forward channel for {} ({}) to {}",
|
||||||
|
message.from.clone().unwrap().full_name(),
|
||||||
|
message.chat.id,
|
||||||
|
channel
|
||||||
|
);
|
||||||
|
let channel_title = match bot.get_chat(channel.clone()).await {
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to get channel {}: {}", channel, e);
|
||||||
|
return Err(SetForwardChannelError::NotBotAdmin(e));
|
||||||
|
}
|
||||||
|
Ok(chat) => {
|
||||||
|
if !chat.is_channel() {
|
||||||
|
return Err(SetForwardChannelError::NotChannel);
|
||||||
|
}
|
||||||
|
chat.title().unwrap().to_string()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match bot.get_chat_administrators(channel.clone()).await {
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to get channel administrators {}: {}", channel, e);
|
||||||
|
return Err(SetForwardChannelError::NotBotAdmin(e));
|
||||||
|
}
|
||||||
|
Ok(chat) => {
|
||||||
|
if !chat.iter().any(|admin| admin.user.id == message.chat.id) {
|
||||||
|
return Err(SetForwardChannelError::NotAdmin);
|
||||||
|
}
|
||||||
|
let bot_id = bot.get_me().await.expect("Failed get bot id").user.id;
|
||||||
|
if let Some(bot_user) = chat.iter().find(|&admin| admin.user.id == bot_id) {
|
||||||
|
if !bot_user.can_post_messages() {
|
||||||
|
return Err(SetForwardChannelError::NotBotCanPost);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(channel_title)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn message_handler(bot: Bot, message: Message) -> Result<(), RequestError> {
|
||||||
|
let text = message.text();
|
||||||
|
if text.is_none() {
|
||||||
|
log::info!("Received a message without text");
|
||||||
|
return respond(());
|
||||||
|
}
|
||||||
|
bot.send_chat_action(message.chat.id, teloxide::types::ChatAction::Typing)
|
||||||
|
.await?;
|
||||||
|
if let Ok(command) = Command::parse(text.unwrap(), "") {
|
||||||
|
match command {
|
||||||
|
Command::Start => {
|
||||||
|
bot.send_message(message.chat.id, "Hello!").await?;
|
||||||
|
}
|
||||||
|
Command::Help => {
|
||||||
|
bot.send_message(message.chat.id, Command::descriptions().to_string())
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
Command::SetForwardChannel(channel) => {
|
||||||
|
let result = match set_forward_channel_handler(&bot, &message, channel).await {
|
||||||
|
Ok(title) => format!("Set forward channel to {}", title),
|
||||||
|
Err(SetForwardChannelError::EmptyParameter) => {
|
||||||
|
"Receive empty parameter.\nYou should enter a channel id or username"
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
Err(SetForwardChannelError::NotChannel) => {
|
||||||
|
"Given id / username is not a channel".to_string()
|
||||||
|
}
|
||||||
|
Err(SetForwardChannelError::NotAdmin) => {
|
||||||
|
"You are not an administrator of the channel".to_string()
|
||||||
|
}
|
||||||
|
Err(SetForwardChannelError::NotBotAdmin(e)) => {
|
||||||
|
e.to_string() + "\nPlease add the bot as an admin to the channel"
|
||||||
|
}
|
||||||
|
Err(SetForwardChannelError::NotBotCanPost) => {
|
||||||
|
"Bot can't post messages to the channel".to_string()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reply(bot, message, result).await?;
|
||||||
|
}
|
||||||
|
Command::RemoveForwardChannel => {
|
||||||
|
log::info!(
|
||||||
|
"Remove forward channel for {} ({})",
|
||||||
|
message.from.unwrap().full_name(),
|
||||||
|
message.chat.id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Command::EditBeforeForward => {
|
||||||
|
log::info!(
|
||||||
|
"Enable edit before forward for {} ({})",
|
||||||
|
message.from.unwrap().full_name(),
|
||||||
|
message.chat.id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Command::SetTemplate(template) => {
|
||||||
|
log::info!(
|
||||||
|
"Set template {} for {} ({})",
|
||||||
|
template,
|
||||||
|
message.from.unwrap().full_name(),
|
||||||
|
message.chat.id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
respond(())
|
||||||
|
}
|
||||||
+68
@@ -0,0 +1,68 @@
|
|||||||
|
use crate::handlers::message_handler;
|
||||||
|
use dotenv::dotenv;
|
||||||
|
use std::env;
|
||||||
|
use std::net::IpAddr;
|
||||||
|
use teloxide::dptree::endpoint;
|
||||||
|
use teloxide::types::InputFile;
|
||||||
|
use teloxide::{prelude::*, update_listeners::webhooks};
|
||||||
|
|
||||||
|
mod handlers;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
dotenv().ok();
|
||||||
|
pretty_env_logger::init();
|
||||||
|
log::info!("Starting bot");
|
||||||
|
|
||||||
|
let bot = Bot::from_env();
|
||||||
|
|
||||||
|
let handler =
|
||||||
|
dptree::entry().branch(Update::filter_message().branch(endpoint(message_handler)));
|
||||||
|
|
||||||
|
let mut dispatcher = Dispatcher::builder(bot.clone(), handler)
|
||||||
|
.dependencies(dptree::deps![""])
|
||||||
|
.enable_ctrlc_handler()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
match env::var("WEBHOOK") {
|
||||||
|
Ok(v) if v.parse::<bool>().unwrap_or(false) => {
|
||||||
|
let url: url::Url = env::var("WEBHOOK_URL")
|
||||||
|
.expect("WEBHOOK_URL is not set")
|
||||||
|
.parse()
|
||||||
|
.expect("Failed to parse WEBHOOK_URL");
|
||||||
|
bot.set_webhook(url.clone()).await.unwrap();
|
||||||
|
let mut options = webhooks::Options::new(
|
||||||
|
(
|
||||||
|
env::var("WEBHOOK_LISTEN")
|
||||||
|
.expect("WEBHOOK_LISTEN is not set")
|
||||||
|
.parse::<IpAddr>()
|
||||||
|
.expect("Failed to parse WEBHOOK_LISTEN"),
|
||||||
|
env::var("WEBHOOK_PORT")
|
||||||
|
.expect("WEBHOOK_PORT is not set")
|
||||||
|
.parse()
|
||||||
|
.expect("Failed to parse WEBHOOK_PORT"),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
url,
|
||||||
|
);
|
||||||
|
if let Ok(cert) = env::var("WEBHOOK_CERT") {
|
||||||
|
options = options.certificate(InputFile::file(cert));
|
||||||
|
}
|
||||||
|
if let Ok(secret) = env::var("WEBHOOK_SECRET_TOKEN") {
|
||||||
|
options = options.secret_token(secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatcher
|
||||||
|
.dispatch_with_listener(
|
||||||
|
webhooks::axum(bot.clone(), options)
|
||||||
|
.await
|
||||||
|
.expect("Failed to create webhook listener"),
|
||||||
|
LoggingErrorHandler::with_custom_text("Error from update listener"),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
dispatcher.dispatch().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user