Skip to content

Implement Interceptor API - #8

Open
sauravzg wants to merge 8 commits into
codec_handlersfrom
interceptor_api
Open

Implement Interceptor API#8
sauravzg wants to merge 8 commits into
codec_handlersfrom
interceptor_api

Conversation

@sauravzg

Copy link
Copy Markdown
Owner

No description provided.

@sauravzg

Copy link
Copy Markdown
Owner Author

These traits are supposed to provide abstractions over standard references and protobuf views and muts to eliminate hard dependency on protobuf

The biggest challenge in the message module is to solve the long-standing difficulty of reborrowing mutable message views.

The Problem: Reborrowing GATs
When working with Generic Associated Types (GATs) for mutable views (e.g., type Mut<'a>), we frequently need to "reborrow" a view to pass it to a child function without consuming the original. However, traditional approaches fail here:
1. Foreign Types: We cannot add a .reborrow() method directly to protobuf::Mut as it is a foreign type.
2. HRTB Hell: Defining a separate Reborrow trait and requiring for<'a> T::Mut<'a>: Reborrow leads to complex Higher-Ranked Trait Bound errors (e.g., "implementation is not general enough") that are extremely difficult to satisfy in Rust's current type system.
The Solution: Static Operator Pattern
We bypass these issues by moving the reborrowing logic into the provider trait itself as a static operator.
* Introduced AsMut::reborrow_view<'a, 'b>(view: &'b mut Self::Mut<'a>) -> Self::Mut<'b>.
* This bundles the reborrowing logic with the type definition, avoiding the need for extra traits or complex HRTB bounds on the view type itself.
Changes:
* as_mut.rs: Defined AsMut with the reborrow_view static operator. Implemented it for protobuf::Message and added tests verifying that views can be reborrowed and mutated without consuming the original.
* as_view.rs: Defined AsView for immutable views.
…terns

This change introduces an initial implementation of the stream API, designed to mimic the API surface of Google's internal C++ versions.

Key Highlights:
*   **API Mimicry**: This implementation mimics the API but does not reflect the true implementation of the internal C++ versions. It is currently functionally incomplete, particularly regarding context management between the producer and the writer.
*   **Dynamic Traits**: We have chosen to use `dyn` traits to allow for simpler injection of functors.

This implementation is currently sufficient to enable experimental development against this form of API. We plan to improve functionality and performance in future iterations.
Introduce the public API traits for server-side gRPC methods (`UnaryMethod`, `ClientStreamingMethod`, `ServerStreamingMethod`, `BidiStreamingMethod`).
These traits are designed to be the primary interface for codegen.

Currently, the API utilizes Google's internal StreamAPIs (e.g., `PushStream`). We plan to eventually support Tonic-like APIs and adapt the implementation later; this step is primarily to unblock server-side implementation progress.

Note on design:
- The public API is scoped to access request and response messages only.
- Modifications to headers and trailers are intended to be handled via "interceptor" APIs, following the Java gRPC model.
- Contextual information is expected to be accessed via a read-only local context.
…c API

This change introduces data objects for the internal generic API.
We introduce separate objects for Unary and Streaming (e.g., `UnaryRequest` vs `StreamingRequest`, `UnaryResponseWriter` vs `StreamingResponseWriter`) as unifying reference and owned APIs proved difficult.

The input side (`UnaryRequest`, `StreamingRequest`) is straightforward, providing access to metadata and the message/stream.

The output side (`StreamingResponseWriter`) is slightly nuanced, offering a "staged builder" like API:
1.  `send_initial_metadata(metadata)` transitions to a `BodyWriter`.
2.  The `BodyWriter` allows writing the actual stream and sending trailers.

A unit test (`test_interceptor_composition`) is added to demonstrate how a writer can be intercepted, which is more nuanced than intercepting the read input stream.

UnaryMethod ByteStream Handler

Unary stuff


Refactor message traits

call changes

Change hander call options(might probably be deleted) since call options shouldn't contain metadata.
…r handling all types of gRPC methods on the server side, along with adapters for specific method types.

Key changes:
- Introduce `StreamingMethodHandler` trait to provide a common interface for method execution.
- Add `UnaryMethodAdapter`, `ServerStreamingAdapter`, `ClientStreamingAdapter`, and `BidiStreamingAdapter` to bridge specific method traits to the unified handler.

Note that `ServerStreamingHandler` (via `ServerStreamingAdapter`) is currently not "zero-cost". It uses a `tokio::sync::oneshot` channel to retrieve the request  before sending it to the application handler. This approach was adopted to avoid complex lifetime issues encountered with inline stream writer chaining without interior mutability. Optimization of this path is deferred to future work.

Migrate to V2 API
This change introduces the `Interceptor` trait and associated infrastructure for intercepting gRPC calls on the server side.

The new `interceptor` module includes:
- `Interceptor` trait: The core abstraction with `intercept_unary` and `intercept_streaming` methods.
- `InterceptorExt` trait: Provides a `chain` combinator for composing multiple interceptors.
- `InterceptedMethodHandler`: Wraps a `MethodHandler` with an `Interceptor`, allowing interception logic to wrap the inner handler execution.
- `ChainedInterceptor`: Implements the composition of two interceptors.

The design supports both generic operations (e.g., logging, metrics) and type-specific inspection (via message downcasting).

Add ByteStream Interceptor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant