feat(api): extend commit and diff services with new functionality

- Add FindCommit, ListCommitsByOid, CommitIsAncestor RPCs to CommitService
- Add CheckObjectsExist, CommitsByMessage, GetCommitStats RPCs to CommitService
- Add LastCommitForPath, CountCommits, CountDivergingCommits RPCs to CommitService
- Add RawDiff, RawPatch, FindChangedPaths RPCs to DiffService
- Add FindMergeBase, WriteRef, SearchFilesByContent RPCs to RepositoryService
- Add SearchFilesByName, ObjectsSize, RepositorySize RPCs to RepositoryService
- Add FindLicense, OptimizeRepository, GetRawChanges RPCs to RepositoryService
- Add FetchRemote, CreateRepositoryFromURL RPCs to RepositoryService
- Implement server handlers for all new RPC methods
- Add new modules for commit counting, finding, and querying features
- Add new modules for diff changed paths and raw operations
- Add new modules for refs and remote operations
- Remove unnecessary comments from various source files
- Update proto definitions with new message types and service methods
This commit is contained in:
zhenyi
2026-06-08 15:37:08 +08:00
parent 8f472a0443
commit 66afd932ed
43 changed files with 3070 additions and 75 deletions
+119
View File
@@ -275,4 +275,123 @@ impl commit_service_server::CommitService for GitksService {
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn find_commit(
&self,
request: tonic::Request<FindCommitRequest>,
) -> Result<tonic::Response<Commit>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.CommitService/FindCommit");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.find_commit(inner).map_err(into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn list_commits_by_oid(
&self,
request: tonic::Request<ListCommitsByOidRequest>,
) -> Result<tonic::Response<ListCommitsByOidResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.CommitService/ListCommitsByOid");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.list_commits_by_oid(inner).map_err(into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn commit_is_ancestor(
&self,
request: tonic::Request<CommitIsAncestorRequest>,
) -> Result<tonic::Response<CommitIsAncestorResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.CommitService/CommitIsAncestor");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.commit_is_ancestor(inner).map_err(into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn check_objects_exist(
&self,
request: tonic::Request<CheckObjectsExistRequest>,
) -> Result<tonic::Response<CheckObjectsExistResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.CommitService/CheckObjectsExist");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.check_objects_exist(inner).map_err(into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn commits_by_message(
&self,
request: tonic::Request<CommitsByMessageRequest>,
) -> Result<tonic::Response<CommitsByMessageResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.CommitService/CommitsByMessage");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.commits_by_message(inner).map_err(into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn get_commit_stats(
&self,
request: tonic::Request<GetCommitStatsRequest>,
) -> Result<tonic::Response<CommitStats>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.CommitService/GetCommitStats");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.get_commit_stats(inner).map_err(into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn last_commit_for_path(
&self,
request: tonic::Request<LastCommitForPathRequest>,
) -> Result<tonic::Response<LastCommitForPathResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.CommitService/LastCommitForPath");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.last_commit_for_path(inner).map_err(into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn count_commits(
&self,
request: tonic::Request<CountCommitsRequest>,
) -> Result<tonic::Response<CountCommitsResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.CommitService/CountCommits");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.count_commits(inner).map_err(into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn count_diverging_commits(
&self,
request: tonic::Request<CountDivergingCommitsRequest>,
) -> Result<tonic::Response<CountDivergingCommitsResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.CommitService/CountDivergingCommits");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.count_diverging_commits(inner).map_err(into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
}
+44
View File
@@ -169,4 +169,48 @@ impl diff_service_server::DiffService for GitksService {
m.record("ok");
Ok(tonic::Response::new(resp))
}
type RawDiffStream = tokio_stream::wrappers::ReceiverStream<Result<RawDiffResponse, tonic::Status>>;
type RawPatchStream = tokio_stream::wrappers::ReceiverStream<Result<RawPatchResponse, tonic::Status>>;
async fn raw_diff(
&self,
request: tonic::Request<RawDiffRequest>,
) -> Result<tonic::Response<Self::RawDiffStream>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.DiffService/RawDiff");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let chunks = gb.raw_diff(inner).map_err(into_status)?;
m.record("ok");
Ok(tonic::Response::new(into_stream(chunks)))
}
async fn raw_patch(
&self,
request: tonic::Request<RawPatchRequest>,
) -> Result<tonic::Response<Self::RawPatchStream>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.DiffService/RawPatch");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let chunks = gb.raw_patch(inner).map_err(into_status)?;
m.record("ok");
Ok(tonic::Response::new(into_stream(chunks)))
}
async fn find_changed_paths(
&self,
request: tonic::Request<FindChangedPathsRequest>,
) -> Result<tonic::Response<FindChangedPathsResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.DiffService/FindChangedPaths");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.find_changed_paths(inner).map_err(into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
}
+6 -2
View File
@@ -38,6 +38,8 @@ mod commit;
mod diff;
mod merge;
mod pack;
mod refs;
mod remote;
mod repository;
mod repository_maint;
mod tag;
@@ -53,8 +55,8 @@ use crate::bare::GitBare;
use crate::error::{GitError, GitResult};
use crate::pb::{
archive_service_server, blame_service_server, branch_service_server, commit_service_server,
diff_service_server, merge_service_server, pack_service_server, repository_service_server,
tag_service_server, tree_service_server,
diff_service_server, merge_service_server, pack_service_server, ref_service_server,
remote_service_server, repository_service_server, tag_service_server, tree_service_server,
};
#[derive(Clone)]
@@ -473,6 +475,8 @@ pub async fn serve(
.add_service(diff_service_server::DiffServiceServer::new(svc.clone()))
.add_service(merge_service_server::MergeServiceServer::new(svc.clone()))
.add_service(pack_service_server::PackServiceServer::new(svc.clone()))
.add_service(ref_service_server::RefServiceServer::new(svc.clone()))
.add_service(remote_service_server::RemoteServiceServer::new(svc.clone()))
.add_service(tag_service_server::TagServiceServer::new(svc.clone()))
.add_service(tree_service_server::TreeServiceServer::new(svc));
tracing::info!("server ready, starting to accept connections");
+85
View File
@@ -0,0 +1,85 @@
use crate::pb::*;
use crate::pb::ref_service_server::RefService;
use super::GitksService;
#[tonic::async_trait]
impl RefService for GitksService {
async fn find_default_branch_name(
&self,
request: tonic::Request<FindDefaultBranchNameRequest>,
) -> Result<tonic::Response<FindDefaultBranchNameResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.RefService/FindDefaultBranchName");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.find_default_branch_name().map_err(super::into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn ref_exists(
&self,
request: tonic::Request<RefExistsRequest>,
) -> Result<tonic::Response<RefExistsResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.RefService/RefExists");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.ref_exists(inner).map_err(super::into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn update_references(
&self,
request: tonic::Request<UpdateReferencesRequest>,
) -> Result<tonic::Response<UpdateReferencesResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.RefService/UpdateReferences");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.update_references(inner).map_err(super::into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn delete_refs(
&self,
request: tonic::Request<DeleteRefsRequest>,
) -> Result<tonic::Response<DeleteRefsResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.RefService/DeleteRefs");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.delete_refs(inner).map_err(super::into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn find_refs_by_oid(
&self,
request: tonic::Request<FindRefsByOidRequest>,
) -> Result<tonic::Response<FindRefsByOidResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.RefService/FindRefsByOID");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.find_refs_by_oid(inner).map_err(super::into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn list_refs(
&self,
request: tonic::Request<ListRefsRequest>,
) -> Result<tonic::Response<ListRefsResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.RefService/ListRefs");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.list_all_refs(inner).map_err(super::into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
}
+43
View File
@@ -0,0 +1,43 @@
use crate::pb::*;
use crate::pb::remote_service_server::RemoteService;
use crate::remote::find_remote::{find_remote_repository, find_remote_root_ref};
use super::GitksService;
#[tonic::async_trait]
impl RemoteService for GitksService {
async fn find_remote_repository(
&self,
request: tonic::Request<FindRemoteRepositoryRequest>,
) -> Result<tonic::Response<FindRemoteRepositoryResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.RemoteService/FindRemoteRepository");
let inner = request.into_inner();
let resp = find_remote_repository(inner).map_err(super::into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn find_remote_root_ref(
&self,
request: tonic::Request<FindRemoteRootRefRequest>,
) -> Result<tonic::Response<FindRemoteRootRefResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.RemoteService/FindRemoteRootRef");
let inner = request.into_inner();
let resp = find_remote_root_ref(inner).map_err(super::into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn update_remote_mirror(
&self,
request: tonic::Request<UpdateRemoteMirrorRequest>,
) -> Result<tonic::Response<UpdateRemoteMirrorResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.RemoteService/UpdateRemoteMirror");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.update_remote_mirror(inner).map_err(super::into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
}
+158 -3
View File
@@ -446,7 +446,6 @@ impl repository_service_server::RepositoryService for GitksService {
Ok(tonic::Response::new(resp))
}
// ── Hooks Management ────────────────────────────────────────────
async fn list_hooks(
&self,
@@ -508,7 +507,6 @@ impl repository_service_server::RepositoryService for GitksService {
Ok(tonic::Response::new(()))
}
// ── Snapshot Operations ──────────────────────────────────────────
async fn create_snapshot(
&self,
@@ -614,7 +612,6 @@ impl repository_service_server::RepositoryService for GitksService {
Ok(tonic::Response::new(()))
}
// ── Repository Move ──────────────────────────────────────────────
type FetchRepositoryDataStream =
ReceiverStream<Result<FetchRepositoryDataResponse, tonic::Status>>;
@@ -706,4 +703,162 @@ impl repository_service_server::RepositoryService for GitksService {
Ok(tonic::Response::new(ReceiverStream::new(rx)))
}
async fn find_merge_base(
&self,
request: tonic::Request<FindMergeBaseRequest>,
) -> Result<tonic::Response<FindMergeBaseResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.RepositoryService/FindMergeBase");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.find_merge_base(inner).map_err(into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn write_ref(
&self,
request: tonic::Request<WriteRefRequest>,
) -> Result<tonic::Response<WriteRefResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.RepositoryService/WriteRef");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.write_ref(inner).map_err(into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn search_files_by_content(
&self,
request: tonic::Request<SearchFilesByContentRequest>,
) -> Result<tonic::Response<SearchFilesByContentResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.RepositoryService/SearchFilesByContent");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.search_files_by_content(inner).map_err(into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn search_files_by_name(
&self,
request: tonic::Request<SearchFilesByNameRequest>,
) -> Result<tonic::Response<SearchFilesByNameResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.RepositoryService/SearchFilesByName");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.search_files_by_name(inner).map_err(into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn objects_size(
&self,
request: tonic::Request<ObjectsSizeRequest>,
) -> Result<tonic::Response<ObjectsSizeResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.RepositoryService/ObjectsSize");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.objects_size(inner).map_err(into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn repository_size(
&self,
request: tonic::Request<RepositorySizeRequest>,
) -> Result<tonic::Response<RepositorySizeResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.RepositoryService/RepositorySize");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.repository_size().map_err(into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn fetch_remote(
&self,
request: tonic::Request<FetchRemoteRequest>,
) -> Result<tonic::Response<FetchRemoteResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.RepositoryService/FetchRemote");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.fetch_remote(inner).map_err(into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn create_repository_from_url(
&self,
request: tonic::Request<CreateRepositoryFromUrlRequest>,
) -> Result<tonic::Response<CreateRepositoryFromUrlResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.RepositoryService/CreateRepositoryFromURL");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let bare_dir = self.resolve_for_init(inner.repository.as_ref())?;
let gb = crate::bare::GitBare::new(bare_dir);
gb.create_repository_from_url(&inner.remote_url, inner.mirror)
.map_err(into_status)?;
if let Some(ref hm) = self.hook_manager {
hm.install_hooks(&gb.bare_dir).map_err(into_status)?;
}
self.notify_ref_update(&self.repo_label(inner.repository.as_ref()), "HEAD", "", "");
m.record("ok");
Ok(tonic::Response::new(CreateRepositoryFromUrlResponse {
repository: Some(Repository {
header: inner.repository,
bare: true,
..Default::default()
}),
}))
}
async fn find_license(
&self,
request: tonic::Request<FindLicenseRequest>,
) -> Result<tonic::Response<FindLicenseResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.RepositoryService/FindLicense");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.find_license().map_err(into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn optimize_repository(
&self,
request: tonic::Request<OptimizeRepositoryRequest>,
) -> Result<tonic::Response<OptimizeRepositoryResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.RepositoryService/OptimizeRepository");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.optimize_repository(inner).map_err(into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
async fn get_raw_changes(
&self,
request: tonic::Request<GetRawChangesRequest>,
) -> Result<tonic::Response<GetRawChangesResponse>, tonic::Status> {
let m = crate::metrics::RequestMetrics::new("gitks.RepositoryService/GetRawChanges");
let inner = request.into_inner();
let _rate = self.acquire_rate_limit(inner.repository.as_ref()).await?;
let gb = self.resolve(inner.repository.as_ref())?;
let resp = gb.get_raw_changes(inner).map_err(into_status)?;
m.record("ok");
Ok(tonic::Response::new(resp))
}
}