feat(storage): add generic object storage adapter with CQRS traits, key validation, StorageConfig, and cargo-generate integration

This commit is contained in:
2026-05-23 22:34:24 +02:00
parent 3fa46a4d58
commit 11e75f9bb4
21 changed files with 1246 additions and 15 deletions

View File

@@ -0,0 +1,27 @@
// Example: stream a stored file as an HTTP response.
// Remove this file or replace with your own handlers.
//
// To use, add to your router:
// .route("/files/*key", get(storage_example::get_file))
//
// use axum::{
// body::Body,
// extract::{Path, State},
// http::StatusCode,
// response::IntoResponse,
// };
// use futures::StreamExt;
// use crate::state::AppState;
//
// pub async fn get_file(
// Path(key): Path<String>,
// State(state): State<AppState>,
// ) -> Result<impl IntoResponse, StatusCode> {
// let stream = state
// .storage
// .get(&key)
// .await
// .map_err(|_| StatusCode::NOT_FOUND)?;
// let body = Body::from_stream(stream.map(|r| r.map_err(|e| e.to_string())));
// Ok(body)
// }

View File

@@ -1,6 +1,6 @@
use std::sync::Arc;
use application::use_cases::{GetProfile, LoginUser, RegisterUser};
use domain::ports::TokenIssuer;
use domain::ports::{StoragePort, TokenIssuer};
#[derive(Clone)]
pub struct AppState {
@@ -8,6 +8,9 @@ pub struct AppState {
pub login_uc: Arc<LoginUser>,
pub get_profile_uc: Arc<GetProfile>,
pub token_issuer: Arc<dyn TokenIssuer>,
/// Direct storage access for handlers. Use cases that need storage should receive
/// `Arc<dyn StoragePort>` in their own constructor rather than reading it from `AppState`.
pub storage: Arc<dyn StoragePort>,
}
impl AppState {
@@ -16,7 +19,8 @@ impl AppState {
login_uc: Arc<LoginUser>,
get_profile_uc: Arc<GetProfile>,
token_issuer: Arc<dyn TokenIssuer>,
storage: Arc<dyn StoragePort>,
) -> Self {
Self { register_uc, login_uc, get_profile_uc, token_issuer }
Self { register_uc, login_uc, get_profile_uc, token_issuer, storage }
}
}

View File

@@ -0,0 +1,28 @@
use std::sync::Arc;
use application::use_cases::{GetProfile, LoginUser, RegisterUser};
{% if storage %}
use domain::ports::{StoragePort, TokenIssuer};
{% else %}
use domain::ports::TokenIssuer;
{% endif %}
#[derive(Clone)]
pub struct AppState {
pub register_uc: Arc<RegisterUser>,
pub login_uc: Arc<LoginUser>,
pub get_profile_uc: Arc<GetProfile>,
pub token_issuer: Arc<dyn TokenIssuer>,
{% if storage %}pub storage: Arc<dyn StoragePort>,{% endif %}
}
impl AppState {
pub fn new(
register_uc: Arc<RegisterUser>,
login_uc: Arc<LoginUser>,
get_profile_uc: Arc<GetProfile>,
token_issuer: Arc<dyn TokenIssuer>,
{% if storage %}storage: Arc<dyn StoragePort>,{% endif %}
) -> Self {
Self { register_uc, login_uc, get_profile_uc, token_issuer{% if storage %}, storage{% endif %} }
}
}