185 lines
6.4 KiB
Rust
185 lines
6.4 KiB
Rust
use std::sync::Arc;
|
|
|
|
use cache::AppCache;
|
|
use tonic::{Request, Response, Status};
|
|
|
|
use crate::rpc::{
|
|
error::{spawn_blocking_error, to_status},
|
|
proto as p,
|
|
registry::RepoRegistry,
|
|
};
|
|
|
|
pub struct TreeServiceImpl {
|
|
pub registry: Arc<RepoRegistry>,
|
|
pub cache: AppCache,
|
|
}
|
|
|
|
#[tonic::async_trait]
|
|
impl p::tree_service_server::TreeService for TreeServiceImpl {
|
|
async fn tree_entries(
|
|
&self,
|
|
req: Request<p::TreeEntriesRequest>,
|
|
) -> Result<Response<p::TreeEntriesResponse>, Status> {
|
|
let inner = req.into_inner();
|
|
let repo_id = inner.repo_id.clone();
|
|
let oid_val = inner.oid.clone().map(|o| o.value).unwrap_or_default();
|
|
let base_path = inner.base_path.clone();
|
|
let want_last = inner.last;
|
|
if !want_last {
|
|
let bare = self.registry.get(&repo_id).await?;
|
|
let oid = inner.oid.unwrap_or_default().into();
|
|
let entries = tokio::task::spawn_blocking(move || {
|
|
use crate::errors::GitError;
|
|
bare.tree_entries(oid)
|
|
.map_err(|e| {
|
|
GitError::Internal(format!("tree_entries: {e}"))
|
|
})
|
|
.map(|e| {
|
|
e.into_iter()
|
|
.map(Into::into)
|
|
.collect::<Vec<p::TreeEntry>>()
|
|
})
|
|
})
|
|
.await
|
|
.map_err(spawn_blocking_error)?
|
|
.map_err(to_status)?;
|
|
return Ok(Response::new(p::TreeEntriesResponse { entries }));
|
|
}
|
|
let cache_key = format!(
|
|
"git:rpc:cache:tree:entries:{}:{}:{}",
|
|
repo_id, oid_val, base_path
|
|
);
|
|
|
|
if let Ok(Some(cached)) =
|
|
self.cache.get::<Vec<p::TreeEntry>>(&cache_key).await
|
|
{
|
|
return Ok(Response::new(p::TreeEntriesResponse {
|
|
entries: cached,
|
|
}));
|
|
}
|
|
|
|
let bare = self.registry.get(&repo_id).await?;
|
|
let bare_bg = bare.clone();
|
|
let oid = inner.oid.unwrap_or_default().into();
|
|
let base_path_bg = base_path.clone();
|
|
let cache_bg = self.cache.clone();
|
|
let cache_key_bg = cache_key.clone();
|
|
|
|
let entries = tokio::task::spawn_blocking(move || {
|
|
use crate::errors::GitError;
|
|
bare.tree_entries(oid)
|
|
.map_err(|e| GitError::Internal(format!("tree_entries: {e}")))
|
|
.map(|e| {
|
|
e.into_iter().map(Into::into).collect::<Vec<p::TreeEntry>>()
|
|
})
|
|
})
|
|
.await
|
|
.map_err(spawn_blocking_error)?
|
|
.map_err(to_status)?;
|
|
|
|
let mut response = entries.clone();
|
|
for entry in &mut response {
|
|
entry.last_commit_message.clear();
|
|
entry.last_commit_time.clear();
|
|
entry.last_commit_author_name.clear();
|
|
entry.last_commit_author_email.clear();
|
|
}
|
|
|
|
tokio::task::spawn(async move {
|
|
let enriched = tokio::task::spawn_blocking(move || {
|
|
let paths: Vec<String> = entries
|
|
.iter()
|
|
.map(|e| {
|
|
if base_path_bg.is_empty() {
|
|
e.name.clone()
|
|
} else {
|
|
format!("{}/{}", base_path_bg, e.name)
|
|
}
|
|
})
|
|
.collect();
|
|
|
|
let last_commits = match bare_bg.last_commits_for_paths(&paths)
|
|
{
|
|
Ok(lc) => lc,
|
|
Err(_) => return entries,
|
|
};
|
|
|
|
let mut out = entries;
|
|
for (i, info) in last_commits.into_iter().enumerate() {
|
|
if let Some(info) = info {
|
|
if let Some(e) = out.get_mut(i) {
|
|
e.last_commit_message = info.message;
|
|
e.last_commit_time = info.time;
|
|
e.last_commit_author_name = info.author_name;
|
|
e.last_commit_author_email = info.author_email;
|
|
}
|
|
}
|
|
}
|
|
out
|
|
})
|
|
.await;
|
|
|
|
if let Ok(entries) = enriched {
|
|
let _ = cache_bg.set(&cache_key_bg, &entries).await;
|
|
}
|
|
});
|
|
|
|
Ok(Response::new(p::TreeEntriesResponse { entries: response }))
|
|
}
|
|
|
|
async fn tree_entry_by_path(
|
|
&self,
|
|
req: Request<p::TreeEntryByPathRequest>,
|
|
) -> Result<Response<p::TreeEntryByPathResponse>, Status> {
|
|
let inner = req.into_inner();
|
|
let bare = self.registry.get(&inner.repo_id).await?;
|
|
let tree_oid = inner.tree_oid.unwrap_or_default().into();
|
|
let path = inner.path;
|
|
let result = tokio::task::spawn_blocking(move || {
|
|
bare.tree_entry_by_path(tree_oid, path)
|
|
})
|
|
.await
|
|
.map_err(spawn_blocking_error)?
|
|
.map_err(to_status)?;
|
|
Ok(Response::new(p::TreeEntryByPathResponse {
|
|
entry: Some(result.into()),
|
|
}))
|
|
}
|
|
|
|
async fn tree_entry_by_path_from_commit(
|
|
&self,
|
|
req: Request<p::TreeEntryByPathFromCommitRequest>,
|
|
) -> Result<Response<p::TreeEntryByPathFromCommitResponse>, Status> {
|
|
let inner = req.into_inner();
|
|
let bare = self.registry.get(&inner.repo_id).await?;
|
|
let commit_oid = inner.commit_oid.unwrap_or_default().into();
|
|
let path = inner.path;
|
|
let result = tokio::task::spawn_blocking(move || {
|
|
bare.tree_entry_by_path_from_commit(commit_oid, path)
|
|
})
|
|
.await
|
|
.map_err(spawn_blocking_error)?
|
|
.map_err(to_status)?;
|
|
Ok(Response::new(p::TreeEntryByPathFromCommitResponse {
|
|
entry: Some(result.into()),
|
|
}))
|
|
}
|
|
|
|
async fn resolve_tree(
|
|
&self,
|
|
req: Request<p::ResolveTreeRequest>,
|
|
) -> Result<Response<p::ResolveTreeResponse>, Status> {
|
|
let inner = req.into_inner();
|
|
let bare = self.registry.get(&inner.repo_id).await?;
|
|
let oid = inner.oid.unwrap_or_default().into();
|
|
let result =
|
|
tokio::task::spawn_blocking(move || bare.resolve_tree(oid))
|
|
.await
|
|
.map_err(spawn_blocking_error)?
|
|
.map_err(to_status)?;
|
|
Ok(Response::new(p::ResolveTreeResponse {
|
|
info: Some(result.into()),
|
|
}))
|
|
}
|
|
}
|