Move some functions from utils::files to media module
This commit is contained in:
parent
0988c0c91e
commit
2acf50fa01
13 changed files with 98 additions and 96 deletions
|
@ -15,6 +15,7 @@ use mitra::ethereum::{
|
||||||
sync::save_current_block_number,
|
sync::save_current_block_number,
|
||||||
utils::key_to_ethereum_address,
|
utils::key_to_ethereum_address,
|
||||||
};
|
};
|
||||||
|
use mitra::media::remove_files;
|
||||||
use mitra::models::{
|
use mitra::models::{
|
||||||
attachments::queries::delete_unused_attachments,
|
attachments::queries::delete_unused_attachments,
|
||||||
cleanup::find_orphaned_files,
|
cleanup::find_orphaned_files,
|
||||||
|
@ -53,7 +54,6 @@ use mitra::utils::{
|
||||||
serialize_private_key,
|
serialize_private_key,
|
||||||
},
|
},
|
||||||
datetime::{days_before_now, get_min_datetime},
|
datetime::{days_before_now, get_min_datetime},
|
||||||
files::remove_files,
|
|
||||||
passwords::hash_password,
|
passwords::hash_password,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ use crate::activitypub::{
|
||||||
};
|
};
|
||||||
use crate::config::Instance;
|
use crate::config::Instance;
|
||||||
use crate::errors::ValidationError;
|
use crate::errors::ValidationError;
|
||||||
|
use crate::media::get_file_url;
|
||||||
use crate::models::profiles::types::{
|
use crate::models::profiles::types::{
|
||||||
ExtraField,
|
ExtraField,
|
||||||
IdentityProof,
|
IdentityProof,
|
||||||
|
@ -29,7 +30,6 @@ use crate::models::profiles::types::{
|
||||||
};
|
};
|
||||||
use crate::models::users::types::User;
|
use crate::models::users::types::User;
|
||||||
use crate::utils::crypto_rsa::{deserialize_private_key, get_public_key_pem};
|
use crate::utils::crypto_rsa::{deserialize_private_key, get_public_key_pem};
|
||||||
use crate::utils::files::get_file_url;
|
|
||||||
use crate::utils::urls::get_hostname;
|
use crate::utils::urls::get_hostname;
|
||||||
use crate::webfinger::types::ActorAddress;
|
use crate::webfinger::types::ActorAddress;
|
||||||
use super::attachments::{
|
use super::attachments::{
|
||||||
|
|
|
@ -26,6 +26,7 @@ use crate::activitypub::{
|
||||||
};
|
};
|
||||||
use crate::config::Instance;
|
use crate::config::Instance;
|
||||||
use crate::database::{DatabaseClient, DatabaseError};
|
use crate::database::{DatabaseClient, DatabaseError};
|
||||||
|
use crate::media::get_file_url;
|
||||||
use crate::models::{
|
use crate::models::{
|
||||||
emojis::types::DbEmoji,
|
emojis::types::DbEmoji,
|
||||||
posts::queries::get_post_author,
|
posts::queries::get_post_author,
|
||||||
|
@ -33,7 +34,6 @@ use crate::models::{
|
||||||
relationships::queries::{get_followers, get_subscribers},
|
relationships::queries::{get_followers, get_subscribers},
|
||||||
users::types::User,
|
users::types::User,
|
||||||
};
|
};
|
||||||
use crate::utils::files::get_file_url;
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
|
|
|
@ -15,11 +15,8 @@ use crate::http_signatures::create::{
|
||||||
create_http_signature,
|
create_http_signature,
|
||||||
HttpSignatureError,
|
HttpSignatureError,
|
||||||
};
|
};
|
||||||
use crate::utils::files::{
|
use crate::media::{save_file, SUPPORTED_MEDIA_TYPES};
|
||||||
save_file,
|
use crate::utils::files::sniff_media_type;
|
||||||
sniff_media_type,
|
|
||||||
SUPPORTED_MEDIA_TYPES,
|
|
||||||
};
|
|
||||||
use crate::utils::urls::guess_protocol;
|
use crate::utils::urls::guess_protocol;
|
||||||
use crate::webfinger::types::{ActorAddress, JsonResourceDescriptor};
|
use crate::webfinger::types::{ActorAddress, JsonResourceDescriptor};
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ pub mod job_queue;
|
||||||
mod json_signatures;
|
mod json_signatures;
|
||||||
pub mod logger;
|
pub mod logger;
|
||||||
pub mod mastodon_api;
|
pub mod mastodon_api;
|
||||||
|
pub mod media;
|
||||||
pub mod models;
|
pub mod models;
|
||||||
pub mod monero;
|
pub mod monero;
|
||||||
pub mod nodeinfo;
|
pub mod nodeinfo;
|
||||||
|
|
|
@ -10,6 +10,7 @@ use crate::mastodon_api::{
|
||||||
pagination::PageSize,
|
pagination::PageSize,
|
||||||
uploads::{save_b64_file, UploadError},
|
uploads::{save_b64_file, UploadError},
|
||||||
};
|
};
|
||||||
|
use crate::media::get_file_url;
|
||||||
use crate::models::{
|
use crate::models::{
|
||||||
profiles::types::{
|
profiles::types::{
|
||||||
DbActorProfile,
|
DbActorProfile,
|
||||||
|
@ -27,10 +28,7 @@ use crate::models::{
|
||||||
User,
|
User,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use crate::utils::{
|
use crate::utils::markdown::markdown_basic_to_html;
|
||||||
files::get_file_url,
|
|
||||||
markdown::markdown_basic_to_html,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// https://docs.joinmastodon.org/entities/field/
|
/// https://docs.joinmastodon.org/entities/field/
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
|
use crate::media::get_file_url;
|
||||||
use crate::models::emojis::types::DbEmoji;
|
use crate::models::emojis::types::DbEmoji;
|
||||||
use crate::utils::files::get_file_url;
|
|
||||||
|
|
||||||
/// https://docs.joinmastodon.org/entities/CustomEmoji/
|
/// https://docs.joinmastodon.org/entities/CustomEmoji/
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
|
|
|
@ -12,11 +12,9 @@ use crate::mastodon_api::{
|
||||||
MASTODON_API_VERSION,
|
MASTODON_API_VERSION,
|
||||||
uploads::UPLOAD_MAX_SIZE,
|
uploads::UPLOAD_MAX_SIZE,
|
||||||
};
|
};
|
||||||
|
use crate::media::SUPPORTED_MEDIA_TYPES;
|
||||||
use crate::models::posts::validators::ATTACHMENTS_MAX_NUM;
|
use crate::models::posts::validators::ATTACHMENTS_MAX_NUM;
|
||||||
use crate::utils::{
|
use crate::utils::markdown::markdown_to_html;
|
||||||
files::SUPPORTED_MEDIA_TYPES,
|
|
||||||
markdown::markdown_to_html,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct InstanceStats {
|
struct InstanceStats {
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use crate::media::get_file_url;
|
||||||
use crate::models::attachments::types::{
|
use crate::models::attachments::types::{
|
||||||
AttachmentType,
|
AttachmentType,
|
||||||
DbMediaAttachment,
|
DbMediaAttachment,
|
||||||
};
|
};
|
||||||
use crate::utils::files::get_file_url;
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct AttachmentCreateData {
|
pub struct AttachmentCreateData {
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use crate::errors::HttpError;
|
use crate::errors::HttpError;
|
||||||
use crate::utils::files::{
|
use crate::media::{save_file, SUPPORTED_MEDIA_TYPES};
|
||||||
save_file,
|
use crate::utils::files::sniff_media_type;
|
||||||
sniff_media_type,
|
|
||||||
SUPPORTED_MEDIA_TYPES,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const UPLOAD_MAX_SIZE: usize = 1024 * 1024 * 5;
|
pub const UPLOAD_MAX_SIZE: usize = 1024 * 1024 * 5;
|
||||||
|
|
||||||
|
|
79
src/media.rs
Normal file
79
src/media.rs
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
use std::fs::remove_file;
|
||||||
|
use std::io::Error;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use sha2::{Digest, Sha256};
|
||||||
|
|
||||||
|
use crate::utils::files::{get_media_type_extension, write_file};
|
||||||
|
|
||||||
|
pub const SUPPORTED_MEDIA_TYPES: [&str; 8] = [
|
||||||
|
"audio/mpeg",
|
||||||
|
"image/apng",
|
||||||
|
"image/gif",
|
||||||
|
"image/jpeg",
|
||||||
|
"image/png",
|
||||||
|
"image/webp",
|
||||||
|
"video/mp4",
|
||||||
|
"video/webm",
|
||||||
|
];
|
||||||
|
|
||||||
|
/// Generates unique file name based on file contents
|
||||||
|
fn get_file_name(data: &[u8], media_type: Option<&str>) -> String {
|
||||||
|
let digest = Sha256::digest(data);
|
||||||
|
let mut file_name = hex::encode(digest);
|
||||||
|
let maybe_extension = media_type
|
||||||
|
.and_then(get_media_type_extension);
|
||||||
|
if let Some(extension) = maybe_extension {
|
||||||
|
// Append extension for known media types
|
||||||
|
file_name = format!("{}.{}", file_name, extension);
|
||||||
|
};
|
||||||
|
file_name
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Save validated file to specified directory
|
||||||
|
pub fn save_file(
|
||||||
|
data: Vec<u8>,
|
||||||
|
output_dir: &Path,
|
||||||
|
media_type: Option<&str>,
|
||||||
|
) -> Result<String, Error> {
|
||||||
|
let file_name = get_file_name(&data, media_type);
|
||||||
|
let file_path = output_dir.join(&file_name);
|
||||||
|
write_file(&data, &file_path)?;
|
||||||
|
Ok(file_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_file_url(instance_url: &str, file_name: &str) -> String {
|
||||||
|
format!("{}/media/{}", instance_url, file_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_files(files: Vec<String>, from_dir: &Path) -> () {
|
||||||
|
for file_name in files {
|
||||||
|
let file_path = from_dir.join(file_name);
|
||||||
|
let file_path_str = file_path.to_string_lossy();
|
||||||
|
match remove_file(&file_path) {
|
||||||
|
Ok(_) => log::info!("removed file {}", file_path_str),
|
||||||
|
Err(err) => {
|
||||||
|
log::warn!("failed to remove file {} ({})", file_path_str, err);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::utils::files::sniff_media_type;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_file_name() {
|
||||||
|
let mut data = vec![];
|
||||||
|
data.extend_from_slice(b"\x89PNG\x0D\x0A\x1A\x0A");
|
||||||
|
let media_type = sniff_media_type(&data);
|
||||||
|
let file_name = get_file_name(&data, media_type.as_deref());
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
file_name,
|
||||||
|
"4c4b6a3be1314ab86138bef4314dde022e600960d8689a2c8f8631802d20dab6.png",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::database::{DatabaseClient, DatabaseError};
|
use crate::database::{DatabaseClient, DatabaseError};
|
||||||
use crate::ipfs::store as ipfs_store;
|
use crate::ipfs::store as ipfs_store;
|
||||||
use crate::utils::files::remove_files;
|
use crate::media::remove_files;
|
||||||
|
|
||||||
pub struct DeletionQueue {
|
pub struct DeletionQueue {
|
||||||
pub files: Vec<String>,
|
pub files: Vec<String>,
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use std::fs::{
|
use std::fs::{
|
||||||
remove_file,
|
|
||||||
set_permissions,
|
set_permissions,
|
||||||
File,
|
File,
|
||||||
Permissions,
|
Permissions,
|
||||||
|
@ -11,35 +10,15 @@ use std::path::Path;
|
||||||
|
|
||||||
use mime_guess::get_mime_extensions_str;
|
use mime_guess::get_mime_extensions_str;
|
||||||
use mime_sniffer::MimeTypeSniffer;
|
use mime_sniffer::MimeTypeSniffer;
|
||||||
use sha2::{Digest, Sha256};
|
|
||||||
|
|
||||||
pub const SUPPORTED_MEDIA_TYPES: [&str; 8] = [
|
|
||||||
"audio/mpeg",
|
|
||||||
"image/apng",
|
|
||||||
"image/gif",
|
|
||||||
"image/jpeg",
|
|
||||||
"image/png",
|
|
||||||
"image/webp",
|
|
||||||
"video/mp4",
|
|
||||||
"video/webm",
|
|
||||||
];
|
|
||||||
|
|
||||||
pub fn sniff_media_type(data: &[u8]) -> Option<String> {
|
pub fn sniff_media_type(data: &[u8]) -> Option<String> {
|
||||||
data.sniff_mime_type().map(|val| val.to_string())
|
data.sniff_mime_type().map(|val| val.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates unique file name based on file contents
|
pub fn get_media_type_extension(media_type: &str) -> Option<String> {
|
||||||
fn get_file_name(data: &[u8], media_type: Option<&str>) -> String {
|
get_mime_extensions_str(media_type)
|
||||||
let digest = Sha256::digest(data);
|
.and_then(|extensions| extensions.first())
|
||||||
let mut file_name = hex::encode(digest);
|
.map(|extension| extension.to_string())
|
||||||
let maybe_extension = media_type
|
|
||||||
.and_then(get_mime_extensions_str)
|
|
||||||
.and_then(|extensions| extensions.first());
|
|
||||||
if let Some(extension) = maybe_extension {
|
|
||||||
// Append extension for known media types
|
|
||||||
file_name = format!("{}.{}", file_name, extension);
|
|
||||||
};
|
|
||||||
file_name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_file(data: &[u8], file_path: &Path) -> Result<(), Error> {
|
pub fn write_file(data: &[u8], file_path: &Path) -> Result<(), Error> {
|
||||||
|
@ -53,50 +32,3 @@ pub fn set_file_permissions(file_path: &Path, mode: u32) -> Result<(), Error> {
|
||||||
set_permissions(file_path, permissions)?;
|
set_permissions(file_path, permissions)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Save validated file to specified directory
|
|
||||||
pub fn save_file(
|
|
||||||
data: Vec<u8>,
|
|
||||||
output_dir: &Path,
|
|
||||||
media_type: Option<&str>,
|
|
||||||
) -> Result<String, Error> {
|
|
||||||
let file_name = get_file_name(&data, media_type);
|
|
||||||
let file_path = output_dir.join(&file_name);
|
|
||||||
write_file(&data, &file_path)?;
|
|
||||||
Ok(file_name)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_file_url(instance_url: &str, file_name: &str) -> String {
|
|
||||||
format!("{}/media/{}", instance_url, file_name)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove_files(files: Vec<String>, from_dir: &Path) -> () {
|
|
||||||
for file_name in files {
|
|
||||||
let file_path = from_dir.join(file_name);
|
|
||||||
let file_path_str = file_path.to_string_lossy();
|
|
||||||
match remove_file(&file_path) {
|
|
||||||
Ok(_) => log::info!("removed file {}", file_path_str),
|
|
||||||
Err(err) => {
|
|
||||||
log::warn!("failed to remove file {} ({})", file_path_str, err);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_get_file_name() {
|
|
||||||
let mut data = vec![];
|
|
||||||
data.extend_from_slice(b"\x89PNG\x0D\x0A\x1A\x0A");
|
|
||||||
let media_type = data.sniff_mime_type();
|
|
||||||
let file_name = get_file_name(&data, media_type);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
file_name,
|
|
||||||
"4c4b6a3be1314ab86138bef4314dde022e600960d8689a2c8f8631802d20dab6.png",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue