feat(tonic): add Interceptor trait (#713)
* Expose `Interceptor` trait. * Revert changes to public API surface. * Rename types, add deprecated alias for old names.
This commit is contained in:
@@ -15,7 +15,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
|
|
||||||
let channel = ServiceBuilder::new()
|
let channel = ServiceBuilder::new()
|
||||||
// Interceptors can be also be applied as middleware
|
// Interceptors can be also be applied as middleware
|
||||||
.layer(tonic::service::interceptor_fn(intercept))
|
.layer(tonic::service::interceptor(intercept))
|
||||||
.layer_fn(AuthSvc::new)
|
.layer_fn(AuthSvc::new)
|
||||||
.service(channel);
|
.service(channel);
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
// Apply our own middleware
|
// Apply our own middleware
|
||||||
.layer(MyMiddlewareLayer::default())
|
.layer(MyMiddlewareLayer::default())
|
||||||
// Interceptors can be also be applied as middleware
|
// Interceptors can be also be applied as middleware
|
||||||
.layer(tonic::service::interceptor_fn(intercept))
|
.layer(tonic::service::interceptor(intercept))
|
||||||
.into_inner();
|
.into_inner();
|
||||||
|
|
||||||
Server::builder()
|
Server::builder()
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ pub fn generate<T: Service>(
|
|||||||
|
|
||||||
pub fn with_interceptor<F>(inner: T, interceptor: F) -> #service_ident<InterceptedService<T, F>>
|
pub fn with_interceptor<F>(inner: T, interceptor: F) -> #service_ident<InterceptedService<T, F>>
|
||||||
where
|
where
|
||||||
F: FnMut(tonic::Request<()>) -> Result<tonic::Request<()>, tonic::Status>,
|
F: tonic::service::Interceptor,
|
||||||
T: tonic::codegen::Service<
|
T: tonic::codegen::Service<
|
||||||
http::Request<tonic::body::BoxBody>,
|
http::Request<tonic::body::BoxBody>,
|
||||||
Response = http::Response<<T as tonic::client::GrpcService<tonic::body::BoxBody>>::ResponseBody>
|
Response = http::Response<<T as tonic::client::GrpcService<tonic::body::BoxBody>>::ResponseBody>
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ pub fn generate<T: Service>(
|
|||||||
|
|
||||||
pub fn with_interceptor<F>(inner: T, interceptor: F) -> InterceptedService<Self, F>
|
pub fn with_interceptor<F>(inner: T, interceptor: F) -> InterceptedService<Self, F>
|
||||||
where
|
where
|
||||||
F: FnMut(tonic::Request<()>) -> Result<tonic::Request<()>, tonic::Status>,
|
F: tonic::service::Interceptor,
|
||||||
{
|
{
|
||||||
InterceptedService::new(Self::new(inner), interceptor)
|
InterceptedService::new(Self::new(inner), interceptor)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ use std::fmt;
|
|||||||
|
|
||||||
/// A type map of protocol extensions.
|
/// 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.
|
/// the underlying protocol.
|
||||||
///
|
///
|
||||||
/// [`interceptor_fn`]: crate::service::interceptor_fn
|
/// [`Interceptor`]: crate::service::Interceptor
|
||||||
/// [`Request`]: crate::Request
|
/// [`Request`]: crate::Request
|
||||||
pub struct Extensions {
|
pub struct Extensions {
|
||||||
inner: http::Extensions,
|
inner: http::Extensions,
|
||||||
|
|||||||
@@ -300,13 +300,13 @@ impl<T> Request<T> {
|
|||||||
/// Extensions can be set in interceptors:
|
/// Extensions can be set in interceptors:
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// use tonic::{Request, service::interceptor_fn};
|
/// use tonic::{Request, service::interceptor};
|
||||||
///
|
///
|
||||||
/// struct MyExtension {
|
/// struct MyExtension {
|
||||||
/// some_piece_of_data: String,
|
/// some_piece_of_data: String,
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// interceptor_fn(|mut request: Request<()>| {
|
/// interceptor(|mut request: Request<()>| {
|
||||||
/// request.extensions_mut().insert(MyExtension {
|
/// request.extensions_mut().insert(MyExtension {
|
||||||
/// some_piece_of_data: "foo".to_string(),
|
/// some_piece_of_data: "foo".to_string(),
|
||||||
/// });
|
/// });
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
//! gRPC interceptors which are a kind of middleware.
|
//! 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 crate::{request::SanitizeHeaders, Status};
|
||||||
use pin_project::pin_project;
|
use pin_project::pin_project;
|
||||||
@@ -13,12 +13,15 @@ use std::{
|
|||||||
use tower_layer::Layer;
|
use tower_layer::Layer;
|
||||||
use tower_service::Service;
|
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
|
/// 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
|
/// 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`.
|
/// 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
|
/// An interceptor can be used on both the server and client side through the `tonic-build` crate's
|
||||||
/// generated structs.
|
/// generated structs.
|
||||||
///
|
///
|
||||||
@@ -35,24 +38,56 @@ use tower_service::Service;
|
|||||||
/// [tower]: https://crates.io/crates/tower
|
/// [tower]: https://crates.io/crates/tower
|
||||||
/// [example]: https://github.com/hyperium/tonic/tree/master/examples/src/interceptor
|
/// [example]: https://github.com/hyperium/tonic/tree/master/examples/src/interceptor
|
||||||
/// [tower-example]: https://github.com/hyperium/tonic/tree/master/examples/src/tower
|
/// [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
|
where
|
||||||
F: FnMut(crate::Request<()>) -> Result<crate::Request<()>, Status>,
|
F: FnMut(crate::Request<()>) -> Result<crate::Request<()>, Status>,
|
||||||
{
|
{
|
||||||
InterceptorFn { f }
|
fn call(&mut self, request: crate::Request<()>) -> Result<crate::Request<()>, Status> {
|
||||||
|
self(request)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An interceptor created from a function.
|
/// Create a new interceptor layer.
|
||||||
///
|
///
|
||||||
/// See [`interceptor_fn`] for more details.
|
/// See [`Interceptor`] for more details.
|
||||||
|
pub fn interceptor<F>(f: F) -> InterceptorLayer<F>
|
||||||
|
where
|
||||||
|
F: Interceptor,
|
||||||
|
{
|
||||||
|
InterceptorLayer { f }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.5.1",
|
||||||
|
note = "Please use the `interceptor` function instead"
|
||||||
|
)]
|
||||||
|
/// Create a new interceptor layer.
|
||||||
|
///
|
||||||
|
/// See [`Interceptor`] for more details.
|
||||||
|
pub fn interceptor_fn<F>(f: F) -> InterceptorLayer<F>
|
||||||
|
where
|
||||||
|
F: Interceptor,
|
||||||
|
{
|
||||||
|
interceptor(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A gRPC interceptor that can be used as a [`Layer`],
|
||||||
|
/// created by calling [`interceptor`].
|
||||||
|
///
|
||||||
|
/// See [`Interceptor`] for more details.
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct InterceptorFn<F> {
|
pub struct InterceptorLayer<F> {
|
||||||
f: F,
|
f: F,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, F> Layer<S> for InterceptorFn<F>
|
impl<S, F> Layer<S> for InterceptorLayer<F>
|
||||||
where
|
where
|
||||||
F: FnMut(crate::Request<()>) -> Result<crate::Request<()>, Status> + Clone,
|
F: Interceptor + Clone,
|
||||||
{
|
{
|
||||||
type Service = InterceptedService<S, F>;
|
type Service = InterceptedService<S, F>;
|
||||||
|
|
||||||
@@ -61,9 +96,19 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.5.1",
|
||||||
|
note = "Please use the `InterceptorLayer` type instead"
|
||||||
|
)]
|
||||||
|
/// A gRPC interceptor that can be used as a [`Layer`],
|
||||||
|
/// created by calling [`interceptor`].
|
||||||
|
///
|
||||||
|
/// See [`Interceptor`] for more details.
|
||||||
|
pub type InterceptorFn<F> = InterceptorLayer<F>;
|
||||||
|
|
||||||
/// A service wrapped in an interceptor middleware.
|
/// A service wrapped in an interceptor middleware.
|
||||||
///
|
///
|
||||||
/// See [`interceptor_fn`] for more details.
|
/// See [`Interceptor`] for more details.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct InterceptedService<S, F> {
|
pub struct InterceptedService<S, F> {
|
||||||
inner: S,
|
inner: S,
|
||||||
@@ -75,7 +120,7 @@ impl<S, F> InterceptedService<S, F> {
|
|||||||
/// function `F`.
|
/// function `F`.
|
||||||
pub fn new(service: S, f: F) -> Self
|
pub fn new(service: S, f: F) -> Self
|
||||||
where
|
where
|
||||||
F: FnMut(crate::Request<()>) -> Result<crate::Request<()>, Status>,
|
F: Interceptor,
|
||||||
{
|
{
|
||||||
Self { inner: service, f }
|
Self { inner: service, f }
|
||||||
}
|
}
|
||||||
@@ -95,7 +140,7 @@ where
|
|||||||
|
|
||||||
impl<S, F, ReqBody, ResBody> Service<http::Request<ReqBody>> for InterceptedService<S, F>
|
impl<S, F, ReqBody, ResBody> Service<http::Request<ReqBody>> for InterceptedService<S, F>
|
||||||
where
|
where
|
||||||
F: FnMut(crate::Request<()>) -> Result<crate::Request<()>, Status>,
|
F: Interceptor,
|
||||||
S: Service<http::Request<ReqBody>, Response = http::Response<ResBody>>,
|
S: Service<http::Request<ReqBody>, Response = http::Response<ResBody>>,
|
||||||
S::Error: Into<crate::Error>,
|
S::Error: Into<crate::Error>,
|
||||||
{
|
{
|
||||||
@@ -113,7 +158,10 @@ where
|
|||||||
let req = crate::Request::from_http(req);
|
let req = crate::Request::from_http(req);
|
||||||
let (metadata, extensions, msg) = req.into_parts();
|
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) => {
|
Ok(req) => {
|
||||||
let (metadata, extensions, _) = req.into_parts();
|
let (metadata, extensions, _) = req.into_parts();
|
||||||
let req = crate::Request::from_parts(metadata, extensions, msg);
|
let req = crate::Request::from_parts(metadata, extensions, msg);
|
||||||
|
|||||||
@@ -3,4 +3,5 @@
|
|||||||
pub mod interceptor;
|
pub mod interceptor;
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use self::interceptor::interceptor_fn;
|
#[allow(deprecated)]
|
||||||
|
pub use self::interceptor::{interceptor, interceptor_fn, Interceptor};
|
||||||
|
|||||||
@@ -395,7 +395,7 @@ impl<L> Server<L> {
|
|||||||
/// # use tower_service::Service;
|
/// # use tower_service::Service;
|
||||||
/// use tower::ServiceBuilder;
|
/// use tower::ServiceBuilder;
|
||||||
/// use std::time::Duration;
|
/// use std::time::Duration;
|
||||||
/// use tonic::{Request, Status, service::interceptor_fn};
|
/// use tonic::{Request, Status, service::interceptor};
|
||||||
///
|
///
|
||||||
/// fn auth_interceptor(request: Request<()>) -> Result<Request<()>, Status> {
|
/// fn auth_interceptor(request: Request<()>) -> Result<Request<()>, Status> {
|
||||||
/// if valid_credentials(&request) {
|
/// if valid_credentials(&request) {
|
||||||
@@ -417,8 +417,8 @@ impl<L> Server<L> {
|
|||||||
/// let layer = ServiceBuilder::new()
|
/// let layer = ServiceBuilder::new()
|
||||||
/// .load_shed()
|
/// .load_shed()
|
||||||
/// .timeout(Duration::from_secs(30))
|
/// .timeout(Duration::from_secs(30))
|
||||||
/// .layer(interceptor_fn(auth_interceptor))
|
/// .layer(interceptor(auth_interceptor))
|
||||||
/// .layer(interceptor_fn(some_other_interceptor))
|
/// .layer(interceptor(some_other_interceptor))
|
||||||
/// .into_inner();
|
/// .into_inner();
|
||||||
///
|
///
|
||||||
/// Server::builder().layer(layer);
|
/// Server::builder().layer(layer);
|
||||||
@@ -428,7 +428,7 @@ impl<L> Server<L> {
|
|||||||
/// [`Layer`]: tower::layer::Layer
|
/// [`Layer`]: tower::layer::Layer
|
||||||
/// [eco]: https://github.com/tower-rs
|
/// [eco]: https://github.com/tower-rs
|
||||||
/// [`ServiceBuilder`]: tower::ServiceBuilder
|
/// [`ServiceBuilder`]: tower::ServiceBuilder
|
||||||
/// [interceptors]: crate::service::interceptor_fn
|
/// [interceptors]: crate::service::Interceptor
|
||||||
pub fn layer<NewLayer>(self, new_layer: NewLayer) -> Server<NewLayer> {
|
pub fn layer<NewLayer>(self, new_layer: NewLayer) -> Server<NewLayer> {
|
||||||
Server {
|
Server {
|
||||||
layer: new_layer,
|
layer: new_layer,
|
||||||
|
|||||||
Reference in New Issue
Block a user