File Storage
10/30/24Less than 1 minute
File Storage
Current implementation only supports local file storage: Base64 image saving and Multipart file upload, with delete functionality. Does not cover S3/OSS or Nginx configuration.
- Directory partitioned by month: YYYY-MM
- File naming: day-dd + Global ID (GID) + extension
- Path configuration:
- Static image directory:
APPCOFIG.server.static_dir - General upload directory:
APPCOFIG.server.upload_dir(default: data/upload) - Return URL prefix:
APPCOFIG.server.domainname
- Static image directory:
Path Conventions
- Base64 Image
- Physical path:
{static_dir}/{YYYY-MM}/{dd}_{GID}.png - Returns:
(url_path, no_domain_path)
- Physical path:
- Multipart Upload
- Physical path:
{upload_dir}/{YYYY-MM}/{dd}-{GID}.{ext} - Returns:
{domainname}/{YYYY-MM}/{file}
- Physical path:
Reference Implementation
use axum::extract::Multipart;
use tokio::{fs, io::AsyncWriteExt};
// Base64 Image Save
pub async fn save_base64_img(base64_data: &str) -> Result<(String, String)> {
let server_config = APPCOFIG.server.clone();
let now = chrono::Local::now();
let file_path_t = format!("{}/{}", server_config.static_dir, &now.format("%Y-%m"));
fs::create_dir_all(&file_path_t).await?;
let fid = GID().await;
let file_name = format!("{}_{}{}", now.format("%d"), fid, ".png");
let file_path = format!("{}/{}", file_path_t, &file_name);
let decoded_data = general_purpose::STANDARD.decode(base64_data)?;
let mut file = fs::File::create(file_path).await?;
file.write_all(&decoded_data).await?;
let url_path = format!("{}/{}/{}/{}", server_config.domainname, "static", &now.format("%Y-%m"), &file_name);
let no_domain_path = format!("{}/{}/{}", "static", &now.format("%Y-%m"), &file_name);
Ok((url_path, no_domain_path))
}Configuration
From APPCOFIG.server:
upload_dir: Local upload directory (default: data/upload)static_dir: Local static image directorydomainname: URL prefix for returned paths
Notes
- Content-Type whitelist: currently jpeg/png/gif, extendable as needed
- Size limits: check
bytes.len()to limit single file size - File uniqueness: uses GID to avoid conflicts
- Old file cleanup: pass old URL via
field.file_name()