mod manager; mod package; pub use manager::RepoGroupManager; use axum::extract::{BodyStream, Path, State}; use axum::http::StatusCode; use axum::response::IntoResponse; use axum::routing::{get_service, post}; use axum::Router; use futures::StreamExt; use futures::TryFutureExt; use futures::TryStreamExt; use std::io::Read; use tokio::{fs, io, io::AsyncWriteExt}; use tower_http::services::ServeDir; use uuid::Uuid; pub fn router(global: &crate::Global) -> Router { // Try to serve packages by default, and try the database files instead if not found let serve_repos = get_service( ServeDir::new(&global.config.pkg_dir).fallback(ServeDir::new(&global.config.repo_dir)), ); Router::new() .route( "/:repo", post(post_package_archive).get(serve_repos.clone()), ) .fallback(serve_repos) .with_state(global.clone()) } async fn post_package_archive( State(global): State, Path(repo): Path, body: BodyStream, ) -> Result<(), StatusCode> { // let mut body_reader = tokio_util::io::StreamReader::new( // body.map_err(|err| io::Error::new(io::ErrorKind::Other, err)), // ); let mut body = body.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR); // We first stream the uploaded file to disk let uuid: uuid::fmt::Simple = Uuid::new_v4().into(); let path = global.config.pkg_dir.join(uuid.to_string()); let mut f = fs::File::create(&path) .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR) .await?; while let Some(chunk) = body.next().await { f.write_all(&chunk?) .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR) .await?; } let pkg = tokio::task::spawn_blocking(move || package::Package::open(&path)) .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR) .await?; println!("{:?}", pkg); Ok(()) }