93 lines
2.5 KiB
Rust
93 lines
2.5 KiB
Rust
use std::{path::PathBuf, sync::Arc};
|
|
|
|
use cache::AppCache;
|
|
use dashmap::DashMap;
|
|
use db::database::AppDatabase;
|
|
use model::repos::RepoModel;
|
|
use sqlx::query_as;
|
|
use uuid::Uuid;
|
|
|
|
use crate::bare::GitBare;
|
|
|
|
const STORAGE_PATH_CACHE_KEY_PREFIX: &str = "git:rpc:repo:storage_path";
|
|
|
|
#[derive(Clone)]
|
|
pub struct RepoRegistry {
|
|
repos: DashMap<Uuid, GitBare>,
|
|
db: AppDatabase,
|
|
cache: AppCache,
|
|
}
|
|
|
|
impl RepoRegistry {
|
|
pub fn new(db: AppDatabase, cache: AppCache) -> Self {
|
|
Self {
|
|
repos: DashMap::new(),
|
|
db,
|
|
cache,
|
|
}
|
|
}
|
|
|
|
pub fn register(&self, repo_id: Uuid, bare_dir: PathBuf) {
|
|
let bare = GitBare { bare_dir };
|
|
self.repos.insert(repo_id, bare);
|
|
}
|
|
|
|
pub fn unregister(&self, repo_id: &Uuid) {
|
|
self.repos.remove(repo_id);
|
|
}
|
|
|
|
pub async fn get(
|
|
&self,
|
|
repo_id_str: &str,
|
|
) -> Result<GitBare, tonic::Status> {
|
|
let repo_id = repo_id_str.parse::<Uuid>().map_err(|e| {
|
|
tonic::Status::invalid_argument(format!(
|
|
"invalid repo_id UUID: {e}"
|
|
))
|
|
})?;
|
|
|
|
if let Some(bare) = self.repos.get(&repo_id) {
|
|
return Ok(bare.value().clone());
|
|
}
|
|
|
|
let storage_path = self.lookup_storage_path(repo_id).await?;
|
|
let bare = GitBare {
|
|
bare_dir: PathBuf::from(storage_path),
|
|
};
|
|
self.repos.insert(repo_id, bare.clone());
|
|
Ok(bare)
|
|
}
|
|
|
|
async fn lookup_storage_path(
|
|
&self,
|
|
repo_id: Uuid,
|
|
) -> Result<String, tonic::Status> {
|
|
let cache_key = format!("{STORAGE_PATH_CACHE_KEY_PREFIX}:{repo_id}");
|
|
|
|
if let Ok(Some(path)) = self.cache.get::<String>(&cache_key).await {
|
|
return Ok(path);
|
|
}
|
|
|
|
let model: RepoModel = query_as(
|
|
"SELECT id, wk, name, description, default_branch, visibility, size_bytes, is_archived, is_template, is_mirror, created_by, storage_path, created_at, updated_at, deleted_at FROM repo WHERE id = $1 AND deleted_at IS NULL",
|
|
)
|
|
.bind(repo_id)
|
|
.fetch_one(self.db.reader())
|
|
.await
|
|
.map_err(|e| tonic::Status::internal(format!("database error: {e}")))?;
|
|
|
|
let path = model.storage_path;
|
|
let _ = self.cache.set(&cache_key, &path).await;
|
|
|
|
Ok(path)
|
|
}
|
|
|
|
pub fn list(&self) -> Vec<Uuid> {
|
|
self.repos.iter().map(|r| *r.key()).collect()
|
|
}
|
|
}
|
|
|
|
pub fn shared_registry(db: AppDatabase, cache: AppCache) -> Arc<RepoRegistry> {
|
|
Arc::new(RepoRegistry::new(db, cache))
|
|
}
|