130 lines
3.5 KiB
Rust
130 lines
3.5 KiB
Rust
use super::{RepoCommand, RepoSharedState};
|
|
use crate::db;
|
|
|
|
use std::{
|
|
collections::HashMap,
|
|
path::{Path, PathBuf},
|
|
sync::{
|
|
atomic::{AtomicU32, Ordering},
|
|
Arc, Mutex, RwLock,
|
|
},
|
|
};
|
|
|
|
use sea_orm::{
|
|
ActiveModelTrait, ColumnTrait, Condition, ConnectionTrait, DbConn, EntityTrait, JoinType,
|
|
ModelTrait, NotSet, QueryFilter, QuerySelect, Related, RelationTrait, Set, TransactionTrait,
|
|
};
|
|
use tokio::{
|
|
runtime,
|
|
sync::mpsc::{unbounded_channel, UnboundedSender},
|
|
};
|
|
use uuid::Uuid;
|
|
|
|
#[derive(Clone)]
|
|
pub struct Handle {
|
|
state: Arc<RepoSharedState>,
|
|
}
|
|
|
|
impl Handle {
|
|
pub fn start(
|
|
repos_dir: impl AsRef<Path>,
|
|
conn: DbConn,
|
|
rt: runtime::Handle,
|
|
actors: u32,
|
|
) -> crate::Result<Self> {
|
|
std::fs::create_dir_all(repos_dir.as_ref())?;
|
|
|
|
let mut repos = HashMap::new();
|
|
let repo_ids: Vec<i32> = rt.block_on(
|
|
db::Repo::find()
|
|
.select_only()
|
|
.column(db::repo::Column::Id)
|
|
.into_tuple()
|
|
.all(&conn),
|
|
)?;
|
|
|
|
for id in repo_ids {
|
|
repos.insert(id, Default::default());
|
|
}
|
|
|
|
let state = Arc::new(RepoSharedState::new(repos_dir, conn, repos));
|
|
|
|
for _ in 0..actors {
|
|
let actor = super::RepoActor::new(rt.clone(), Arc::clone(&state));
|
|
|
|
std::thread::spawn(|| actor.run());
|
|
}
|
|
|
|
Ok(Self { state })
|
|
}
|
|
|
|
pub fn random_file_paths<const C: usize>(&self) -> [PathBuf; C] {
|
|
std::array::from_fn(|_| {
|
|
let uuid: uuid::fmt::Simple = Uuid::new_v4().into();
|
|
self.state.repos_dir.join(uuid.to_string())
|
|
})
|
|
}
|
|
|
|
pub async fn get_or_create_repo(&self, distro: &str, repo: &str) -> crate::Result<i32> {
|
|
let mut repos = self.state.repos.write().await;
|
|
|
|
let distro_id: Option<i32> = db::Distro::find()
|
|
.filter(db::distro::Column::Name.eq(distro))
|
|
.select_only()
|
|
.column(db::distro::Column::Id)
|
|
.into_tuple()
|
|
.one(&self.state.conn)
|
|
.await?;
|
|
|
|
let distro_id = if let Some(id) = distro_id {
|
|
id
|
|
} else {
|
|
let new_distro = db::distro::ActiveModel {
|
|
id: NotSet,
|
|
name: Set(distro.to_string()),
|
|
description: NotSet,
|
|
};
|
|
|
|
new_distro.insert(&self.state.conn).await?.id
|
|
};
|
|
|
|
let repo_id: Option<i32> = db::Repo::find()
|
|
.filter(db::repo::Column::DistroId.eq(distro_id))
|
|
.filter(db::repo::Column::Name.eq(repo))
|
|
.select_only()
|
|
.column(db::repo::Column::Id)
|
|
.into_tuple()
|
|
.one(&self.state.conn)
|
|
.await?;
|
|
|
|
let repo_id = if let Some(id) = repo_id {
|
|
id
|
|
} else {
|
|
let new_repo = db::repo::ActiveModel {
|
|
id: NotSet,
|
|
distro_id: Set(distro_id),
|
|
name: Set(repo.to_string()),
|
|
description: NotSet,
|
|
};
|
|
let id = new_repo.insert(&self.state.conn).await?.id;
|
|
|
|
tokio::fs::create_dir(self.state.repos_dir.join(id.to_string())).await?;
|
|
repos.insert(id, Default::default());
|
|
|
|
id
|
|
};
|
|
|
|
Ok(repo_id)
|
|
}
|
|
|
|
pub async fn queue_pkg(&self, repo: i32, path: PathBuf) {
|
|
self.state
|
|
.tx
|
|
.send(RepoCommand::ParsePkg(repo, path))
|
|
.unwrap();
|
|
self.state.repos.read().await.get(&repo).inspect(|n| {
|
|
n.0.fetch_add(1, Ordering::SeqCst);
|
|
});
|
|
}
|
|
}
|