Skip to content

Commit 5b4f468

Browse files
authored
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 luciofranco14@gmail.com
1 parent a17049f commit 5b4f468

File tree

20 files changed

+473
-176
lines changed

20 files changed

+473
-176
lines changed

tonic-build/src/server.rs

Lines changed: 40 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -7,63 +7,32 @@ use syn::{Ident, Lit, LitStr};
77
pub(crate) fn generate(service: &Service, proto_path: &str) -> TokenStream {
88
let methods = generate_methods(&service, proto_path);
99

10-
let server_make_service = quote::format_ident!("{}Server", service.name);
11-
let server_service = quote::format_ident!("{}ServerSvc", service.name);
10+
let server_service = quote::format_ident!("{}Server", service.name);
1211
let server_trait = quote::format_ident!("{}", service.name);
1312
let generated_trait = generate_trait(service, proto_path, server_trait.clone());
1413
let service_doc = generate_doc_comments(&service.comments.leading);
15-
let server_new_doc = generate_doc_comment(&format!(
16-
"Create a new {} from a type that implements {}.",
17-
server_make_service, server_trait
18-
));
14+
15+
// Transport based implementations
16+
let path = format!("{}.{}", service.package, service.proto_name);
17+
let transport = generate_transport(&server_service, &server_trait, &path);
1918

2019
quote! {
2120
#generated_trait
2221

2322
#service_doc
24-
#[derive(Clone, Debug)]
25-
pub struct #server_make_service<T: #server_trait> {
26-
inner: Arc<T>,
27-
}
28-
29-
#[derive(Clone, Debug)]
23+
#[derive(Debug)]
3024
#[doc(hidden)]
3125
pub struct #server_service<T: #server_trait> {
3226
inner: Arc<T>,
3327
}
3428

35-
impl<T: #server_trait> #server_make_service<T> {
36-
#server_new_doc
29+
impl<T: #server_trait> #server_service<T> {
3730
pub fn new(inner: T) -> Self {
3831
let inner = Arc::new(inner);
39-
Self::from_shared(inner)
40-
}
41-
42-
pub fn from_shared(inner: Arc<T>) -> Self {
4332
Self { inner }
4433
}
4534
}
4635

47-
impl<T: #server_trait> #server_service<T> {
48-
pub fn new(inner: Arc<T>) -> Self {
49-
Self { inner }
50-
}
51-
}
52-
53-
impl<T: #server_trait, R> Service<R> for #server_make_service<T> {
54-
type Response = #server_service<T>;
55-
type Error = Never;
56-
type Future = Ready<Result<Self::Response, Self::Error>>;
57-
58-
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
59-
Poll::Ready(Ok(()))
60-
}
61-
62-
fn call(&mut self, _: R) -> Self::Future {
63-
ok(#server_service::new(self.inner.clone()))
64-
}
65-
}
66-
6736
impl<T: #server_trait> Service<http::Request<HyperBody>> for #server_service<T> {
6837
type Response = http::Response<tonic::body::BoxBody>;
6938
type Error = Never;
@@ -89,6 +58,15 @@ pub(crate) fn generate(service: &Service, proto_path: &str) -> TokenStream {
8958
}
9059
}
9160
}
61+
62+
impl<T: #server_trait> Clone for #server_service<T> {
63+
fn clone(&self) -> Self {
64+
let inner = self.inner.clone();
65+
Self { inner }
66+
}
67+
}
68+
69+
#transport
9270
}
9371
}
9472

@@ -181,6 +159,30 @@ fn generate_trait_methods(service: &Service, proto_path: &str) -> TokenStream {
181159
stream
182160
}
183161

162+
#[cfg(feature = "transport")]
163+
fn generate_transport(
164+
server_service: &syn::Ident,
165+
server_trait: &syn::Ident,
166+
service_name: &str,
167+
) -> TokenStream {
168+
let service_name = syn::LitStr::new(service_name, proc_macro2::Span::call_site());
169+
170+
quote! {
171+
impl<T: #server_trait> tonic::transport::ServiceName for #server_service<T> {
172+
const NAME: &'static str = #service_name;
173+
}
174+
}
175+
}
176+
177+
#[cfg(not(feature = "transport"))]
178+
fn generate_transport(
179+
_server_service: &syn::Ident,
180+
_server_trait: &syn::Ident,
181+
_service_name: &str,
182+
) -> TokenStream {
183+
TokenStream::new()
184+
}
185+
184186
fn generate_methods(service: &Service, proto_path: &str) -> TokenStream {
185187
let mut stream = TokenStream::new();
186188

tonic-examples/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ path = "src/tls_client_auth/server.rs"
5252
name = "tls-client-auth-client"
5353
path = "src/tls_client_auth/client.rs"
5454

55+
[[bin]]
56+
name = "multiplex-server"
57+
path = "src/multiplex/server.rs"
58+
59+
[[bin]]
60+
name = "multiplex-client"
61+
path = "src/multiplex/client.rs"
62+
5563
[[bin]]
5664
name = "gcp-client"
5765
path = "src/gcp/client.rs"

tonic-examples/helloworld-tutorial.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
191191
let greeter = MyGreeter {};
192192

193193
Server::builder()
194-
.serve(addr, GreeterServer::new(greeter))
194+
.add_service(GreeterServer::new(greeter))
195+
.serve(addr)
195196
.await?;
196197

197198
Ok(())
@@ -236,7 +237,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
236237
let greeter = MyGreeter {};
237238

238239
Server::builder()
239-
.serve(addr, GreeterServer::new(greeter))
240+
.add_service(GreeterServer::new(greeter))
241+
.serve(addr)
240242
.await?;
241243

242244
Ok(())

tonic-examples/routeguide-tutorial.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
558558

559559
let svc = server::RouteGuideServer::new(route_guide);
560560

561-
Server::builder().serve(addr, svc).await?;
561+
Server::builder()
562+
.add_service(svc)
563+
.serve(addr)
564+
.await?;
562565

563566
Ok(())
564567
}

