Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(tonic): expose Interceptor trait #713

Merged
merged 3 commits into from
Jul 27, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion tonic-build/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ pub fn generate<T: Service>(

pub fn with_interceptor<F>(inner: T, interceptor: F) -> #service_ident<InterceptedService<T, F>>
where
F: FnMut(tonic::Request<()>) -> Result<tonic::Request<()>, tonic::Status>,
F: tonic::service::Interceptor,
T: tonic::codegen::Service<
http::Request<tonic::body::BoxBody>,
Response = http::Response<<T as tonic::client::GrpcService<tonic::body::BoxBody>>::ResponseBody>
Expand Down
2 changes: 1 addition & 1 deletion tonic-build/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ pub fn generate<T: Service>(

pub fn with_interceptor<F>(inner: T, interceptor: F) -> InterceptedService<Self, F>
where
F: FnMut(tonic::Request<()>) -> Result<tonic::Request<()>, tonic::Status>,
F: tonic::service::Interceptor,
{
InterceptedService::new(Self::new(inner), interceptor)
}
Expand Down
4 changes: 2 additions & 2 deletions tonic/src/extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ use std::fmt;

/// A type map of protocol extensions.
///
/// `Extensions` can be used by [`interceptor_fn`] and [`Request`] to store extra data derived from
/// `Extensions` can be used by [`Interceptor`] and [`Request`] to store extra data derived from
/// the underlying protocol.
///
/// [`interceptor_fn`]: crate::service::interceptor_fn
/// [`Interceptor`]: crate::service::Interceptor
/// [`Request`]: crate::Request
pub struct Extensions {
inner: http::Extensions,
Expand Down
44 changes: 34 additions & 10 deletions tonic/src/service/interceptor.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! gRPC interceptors which are a kind of middleware.
//!
//! See [`interceptor_fn`] for more details.
//! See [`Interceptor`] for more details.

use crate::{request::SanitizeHeaders, Status};
use pin_project::pin_project;
Expand All @@ -13,12 +13,15 @@ use std::{
use tower_layer::Layer;
use tower_service::Service;

/// Create a new interceptor from a function.
/// A gRPC incerceptor.
///
/// gRPC interceptors are similar to middleware but have less flexibility. An interceptor allows
/// you to do two main things, one is to add/remove/check items in the `MetadataMap` of each
/// request. Two, cancel a request with a `Status`.
///
/// Any function that satisfies the bound `FnMut(Request<()>) -> Result<Request<()>, Status>` can be
/// used as an `Interceptor`.
///
/// An interceptor can be used on both the server and client side through the `tonic-build` crate's
/// generated structs.
///
Expand All @@ -35,24 +38,42 @@ use tower_service::Service;
/// [tower]: https://crates.io/crates/tower
/// [example]: https://github.com/hyperium/tonic/tree/master/examples/src/interceptor
/// [tower-example]: https://github.com/hyperium/tonic/tree/master/examples/src/tower
pub fn interceptor_fn<F>(f: F) -> InterceptorFn<F>
pub trait Interceptor {
/// Intercept a request before it is sent, optionally cancelling it.
fn call(&mut self, request: crate::Request<()>) -> Result<crate::Request<()>, Status>;
}

impl<F> Interceptor for F
where
F: FnMut(crate::Request<()>) -> Result<crate::Request<()>, Status>,
{
fn call(&mut self, request: crate::Request<()>) -> Result<crate::Request<()>, Status> {
self(request)
}
}

/// Create a new interceptor layer.
///
/// See [`Interceptor`] for more details.
pub fn interceptor_fn<F>(f: F) -> InterceptorFn<F>
yotamofek marked this conversation as resolved.
Show resolved Hide resolved
where
F: Interceptor,
{
InterceptorFn { f }
}

/// An interceptor created from a function.
/// A gRPC interceptor that can be used as a [`Layer`],
/// created by calling [`interceptor_fn`].
///
/// See [`interceptor_fn`] for more details.
/// See [`Interceptor`] for more details.
#[derive(Debug, Clone, Copy)]
pub struct InterceptorFn<F> {
f: F,
}

impl<S, F> Layer<S> for InterceptorFn<F>
where
F: FnMut(crate::Request<()>) -> Result<crate::Request<()>, Status> + Clone,
F: Interceptor + Clone,
{
type Service = InterceptedService<S, F>;

Expand All @@ -63,7 +84,7 @@ where

/// A service wrapped in an interceptor middleware.
///
/// See [`interceptor_fn`] for more details.
/// See [`Interceptor`] for more details.
#[derive(Clone, Copy)]
pub struct InterceptedService<S, F> {
inner: S,
Expand All @@ -75,7 +96,7 @@ impl<S, F> InterceptedService<S, F> {
/// function `F`.
pub fn new(service: S, f: F) -> Self
where
F: FnMut(crate::Request<()>) -> Result<crate::Request<()>, Status>,
F: Interceptor,
{
Self { inner: service, f }
}
Expand All @@ -95,7 +116,7 @@ where

impl<S, F, ReqBody, ResBody> Service<http::Request<ReqBody>> for InterceptedService<S, F>
where
F: FnMut(crate::Request<()>) -> Result<crate::Request<()>, Status>,
F: Interceptor,
S: Service<http::Request<ReqBody>, Response = http::Response<ResBody>>,
S::Error: Into<crate::Error>,
{
Expand All @@ -113,7 +134,10 @@ where
let req = crate::Request::from_http(req);
let (metadata, extensions, msg) = req.into_parts();

match (self.f)(crate::Request::from_parts(metadata, extensions, ())) {
match self
.f
.call(crate::Request::from_parts(metadata, extensions, ()))
{
Ok(req) => {
let (metadata, extensions, _) = req.into_parts();
let req = crate::Request::from_parts(metadata, extensions, msg);
Expand Down
2 changes: 1 addition & 1 deletion tonic/src/service/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
pub mod interceptor;

#[doc(inline)]
pub use self::interceptor::interceptor_fn;
pub use self::interceptor::{interceptor_fn, Interceptor};
2 changes: 1 addition & 1 deletion tonic/src/transport/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ impl<L> Server<L> {
/// [`Layer`]: tower::layer::Layer
/// [eco]: https://github.com/tower-rs
/// [`ServiceBuilder`]: tower::ServiceBuilder
/// [interceptors]: crate::service::interceptor_fn
/// [interceptors]: crate::service::Interceptor
pub fn layer<NewLayer>(self, new_layer: NewLayer) -> Server<NewLayer> {
Server {
layer: new_layer,
Expand Down