From 27674a03ab2068b7375ad39c56b00dfc1bc598f9 Mon Sep 17 00:00:00 2001 From: JasterV <49537445+JasterV@users.noreply.github.com> Date: Wed, 21 Jan 2026 15:49:56 +0100 Subject: [PATCH] refactor: decouple ReflectionClient to possibly publish in a separate crate --- granc/src/core.rs | 7 ++-- granc/src/core/reflection/client.rs | 21 ++++++---- .../reflection/client/integration_test.rs | 41 ++++++++++++------- 3 files changed, 44 insertions(+), 25 deletions(-) diff --git a/granc/src/core.rs b/granc/src/core.rs index 28f9df9..b2b3106 100644 --- a/granc/src/core.rs +++ b/granc/src/core.rs @@ -72,10 +72,9 @@ pub async fn run(input: Input) -> Result { Some(path) => DescriptorRegistry::from_file(path)?, // If no proto-set file is passed, we'll try to reach the server reflection service None => { - let mut service = ReflectionClient::connect(input.url.clone()).await?; - service - .resolve_service_descriptor_registry(&input.service) - .await? + let mut client = ReflectionClient::connect(input.url.clone()).await?; + let fd_set = client.file_descriptor_set_by_symbol(&input.service).await?; + DescriptorRegistry::from_file_descriptor_set(fd_set)? } }; diff --git a/granc/src/core/reflection/client.rs b/granc/src/core/reflection/client.rs index 4a88d4d..9d0f8de 100644 --- a/granc/src/core/reflection/client.rs +++ b/granc/src/core/reflection/client.rs @@ -19,7 +19,6 @@ use super::generated::reflection_v1::{ server_reflection_response::MessageResponse, }; use crate::core::BoxError; -use crate::core::reflection::DescriptorRegistry; use http_body::Body as HttpBody; use prost::Message; use prost_types::{FileDescriptorProto, FileDescriptorSet}; @@ -64,9 +63,6 @@ pub enum ReflectionResolveError { #[error("Failed to decode FileDescriptorProto: {0}")] DecodeError(#[from] prost::DecodeError), - - #[error("Failed to build DescriptorRegistry: {0}")] - RegistryError(#[from] crate::core::reflection::registry::DescriptorError), } /// A generic client for the gRPC Server Reflection Protocol. @@ -99,10 +95,21 @@ where T::ResponseBody: HttpBody + Send + 'static, ::Error: Into + Send, { - pub async fn resolve_service_descriptor_registry( + /// Asks the reflection service for the file containing the requested symbol (e.g., `my.package.MyService`). + /// + /// **Recursive Resolution**: + /// - The server returns a `FileDescriptorProto`. + /// - The client inspects the imports (dependencies) of that file. + /// - It recursively requests any missing dependencies until the full `FileDescriptorSet` is built. + /// + /// # Returns + /// + /// * `Ok(fd_set)` - Successful reflection requests execution. + /// * `Err(ReflectionResolveError)` - Failed to request file descriptors to the reflection service. + pub async fn file_descriptor_set_by_symbol( &mut self, service_name: &str, - ) -> Result { + ) -> Result { // Initialize Stream let (tx, rx) = mpsc::channel(100); @@ -133,7 +140,7 @@ where file: file_map.into_values().collect(), }; - Ok(DescriptorRegistry::from_file_descriptor_set(fd_set)?) + Ok(fd_set) } async fn collect_descriptors( diff --git a/granc/src/core/reflection/client/integration_test.rs b/granc/src/core/reflection/client/integration_test.rs index b5d25a1..03aa461 100644 --- a/granc/src/core/reflection/client/integration_test.rs +++ b/granc/src/core/reflection/client/integration_test.rs @@ -1,4 +1,5 @@ use crate::core::reflection::{ + DescriptorRegistry, client::{ ReflectionClient, ReflectionResolveError, integration_test::dummy_service::DummyEchoService, }, @@ -28,10 +29,13 @@ fn setup_reflection_client() async fn test_reflection_client_fetches_unary_echo() { let mut client = setup_reflection_client(); - let registry = client - .resolve_service_descriptor_registry("echo.EchoService") + let fd_set = client + .file_descriptor_set_by_symbol("echo.EchoService") .await - .expect("Failed to resolve service descriptor registry"); + .expect("Failed to fetch file descriptor set by symbol"); + + let registry = DescriptorRegistry::from_file_descriptor_set(fd_set) + .expect("Failed to build descriptor registry"); let method = registry .get_method_descriptor("echo.EchoService", "UnaryEcho") @@ -56,10 +60,13 @@ async fn test_reflection_client_fetches_unary_echo() { async fn test_reflection_client_fetches_server_streaming_echo() { let mut client = setup_reflection_client(); - let registry = client - .resolve_service_descriptor_registry("echo.EchoService") + let fd_set = client + .file_descriptor_set_by_symbol("echo.EchoService") .await - .expect("Failed to resolve service descriptor registry"); + .expect("Failed to fetch file descriptor set by symbol"); + + let registry = DescriptorRegistry::from_file_descriptor_set(fd_set) + .expect("Failed to build descriptor registry"); let method = registry .get_method_descriptor("echo.EchoService", "ServerStreamingEcho") @@ -84,10 +91,13 @@ async fn test_reflection_client_fetches_server_streaming_echo() { async fn test_reflection_client_fetches_client_streaming_echo() { let mut client = setup_reflection_client(); - let registry = client - .resolve_service_descriptor_registry("echo.EchoService") + let fd_set = client + .file_descriptor_set_by_symbol("echo.EchoService") .await - .expect("Failed to resolve service descriptor registry"); + .expect("Failed to fetch file descriptor set by symbol"); + + let registry = DescriptorRegistry::from_file_descriptor_set(fd_set) + .expect("Failed to build descriptor registry"); let method = registry .get_method_descriptor("echo.EchoService", "ClientStreamingEcho") @@ -112,10 +122,13 @@ async fn test_reflection_client_fetches_client_streaming_echo() { async fn test_reflection_client_fetches_bidirectional_echo() { let mut client = setup_reflection_client(); - let registry = client - .resolve_service_descriptor_registry("echo.EchoService") + let fd_set = client + .file_descriptor_set_by_symbol("echo.EchoService") .await - .expect("Failed to resolve service descriptor registry"); + .expect("Failed to fetch file descriptor set by symbol"); + + let registry = DescriptorRegistry::from_file_descriptor_set(fd_set) + .expect("Failed to build descriptor registry"); let method = registry .get_method_descriptor("echo.EchoService", "BidirectionalEcho") @@ -139,7 +152,7 @@ async fn test_reflection_service_not_found_error() { let mut client = setup_reflection_client(); let result: Result<_, _> = client - .resolve_service_descriptor_registry("non.existent.Service") + .file_descriptor_set_by_symbol("non.existent.Service") .await; assert!(matches!( @@ -161,7 +174,7 @@ async fn test_server_does_not_support_reflection() { // The client will attempt to call `/grpc.reflection.v1.ServerReflection/ServerReflectionInfo` on this service. let result = client - .resolve_service_descriptor_registry("echo.EchoService") + .file_descriptor_set_by_symbol("echo.EchoService") .await; match result {