feat(transport): Add service multiplexing/routing (#99)
* feat(transport): Add service multiplexing/routing
This change introduces a new "router" built on top of
`transport::Server` that allows one to run multiple
gRPC services on the same socket.
```rust
Server::builder()
.add_service(greeter)
.add_service(echo)
.serve(addr)
.await?;
```
There is also a new `multiplex` example showcasing
server side service multiplexing and client side
service multiplexing.
BREAKING CHANGES: `Server::serve` is now crate private
and all services must be added via `Server::add_service`.
Codegen also returns just a `Service` now instead of a
`MakeService` pair.
Closes #29
Signed-off-by: Lucio Franco [email protected]
This commit is contained in:
@@ -57,106 +57,15 @@ async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
});
|
||||
|
||||
let test_service = server::TestServiceServer::new(server::TestService::default());
|
||||
let unimplemented_service =
|
||||
server::UnimplementedServiceServer::new(server::UnimplementedService::default());
|
||||
|
||||
builder
|
||||
.serve(
|
||||
addr,
|
||||
router::Router {
|
||||
test_service: std::sync::Arc::new(server::TestService),
|
||||
unimplemented_service: std::sync::Arc::new(server::UnimplementedService),
|
||||
},
|
||||
)
|
||||
.add_service(test_service)
|
||||
.add_service(unimplemented_service)
|
||||
.serve(addr)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
mod router {
|
||||
use futures_util::future;
|
||||
use http::{Request, Response};
|
||||
use std::sync::Arc;
|
||||
use std::{
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
use tonic::{body::BoxBody, transport::Body};
|
||||
use tonic_interop::server::{
|
||||
TestService, TestServiceServer, UnimplementedService, UnimplementedServiceServer,
|
||||
};
|
||||
use tower::Service;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Router {
|
||||
pub test_service: Arc<TestService>,
|
||||
pub unimplemented_service: Arc<UnimplementedService>,
|
||||
}
|
||||
|
||||
impl Service<()> for Router {
|
||||
type Response = Router;
|
||||
type Error = Never;
|
||||
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: ()) -> Self::Future {
|
||||
future::ok(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl Service<Request<Body>> for Router {
|
||||
type Response = Response<BoxBody>;
|
||||
type Error = Never;
|
||||
type Future =
|
||||
Pin<Box<dyn Future<Output = Result<Response<BoxBody>, Never>> + Send + 'static>>;
|
||||
|
||||
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
Ok(()).into()
|
||||
}
|
||||
|
||||
fn call(&mut self, req: Request<Body>) -> Self::Future {
|
||||
let mut segments = req.uri().path().split("/");
|
||||
segments.next();
|
||||
let service = segments.next().unwrap();
|
||||
|
||||
match service {
|
||||
"grpc.testing.TestService" => {
|
||||
let me = self.clone();
|
||||
Box::pin(async move {
|
||||
let mut svc = TestServiceServer::from_shared(me.test_service);
|
||||
let mut svc = svc.call(()).await.unwrap();
|
||||
|
||||
let res = svc.call(req).await.unwrap();
|
||||
Ok(res)
|
||||
})
|
||||
}
|
||||
|
||||
"grpc.testing.UnimplementedService" => {
|
||||
let me = self.clone();
|
||||
Box::pin(async move {
|
||||
let mut svc =
|
||||
UnimplementedServiceServer::from_shared(me.unimplemented_service);
|
||||
let mut svc = svc.call(()).await.unwrap();
|
||||
|
||||
let res = svc.call(req).await.unwrap();
|
||||
Ok(res)
|
||||
})
|
||||
}
|
||||
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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 {}
|
||||
}
|
||||
|
||||
@@ -150,6 +150,7 @@ impl pb::server::TestService for TestService {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct UnimplementedService;
|
||||
|
||||
#[tonic::async_trait]
|
||||
|
||||
Reference in New Issue
Block a user