vyuh 0.2.7

Vyuh web framework for Axum and SQLx with handler-first APIs
Documentation
use std::pin::Pin;

use serde::{Deserialize, Serialize};

mod error;
mod local;
mod path;

pub use error::FileStorageError;
pub use local::LocalStorage;
pub use path::StorageName;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UploadConf {
    pub dir: String,
    pub base_url: Option<String>,
    pub temp_dir: Option<String>,
    pub max_request_bytes: u64,
    pub max_file_bytes: u64,
    pub max_files: usize,
    pub max_fields: usize,
    pub memory_threshold_bytes: u64,
}

impl Default for UploadConf {
    fn default() -> Self {
        Self {
            dir: "uploads".into(),
            base_url: Some("/uploads".into()),
            temp_dir: None,
            max_request_bytes: 25 * 1024 * 1024,
            max_file_bytes: 10 * 1024 * 1024,
            max_files: 20,
            max_fields: 100,
            memory_threshold_bytes: 256 * 1024,
        }
    }
}

#[derive(Debug, Clone)]
pub struct SavedFile {
    pub name: StorageName,
    pub path: std::path::PathBuf,
    pub url: Option<String>,
}

impl SavedFile {
    pub fn new(name: StorageName, path: std::path::PathBuf, base_url: Option<String>) -> Self {
        let url = base_url.map(|base| {
            format!(
                "{}/{}",
                base.trim_end_matches('/'),
                percent_encoding::utf8_percent_encode(
                    name.as_str(),
                    percent_encoding::NON_ALPHANUMERIC
                )
            )
        });
        Self { name, path, url }
    }
}

pub trait StorageBackend: Clone + Send + Sync + 'static {
    fn save<'a>(
        &'a self,
        file: &'a crate::routes::multipart::UploadedFile,
    ) -> Pin<Box<dyn std::future::Future<Output = Result<SavedFile, FileStorageError>> + Send + 'a>>;

    fn save_as<'a>(
        &'a self,
        file: &'a crate::routes::multipart::UploadedFile,
        name: StorageName,
    ) -> Pin<Box<dyn std::future::Future<Output = Result<SavedFile, FileStorageError>> + Send + 'a>>;

    fn open<'a>(
        &'a self,
        name: &'a StorageName,
    ) -> Pin<
        Box<
            dyn std::future::Future<Output = Result<tokio::fs::File, FileStorageError>> + Send + 'a,
        >,
    >;

    fn delete<'a>(
        &'a self,
        name: &'a StorageName,
    ) -> Pin<Box<dyn std::future::Future<Output = Result<(), FileStorageError>> + Send + 'a>>;

    fn url(&self, name: &StorageName) -> Option<String>;
}