Add get link handler

This commit is contained in:
2023-08-15 21:39:26 +02:00
parent 7bb39281d2
commit 2b1f03c076
7 changed files with 313 additions and 7 deletions

View File

@@ -1,5 +1,9 @@
use std::io::{Write, Seek, SeekFrom};
use bytes::Buf;
use futures::TryStreamExt;
use reqwest::Response;
use tempfile::SpooledTempFile;
use tokio::io::AsyncRead;
use tokio_util::compat::FuturesAsyncReadCompatExt;
@@ -17,3 +21,36 @@ pub fn get_response_async_read(it: Response) -> impl AsyncRead {
.into_async_read()
.compat()
}
pub async fn response_to_tempfile(res: &mut Response) -> Option<(SpooledTempFile, usize)> {
let mut tmp_file = tempfile::spooled_tempfile(5 * 1024 * 1024);
let mut data_size: usize = 0;
{
loop {
let chunk = res.chunk().await;
let result = match chunk {
Ok(v) => v,
Err(_) => return None,
};
let data = match result {
Some(v) => v,
None => break,
};
data_size += data.len();
match tmp_file.write(data.chunk()) {
Ok(_) => (),
Err(_) => return None,
}
}
tmp_file.seek(SeekFrom::Start(0)).unwrap();
}
Some((tmp_file, data_size))
}

73
src/services/minio.rs Normal file
View File

@@ -0,0 +1,73 @@
use std::io::Read;
use async_stream::stream;
use bytes::Bytes;
use minio_rsc::{provider::StaticProvider, Minio, types::args::{ObjectArgs, PresignedArgs}, errors::MinioError};
use tempfile::SpooledTempFile;
use crate::config;
pub fn get_minio() -> Minio {
let provider = StaticProvider::new(
&config::CONFIG.minio_access_key,
&config::CONFIG.minio_secret_key,
None
);
Minio::builder()
.host(&config::CONFIG.minio_host)
.provider(provider)
.secure(false)
.build()
.unwrap()
}
pub fn get_stream(mut temp_file: Box<dyn Read + Send>) -> impl futures_core::Stream<Item = Result<Bytes, MinioError>> {
stream! {
let mut buf = [0; 2048];
while let Ok(count) = temp_file.read(&mut buf) {
if count == 0 {
break;
}
yield Ok(Bytes::copy_from_slice(&buf[0..count]))
}
}
}
pub async fn upload_to_minio(archive: SpooledTempFile, filename: String) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
let minio = get_minio();
let is_bucket_exist = match minio.bucket_exists(&config::CONFIG.minio_bucket).await {
Ok(v) => v,
Err(err) => return Err(Box::new(err)),
};
if !is_bucket_exist {
let _ = minio.make_bucket(&config::CONFIG.minio_bucket, false).await;
}
let data_stream = get_stream(Box::new(archive));
if let Err(err) = minio.put_object_stream(
ObjectArgs::new(&config::CONFIG.minio_bucket, filename.clone()),
Box::pin(data_stream)
).await {
return Err(Box::new(err));
}
let link = match minio.presigned_get_object(
PresignedArgs::new(&config::CONFIG.minio_bucket, filename)
).await {
Ok(v) => v,
Err(err) => {
return Err(Box::new(err));
},
};
Ok(link)
}

View File

@@ -2,13 +2,15 @@ pub mod book_library;
pub mod download_utils;
pub mod telegram_files;
pub mod downloader;
pub mod minio;
use chrono::Duration;
use serde::Serialize;
use tracing::log;
use crate::{prisma::cached_file, views::Database};
use self::{download_utils::DownloadResult, telegram_files::{download_from_telegram_files, UploadData, upload_to_telegram_files}, downloader::{get_filename, FilenameData, download_from_downloader}, book_library::{get_book, types::BaseBook, get_books}};
use self::{download_utils::{DownloadResult, response_to_tempfile}, telegram_files::{download_from_telegram_files, UploadData, upload_to_telegram_files}, downloader::{get_filename, FilenameData, download_from_downloader}, book_library::{get_book, types::BaseBook, get_books}, minio::upload_to_minio};
pub async fn get_cached_file_or_cache(
@@ -131,6 +133,49 @@ pub async fn download_from_cache(
})
}
#[derive(Serialize)]
pub struct FileLinkResult {
pub link: String,
pub filename: String,
pub filename_ascii: String,
pub caption: String
}
pub async fn get_download_link(
object_id: i32,
object_type: String,
db: Database
) -> Result<Option<FileLinkResult>, Box<dyn std::error::Error + Send + Sync>> {
let cached_file = match get_cached_file_or_cache(object_id, object_type, db.clone()).await {
Some(v) => v,
None => return Ok(None),
};
let data = match download_from_cache(cached_file, db).await {
Some(v) => v,
None => return Ok(None),
};
let DownloadResult { mut response, filename, filename_ascii, caption } = data;
let tempfile = match response_to_tempfile(&mut response).await {
Some(v) => v.0,
None => return Ok(None),
};
let link = match upload_to_minio(tempfile, filename.clone()).await {
Ok(v) => v,
Err(err) => return Err(err),
};
Ok(Some(FileLinkResult {
link,
filename,
filename_ascii,
caption
}))
}
pub async fn get_books_for_update() -> Result<Vec<BaseBook>, Box<dyn std::error::Error + Send + Sync>> {
let mut result: Vec<BaseBook> = vec![];