152 lines
4.4 KiB
Rust
152 lines
4.4 KiB
Rust
mod archive;
|
|
mod manager;
|
|
pub mod package;
|
|
|
|
pub use manager::DistroMgr;
|
|
|
|
use axum::{
|
|
body::Body,
|
|
extract::{Path, State},
|
|
http::{Request, StatusCode},
|
|
response::IntoResponse,
|
|
routing::{delete, post},
|
|
Router,
|
|
};
|
|
use futures::TryStreamExt;
|
|
use tokio_util::io::StreamReader;
|
|
use tower::util::ServiceExt;
|
|
use tower_http::{services::ServeFile, validate_request::ValidateRequestHeaderLayer};
|
|
|
|
pub fn router(api_key: &str) -> Router<crate::Global> {
|
|
Router::new()
|
|
.route(
|
|
"/:distro/:repo",
|
|
post(post_package_archive)
|
|
.delete(delete_repo)
|
|
.route_layer(ValidateRequestHeaderLayer::bearer(api_key)),
|
|
)
|
|
.route(
|
|
"/:distro/:repo/:arch",
|
|
delete(delete_arch_repo).route_layer(ValidateRequestHeaderLayer::bearer(api_key)),
|
|
)
|
|
// Routes added after the layer do not get that layer applied, so the GET requests will not
|
|
// be authorized
|
|
.route(
|
|
"/:distro/:repo/:arch/:filename",
|
|
delete(delete_package)
|
|
.route_layer(ValidateRequestHeaderLayer::bearer(api_key))
|
|
.get(get_file),
|
|
)
|
|
}
|
|
|
|
/// Serve the package archive files and database archives. If files are requested for an
|
|
/// architecture that does not have any explicit packages, a repository containing only "any" files
|
|
/// is returned.
|
|
async fn get_file(
|
|
State(global): State<crate::Global>,
|
|
Path((distro, repo, arch, file_name)): Path<(String, String, String, String)>,
|
|
req: Request<Body>,
|
|
) -> crate::Result<impl IntoResponse> {
|
|
let repo_dir = global
|
|
.config
|
|
.data_dir
|
|
.join("distros")
|
|
.join(&distro)
|
|
.join(&repo);
|
|
|
|
let file_name =
|
|
if file_name == format!("{}.db", repo) || file_name == format!("{}.db.tar.gz", repo) {
|
|
format!("{}.db.tar.gz", arch)
|
|
} else if file_name == format!("{}.files", repo)
|
|
|| file_name == format!("{}.files.tar.gz", repo)
|
|
{
|
|
format!("{}.files.tar.gz", arch)
|
|
} else {
|
|
file_name
|
|
};
|
|
|
|
Ok(ServeFile::new(repo_dir.join(file_name)).oneshot(req).await)
|
|
}
|
|
|
|
async fn post_package_archive(
|
|
State(global): State<crate::Global>,
|
|
Path((distro, repo)): Path<(String, String)>,
|
|
body: Body,
|
|
) -> crate::Result<()> {
|
|
let mut body = StreamReader::new(body.into_data_stream().map_err(std::io::Error::other));
|
|
let mgr = global.mgr.get_or_create_mgr(&distro).await?;
|
|
let (name, version, arch) = mgr.add_pkg_from_reader(&mut body, &repo).await?;
|
|
|
|
tracing::info!(
|
|
"Added '{}-{}' to repository '{}' ({})",
|
|
name,
|
|
version,
|
|
repo,
|
|
arch
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
async fn delete_repo(
|
|
State(global): State<crate::Global>,
|
|
Path((distro, repo)): Path<(String, String)>,
|
|
) -> crate::Result<StatusCode> {
|
|
if let Some(mgr) = global.mgr.get_mgr(&distro).await {
|
|
let repo_removed = mgr.remove_repo(&repo).await?;
|
|
|
|
if repo_removed {
|
|
tracing::info!("Removed repository '{}'", repo);
|
|
|
|
Ok(StatusCode::OK)
|
|
} else {
|
|
Ok(StatusCode::NOT_FOUND)
|
|
}
|
|
} else {
|
|
Ok(StatusCode::NOT_FOUND)
|
|
}
|
|
}
|
|
|
|
async fn delete_arch_repo(
|
|
State(global): State<crate::Global>,
|
|
Path((distro, repo, arch)): Path<(String, String, String)>,
|
|
) -> crate::Result<StatusCode> {
|
|
if let Some(mgr) = global.mgr.get_mgr(&distro).await {
|
|
let repo_removed = mgr.remove_repo_arch(&repo, &arch).await?;
|
|
|
|
if repo_removed {
|
|
tracing::info!("Removed arch '{}' from repository '{}'", arch, repo);
|
|
|
|
Ok(StatusCode::OK)
|
|
} else {
|
|
Ok(StatusCode::NOT_FOUND)
|
|
}
|
|
} else {
|
|
Ok(StatusCode::NOT_FOUND)
|
|
}
|
|
}
|
|
|
|
async fn delete_package(
|
|
State(global): State<crate::Global>,
|
|
Path((distro, repo, arch, pkg_name)): Path<(String, String, String, String)>,
|
|
) -> crate::Result<StatusCode> {
|
|
if let Some(mgr) = global.mgr.get_mgr(&distro).await {
|
|
let pkg_removed = mgr.remove_pkg(&repo, &arch, &pkg_name).await?;
|
|
|
|
if pkg_removed {
|
|
tracing::info!(
|
|
"Removed package '{}' ({}) from repository '{}'",
|
|
pkg_name,
|
|
arch,
|
|
repo
|
|
);
|
|
|
|
Ok(StatusCode::OK)
|
|
} else {
|
|
Ok(StatusCode::NOT_FOUND)
|
|
}
|
|
} else {
|
|
Ok(StatusCode::NOT_FOUND)
|
|
}
|
|
}
|