use crate::pb::*; use crate::pb::commit_service_client::CommitServiceClient; use super::{GitksService, cache, into_status}; async fn remote_commit_client( svc: &GitksService, header: Option<&RepositoryHeader>, ) -> Result>, tonic::Status> { let header = match header { Some(h) => h, None => return Ok(None), }; let Some(route) = svc.route_repository(header).await? else { return Ok(None); }; tracing::info!(storage_name = %route.storage_name, relative_path = %route.relative_path, actor_name = %route.actor_name, grpc_addr = %route.grpc_addr, "forwarding commit rpc"); let endpoint = super::remote_endpoint(&route.grpc_addr).await?; let client = CommitServiceClient::connect(endpoint) .await .map_err(|e| tonic::Status::unavailable(e.to_string()))?; Ok(Some(client)) } #[tonic::async_trait] impl commit_service_server::CommitService for GitksService { async fn list_commits( &self, request: tonic::Request, ) -> Result, tonic::Status> { let inner = request.into_inner(); let repo = self.repo_label(inner.repository.as_ref()); let span = tracing::info_span!("commit.list_commits", %repo); let _enter = span.enter(); let gb = match self.resolve(inner.repository.as_ref()) { Ok(gb) => gb, Err(err) if err.code() == tonic::Code::NotFound => { if let Some(mut client) = remote_commit_client(self, inner.repository.as_ref()).await? { return client.list_commits(inner).await; } return Err(err); } Err(err) => return Err(err), }; let resp = if !inner.all && cache::selector_is_oid(&inner.revision) { cache::cached_response("commit.list_commits", &inner, || { gb.list_commits(inner.clone()).map_err(into_status) })? } else { gb.list_commits(inner).map_err(into_status)? }; tracing::info!(%repo, count = resp.commits.len(), total = resp.page_info.as_ref().map(|p| p.total_count).unwrap_or(0), "list_commits done"); Ok(tonic::Response::new(resp)) } async fn get_commit( &self, request: tonic::Request, ) -> Result, tonic::Status> { let inner = request.into_inner(); let repo = self.repo_label(inner.repository.as_ref()); let span = tracing::info_span!("commit.get_commit", %repo); let _enter = span.enter(); let gb = match self.resolve(inner.repository.as_ref()) { Ok(gb) => gb, Err(err) if err.code() == tonic::Code::NotFound => { if let Some(mut client) = remote_commit_client(self, inner.repository.as_ref()).await? { return client.get_commit(inner).await; } return Err(err); } Err(err) => return Err(err), }; let resp = if cache::selector_is_oid(&inner.revision) { cache::cached_response("commit.get_commit", &inner, || { gb.get_commit(inner.clone()).map_err(into_status) })? } else { gb.get_commit(inner).map_err(into_status)? }; Ok(tonic::Response::new(resp)) } async fn get_commit_ancestors( &self, request: tonic::Request, ) -> Result, tonic::Status> { let inner = request.into_inner(); let repo = self.repo_label(inner.repository.as_ref()); let span = tracing::info_span!("commit.get_commit_ancestors", %repo); let _enter = span.enter(); let gb = match self.resolve(inner.repository.as_ref()) { Ok(gb) => gb, Err(err) if err.code() == tonic::Code::NotFound => { if let Some(mut client) = remote_commit_client(self, inner.repository.as_ref()).await? { return client.get_commit_ancestors(inner).await; } return Err(err); } Err(err) => return Err(err), }; let resp = if cache::selector_is_oid(&inner.revision) { cache::cached_response("commit.get_commit_ancestors", &inner, || { gb.get_commit_ancestors(inner.clone()).map_err(into_status) })? } else { gb.get_commit_ancestors(inner).map_err(into_status)? }; tracing::info!(%repo, count = resp.commits.len(), "get_commit_ancestors done"); Ok(tonic::Response::new(resp)) } async fn create_commit( &self, request: tonic::Request, ) -> Result, tonic::Status> { let inner = request.into_inner(); let repo = self.repo_label(inner.repository.as_ref()); let branch = inner.branch.clone(); let span = tracing::info_span!("commit.create_commit", %repo, %branch); let _enter = span.enter(); let gb = match self.resolve(inner.repository.as_ref()) { Ok(gb) => gb, Err(err) if err.code() == tonic::Code::NotFound => { if let Some(mut client) = remote_commit_client(self, inner.repository.as_ref()).await? { return client.create_commit(inner).await; } return Err(err); } Err(err) => return Err(err), }; let resp = gb.create_commit(inner).map_err(into_status)?; let commit_hex = resp.commit.as_ref() .and_then(|c| c.oid.as_ref().map(|o| o.hex.as_str()).or(Some("?"))) .unwrap_or("?"); tracing::info!(%repo, %branch, %commit_hex, "commit created"); Ok(tonic::Response::new(resp)) } async fn revert_commit( &self, request: tonic::Request, ) -> Result, tonic::Status> { let inner = request.into_inner(); let repo = self.repo_label(inner.repository.as_ref()); let branch = inner.branch.clone(); let span = tracing::info_span!("commit.revert_commit", %repo, %branch); let _enter = span.enter(); let gb = match self.resolve(inner.repository.as_ref()) { Ok(gb) => gb, Err(err) if err.code() == tonic::Code::NotFound => { if let Some(mut client) = remote_commit_client(self, inner.repository.as_ref()).await? { return client.revert_commit(inner).await; } return Err(err); } Err(err) => return Err(err), }; let resp = gb.revert_commit(inner).map_err(into_status)?; tracing::info!(%repo, %branch, "commit reverted"); Ok(tonic::Response::new(resp)) } async fn cherry_pick_commit( &self, request: tonic::Request, ) -> Result, tonic::Status> { let inner = request.into_inner(); let repo = self.repo_label(inner.repository.as_ref()); let branch = inner.branch.clone(); let span = tracing::info_span!("commit.cherry_pick_commit", %repo, %branch); let _enter = span.enter(); let gb = match self.resolve(inner.repository.as_ref()) { Ok(gb) => gb, Err(err) if err.code() == tonic::Code::NotFound => { if let Some(mut client) = remote_commit_client(self, inner.repository.as_ref()).await? { return client.cherry_pick_commit(inner).await; } return Err(err); } Err(err) => return Err(err), }; let resp = gb.cherry_pick_commit(inner).map_err(into_status)?; tracing::info!(%repo, %branch, "commit cherry-picked"); Ok(tonic::Response::new(resp)) } async fn compare_commits( &self, request: tonic::Request, ) -> Result, tonic::Status> { let inner = request.into_inner(); let repo = self.repo_label(inner.repository.as_ref()); let span = tracing::info_span!("commit.compare_commits", %repo); let _enter = span.enter(); let gb = match self.resolve(inner.repository.as_ref()) { Ok(gb) => gb, Err(err) if err.code() == tonic::Code::NotFound => { if let Some(mut client) = remote_commit_client(self, inner.repository.as_ref()).await? { return client.compare_commits(inner).await; } return Err(err); } Err(err) => return Err(err), }; let resp = if cache::selectors_are_oid(&inner.base, &inner.head) { cache::cached_response("commit.compare_commits", &inner, || { gb.compare_commits(inner.clone()).map_err(into_status) })? } else { gb.compare_commits(inner).map_err(into_status)? }; tracing::info!(%repo, count = resp.commits.len(), "compare_commits done"); Ok(tonic::Response::new(resp)) } }