mirror of
https://github.com/flibusta-apps/telegram_files_cache_server.git
synced 2025-12-06 14:45:36 +01:00
Add copy message
This commit is contained in:
@@ -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
32
src/services/bots.rs
Normal 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()));
|
||||
@@ -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,
|
||||
|
||||
32
src/views.rs
32
src/views.rs
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user