feat: partially implemented package GET request
parent
ce7b5159e8
commit
633e670840
|
@ -1660,6 +1660,7 @@ dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"libarchive",
|
"libarchive",
|
||||||
|
"regex",
|
||||||
"sea-orm",
|
"sea-orm",
|
||||||
"sea-orm-migration",
|
"sea-orm-migration",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
|
@ -13,6 +13,7 @@ clap = { version = "4.3.12", features = ["env", "derive"] }
|
||||||
futures = "0.3.28"
|
futures = "0.3.28"
|
||||||
http-body-util = "0.1.1"
|
http-body-util = "0.1.1"
|
||||||
libarchive = { path = "../libarchive" }
|
libarchive = { path = "../libarchive" }
|
||||||
|
regex = "1.10.4"
|
||||||
sea-orm-migration = "0.12.1"
|
sea-orm-migration = "0.12.1"
|
||||||
serde = { version = "1.0.178", features = ["derive"] }
|
serde = { version = "1.0.178", features = ["derive"] }
|
||||||
sha256 = "1.1.4"
|
sha256 = "1.1.4"
|
||||||
|
|
|
@ -91,10 +91,13 @@ impl Cli {
|
||||||
};
|
};
|
||||||
let repo_manager = MetaRepoMgr::new(&config.repo_dir, &self.pkg_dir);
|
let repo_manager = MetaRepoMgr::new(&config.repo_dir, &self.pkg_dir);
|
||||||
|
|
||||||
|
let pkg_filename_re = regex::Regex::new(r"^([a-z0-9@_+][a-z0-9@_+-.]*)-((?:[0-9]+:)?[a-z0-9._]+-[0-9.]+)-([a-z0-9_]+)\.pkg\.tar\.([a-z0-9]+)$").unwrap();
|
||||||
|
|
||||||
let global = Global {
|
let global = Global {
|
||||||
config,
|
config,
|
||||||
repo_manager: Arc::new(RwLock::new(repo_manager)),
|
repo_manager: Arc::new(RwLock::new(repo_manager)),
|
||||||
db,
|
db,
|
||||||
|
pkg_filename_re,
|
||||||
};
|
};
|
||||||
|
|
||||||
// build our application with a single route
|
// build our application with a single route
|
||||||
|
|
|
@ -47,13 +47,23 @@ pub async fn by_fields(
|
||||||
repo_id: i32,
|
repo_id: i32,
|
||||||
arch: &str,
|
arch: &str,
|
||||||
name: &str,
|
name: &str,
|
||||||
|
version: Option<&str>,
|
||||||
|
compression: Option<&str>,
|
||||||
) -> Result<Option<package::Model>> {
|
) -> Result<Option<package::Model>> {
|
||||||
Package::find()
|
let mut query = Package::find()
|
||||||
.filter(package::Column::RepoId.eq(repo_id))
|
.filter(package::Column::RepoId.eq(repo_id))
|
||||||
.filter(package::Column::Name.eq(name))
|
.filter(package::Column::Name.eq(name))
|
||||||
.filter(package::Column::Arch.eq(arch))
|
.filter(package::Column::Arch.eq(arch));
|
||||||
.one(conn)
|
|
||||||
.await
|
if let Some(version) = version {
|
||||||
|
query = query.filter(package::Column::Version.eq(version));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(compression) = compression {
|
||||||
|
query = query.filter(package::Column::Compression.eq(compression));
|
||||||
|
}
|
||||||
|
|
||||||
|
query.one(conn).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_with_arch(conn: &DbConn, repo_id: i32, arch: &str) -> Result<DeleteResult> {
|
pub async fn delete_with_arch(conn: &DbConn, repo_id: i32, arch: &str) -> Result<DeleteResult> {
|
||||||
|
|
|
@ -25,6 +25,7 @@ pub struct Global {
|
||||||
config: Config,
|
config: Config,
|
||||||
repo_manager: Arc<RwLock<MetaRepoMgr>>,
|
repo_manager: Arc<RwLock<MetaRepoMgr>>,
|
||||||
db: sea_orm::DbConn,
|
db: sea_orm::DbConn,
|
||||||
|
pkg_filename_re: regex::Regex,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
|
|
|
@ -135,7 +135,7 @@ impl MetaRepoMgr {
|
||||||
let repo = db::query::repo::by_name(conn, repo).await?;
|
let repo = db::query::repo::by_name(conn, repo).await?;
|
||||||
|
|
||||||
if let Some(repo) = repo {
|
if let Some(repo) = repo {
|
||||||
let pkg = db::query::package::by_fields(conn, repo.id, arch, name).await?;
|
let pkg = db::query::package::by_fields(conn, repo.id, arch, name, None, None).await?;
|
||||||
|
|
||||||
if let Some(pkg) = pkg {
|
if let Some(pkg) = pkg {
|
||||||
// Remove package from database
|
// Remove package from database
|
||||||
|
@ -180,8 +180,15 @@ impl MetaRepoMgr {
|
||||||
};
|
};
|
||||||
|
|
||||||
// If the package already exists in the database, we remove it first
|
// If the package already exists in the database, we remove it first
|
||||||
let res =
|
let res = db::query::package::by_fields(
|
||||||
db::query::package::by_fields(conn, repo_id, &pkg.info.arch, &pkg.info.name).await?;
|
conn,
|
||||||
|
repo_id,
|
||||||
|
&pkg.info.arch,
|
||||||
|
&pkg.info.name,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
if let Some(entry) = res {
|
if let Some(entry) = res {
|
||||||
entry.delete(conn).await?;
|
entry.delete(conn).await?;
|
||||||
|
|
|
@ -19,6 +19,7 @@ use axum::routing::{delete, post};
|
||||||
use axum::Router;
|
use axum::Router;
|
||||||
use futures::TryStreamExt;
|
use futures::TryStreamExt;
|
||||||
use futures::{Stream, StreamExt};
|
use futures::{Stream, StreamExt};
|
||||||
|
use regex::Regex;
|
||||||
use sea_orm::ModelTrait;
|
use sea_orm::ModelTrait;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::{fs, io::AsyncWriteExt};
|
use tokio::{fs, io::AsyncWriteExt};
|
||||||
|
@ -56,52 +57,43 @@ pub fn router(api_key: &str) -> Router<crate::Global> {
|
||||||
/// is returned.
|
/// is returned.
|
||||||
async fn get_file(
|
async fn get_file(
|
||||||
State(global): State<crate::Global>,
|
State(global): State<crate::Global>,
|
||||||
Path((repo, arch, mut file_name)): Path<(String, String, String)>,
|
Path((repo, _arch, file_name)): Path<(String, String, String)>,
|
||||||
req: Request<Body>,
|
req: Request<Body>,
|
||||||
) -> crate::Result<impl IntoResponse> {
|
) -> crate::Result<impl IntoResponse> {
|
||||||
let repo_dir = global.config.repo_dir.join(&repo).join(&arch);
|
// Query the repo to see if it exists
|
||||||
let repo_exists = tokio::fs::try_exists(&repo_dir).await?;
|
let repo = db::query::repo::by_name(&global.db, &repo)
|
||||||
|
.await?
|
||||||
|
.ok_or(StatusCode::NOT_FOUND)?;
|
||||||
|
|
||||||
let res = if DB_FILE_EXTS.iter().any(|ext| file_name.ends_with(ext)) {
|
// Match the filename
|
||||||
// Append tar extension to ensure we find the file
|
let caps = global
|
||||||
if !file_name.ends_with(".tar.gz") {
|
.pkg_filename_re
|
||||||
file_name.push_str(".tar.gz");
|
.captures(&file_name)
|
||||||
};
|
.ok_or(StatusCode::NOT_FOUND)?;
|
||||||
|
let arch = caps.get(3).unwrap().as_str();
|
||||||
|
|
||||||
if repo_exists {
|
// Query the package to see if it exists
|
||||||
ServeFile::new(repo_dir.join(file_name)).oneshot(req).await
|
let pkg = db::query::package::by_fields(
|
||||||
} else {
|
&global.db,
|
||||||
let path = global
|
repo.id,
|
||||||
.config
|
arch,
|
||||||
.repo_dir
|
caps.get(1).unwrap().as_str(),
|
||||||
.join(repo)
|
Some(caps.get(2).unwrap().as_str()),
|
||||||
.join(manager::ANY_ARCH)
|
Some(caps.get(4).unwrap().as_str()),
|
||||||
.join(file_name);
|
)
|
||||||
|
.await?
|
||||||
|
.ok_or(StatusCode::NOT_FOUND)?;
|
||||||
|
|
||||||
ServeFile::new(path).oneshot(req).await
|
// Serve the file if it idoes
|
||||||
}
|
let pkg_path = global
|
||||||
} else {
|
.config
|
||||||
let any_file = global
|
.pkg_dir
|
||||||
.config
|
.join(repo.name)
|
||||||
.pkg_dir
|
.join(arch)
|
||||||
.join(repo)
|
.join(package::filename(&pkg));
|
||||||
.join(manager::ANY_ARCH)
|
Ok(ServeFile::new(pkg_path).oneshot(req).await.unwrap())
|
||||||
.join(file_name);
|
|
||||||
|
|
||||||
if repo_exists {
|
|
||||||
ServeDir::new(global.config.pkg_dir)
|
|
||||||
.fallback(ServeFile::new(any_file))
|
|
||||||
.oneshot(req)
|
|
||||||
.await
|
|
||||||
} else {
|
|
||||||
ServeFile::new(any_file).oneshot(req).await
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[axum::debug_handler]
|
|
||||||
async fn post_package_archive(
|
async fn post_package_archive(
|
||||||
State(global): State<crate::Global>,
|
State(global): State<crate::Global>,
|
||||||
Path(repo): Path<String>,
|
Path(repo): Path<String>,
|
||||||
|
@ -122,7 +114,6 @@ async fn post_package_archive(
|
||||||
//tracing::info!("Added '{}' to repository '{}'", pkg.file_name(), repo);
|
//tracing::info!("Added '{}' to repository '{}'", pkg.file_name(), repo);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[axum::debug_handler]
|
|
||||||
async fn delete_repo(
|
async fn delete_repo(
|
||||||
State(global): State<crate::Global>,
|
State(global): State<crate::Global>,
|
||||||
Path(repo): Path<String>,
|
Path(repo): Path<String>,
|
||||||
|
@ -207,11 +198,3 @@ async fn delete_package(
|
||||||
// Ok(StatusCode::NOT_FOUND)
|
// Ok(StatusCode::NOT_FOUND)
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn help_me_figure_this_out(_: impl Send) {}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn assert_my_handler_is_ok() {
|
|
||||||
// This is the fun part: we need to call our handler, and *not* await it's Future.
|
|
||||||
help_me_figure_this_out(delete_repo)
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue