use std::fs::remove_file; use std::io::Error; use std::path::Path; use sha2::{Digest, Sha256}; use mitra_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, output_dir: &Path, media_type: Option<&str>, ) -> Result { 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, 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 mitra_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", ); } }