Compress images only for NIP-96 endpoint
This commit is contained in:
parent
423fbfdb77
commit
8a58cfe825
11
README.md
Normal file
11
README.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# void-cat-rs
|
||||||
|
|
||||||
|
Image hosting service
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- NIP-96 Support
|
||||||
|
- Blossom Support
|
||||||
|
- Image compression to WebP (FFMPEG)
|
||||||
|
|
||||||
|
## Planned
|
||||||
|
- Torrent seed V2
|
@ -44,32 +44,48 @@ impl FileStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Store a new file
|
/// Store a new file
|
||||||
pub async fn put<TStream>(&self, mut stream: TStream, mime_type: &str) -> Result<FileSystemResult, Error>
|
pub async fn put<TStream>(&self, stream: TStream, mime_type: &str, compress: bool) -> Result<FileSystemResult, Error>
|
||||||
|
where
|
||||||
|
TStream: AsyncRead + Unpin,
|
||||||
|
{
|
||||||
|
let result = self.store_compress_file(stream, mime_type, compress).await?;
|
||||||
|
let dst_path = self.map_path(&result.sha256);
|
||||||
|
fs::create_dir_all(dst_path.parent().unwrap())?;
|
||||||
|
if let Err(e) = fs::copy(&result.path, &dst_path) {
|
||||||
|
fs::remove_file(&result.path)?;
|
||||||
|
Err(Error::from(e))
|
||||||
|
} else {
|
||||||
|
fs::remove_file(result.path)?;
|
||||||
|
Ok(FileSystemResult {
|
||||||
|
path: dst_path,
|
||||||
|
..result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn store_compress_file<TStream>(&self, mut stream: TStream, mime_type: &str, compress: bool) -> Result<FileSystemResult, Error>
|
||||||
where
|
where
|
||||||
TStream: AsyncRead + Unpin,
|
TStream: AsyncRead + Unpin,
|
||||||
{
|
{
|
||||||
let random_id = uuid::Uuid::new_v4();
|
let random_id = uuid::Uuid::new_v4();
|
||||||
|
let tmp_path = FileStore::map_temp(random_id);
|
||||||
|
let mut file = File::options()
|
||||||
|
.create(true)
|
||||||
|
.write(true)
|
||||||
|
.read(true)
|
||||||
|
.open(tmp_path.clone())
|
||||||
|
.await?;
|
||||||
|
tokio::io::copy(&mut stream, &mut file).await?;
|
||||||
|
|
||||||
let mut mime_type = mime_type.to_string();
|
info!("File saved to temp path: {}", tmp_path.to_str().unwrap());
|
||||||
let (n, hash, tmp_path, width, height, blur_hash) = {
|
|
||||||
let mut tmp_path = FileStore::map_temp(random_id);
|
|
||||||
let mut file = File::options()
|
|
||||||
.create(true)
|
|
||||||
.write(true)
|
|
||||||
.read(true)
|
|
||||||
.open(tmp_path.clone())
|
|
||||||
.await?;
|
|
||||||
tokio::io::copy(&mut stream, &mut file).await?;
|
|
||||||
|
|
||||||
info!("File saved to temp path: {}", tmp_path.to_str().unwrap());
|
|
||||||
|
|
||||||
|
if compress {
|
||||||
let start = SystemTime::now();
|
let start = SystemTime::now();
|
||||||
let proc_result = {
|
let proc_result = {
|
||||||
let mut p_lock = self.processor.lock().expect("asd");
|
let mut p_lock = self.processor.lock().expect("asd");
|
||||||
p_lock.process_file(tmp_path.clone(), &mime_type)?
|
p_lock.process_file(tmp_path.clone(), &mime_type)?
|
||||||
};
|
};
|
||||||
if let FileProcessorResult::NewFile(new_temp) = proc_result {
|
if let FileProcessorResult::NewFile(new_temp) = proc_result {
|
||||||
mime_type = new_temp.mime_type;
|
|
||||||
let old_size = tmp_path.metadata()?.len();
|
let old_size = tmp_path.metadata()?.len();
|
||||||
let new_size = new_temp.result.metadata()?.len();
|
let new_size = new_temp.result.metadata()?.len();
|
||||||
info!("Compressed media: ratio={:.2}x, old_size={:.3}kb, new_size={:.3}kb, duration={:.2}ms",
|
info!("Compressed media: ratio={:.2}x, old_size={:.3}kb, new_size={:.3}kb, duration={:.2}ms",
|
||||||
@ -89,30 +105,28 @@ impl FileStore {
|
|||||||
.await?;
|
.await?;
|
||||||
let n = file.metadata().await?.len();
|
let n = file.metadata().await?.len();
|
||||||
let hash = FileStore::hash_file(&mut file).await?;
|
let hash = FileStore::hash_file(&mut file).await?;
|
||||||
(n, hash, new_temp.result, Some(new_temp.width), Some(new_temp.height), Some(new_temp.blur_hash))
|
return Ok(FileSystemResult {
|
||||||
} else {
|
size: n,
|
||||||
let n = file.metadata().await?.len();
|
sha256: hash,
|
||||||
let hash = FileStore::hash_file(&mut file).await?;
|
path: new_temp.result,
|
||||||
(n, hash, tmp_path, None, None, None)
|
width: Some(new_temp.width),
|
||||||
|
height: Some(new_temp.height),
|
||||||
|
blur_hash: Some(new_temp.blur_hash),
|
||||||
|
mime_type: new_temp.mime_type,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
|
||||||
let dst_path = self.map_path(&hash);
|
|
||||||
fs::create_dir_all(dst_path.parent().unwrap())?;
|
|
||||||
if let Err(e) = fs::copy(&tmp_path, &dst_path) {
|
|
||||||
fs::remove_file(&tmp_path)?;
|
|
||||||
Err(Error::from(e))
|
|
||||||
} else {
|
|
||||||
fs::remove_file(tmp_path)?;
|
|
||||||
Ok(FileSystemResult {
|
|
||||||
size: n,
|
|
||||||
sha256: hash,
|
|
||||||
path: dst_path,
|
|
||||||
mime_type,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
blur_hash,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
let n = file.metadata().await?.len();
|
||||||
|
let hash = FileStore::hash_file(&mut file).await?;
|
||||||
|
Ok(FileSystemResult {
|
||||||
|
path: tmp_path,
|
||||||
|
sha256: hash,
|
||||||
|
size: n,
|
||||||
|
mime_type: mime_type.to_string(),
|
||||||
|
width: None,
|
||||||
|
height: None,
|
||||||
|
blur_hash: None,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn hash_file(file: &mut File) -> Result<Vec<u8>, Error> {
|
async fn hash_file(file: &mut File) -> Result<Vec<u8>, Error> {
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
use std::sync::{Mutex, RwLock};
|
|
||||||
|
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use log::error;
|
use log::error;
|
||||||
use nostr::prelude::hex;
|
use nostr::prelude::hex;
|
||||||
@ -108,7 +106,7 @@ async fn upload(
|
|||||||
.unwrap_or("application/octet-stream".to_string());
|
.unwrap_or("application/octet-stream".to_string());
|
||||||
|
|
||||||
match fs
|
match fs
|
||||||
.put(data.open(ByteUnit::from(settings.max_upload_bytes)), &mime_type)
|
.put(data.open(ByteUnit::from(settings.max_upload_bytes)), &mime_type, false)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(blob) => {
|
Ok(blob) => {
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Mutex;
|
|
||||||
|
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use rocket::{FromForm, Responder, Route, routes, State};
|
use rocket::{FromForm, Responder, Route, routes, State};
|
||||||
use rocket::data::ByteUnit;
|
|
||||||
use rocket::form::Form;
|
use rocket::form::Form;
|
||||||
use rocket::fs::TempFile;
|
use rocket::fs::TempFile;
|
||||||
use rocket::serde::json::Json;
|
use rocket::serde::json::Json;
|
||||||
@ -161,7 +159,7 @@ async fn upload(
|
|||||||
let mime_type = form.media_type
|
let mime_type = form.media_type
|
||||||
.unwrap_or("application/octet-stream");
|
.unwrap_or("application/octet-stream");
|
||||||
match fs
|
match fs
|
||||||
.put(file, mime_type)
|
.put(file, mime_type, true)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(blob) => {
|
Ok(blob) => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user