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,
|
||||
{
|
||||
type Response = http::Response<tonic::body::BoxBody>;
|
||||
type Error = Never;
|
||||
type Error = std::convert::Infallible;
|
||||
type Future = BoxFuture<Self::Response, 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-webpki-roots = ["tls-roots-common", "webpki-roots"]
|
||||
transport = [
|
||||
"axum",
|
||||
"h2",
|
||||
"hyper",
|
||||
"tokio",
|
||||
@@ -77,6 +78,7 @@ tokio = {version = "1.0.1", features = ["net"], optional = true}
|
||||
tokio-stream = "0.1"
|
||||
tower = {version = "0.4.7", features = ["balance", "buffer", "discover", "limit", "load", "make", "timeout", "util"], optional = true}
|
||||
tracing-futures = {version = "0.2", optional = true}
|
||||
axum = {version = "0.4", default_features = false, optional = true}
|
||||
|
||||
# rustls
|
||||
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.
|
||||
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
|
||||
// `#[cfg(feature = "codegen")]`.
|
||||
/// Create an empty `BoxBody`
|
||||
|
||||
@@ -24,17 +24,6 @@ pub mod 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 {
|
||||
http_body::Empty::new()
|
||||
.map_err(|err| match err {})
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
//!
|
||||
//! See [`Interceptor`] for more details.
|
||||
|
||||
use crate::{request::SanitizeHeaders, Status};
|
||||
use crate::{
|
||||
body::{boxed, BoxBody},
|
||||
request::SanitizeHeaders,
|
||||
Status,
|
||||
};
|
||||
use bytes::Bytes;
|
||||
use pin_project::pin_project;
|
||||
use std::{
|
||||
@@ -145,15 +149,16 @@ where
|
||||
F: Interceptor,
|
||||
S: Service<http::Request<ReqBody>, Response = http::Response<ResBody>>,
|
||||
S::Error: Into<crate::Error>,
|
||||
ResBody: http_body::Body<Data = bytes::Bytes> + Send + 'static,
|
||||
ResBody::Error: Into<crate::Error>,
|
||||
{
|
||||
type Response = http::Response<ResBody>;
|
||||
type Error = crate::Error;
|
||||
type Response = http::Response<BoxBody>;
|
||||
type Error = S::Error;
|
||||
type Future = ResponseFuture<S::Future>;
|
||||
|
||||
#[inline]
|
||||
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 {
|
||||
@@ -171,7 +176,7 @@ where
|
||||
let req = req.into_http(uri, SanitizeHeaders::No);
|
||||
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 {
|
||||
kind: Kind::Error(Some(status)),
|
||||
kind: Kind::Status(Some(status)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -211,7 +216,7 @@ impl<F> ResponseFuture<F> {
|
||||
#[derive(Debug)]
|
||||
enum Kind<F> {
|
||||
Future(#[pin] F),
|
||||
Error(Option<Status>),
|
||||
Status(Option<Status>),
|
||||
}
|
||||
|
||||
impl<F, E, B> Future for ResponseFuture<F>
|
||||
@@ -221,14 +226,20 @@ where
|
||||
B: Default + http_body::Body<Data = Bytes> + Send + 'static,
|
||||
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> {
|
||||
match self.project().kind.project() {
|
||||
KindProj::Future(future) => future.poll(cx).map_err(Into::into),
|
||||
KindProj::Error(status) => {
|
||||
let response = status.take().unwrap().to_http().map(|_| B::default());
|
||||
|
||||
KindProj::Future(future) => future
|
||||
.poll(cx)
|
||||
.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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ mod tls;
|
||||
#[cfg(unix)]
|
||||
mod unix;
|
||||
|
||||
pub use super::service::Routes;
|
||||
pub use conn::{Connected, TcpConnectInfo};
|
||||
#[cfg(feature = "tls")]
|
||||
pub use tls::ServerTlsConfig;
|
||||
@@ -31,19 +32,17 @@ pub(crate) use tokio_rustls::server::TlsStream;
|
||||
use crate::transport::Error;
|
||||
|
||||
use self::recover_error::RecoverError;
|
||||
use super::service::{GrpcTimeout, Or, Routes, ServerIo};
|
||||
use super::service::{GrpcTimeout, ServerIo};
|
||||
use crate::body::BoxBody;
|
||||
use bytes::Bytes;
|
||||
use futures_core::Stream;
|
||||
use futures_util::{
|
||||
future::{self, MapErr},
|
||||
ready, TryFutureExt,
|
||||
};
|
||||
use futures_util::{future, ready};
|
||||
use http::{Request, Response};
|
||||
use http_body::Body as _;
|
||||
use hyper::{server::accept, Body};
|
||||
use pin_project::pin_project;
|
||||
use std::{
|
||||
convert::Infallible,
|
||||
fmt,
|
||||
future::Future,
|
||||
marker::PhantomData,
|
||||
@@ -94,41 +93,9 @@ pub struct Server<L = Identity> {
|
||||
|
||||
/// A stack based `Service` router.
|
||||
#[derive(Debug)]
|
||||
pub struct Router<A, B, L = Identity> {
|
||||
pub struct Router<L = Identity> {
|
||||
server: Server<L>,
|
||||
routes: Routes<A, B, Request<Body>>,
|
||||
}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
routes: Routes,
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// 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
|
||||
S: Service<Request<Body>, Response = Response<BoxBody>>
|
||||
S: Service<Request<Body>, Response = Response<BoxBody>, Error = Infallible>
|
||||
+ NamedService
|
||||
+ Clone
|
||||
+ Send
|
||||
+ 'static,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::Error> + Send,
|
||||
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.
|
||||
@@ -352,25 +318,18 @@ impl<L> Server<L> {
|
||||
/// # Note
|
||||
/// 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.
|
||||
pub fn add_optional_service<S>(
|
||||
&mut self,
|
||||
svc: Option<S>,
|
||||
) -> Router<Either<S, Unimplemented>, Unimplemented, L>
|
||||
pub fn add_optional_service<S>(&mut self, svc: Option<S>) -> Router<L>
|
||||
where
|
||||
S: Service<Request<Body>, Response = Response<BoxBody>>
|
||||
S: Service<Request<Body>, Response = Response<BoxBody>, Error = Infallible>
|
||||
+ NamedService
|
||||
+ Clone
|
||||
+ Send
|
||||
+ 'static,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::Error> + Send,
|
||||
L: Clone,
|
||||
{
|
||||
let svc = match svc {
|
||||
Some(some) => Either::A(some),
|
||||
None => Either::B(Unimplemented::default()),
|
||||
};
|
||||
Router::new(self.clone(), svc)
|
||||
let routes = svc.map(Routes::new).unwrap_or_default();
|
||||
Router::new(self.clone(), routes)
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
pub(crate) fn new(server: Server<L>, svc: S) -> Self
|
||||
where
|
||||
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<L> Router<L> {
|
||||
pub(crate) fn new(server: Server<L>, routes: Routes) -> Self {
|
||||
Self { server, routes }
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, L> Router<A, B, 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,
|
||||
{
|
||||
impl<L> Router<L> {
|
||||
/// 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
|
||||
S: Service<Request<Body>, Response = Response<BoxBody>>
|
||||
S: Service<Request<Body>, Response = Response<BoxBody>, Error = Infallible>
|
||||
+ NamedService
|
||||
+ Clone
|
||||
+ Send
|
||||
+ 'static,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::Error> + Send,
|
||||
{
|
||||
let Self { routes, server } = 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 }
|
||||
self.routes = self.routes.add_service(svc);
|
||||
self
|
||||
}
|
||||
|
||||
/// 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.
|
||||
/// As a result, one cannot use this to toggle between two identically named implementations.
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn add_optional_service<S>(
|
||||
self,
|
||||
svc: Option<S>,
|
||||
) -> Router<Either<S, Unimplemented>, Or<A, B, Request<Body>>, L>
|
||||
pub fn add_optional_service<S>(mut self, svc: Option<S>) -> Self
|
||||
where
|
||||
S: Service<Request<Body>, Response = Response<BoxBody>>
|
||||
S: Service<Request<Body>, Response = Response<BoxBody>, Error = Infallible>
|
||||
+ NamedService
|
||||
+ Clone
|
||||
+ Send
|
||||
+ 'static,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::Error> + Send,
|
||||
{
|
||||
let Self { routes, server } = 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 svc = match svc {
|
||||
Some(some) => Either::A(some),
|
||||
None => Either::B(Unimplemented::default()),
|
||||
};
|
||||
let routes = routes.push(pred, svc);
|
||||
|
||||
Router { server, routes }
|
||||
if let Some(svc) = svc {
|
||||
self.routes = self.routes.add_service(svc);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Consume this [`Server`] creating a future that will execute the server
|
||||
@@ -626,12 +531,10 @@ where
|
||||
/// [tokio]: https://docs.rs/tokio
|
||||
pub async fn serve<ResBody>(self, addr: SocketAddr) -> Result<(), super::Error>
|
||||
where
|
||||
L: Layer<Routes<A, B, Request<Body>>>,
|
||||
L: Layer<Routes>,
|
||||
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:
|
||||
Send + 'static,
|
||||
<<L as Layer<Routes<A, B, Request<Body>>>>::Service as Service<Request<Body>>>::Error:
|
||||
Into<crate::Error> + Send,
|
||||
<<L as Layer<Routes>>::Service as Service<Request<Body>>>::Future: Send + 'static,
|
||||
<<L as Layer<Routes>>::Service as Service<Request<Body>>>::Error: Into<crate::Error> + Send,
|
||||
ResBody: http_body::Body<Data = Bytes> + Send + 'static,
|
||||
ResBody::Error: Into<crate::Error>,
|
||||
{
|
||||
@@ -658,12 +561,10 @@ where
|
||||
signal: F,
|
||||
) -> Result<(), super::Error>
|
||||
where
|
||||
L: Layer<Routes<A, B, Request<Body>>>,
|
||||
L: Layer<Routes>,
|
||||
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:
|
||||
Send + 'static,
|
||||
<<L as Layer<Routes<A, B, Request<Body>>>>::Service as Service<Request<Body>>>::Error:
|
||||
Into<crate::Error> + Send,
|
||||
<<L as Layer<Routes>>::Service as Service<Request<Body>>>::Future: Send + 'static,
|
||||
<<L as Layer<Routes>>::Service as Service<Request<Body>>>::Error: Into<crate::Error> + Send,
|
||||
ResBody: http_body::Body<Data = Bytes> + Send + 'static,
|
||||
ResBody::Error: Into<crate::Error>,
|
||||
{
|
||||
@@ -687,12 +588,10 @@ where
|
||||
IO: AsyncRead + AsyncWrite + Connected + Unpin + Send + 'static,
|
||||
IO::ConnectInfo: Clone + Send + Sync + 'static,
|
||||
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 as Layer<Routes<A, B, Request<Body>>>>::Service as Service<Request<Body>>>::Future:
|
||||
Send + 'static,
|
||||
<<L as Layer<Routes<A, B, Request<Body>>>>::Service as Service<Request<Body>>>::Error:
|
||||
Into<crate::Error> + Send,
|
||||
<<L as Layer<Routes>>::Service as Service<Request<Body>>>::Future: Send + 'static,
|
||||
<<L as Layer<Routes>>::Service as Service<Request<Body>>>::Error: Into<crate::Error> + Send,
|
||||
ResBody: http_body::Body<Data = Bytes> + Send + 'static,
|
||||
ResBody::Error: Into<crate::Error>,
|
||||
{
|
||||
@@ -722,12 +621,10 @@ where
|
||||
IO::ConnectInfo: Clone + Send + Sync + 'static,
|
||||
IE: Into<crate::Error>,
|
||||
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 as Layer<Routes<A, B, Request<Body>>>>::Service as Service<Request<Body>>>::Future:
|
||||
Send + 'static,
|
||||
<<L as Layer<Routes<A, B, Request<Body>>>>::Service as Service<Request<Body>>>::Error:
|
||||
Into<crate::Error> + Send,
|
||||
<<L as Layer<Routes>>::Service as Service<Request<Body>>>::Future: Send + 'static,
|
||||
<<L as Layer<Routes>>::Service as Service<Request<Body>>>::Error: Into<crate::Error> + Send,
|
||||
ResBody: http_body::Body<Data = Bytes> + Send + 'static,
|
||||
ResBody::Error: Into<crate::Error>,
|
||||
{
|
||||
@@ -737,19 +634,16 @@ where
|
||||
}
|
||||
|
||||
/// 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
|
||||
L: Layer<Routes<A, B, Request<Body>>>,
|
||||
L: Layer<Routes>,
|
||||
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:
|
||||
Send + 'static,
|
||||
<<L as Layer<Routes<A, B, Request<Body>>>>::Service as Service<Request<Body>>>::Error:
|
||||
Into<crate::Error> + Send,
|
||||
<<L as Layer<Routes>>::Service as Service<Request<Body>>>::Future: Send + 'static,
|
||||
<<L as Layer<Routes>>::Service as Service<Request<Body>>>::Error: Into<crate::Error> + Send,
|
||||
ResBody: http_body::Body<Data = Bytes> + Send + 'static,
|
||||
ResBody::Error: Into<crate::Error>,
|
||||
{
|
||||
let inner = self.server.layer.layer(self.routes);
|
||||
RouterService { inner }
|
||||
self.server.layer.layer(self.routes)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -905,30 +799,3 @@ where
|
||||
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::grpc_timeout::GrpcTimeout;
|
||||
pub(crate) use self::io::ServerIo;
|
||||
pub(crate) use self::router::{Or, Routes};
|
||||
#[cfg(feature = "tls")]
|
||||
pub(crate) use self::tls::{TlsAcceptor, TlsConnector};
|
||||
pub(crate) use self::user_agent::UserAgent;
|
||||
|
||||
pub use self::grpc_timeout::TimeoutExpired;
|
||||
pub use self::router::Routes;
|
||||
|
||||
@@ -1,132 +1,90 @@
|
||||
use futures_util::{
|
||||
future::Either,
|
||||
future::{MapErr, TryFutureExt},
|
||||
use crate::{
|
||||
body::{boxed, BoxBody},
|
||||
transport::NamedService,
|
||||
};
|
||||
use axum::handler::Handler;
|
||||
use http::{Request, Response};
|
||||
use hyper::Body;
|
||||
use pin_project::pin_project;
|
||||
use std::{
|
||||
fmt,
|
||||
sync::Arc,
|
||||
convert::Infallible,
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
use tower::ServiceExt;
|
||||
use tower_service::Service;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[derive(Debug)]
|
||||
pub struct Routes<A, B, Request> {
|
||||
routes: Or<A, B, Request>,
|
||||
/// A [`Service`] router.
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct Routes {
|
||||
router: axum::Router,
|
||||
}
|
||||
|
||||
impl<A, B, Request> Routes<A, B, Request> {
|
||||
pub(crate) fn new(
|
||||
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
|
||||
impl Routes {
|
||||
pub(crate) fn new<S>(svc: S) -> Self
|
||||
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);
|
||||
Self { predicate, a, b }
|
||||
let router = axum::Router::new().fallback(unimplemented.into_service());
|
||||
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>
|
||||
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;
|
||||
async fn unimplemented() -> impl axum::response::IntoResponse {
|
||||
let status = http::StatusCode::OK;
|
||||
let headers =
|
||||
axum::response::Headers([("grpc-status", "12"), ("content-type", "application/grpc")]);
|
||||
(status, headers)
|
||||
}
|
||||
|
||||
impl Service<Request<Body>> for Routes {
|
||||
type Response = Response<BoxBody>;
|
||||
type Error = crate::Error;
|
||||
type Future = RoutesFuture;
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
type Future = Either<
|
||||
MapErr<A::Future, fn(A::Error) -> crate::Error>,
|
||||
MapErr<B::Future, fn(B::Error) -> crate::Error>,
|
||||
>;
|
||||
|
||||
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
Ok(()).into()
|
||||
#[inline]
|
||||
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, req: Request) -> Self::Future {
|
||||
if (self.predicate)(&req) {
|
||||
Either::Left(self.a.call(req).map_err(|e| e.into()))
|
||||
} else {
|
||||
Either::Right(self.b.call(req).map_err(|e| e.into()))
|
||||
fn call(&mut self, req: Request<Body>) -> Self::Future {
|
||||
RoutesFuture(self.router.call(req))
|
||||
}
|
||||
}
|
||||
|
||||
#[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