gitdataai/lib/git/rpc/registry.rs
2026-05-30 01:38:40 +08:00

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))
}