feat(transport): port router to axum (#830)
This commit is contained in:
@@ -124,7 +124,7 @@ pub fn generate<T: Service>(
|
|||||||
B::Error: Into<StdError> + Send + 'static,
|
B::Error: Into<StdError> + Send + 'static,
|
||||||
{
|
{
|
||||||
type Response = http::Response<tonic::body::BoxBody>;
|
type Response = http::Response<tonic::body::BoxBody>;
|
||||||
type Error = Never;
|
type Error = std::convert::Infallible;
|
||||||
type Future = BoxFuture<Self::Response, Self::Error>;
|
type Future = BoxFuture<Self::Response, Self::Error>;
|
||||||
|
|
||||||
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ tls-roots = ["tls-roots-common", "rustls-native-certs"]
|
|||||||
tls-roots-common = ["tls"]
|
tls-roots-common = ["tls"]
|
||||||
tls-webpki-roots = ["tls-roots-common", "webpki-roots"]
|
tls-webpki-roots = ["tls-roots-common", "webpki-roots"]
|
||||||
transport = [
|
transport = [
|
||||||
|
"axum",
|
||||||
"h2",
|
"h2",
|
||||||
"hyper",
|
"hyper",
|
||||||
"tokio",
|
"tokio",
|
||||||
@@ -77,6 +78,7 @@ tokio = {version = "1.0.1", features = ["net"], optional = true}
|
|||||||
tokio-stream = "0.1"
|
tokio-stream = "0.1"
|
||||||
tower = {version = "0.4.7", features = ["balance", "buffer", "discover", "limit", "load", "make", "timeout", "util"], optional = true}
|
tower = {version = "0.4.7", features = ["balance", "buffer", "discover", "limit", "load", "make", "timeout", "util"], optional = true}
|
||||||
tracing-futures = {version = "0.2", optional = true}
|
tracing-futures = {version = "0.2", optional = true}
|
||||||
|
axum = {version = "0.4", default_features = false, optional = true}
|
||||||
|
|
||||||
# rustls
|
# rustls
|
||||||
rustls-pemfile = { version = "0.2.1", optional = true }
|
rustls-pemfile = { version = "0.2.1", optional = true }
|
||||||
|
|||||||
@@ -5,6 +5,15 @@ use http_body::Body;
|
|||||||
/// A type erased HTTP body used for tonic services.
|
/// A type erased HTTP body used for tonic services.
|
||||||
pub type BoxBody = http_body::combinators::UnsyncBoxBody<bytes::Bytes, crate::Status>;
|
pub type BoxBody = http_body::combinators::UnsyncBoxBody<bytes::Bytes, crate::Status>;
|
||||||
|
|
||||||
|
/// Convert a [`http_body::Body`] into a [`BoxBody`].
|
||||||
|
pub(crate) fn boxed<B>(body: B) -> BoxBody
|
||||||
|
where
|
||||||
|
B: http_body::Body<Data = bytes::Bytes> + Send + 'static,
|
||||||
|
B::Error: Into<crate::Error>,
|
||||||
|
{
|
||||||
|
body.map_err(crate::Status::map_error).boxed_unsync()
|
||||||
|
}
|
||||||
|
|
||||||
// this also exists in `crate::codegen` but we need it here since `codegen` has
|
// this also exists in `crate::codegen` but we need it here since `codegen` has
|
||||||
// `#[cfg(feature = "codegen")]`.
|
// `#[cfg(feature = "codegen")]`.
|
||||||
/// Create an empty `BoxBody`
|
/// Create an empty `BoxBody`
|
||||||
|
|||||||
@@ -24,17 +24,6 @@ pub mod http {
|
|||||||
pub use http::*;
|
pub use http::*;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Never {}
|
|
||||||
|
|
||||||
impl std::fmt::Display for Never {
|
|
||||||
fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match *self {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::error::Error for Never {}
|
|
||||||
|
|
||||||
pub fn empty_body() -> crate::body::BoxBody {
|
pub fn empty_body() -> crate::body::BoxBody {
|
||||||
http_body::Empty::new()
|
http_body::Empty::new()
|
||||||
.map_err(|err| match err {})
|
.map_err(|err| match err {})
|
||||||
|
|||||||
@@ -2,7 +2,11 @@
|
|||||||
//!
|
//!
|
||||||
//! See [`Interceptor`] for more details.
|
//! See [`Interceptor`] for more details.
|
||||||
|
|
||||||
use crate::{request::SanitizeHeaders, Status};
|
use crate::{
|
||||||
|
body::{boxed, BoxBody},
|
||||||
|
request::SanitizeHeaders,
|
||||||
|
Status,
|
||||||
|
};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use pin_project::pin_project;
|
use pin_project::pin_project;
|
||||||
use std::{
|
use std::{
|
||||||
@@ -145,15 +149,16 @@ where
|
|||||||
F: Interceptor,
|
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>,
|
||||||
|
ResBody: http_body::Body<Data = bytes::Bytes> + Send + 'static,
|
||||||
ResBody::Error: Into<crate::Error>,
|
ResBody::Error: Into<crate::Error>,
|
||||||
{
|
{
|
||||||
type Response = http::Response<ResBody>;
|
type Response = http::Response<BoxBody>;
|
||||||
type Error = crate::Error;
|
type Error = S::Error;
|
||||||
type Future = ResponseFuture<S::Future>;
|
type Future = ResponseFuture<S::Future>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||||
self.inner.poll_ready(cx).map_err(Into::into)
|
self.inner.poll_ready(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, req: http::Request<ReqBody>) -> Self::Future {
|
fn call(&mut self, req: http::Request<ReqBody>) -> Self::Future {
|
||||||
@@ -171,7 +176,7 @@ where
|
|||||||
let req = req.into_http(uri, SanitizeHeaders::No);
|
let req = req.into_http(uri, SanitizeHeaders::No);
|
||||||
ResponseFuture::future(self.inner.call(req))
|
ResponseFuture::future(self.inner.call(req))
|
||||||
}
|
}
|
||||||
Err(status) => ResponseFuture::error(status),
|
Err(status) => ResponseFuture::status(status),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,9 +205,9 @@ impl<F> ResponseFuture<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error(status: Status) -> Self {
|
fn status(status: Status) -> Self {
|
||||||
Self {
|
Self {
|
||||||
kind: Kind::Error(Some(status)),
|
kind: Kind::Status(Some(status)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -211,7 +216,7 @@ impl<F> ResponseFuture<F> {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Kind<F> {
|
enum Kind<F> {
|
||||||
Future(#[pin] F),
|
Future(#[pin] F),
|
||||||
Error(Option<Status>),
|
Status(Option<Status>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F, E, B> Future for ResponseFuture<F>
|
impl<F, E, B> Future for ResponseFuture<F>
|
||||||
@@ -221,14 +226,20 @@ where
|
|||||||
B: Default + http_body::Body<Data = Bytes> + Send + 'static,
|
B: Default + http_body::Body<Data = Bytes> + Send + 'static,
|
||||||
B::Error: Into<crate::Error>,
|
B::Error: Into<crate::Error>,
|
||||||
{
|
{
|
||||||
type Output = Result<http::Response<B>, crate::Error>;
|
type Output = Result<http::Response<BoxBody>, E>;
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
match self.project().kind.project() {
|
match self.project().kind.project() {
|
||||||
KindProj::Future(future) => future.poll(cx).map_err(Into::into),
|
KindProj::Future(future) => future
|
||||||
KindProj::Error(status) => {
|
.poll(cx)
|
||||||
let response = status.take().unwrap().to_http().map(|_| B::default());
|
.map(|result| result.map(|res| res.map(boxed))),
|
||||||
|
KindProj::Status(status) => {
|
||||||
|
let response = status
|
||||||
|
.take()
|
||||||
|
.unwrap()
|
||||||
|
.to_http()
|
||||||
|
.map(|_| B::default())
|
||||||
|
.map(boxed);
|
||||||
Poll::Ready(Ok(response))
|
Poll::Ready(Ok(response))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ mod tls;
|
|||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
mod unix;
|
mod unix;
|
||||||
|
|
||||||
|
pub use super::service::Routes;
|
||||||
pub use conn::{Connected, TcpConnectInfo};
|
pub use conn::{Connected, TcpConnectInfo};
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "tls")]
|
||||||
pub use tls::ServerTlsConfig;
|
pub use tls::ServerTlsConfig;
|
||||||
@@ -31,19 +32,17 @@ pub(crate) use tokio_rustls::server::TlsStream;
|
|||||||
use crate::transport::Error;
|
use crate::transport::Error;
|
||||||
|
|
||||||
use self::recover_error::RecoverError;
|
use self::recover_error::RecoverError;
|
||||||
use super::service::{GrpcTimeout, Or, Routes, ServerIo};
|
use super::service::{GrpcTimeout, ServerIo};
|
||||||
use crate::body::BoxBody;
|
use crate::body::BoxBody;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use futures_core::Stream;
|
use futures_core::Stream;
|
||||||
use futures_util::{
|
use futures_util::{future, ready};
|
||||||
future::{self, MapErr},
|
|
||||||
ready, TryFutureExt,
|
|
||||||
};
|
|
||||||
use http::{Request, Response};
|
use http::{Request, Response};
|
||||||
use http_body::Body as _;
|
use http_body::Body as _;
|
||||||
use hyper::{server::accept, Body};
|
use hyper::{server::accept, Body};
|
||||||
use pin_project::pin_project;
|
use pin_project::pin_project;
|
||||||
use std::{
|
use std::{
|
||||||
|
convert::Infallible,
|
||||||
fmt,
|
fmt,
|
||||||
future::Future,
|
future::Future,
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
@@ -94,41 +93,9 @@ pub struct Server<L = Identity> {
|
|||||||
|
|
||||||
/// A stack based `Service` router.
|
/// A stack based `Service` router.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Router<A, B, L = Identity> {
|
pub struct Router<L = Identity> {
|
||||||
server: Server<L>,
|
server: Server<L>,
|
||||||
routes: Routes<A, B, Request<Body>>,
|
routes: Routes,
|
||||||
}
|
|
||||||
|
|
||||||
/// A service that is produced from a Tonic `Router`.
|
|
||||||
///
|
|
||||||
/// This service implementation will route between multiple Tonic
|
|
||||||
/// gRPC endpoints and can be consumed with the rest of the `tower`
|
|
||||||
/// ecosystem.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct RouterService<S> {
|
|
||||||
inner: S,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> Service<Request<Body>> for RouterService<S>
|
|
||||||
where
|
|
||||||
S: Service<Request<Body>, Response = Response<BoxBody>> + Clone + Send + 'static,
|
|
||||||
S::Future: Send + 'static,
|
|
||||||
S::Error: Into<crate::Error> + Send,
|
|
||||||
{
|
|
||||||
type Response = Response<BoxBody>;
|
|
||||||
type Error = crate::Error;
|
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
type Future = MapErr<S::Future, fn(S::Error) -> crate::Error>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
||||||
Poll::Ready(Ok(()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call(&mut self, req: Request<Body>) -> Self::Future {
|
|
||||||
self.inner.call(req).map_err(Into::into)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait to provide a static reference to the service's
|
/// A trait to provide a static reference to the service's
|
||||||
@@ -330,18 +297,17 @@ impl<L> Server<L> {
|
|||||||
///
|
///
|
||||||
/// This will clone the `Server` builder and create a router that will
|
/// This will clone the `Server` builder and create a router that will
|
||||||
/// route around different services.
|
/// route around different services.
|
||||||
pub fn add_service<S>(&mut self, svc: S) -> Router<S, Unimplemented, L>
|
pub fn add_service<S>(&mut self, svc: S) -> Router<L>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Response = Response<BoxBody>>
|
S: Service<Request<Body>, Response = Response<BoxBody>, Error = Infallible>
|
||||||
+ NamedService
|
+ NamedService
|
||||||
+ Clone
|
+ Clone
|
||||||
+ Send
|
+ Send
|
||||||
+ 'static,
|
+ 'static,
|
||||||
S::Future: Send + 'static,
|
S::Future: Send + 'static,
|
||||||
S::Error: Into<crate::Error> + Send,
|
|
||||||
L: Clone,
|
L: Clone,
|
||||||
{
|
{
|
||||||
Router::new(self.clone(), svc)
|
Router::new(self.clone(), Routes::new(svc))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a router with the optional `S` typed service as the first service.
|
/// Create a router with the optional `S` typed service as the first service.
|
||||||
@@ -352,25 +318,18 @@ impl<L> Server<L> {
|
|||||||
/// # Note
|
/// # Note
|
||||||
/// Even when the argument given is `None` this will capture *all* requests to this service name.
|
/// Even when the argument given is `None` this will capture *all* requests to this service name.
|
||||||
/// As a result, one cannot use this to toggle between two identically named implementations.
|
/// As a result, one cannot use this to toggle between two identically named implementations.
|
||||||
pub fn add_optional_service<S>(
|
pub fn add_optional_service<S>(&mut self, svc: Option<S>) -> Router<L>
|
||||||
&mut self,
|
|
||||||
svc: Option<S>,
|
|
||||||
) -> Router<Either<S, Unimplemented>, Unimplemented, L>
|
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Response = Response<BoxBody>>
|
S: Service<Request<Body>, Response = Response<BoxBody>, Error = Infallible>
|
||||||
+ NamedService
|
+ NamedService
|
||||||
+ Clone
|
+ Clone
|
||||||
+ Send
|
+ Send
|
||||||
+ 'static,
|
+ 'static,
|
||||||
S::Future: Send + 'static,
|
S::Future: Send + 'static,
|
||||||
S::Error: Into<crate::Error> + Send,
|
|
||||||
L: Clone,
|
L: Clone,
|
||||||
{
|
{
|
||||||
let svc = match svc {
|
let routes = svc.map(Routes::new).unwrap_or_default();
|
||||||
Some(some) => Either::A(some),
|
Router::new(self.clone(), routes)
|
||||||
None => Either::B(Unimplemented::default()),
|
|
||||||
};
|
|
||||||
Router::new(self.clone(), svc)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the [Tower] [`Layer`] all services will be wrapped in.
|
/// Set the [Tower] [`Layer`] all services will be wrapped in.
|
||||||
@@ -523,63 +482,25 @@ impl<L> Server<L> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, L> Router<S, Unimplemented, L> {
|
impl<L> Router<L> {
|
||||||
pub(crate) fn new(server: Server<L>, svc: S) -> Self
|
pub(crate) fn new(server: Server<L>, routes: Routes) -> Self {
|
||||||
where
|
Self { server, routes }
|
||||||
S: Service<Request<Body>, Response = Response<BoxBody>>
|
|
||||||
+ NamedService
|
|
||||||
+ Clone
|
|
||||||
+ Send
|
|
||||||
+ 'static,
|
|
||||||
S::Future: Send + 'static,
|
|
||||||
S::Error: Into<crate::Error> + Send,
|
|
||||||
{
|
|
||||||
let svc_name = <S as NamedService>::NAME;
|
|
||||||
let svc_route = format!("/{}", svc_name);
|
|
||||||
let pred = move |req: &Request<Body>| {
|
|
||||||
let path = req.uri().path();
|
|
||||||
|
|
||||||
path.starts_with(&svc_route)
|
|
||||||
};
|
|
||||||
Self {
|
|
||||||
server,
|
|
||||||
routes: Routes::new(pred, svc, Unimplemented::default()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A, B, L> Router<A, B, L>
|
impl<L> Router<L> {
|
||||||
where
|
|
||||||
A: Service<Request<Body>, Response = Response<BoxBody>> + Clone + Send + 'static,
|
|
||||||
A::Future: Send + 'static,
|
|
||||||
A::Error: Into<crate::Error> + Send,
|
|
||||||
B: Service<Request<Body>, Response = Response<BoxBody>> + Clone + Send + 'static,
|
|
||||||
B::Future: Send + 'static,
|
|
||||||
B::Error: Into<crate::Error> + Send,
|
|
||||||
{
|
|
||||||
/// Add a new service to this router.
|
/// Add a new service to this router.
|
||||||
pub fn add_service<S>(self, svc: S) -> Router<S, Or<A, B, Request<Body>>, L>
|
pub fn add_service<S>(mut self, svc: S) -> Self
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Response = Response<BoxBody>>
|
S: Service<Request<Body>, Response = Response<BoxBody>, Error = Infallible>
|
||||||
+ NamedService
|
+ NamedService
|
||||||
+ Clone
|
+ Clone
|
||||||
+ Send
|
+ Send
|
||||||
+ 'static,
|
+ 'static,
|
||||||
S::Future: Send + 'static,
|
S::Future: Send + 'static,
|
||||||
S::Error: Into<crate::Error> + Send,
|
|
||||||
{
|
{
|
||||||
let Self { routes, server } = self;
|
self.routes = self.routes.add_service(svc);
|
||||||
|
self
|
||||||
let svc_name = <S as NamedService>::NAME;
|
|
||||||
let svc_route = format!("/{}", svc_name);
|
|
||||||
let pred = move |req: &Request<Body>| {
|
|
||||||
let path = req.uri().path();
|
|
||||||
|
|
||||||
path.starts_with(&svc_route)
|
|
||||||
};
|
|
||||||
let routes = routes.push(pred, svc);
|
|
||||||
|
|
||||||
Router { server, routes }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a new optional service to this router.
|
/// Add a new optional service to this router.
|
||||||
@@ -588,35 +509,19 @@ where
|
|||||||
/// Even when the argument given is `None` this will capture *all* requests to this service name.
|
/// Even when the argument given is `None` this will capture *all* requests to this service name.
|
||||||
/// As a result, one cannot use this to toggle between two identically named implementations.
|
/// As a result, one cannot use this to toggle between two identically named implementations.
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub fn add_optional_service<S>(
|
pub fn add_optional_service<S>(mut self, svc: Option<S>) -> Self
|
||||||
self,
|
|
||||||
svc: Option<S>,
|
|
||||||
) -> Router<Either<S, Unimplemented>, Or<A, B, Request<Body>>, L>
|
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Response = Response<BoxBody>>
|
S: Service<Request<Body>, Response = Response<BoxBody>, Error = Infallible>
|
||||||
+ NamedService
|
+ NamedService
|
||||||
+ Clone
|
+ Clone
|
||||||
+ Send
|
+ Send
|
||||||
+ 'static,
|
+ 'static,
|
||||||
S::Future: Send + 'static,
|
S::Future: Send + 'static,
|
||||||
S::Error: Into<crate::Error> + Send,
|
|
||||||
{
|
{
|
||||||
let Self { routes, server } = self;
|
if let Some(svc) = svc {
|
||||||
|
self.routes = self.routes.add_service(svc);
|
||||||
let svc_name = <S as NamedService>::NAME;
|
}
|
||||||
let svc_route = format!("/{}", svc_name);
|
self
|
||||||
let pred = move |req: &Request<Body>| {
|
|
||||||
let path = req.uri().path();
|
|
||||||
|
|
||||||
path.starts_with(&svc_route)
|
|
||||||
};
|
|
||||||
let svc = match svc {
|
|
||||||
Some(some) => Either::A(some),
|
|
||||||
None => Either::B(Unimplemented::default()),
|
|
||||||
};
|
|
||||||
let routes = routes.push(pred, svc);
|
|
||||||
|
|
||||||
Router { server, routes }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consume this [`Server`] creating a future that will execute the server
|
/// Consume this [`Server`] creating a future that will execute the server
|
||||||
@@ -626,12 +531,10 @@ where
|
|||||||
/// [tokio]: https://docs.rs/tokio
|
/// [tokio]: https://docs.rs/tokio
|
||||||
pub async fn serve<ResBody>(self, addr: SocketAddr) -> Result<(), super::Error>
|
pub async fn serve<ResBody>(self, addr: SocketAddr) -> Result<(), super::Error>
|
||||||
where
|
where
|
||||||
L: Layer<Routes<A, B, Request<Body>>>,
|
L: Layer<Routes>,
|
||||||
L::Service: Service<Request<Body>, Response = Response<ResBody>> + Clone + Send + 'static,
|
L::Service: Service<Request<Body>, Response = Response<ResBody>> + Clone + Send + 'static,
|
||||||
<<L as Layer<Routes<A, B, Request<Body>>>>::Service as Service<Request<Body>>>::Future:
|
<<L as Layer<Routes>>::Service as Service<Request<Body>>>::Future: Send + 'static,
|
||||||
Send + 'static,
|
<<L as Layer<Routes>>::Service as Service<Request<Body>>>::Error: Into<crate::Error> + Send,
|
||||||
<<L as Layer<Routes<A, B, Request<Body>>>>::Service as Service<Request<Body>>>::Error:
|
|
||||||
Into<crate::Error> + Send,
|
|
||||||
ResBody: http_body::Body<Data = Bytes> + Send + 'static,
|
ResBody: http_body::Body<Data = Bytes> + Send + 'static,
|
||||||
ResBody::Error: Into<crate::Error>,
|
ResBody::Error: Into<crate::Error>,
|
||||||
{
|
{
|
||||||
@@ -658,12 +561,10 @@ where
|
|||||||
signal: F,
|
signal: F,
|
||||||
) -> Result<(), super::Error>
|
) -> Result<(), super::Error>
|
||||||
where
|
where
|
||||||
L: Layer<Routes<A, B, Request<Body>>>,
|
L: Layer<Routes>,
|
||||||
L::Service: Service<Request<Body>, Response = Response<ResBody>> + Clone + Send + 'static,
|
L::Service: Service<Request<Body>, Response = Response<ResBody>> + Clone + Send + 'static,
|
||||||
<<L as Layer<Routes<A, B, Request<Body>>>>::Service as Service<Request<Body>>>::Future:
|
<<L as Layer<Routes>>::Service as Service<Request<Body>>>::Future: Send + 'static,
|
||||||
Send + 'static,
|
<<L as Layer<Routes>>::Service as Service<Request<Body>>>::Error: Into<crate::Error> + Send,
|
||||||
<<L as Layer<Routes<A, B, Request<Body>>>>::Service as Service<Request<Body>>>::Error:
|
|
||||||
Into<crate::Error> + Send,
|
|
||||||
ResBody: http_body::Body<Data = Bytes> + Send + 'static,
|
ResBody: http_body::Body<Data = Bytes> + Send + 'static,
|
||||||
ResBody::Error: Into<crate::Error>,
|
ResBody::Error: Into<crate::Error>,
|
||||||
{
|
{
|
||||||
@@ -687,12 +588,10 @@ where
|
|||||||
IO: AsyncRead + AsyncWrite + Connected + Unpin + Send + 'static,
|
IO: AsyncRead + AsyncWrite + Connected + Unpin + Send + 'static,
|
||||||
IO::ConnectInfo: Clone + Send + Sync + 'static,
|
IO::ConnectInfo: Clone + Send + Sync + 'static,
|
||||||
IE: Into<crate::Error>,
|
IE: Into<crate::Error>,
|
||||||
L: Layer<Routes<A, B, Request<Body>>>,
|
L: Layer<Routes>,
|
||||||
L::Service: Service<Request<Body>, Response = Response<ResBody>> + Clone + Send + 'static,
|
L::Service: Service<Request<Body>, Response = Response<ResBody>> + Clone + Send + 'static,
|
||||||
<<L as Layer<Routes<A, B, Request<Body>>>>::Service as Service<Request<Body>>>::Future:
|
<<L as Layer<Routes>>::Service as Service<Request<Body>>>::Future: Send + 'static,
|
||||||
Send + 'static,
|
<<L as Layer<Routes>>::Service as Service<Request<Body>>>::Error: Into<crate::Error> + Send,
|
||||||
<<L as Layer<Routes<A, B, Request<Body>>>>::Service as Service<Request<Body>>>::Error:
|
|
||||||
Into<crate::Error> + Send,
|
|
||||||
ResBody: http_body::Body<Data = Bytes> + Send + 'static,
|
ResBody: http_body::Body<Data = Bytes> + Send + 'static,
|
||||||
ResBody::Error: Into<crate::Error>,
|
ResBody::Error: Into<crate::Error>,
|
||||||
{
|
{
|
||||||
@@ -722,12 +621,10 @@ where
|
|||||||
IO::ConnectInfo: Clone + Send + Sync + 'static,
|
IO::ConnectInfo: Clone + Send + Sync + 'static,
|
||||||
IE: Into<crate::Error>,
|
IE: Into<crate::Error>,
|
||||||
F: Future<Output = ()>,
|
F: Future<Output = ()>,
|
||||||
L: Layer<Routes<A, B, Request<Body>>>,
|
L: Layer<Routes>,
|
||||||
L::Service: Service<Request<Body>, Response = Response<ResBody>> + Clone + Send + 'static,
|
L::Service: Service<Request<Body>, Response = Response<ResBody>> + Clone + Send + 'static,
|
||||||
<<L as Layer<Routes<A, B, Request<Body>>>>::Service as Service<Request<Body>>>::Future:
|
<<L as Layer<Routes>>::Service as Service<Request<Body>>>::Future: Send + 'static,
|
||||||
Send + 'static,
|
<<L as Layer<Routes>>::Service as Service<Request<Body>>>::Error: Into<crate::Error> + Send,
|
||||||
<<L as Layer<Routes<A, B, Request<Body>>>>::Service as Service<Request<Body>>>::Error:
|
|
||||||
Into<crate::Error> + Send,
|
|
||||||
ResBody: http_body::Body<Data = Bytes> + Send + 'static,
|
ResBody: http_body::Body<Data = Bytes> + Send + 'static,
|
||||||
ResBody::Error: Into<crate::Error>,
|
ResBody::Error: Into<crate::Error>,
|
||||||
{
|
{
|
||||||
@@ -737,19 +634,16 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a tower service out of a router.
|
/// Create a tower service out of a router.
|
||||||
pub fn into_service<ResBody>(self) -> RouterService<L::Service>
|
pub fn into_service<ResBody>(self) -> L::Service
|
||||||
where
|
where
|
||||||
L: Layer<Routes<A, B, Request<Body>>>,
|
L: Layer<Routes>,
|
||||||
L::Service: Service<Request<Body>, Response = Response<ResBody>> + Clone + Send + 'static,
|
L::Service: Service<Request<Body>, Response = Response<ResBody>> + Clone + Send + 'static,
|
||||||
<<L as Layer<Routes<A, B, Request<Body>>>>::Service as Service<Request<Body>>>::Future:
|
<<L as Layer<Routes>>::Service as Service<Request<Body>>>::Future: Send + 'static,
|
||||||
Send + 'static,
|
<<L as Layer<Routes>>::Service as Service<Request<Body>>>::Error: Into<crate::Error> + Send,
|
||||||
<<L as Layer<Routes<A, B, Request<Body>>>>::Service as Service<Request<Body>>>::Error:
|
|
||||||
Into<crate::Error> + Send,
|
|
||||||
ResBody: http_body::Body<Data = Bytes> + Send + 'static,
|
ResBody: http_body::Body<Data = Bytes> + Send + 'static,
|
||||||
ResBody::Error: Into<crate::Error>,
|
ResBody::Error: Into<crate::Error>,
|
||||||
{
|
{
|
||||||
let inner = self.server.layer.layer(self.routes);
|
self.server.layer.layer(self.routes)
|
||||||
RouterService { inner }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -905,30 +799,3 @@ where
|
|||||||
future::ready(Ok(svc))
|
future::ready(Ok(svc))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone, Debug)]
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub struct Unimplemented {
|
|
||||||
_p: (),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Service<Request<Body>> for Unimplemented {
|
|
||||||
type Response = Response<BoxBody>;
|
|
||||||
type Error = crate::Error;
|
|
||||||
type Future = future::Ready<Result<Self::Response, Self::Error>>;
|
|
||||||
|
|
||||||
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
||||||
Ok(()).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call(&mut self, _req: Request<Body>) -> Self::Future {
|
|
||||||
future::ok(
|
|
||||||
http::Response::builder()
|
|
||||||
.status(200)
|
|
||||||
.header("grpc-status", "12")
|
|
||||||
.header("content-type", "application/grpc")
|
|
||||||
.body(crate::body::empty_body())
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ pub(crate) use self::connector::connector;
|
|||||||
pub(crate) use self::discover::DynamicServiceStream;
|
pub(crate) use self::discover::DynamicServiceStream;
|
||||||
pub(crate) use self::grpc_timeout::GrpcTimeout;
|
pub(crate) use self::grpc_timeout::GrpcTimeout;
|
||||||
pub(crate) use self::io::ServerIo;
|
pub(crate) use self::io::ServerIo;
|
||||||
pub(crate) use self::router::{Or, Routes};
|
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "tls")]
|
||||||
pub(crate) use self::tls::{TlsAcceptor, TlsConnector};
|
pub(crate) use self::tls::{TlsAcceptor, TlsConnector};
|
||||||
pub(crate) use self::user_agent::UserAgent;
|
pub(crate) use self::user_agent::UserAgent;
|
||||||
|
|
||||||
pub use self::grpc_timeout::TimeoutExpired;
|
pub use self::grpc_timeout::TimeoutExpired;
|
||||||
|
pub use self::router::Routes;
|
||||||
|
|||||||
@@ -1,132 +1,90 @@
|
|||||||
use futures_util::{
|
use crate::{
|
||||||
future::Either,
|
body::{boxed, BoxBody},
|
||||||
future::{MapErr, TryFutureExt},
|
transport::NamedService,
|
||||||
};
|
};
|
||||||
|
use axum::handler::Handler;
|
||||||
|
use http::{Request, Response};
|
||||||
|
use hyper::Body;
|
||||||
|
use pin_project::pin_project;
|
||||||
use std::{
|
use std::{
|
||||||
fmt,
|
convert::Infallible,
|
||||||
sync::Arc,
|
future::Future,
|
||||||
|
pin::Pin,
|
||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
};
|
};
|
||||||
|
use tower::ServiceExt;
|
||||||
use tower_service::Service;
|
use tower_service::Service;
|
||||||
|
|
||||||
#[doc(hidden)]
|
/// A [`Service`] router.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub struct Routes<A, B, Request> {
|
pub struct Routes {
|
||||||
routes: Or<A, B, Request>,
|
router: axum::Router,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A, B, Request> Routes<A, B, Request> {
|
impl Routes {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new<S>(svc: S) -> Self
|
||||||
predicate: impl Fn(&Request) -> bool + Send + Sync + 'static,
|
|
||||||
a: A,
|
|
||||||
b: B,
|
|
||||||
) -> Self {
|
|
||||||
let routes = Or::new(predicate, a, b);
|
|
||||||
Self { routes }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A, B, Request> Routes<A, B, Request> {
|
|
||||||
pub(crate) fn push<C>(
|
|
||||||
self,
|
|
||||||
predicate: impl Fn(&Request) -> bool + Send + Sync + 'static,
|
|
||||||
route: C,
|
|
||||||
) -> Routes<C, Or<A, B, Request>, Request> {
|
|
||||||
let routes = Or::new(predicate, route, self.routes);
|
|
||||||
Routes { routes }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A, B, Request> Service<Request> for Routes<A, B, Request>
|
|
||||||
where
|
|
||||||
A: Service<Request>,
|
|
||||||
A::Future: Send + 'static,
|
|
||||||
A::Error: Into<crate::Error>,
|
|
||||||
B: Service<Request, Response = A::Response>,
|
|
||||||
B::Future: Send + 'static,
|
|
||||||
B::Error: Into<crate::Error>,
|
|
||||||
{
|
|
||||||
type Response = A::Response;
|
|
||||||
type Error = crate::Error;
|
|
||||||
type Future = <Or<A, B, Request> as Service<Request>>::Future;
|
|
||||||
|
|
||||||
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
||||||
Ok(()).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call(&mut self, req: Request) -> Self::Future {
|
|
||||||
self.routes.call(req)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A: Clone, B: Clone, Request> Clone for Routes<A, B, Request> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
routes: self.routes.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub struct Or<A, B, Request> {
|
|
||||||
predicate: Arc<dyn Fn(&Request) -> bool + Send + Sync + 'static>,
|
|
||||||
a: A,
|
|
||||||
b: B,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A, B, Request> Or<A, B, Request> {
|
|
||||||
pub(crate) fn new<F>(predicate: F, a: A, b: B) -> Self
|
|
||||||
where
|
where
|
||||||
F: Fn(&Request) -> bool + Send + Sync + 'static,
|
S: Service<Request<Body>, Response = Response<BoxBody>, Error = Infallible>
|
||||||
|
+ NamedService
|
||||||
|
+ Clone
|
||||||
|
+ Send
|
||||||
|
+ 'static,
|
||||||
|
S::Future: Send + 'static,
|
||||||
|
S::Error: Into<crate::Error> + Send,
|
||||||
{
|
{
|
||||||
let predicate = Arc::new(predicate);
|
let router = axum::Router::new().fallback(unimplemented.into_service());
|
||||||
Self { predicate, a, b }
|
Self { router }.add_service(svc)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_service<S>(mut self, svc: S) -> Self
|
||||||
|
where
|
||||||
|
S: Service<Request<Body>, Response = Response<BoxBody>, Error = Infallible>
|
||||||
|
+ NamedService
|
||||||
|
+ Clone
|
||||||
|
+ Send
|
||||||
|
+ 'static,
|
||||||
|
S::Future: Send + 'static,
|
||||||
|
S::Error: Into<crate::Error> + Send,
|
||||||
|
{
|
||||||
|
let svc = svc.map_response(|res| res.map(axum::body::boxed));
|
||||||
|
self.router = self.router.route(&format!("/{}/*rest", S::NAME), svc);
|
||||||
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A, B, Request> Service<Request> for Or<A, B, Request>
|
async fn unimplemented() -> impl axum::response::IntoResponse {
|
||||||
where
|
let status = http::StatusCode::OK;
|
||||||
A: Service<Request>,
|
let headers =
|
||||||
A::Future: Send + 'static,
|
axum::response::Headers([("grpc-status", "12"), ("content-type", "application/grpc")]);
|
||||||
A::Error: Into<crate::Error>,
|
(status, headers)
|
||||||
B: Service<Request, Response = A::Response>,
|
}
|
||||||
B::Future: Send + 'static,
|
|
||||||
B::Error: Into<crate::Error>,
|
impl Service<Request<Body>> for Routes {
|
||||||
{
|
type Response = Response<BoxBody>;
|
||||||
type Response = A::Response;
|
|
||||||
type Error = crate::Error;
|
type Error = crate::Error;
|
||||||
|
type Future = RoutesFuture;
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
#[inline]
|
||||||
type Future = Either<
|
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||||
MapErr<A::Future, fn(A::Error) -> crate::Error>,
|
Poll::Ready(Ok(()))
|
||||||
MapErr<B::Future, fn(B::Error) -> crate::Error>,
|
|
||||||
>;
|
|
||||||
|
|
||||||
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
||||||
Ok(()).into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, req: Request) -> Self::Future {
|
fn call(&mut self, req: Request<Body>) -> Self::Future {
|
||||||
if (self.predicate)(&req) {
|
RoutesFuture(self.router.call(req))
|
||||||
Either::Left(self.a.call(req).map_err(|e| e.into()))
|
}
|
||||||
} else {
|
}
|
||||||
Either::Right(self.b.call(req).map_err(|e| e.into()))
|
|
||||||
|
#[pin_project]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RoutesFuture(#[pin] axum::routing::future::RouterFuture<Body>);
|
||||||
|
|
||||||
|
impl Future for RoutesFuture {
|
||||||
|
type Output = Result<Response<BoxBody>, crate::Error>;
|
||||||
|
|
||||||
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
match futures_util::ready!(self.project().0.poll(cx)) {
|
||||||
|
Ok(res) => Ok(res.map(boxed)).into(),
|
||||||
|
Err(err) => match err {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: Clone, B: Clone, Request> Clone for Or<A, B, Request> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
predicate: self.predicate.clone(),
|
|
||||||
a: self.a.clone(),
|
|
||||||
b: self.b.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A, B, Request> fmt::Debug for Or<A, B, Request> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "Or {{ .. }}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user