103 lines
3.0 KiB
Rust
103 lines
3.0 KiB
Rust
use axum::{
|
|
body::Body,
|
|
extract::{Query, State},
|
|
};
|
|
use base64::Engine as _;
|
|
use serde::{Deserialize, Serialize};
|
|
use thiserror::Error;
|
|
use tokio_util::io::ReaderStream;
|
|
use uuid::Uuid;
|
|
|
|
use crate::{
|
|
domain::warren::{
|
|
models::{
|
|
auth_session::AuthRequest,
|
|
file::{AbsoluteFilePathError, FilePath, FilePathError, FileStream},
|
|
warren::FetchWarrenFileRequest,
|
|
},
|
|
ports::{AuthService, WarrenService},
|
|
},
|
|
inbound::http::{AppState, handlers::extractors::SessionIdHeader, responses::ApiError},
|
|
};
|
|
|
|
#[derive(Debug, Clone, Serialize, PartialEq, Hash)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub(super) struct FetchWarrenFileHttpResponseBody {
|
|
// base64 encoded file content bytes
|
|
contents: String,
|
|
}
|
|
|
|
impl From<Vec<u8>> for FetchWarrenFileHttpResponseBody {
|
|
fn from(value: Vec<u8>) -> Self {
|
|
Self {
|
|
contents: base64::prelude::BASE64_STANDARD.encode(&value),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct FetchWarrenFileHttpRequestBody {
|
|
warren_id: Uuid,
|
|
path: String,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Error)]
|
|
pub enum ParseFetchWarrenFileHttpRequestError {
|
|
#[error(transparent)]
|
|
FilePath(#[from] FilePathError),
|
|
#[error(transparent)]
|
|
AbsoluteFilePath(#[from] AbsoluteFilePathError),
|
|
}
|
|
|
|
impl From<ParseFetchWarrenFileHttpRequestError> for ApiError {
|
|
fn from(value: ParseFetchWarrenFileHttpRequestError) -> Self {
|
|
match value {
|
|
ParseFetchWarrenFileHttpRequestError::FilePath(err) => match err {
|
|
FilePathError::InvalidPath => {
|
|
ApiError::BadRequest("The file path must be valid".to_string())
|
|
}
|
|
},
|
|
ParseFetchWarrenFileHttpRequestError::AbsoluteFilePath(err) => match err {
|
|
AbsoluteFilePathError::NotAbsolute => {
|
|
ApiError::BadRequest("The file path must be absolute".to_string())
|
|
}
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl FetchWarrenFileHttpRequestBody {
|
|
fn try_into_domain(
|
|
self,
|
|
) -> Result<FetchWarrenFileRequest, ParseFetchWarrenFileHttpRequestError> {
|
|
let path = FilePath::new(&self.path)?.try_into()?;
|
|
|
|
Ok(FetchWarrenFileRequest::new(self.warren_id, path))
|
|
}
|
|
}
|
|
|
|
impl From<FileStream> for Body {
|
|
fn from(value: FileStream) -> Self {
|
|
Body::from_stream::<ReaderStream<tokio::fs::File>>(value.into())
|
|
}
|
|
}
|
|
|
|
pub async fn fetch_file<WS: WarrenService, AS: AuthService>(
|
|
State(state): State<AppState<WS, AS>>,
|
|
SessionIdHeader(session): SessionIdHeader,
|
|
Query(request): Query<FetchWarrenFileHttpRequestBody>,
|
|
) -> Result<Body, ApiError> {
|
|
let domain_request = request.try_into_domain()?;
|
|
|
|
state
|
|
.auth_service
|
|
.fetch_warren_file(
|
|
AuthRequest::new(session, domain_request),
|
|
state.warren_service.as_ref(),
|
|
)
|
|
.await
|
|
.map(|contents| contents.into())
|
|
.map_err(ApiError::from)
|
|
}
|