Add copy message

This commit is contained in:
2024-05-05 14:56:38 +02:00
parent 3b565e693a
commit 6aa0d2d4bb
6 changed files with 596 additions and 20 deletions

View File

@@ -24,6 +24,9 @@ pub struct Config {
pub files_api_key: String,
pub files_url: String,
pub bot_tokens: Vec<String>,
pub temp_channel_username: String,
pub sentry_dsn: String,
}
@@ -57,6 +60,9 @@ impl Config {
files_api_key: get_env("FILES_SERVER_API_KEY"),
files_url: get_env("FILES_SERVER_URL"),
bot_tokens: serde_json::from_str(&get_env("BOT_TOKENS")).unwrap(),
temp_channel_username: get_env("TEMP_CHANNEL_USERNAME"),
sentry_dsn: get_env("SENTRY_DSN"),
}
}

32
src/services/bots.rs Normal file
View File

@@ -0,0 +1,32 @@
use std::sync::{
atomic::{AtomicUsize, Ordering},
Arc,
};
use once_cell::sync::Lazy;
use teloxide::Bot;
use crate::config;
pub struct RoundRobinBot {
bot_tokens: Arc<Vec<String>>,
current_index: AtomicUsize,
}
impl RoundRobinBot {
pub fn new(bot_tokens: Vec<String>) -> Self {
RoundRobinBot {
bot_tokens: Arc::new(bot_tokens),
current_index: AtomicUsize::new(0),
}
}
pub fn get_bot(&self) -> Bot {
let index = self.current_index.fetch_add(1, Ordering::Relaxed) % self.bot_tokens.len();
Bot::new(self.bot_tokens[index].clone())
}
}
pub static ROUND_ROBIN_BOT: Lazy<RoundRobinBot> =
Lazy::new(|| RoundRobinBot::new(config::CONFIG.bot_tokens.clone()));

View File

@@ -1,23 +1,59 @@
pub mod book_library;
pub mod bots;
pub mod download_utils;
pub mod downloader;
pub mod minio;
pub mod telegram_files;
use chrono::Duration;
use moka::future::Cache;
use once_cell::sync::Lazy;
use serde::Serialize;
use teloxide::{
requests::Requester,
types::{ChatId, MessageId},
};
use tracing::log;
use crate::{prisma::cached_file, views::Database};
use crate::{
config::{self},
prisma::cached_file,
views::Database,
};
use self::{
book_library::{get_book, get_books, types::BaseBook},
bots::ROUND_ROBIN_BOT,
download_utils::{response_to_tempfile, DownloadResult},
downloader::{download_from_downloader, get_filename, FilenameData},
minio::upload_to_minio,
telegram_files::{download_from_telegram_files, upload_to_telegram_files, UploadData},
};
#[derive(Serialize)]
pub struct CacheData {
pub id: Option<i32>,
pub object_id: i32,
pub object_type: String,
pub message_id: i32,
pub chat_id: String,
}
pub static CHAT_DONATION_NOTIFICATIONS_CACHE: Lazy<Cache<i32, MessageId>> = Lazy::new(|| {
Cache::builder()
.time_to_idle(std::time::Duration::from_secs(16))
.max_capacity(4098)
.async_eviction_listener(|_data_id, message_id, _cause| {
Box::pin(async move {
let bot = ROUND_ROBIN_BOT.get_bot();
let _ = bot
.delete_message(config::CONFIG.temp_channel_username.to_string(), message_id)
.await;
})
})
.build()
});
pub async fn get_cached_file_or_cache(
object_id: i32,
object_type: String,
@@ -39,6 +75,53 @@ pub async fn get_cached_file_or_cache(
}
}
pub async fn get_cached_file_copy(original: cached_file::Data, db: Database) -> CacheData {
let bot = ROUND_ROBIN_BOT.get_bot();
let message_id = match bot
.copy_message(
config::CONFIG.temp_channel_username.to_string(),
ChatId(original.chat_id),
MessageId(original.message_id.try_into().unwrap()),
)
.await
{
Ok(v) => v,
Err(_) => {
let _ = db
.cached_file()
.delete(cached_file::id::equals(original.id))
.exec()
.await;
let new_original =
get_cached_file_or_cache(original.object_id, original.object_type.clone(), db)
.await
.unwrap();
bot.copy_message(
config::CONFIG.temp_channel_username.to_string(),
ChatId(new_original.chat_id),
MessageId(new_original.message_id.try_into().unwrap()),
)
.await
.unwrap()
}
};
CHAT_DONATION_NOTIFICATIONS_CACHE
.insert(original.id, message_id)
.await;
CacheData {
id: None,
object_id: original.object_id,
object_type: original.object_type,
message_id: message_id.0,
chat_id: config::CONFIG.temp_channel_username.to_string(),
}
}
pub async fn cache_file(
object_id: i32,
object_type: String,

View File

@@ -1,6 +1,6 @@
use axum::{
body::Body,
extract::Path,
extract::{Path, Query},
http::{self, header, Request, StatusCode},
middleware::{self, Next},
response::{AppendHeaders, IntoResponse, Response},
@@ -9,6 +9,7 @@ use axum::{
};
use axum_prometheus::PrometheusMetricLayer;
use base64::{engine::general_purpose, Engine};
use serde::Deserialize;
use std::sync::Arc;
use tokio_util::io::ReaderStream;
use tower_http::trace::{self, TraceLayer};
@@ -17,13 +18,10 @@ use tracing::{log, Level};
use crate::{
config::CONFIG,
db::get_prisma_client,
prisma::{
cached_file::{self},
PrismaClient,
},
prisma::{cached_file, PrismaClient},
services::{
download_from_cache, download_utils::get_response_async_read, get_cached_file_or_cache,
get_download_link, start_update_cache,
download_from_cache, download_utils::get_response_async_read, get_cached_file_copy,
get_cached_file_or_cache, get_download_link, start_update_cache, CacheData,
},
};
@@ -31,14 +29,28 @@ pub type Database = Arc<PrismaClient>;
//
#[derive(Deserialize)]
pub struct GetCachedFileQuery {
pub copy: bool,
}
async fn get_cached_file(
Path((object_id, object_type)): Path<(i32, String)>,
Query(GetCachedFileQuery { copy }): Query<GetCachedFileQuery>,
Extension(Ext { db, .. }): Extension<Ext>,
) -> impl IntoResponse {
match get_cached_file_or_cache(object_id, object_type, db).await {
Some(cached_file) => Json(cached_file).into_response(),
None => StatusCode::NOT_FOUND.into_response(),
let cached_file = match get_cached_file_or_cache(object_id, object_type, db.clone()).await {
Some(cached_file) => cached_file,
None => return StatusCode::NOT_FOUND.into_response(),
};
if !copy {
return Json(cached_file).into_response();
}
let copy_file: CacheData = get_cached_file_copy(cached_file, db).await;
Json(copy_file).into_response()
}
async fn download_cached_file(