diff --git a/server/src/repo/actor.rs b/server/src/repo/actor.rs index b90fcee..d76efa3 100644 --- a/server/src/repo/actor.rs +++ b/server/src/repo/actor.rs @@ -27,6 +27,8 @@ use uuid::Uuid; pub enum RepoCommand { ParsePkg(i32, PathBuf), + SyncRepo(i32), + Clean, } pub struct RepoSharedState { @@ -98,6 +100,12 @@ impl RepoActor { let _ = self.sync_repo(repo); } } + RepoCommand::SyncRepo(repo) => { + let _ = self.sync_repo(repo); + } + RepoCommand::Clean => { + let _ = self.clean(); + } } } } @@ -223,4 +231,8 @@ impl RepoActor { Ok(()) } + + fn clean(&self) -> crate::Result<()> { + todo!() + } } diff --git a/server/src/repo/handle.rs b/server/src/repo/handle.rs index 262f274..9e63e81 100644 --- a/server/src/repo/handle.rs +++ b/server/src/repo/handle.rs @@ -14,6 +14,7 @@ use sea_orm::{ ActiveModelTrait, ColumnTrait, Condition, ConnectionTrait, DbConn, EntityTrait, JoinType, ModelTrait, NotSet, QueryFilter, QuerySelect, Related, RelationTrait, Set, TransactionTrait, }; +use sea_query::{Alias, Expr, Query}; use tokio::{ runtime, sync::mpsc::{unbounded_channel, UnboundedSender}, @@ -117,6 +118,50 @@ impl Handle { Ok(repo_id) } + pub async fn get_repo(&self, distro: &str, repo: &str) -> crate::Result> { + Ok(db::Repo::find() + .find_also_related(db::Distro) + .filter( + Condition::all() + .add(db::repo::Column::Name.eq(repo)) + .add(db::distro::Column::Name.eq(distro)), + ) + .one(&self.state.conn) + .await + .map(|res| res.map(|(repo, _)| repo.id))?) + } + + pub async fn remove_repo(&self, repo: i32) -> crate::Result<()> { + self.state.repos.write().await.remove(&repo); + db::Repo::delete_by_id(repo).exec(&self.state.conn).await?; + let _ = tokio::fs::remove_dir_all(self.state.repos_dir.join(repo.to_string())).await; + + Ok(()) + } + + /// Remove all packages in the repository that have a given arch. This method marks all + /// packages with the given architecture as "pending deletion", before performing a manual sync + /// & removal of stale packages. + pub async fn remove_repo_arch(&self, repo: i32, arch: &str) -> crate::Result<()> { + db::Package::update_many() + .col_expr( + db::package::Column::State, + Expr::value(db::PackageState::PendingDeletion), + ) + .filter( + Condition::all() + .add(db::package::Column::RepoId.eq(repo)) + .add(db::package::Column::Arch.eq(arch)), + ) + .exec(&self.state.conn) + .await?; + + self.queue_sync(repo).await; + self.queue_clean().await; + + Ok(()) + } + pub async fn queue_pkg(&self, repo: i32, path: PathBuf) { self.state .tx @@ -126,4 +171,12 @@ impl Handle { n.0.fetch_add(1, Ordering::SeqCst); }); } + + async fn queue_sync(&self, repo: i32) { + self.state.tx.send(RepoCommand::SyncRepo(repo)).unwrap(); + } + + async fn queue_clean(&self) { + self.state.tx.send(RepoCommand::Clean).unwrap(); + } } diff --git a/server/src/repo/mod.rs b/server/src/repo/mod.rs index e8b65e3..f48c0d7 100644 --- a/server/src/repo/mod.rs +++ b/server/src/repo/mod.rs @@ -51,31 +51,30 @@ async fn get_file( Path((distro, repo, arch, file_name)): Path<(String, String, String, String)>, req: Request, ) -> crate::Result { - Ok(StatusCode::NOT_FOUND) - //if let Some(repo_id) = global.mgr.get_repo(&distro, &repo).await? { - // match global.config.fs { - // FsConfig::Local { data_dir } => { - // let repo_dir = data_dir.join("repos").join(repo_id.to_string()); - // - // 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 - // }; - // - // let path = repo_dir.join(file_name); - // Ok(ServeFile::new(path).oneshot(req).await) - // } - // } - //} else { - // Err(StatusCode::NOT_FOUND.into()) - //} + if let Some(repo_id) = global.repo.get_repo(&distro, &repo).await? { + match global.config.fs { + FsConfig::Local { data_dir } => { + let repo_dir = data_dir.join("repos").join(repo_id.to_string()); + + 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 + }; + + let path = repo_dir.join(file_name); + Ok(ServeFile::new(path).oneshot(req).await) + } + } + } else { + Err(StatusCode::NOT_FOUND.into()) + } } async fn post_package_archive( @@ -99,45 +98,30 @@ async fn delete_repo( State(global): State, Path((distro, repo)): Path<(String, String)>, ) -> crate::Result { - Ok(StatusCode::NOT_FOUND) - //if let Some(repo) = global.mgr.get_repo(&distro, &repo).await? { - // global.mgr.remove_repo(repo).await?; - // - // tracing::info!("Removed repository {repo}"); - // - // Ok(StatusCode::OK) - //} else { - // Ok(StatusCode::NOT_FOUND) - //} + if let Some(repo) = global.repo.get_repo(&distro, &repo).await? { + global.repo.remove_repo(repo).await?; + + tracing::info!("Removed repository {repo}"); + + Ok(StatusCode::OK) + } else { + Ok(StatusCode::NOT_FOUND) + } } async fn delete_arch_repo( State(global): State, Path((distro, repo, arch)): Path<(String, String, String)>, ) -> crate::Result { - Ok(StatusCode::NOT_FOUND) - //if let Some(repo) = global.mgr.get_repo(&distro, &repo).await? { - // global.mgr.remove_repo_arch(repo, &arch).await?; - // - // tracing::info!("Removed architecture '{arch}' from repository {repo}"); - // - // Ok(StatusCode::OK) - //} else { - // Ok(StatusCode::NOT_FOUND) - //} - //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) - //} + if let Some(repo) = global.repo.get_repo(&distro, &repo).await? { + global.repo.remove_repo_arch(repo, &arch).await?; + + tracing::info!("Removed architecture '{arch}' from repository {repo}"); + + Ok(StatusCode::OK) + } else { + Ok(StatusCode::NOT_FOUND) + } } async fn delete_package(