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:
Lucio Franco
2019-10-29 16:32:04 -04:00
committed by GitHub
parent a17049f1f7
commit 5b4f4689a2
20 changed files with 473 additions and 176 deletions
+7 -98
View File
@@ -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 {}
}
+1
View File
@@ -150,6 +150,7 @@ impl pb::server::TestService for TestService {
}
}
#[derive(Default)]
pub struct UnimplementedService;
#[tonic::async_trait]