use std::sync::Arc;
use axum::{response::IntoResponse, Router};
use crate::auth::{ArcAuthzPolicy, AuthExtractor, HasOwnerId};
use crate::error::{BucketError, BucketResult};
use crate::presentation::http::{
create_bucket_routes,
create_content_hash_routes,
create_conversion_job_routes,
create_file_comment_routes,
create_file_lock_routes,
create_file_share_routes,
create_processing_job_routes,
create_stored_file_routes,
create_upload_session_routes,
create_user_quota_routes,
serving_router as build_serving_router,
upload_router as build_upload_router,
ServingContext,
UploadConfig,
UploadContext,
};
use crate::BucketModule;
impl BucketModule {
pub fn http_routes(&self) -> Router {
Router::new()
.merge(create_bucket_routes(self.bucket_service.clone()))
.merge(create_content_hash_routes(self.content_hash_service.clone()))
.merge(create_conversion_job_routes(self.conversion_job_service.clone()))
.merge(create_file_comment_routes(self.file_comment_service.clone()))
.merge(create_file_lock_routes(self.file_lock_service.clone()))
.merge(create_file_share_routes(self.file_share_service.clone()))
.merge(create_processing_job_routes(self.processing_job_service.clone()))
.merge(create_stored_file_routes(self.stored_file_service.clone()))
.merge(create_upload_session_routes(self.upload_session_service.clone()))
.merge(create_user_quota_routes(self.user_quota_service.clone()))
}
pub fn crud_router(&self) -> Router {
self.http_routes()
}
pub fn serving_router<A>(&self, authz: ArcAuthzPolicy<A>) -> BucketResult<Router>
where
A: AuthExtractor<()> + HasOwnerId + Clone + 'static,
A::Rejection: IntoResponse,
{
let storage = self
.storage
.clone()
.ok_or_else(|| BucketError::Config("storage backend not configured".into()))?;
let config = self
.bucket_config
.clone()
.ok_or_else(|| BucketError::Config("bucket config not provided".into()))?;
let ctx = ServingContext::<A> {
storage,
file_repo: self.stored_file_repository.clone(),
authz,
config,
};
Ok(build_serving_router::<A>(ctx))
}
pub fn upload_router<A>(&self, config: UploadConfig) -> BucketResult<Router>
where
A: AuthExtractor<()> + HasOwnerId + Clone + 'static,
A::Rejection: IntoResponse,
{
let storage = self
.storage
.clone()
.ok_or_else(|| BucketError::Config("storage backend not configured".into()))?;
let file_service = self
.file_service
.clone()
.ok_or_else(|| BucketError::Config("file service not configured (call .with_storage() and .with_config())".into()))?;
let ctx = UploadContext {
file_service,
multipart_service: self.multipart_upload_service.clone(),
bucket_service: self.bucket_service.clone(),
storage,
};
Ok(build_upload_router::<A>(ctx, config))
}
pub fn router<A>(&self, opts: RouterOptions<A>) -> BucketResult<Router>
where
A: AuthExtractor<()> + HasOwnerId + Clone + 'static,
A::Rejection: IntoResponse,
{
let RouterOptions {
upload_config,
authz,
serving_prefix,
} = opts;
let serving = self.serving_router::<A>(authz)?;
let uploads = self.upload_router::<A>(upload_config)?;
Ok(self
.crud_router()
.merge(uploads)
.nest(&serving_prefix, serving))
}
}
pub struct RouterOptions<A> {
pub upload_config: UploadConfig,
pub authz: ArcAuthzPolicy<A>,
pub serving_prefix: String,
}
impl<A> RouterOptions<A> {
pub fn new(authz: ArcAuthzPolicy<A>) -> Self {
Self {
upload_config: UploadConfig::default(),
authz,
serving_prefix: "/cdn".to_string(),
}
}
pub fn with_upload_config(mut self, cfg: UploadConfig) -> Self {
self.upload_config = cfg;
self
}
pub fn with_serving_prefix(mut self, prefix: impl Into<String>) -> Self {
self.serving_prefix = prefix.into();
self
}
}