tonic-examples/src/authentication/server.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
7878
}
7979
}
8080
})
81-
.clone()
82-
.serve(addr, pb::server::EchoServer::new(server))
81+
.add_service(pb::server::EchoServer::new(server))
82+
.serve(addr)
8383
.await?;
8484

8585
Ok(())

tonic-examples/src/helloworld/server.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
3333
let greeter = MyGreeter::default();
3434

3535
Server::builder()
36-
.serve(addr, GreeterServer::new(greeter))
36+
.add_service(GreeterServer::new(greeter))
37+
.serve(addr)
3738
.await?;
3839

3940
Ok(())

tonic-examples/src/load_balance/server.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
6060
let mut tx = tx.clone();
6161

6262
let server = EchoServer { addr };
63-
let serve = Server::builder().serve(addr, pb::server::EchoServer::new(server));
63+
let serve = Server::builder()
64+
.add_service(pb::server::EchoServer::new(server))
65+
.serve(addr);
6466

6567
tokio::spawn(async move {
6668
if let Err(e) = serve.await {
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
pub mod hello_world {
2+
tonic::include_proto!("helloworld");
3+
}
4+
5+
pub mod echo {
6+
tonic::include_proto!("grpc.examples.echo");
7+
}
8+
9+
use echo::{client::EchoClient, EchoRequest};
10+
use hello_world::{client::GreeterClient, HelloRequest};
11+
use tonic::transport::Endpoint;
12+
13+
#[tokio::main]
14+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
15+
let channel = Endpoint::from_static("http://[::1]:50051").channel();
16+
17+
let mut greeter_client = GreeterClient::new(channel.clone());
18+
let mut echo_client = EchoClient::new(channel);
19+
20+
let request = tonic::Request::new(HelloRequest {
21+
name: "Tonic".into(),
22+
});
23+
24+
let response = greeter_client.say_hello(request).await?;
25+
26+
println!("GREETER RESPONSE={:?}", response);
27+
28+
let request = tonic::Request::new(EchoRequest {
29+
message: "hello".into(),
30+
});
31+
32+
let response = echo_client.unary_echo(request).await?;
33+
34+
println!("ECHO RESPONSE={:?}", response);
35+
36+
Ok(())
37+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
use std::collections::VecDeque;
2+
use tonic::{transport::Server, Request, Response, Status};
3+
4+
pub mod hello_world {
5+
tonic::include_proto!("helloworld");
6+
}
7+
8+
pub mod echo {
9+
tonic::include_proto!("grpc.examples.echo");
10+
}
11+
12+
use hello_world::{
13+
server::{Greeter, GreeterServer},
14+
HelloReply, HelloRequest,
15+
};
16+
17+
use echo::{
18+
server::{Echo, EchoServer},
19+
EchoRequest, EchoResponse,
20+
};
21+
22+
#[tokio::main]
23+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
24+
let addr = "[::1]:50051".parse().unwrap();
25+
26+
let greeter = GreeterServer::new(MyGreeter::default());
27+
let echo = EchoServer::new(MyEcho::default());
28+
29+
Server::builder()
30+
.add_service(greeter)
31+
.add_service(echo)
32+
.serve(addr)
33+
.await?;
34+
35+
Ok(())
36+
}
37+
38+
#[derive(Default)]
39+
pub struct MyGreeter {}
40+
41+
#[tonic::async_trait]
42+
impl Greeter for MyGreeter {
43+
async fn say_hello(
44+
&self,
45+
request: Request<HelloRequest>,
46+
) -> Result<Response<HelloReply>, Status> {
47+
let reply = hello_world::HelloReply {
48+
message: format!("Hello {}!", request.into_inner().name).into(),
49+
};
50+
Ok(Response::new(reply))
51+
}
52+
}
53+
54+
#[derive(Default)]
55+
pub struct MyEcho;
56+
57+
#[tonic::async_trait]
58+
impl Echo for MyEcho {
59+
async fn unary_echo(
60+
&self,
61+
request: Request<EchoRequest>,
62+
) -> Result<Response<EchoResponse>, Status> {
63+
let message = request.into_inner().message;
64+
Ok(Response::new(EchoResponse { message }))
65+
}
66+
67+
type ServerStreamingEchoStream = VecDeque<Result<EchoResponse, Status>>;
68+
type BidirectionalStreamingEchoStream = VecDeque<Result<EchoResponse, Status>>;
69+
}

tonic-examples/src/routeguide/server.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
155155

156156
let svc = server::RouteGuideServer::new(route_guide);
157157

158-
Server::builder().serve(addr, svc).await?;
158+
Server::builder().add_service(svc).serve(addr).await?;
159159

160160
Ok(())
161161
}

0 commit comments

Comments
 (0)