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:
+40
-38
@@ -7,63 +7,32 @@ use syn::{Ident, Lit, LitStr};
|
||||
pub(crate) fn generate(service: &Service, proto_path: &str) -> TokenStream {
|
||||
let methods = generate_methods(&service, proto_path);
|
||||
|
||||
let server_make_service = quote::format_ident!("{}Server", service.name);
|
||||
let server_service = quote::format_ident!("{}ServerSvc", service.name);
|
||||
let server_service = quote::format_ident!("{}Server", service.name);
|
||||
let server_trait = quote::format_ident!("{}", service.name);
|
||||
let generated_trait = generate_trait(service, proto_path, server_trait.clone());
|
||||
let service_doc = generate_doc_comments(&service.comments.leading);
|
||||
let server_new_doc = generate_doc_comment(&format!(
|
||||
"Create a new {} from a type that implements {}.",
|
||||
server_make_service, server_trait
|
||||
));
|
||||
|
||||
// Transport based implementations
|
||||
let path = format!("{}.{}", service.package, service.proto_name);
|
||||
let transport = generate_transport(&server_service, &server_trait, &path);
|
||||
|
||||
quote! {
|
||||
#generated_trait
|
||||
|
||||
#service_doc
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct #server_make_service<T: #server_trait> {
|
||||
inner: Arc<T>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
#[doc(hidden)]
|
||||
pub struct #server_service<T: #server_trait> {
|
||||
inner: Arc<T>,
|
||||
}
|
||||
|
||||
impl<T: #server_trait> #server_make_service<T> {
|
||||
#server_new_doc
|
||||
impl<T: #server_trait> #server_service<T> {
|
||||
pub fn new(inner: T) -> Self {
|
||||
let inner = Arc::new(inner);
|
||||
Self::from_shared(inner)
|
||||
}
|
||||
|
||||
pub fn from_shared(inner: Arc<T>) -> Self {
|
||||
Self { inner }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: #server_trait> #server_service<T> {
|
||||
pub fn new(inner: Arc<T>) -> Self {
|
||||
Self { inner }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: #server_trait, R> Service<R> for #server_make_service<T> {
|
||||
type Response = #server_service<T>;
|
||||
type Error = Never;
|
||||
type Future = Ready<Result<Self::Response, Self::Error>>;
|
||||
|
||||
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, _: R) -> Self::Future {
|
||||
ok(#server_service::new(self.inner.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: #server_trait> Service<http::Request<HyperBody>> for #server_service<T> {
|
||||
type Response = http::Response<tonic::body::BoxBody>;
|
||||
type Error = Never;
|
||||
@@ -89,6 +58,15 @@ pub(crate) fn generate(service: &Service, proto_path: &str) -> TokenStream {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: #server_trait> Clone for #server_service<T> {
|
||||
fn clone(&self) -> Self {
|
||||
let inner = self.inner.clone();
|
||||
Self { inner }
|
||||
}
|
||||
}
|
||||
|
||||
#transport
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,6 +159,30 @@ fn generate_trait_methods(service: &Service, proto_path: &str) -> TokenStream {
|
||||
stream
|
||||
}
|
||||
|
||||
#[cfg(feature = "transport")]
|
||||
fn generate_transport(
|
||||
server_service: &syn::Ident,
|
||||
server_trait: &syn::Ident,
|
||||
service_name: &str,
|
||||
) -> TokenStream {
|
||||
let service_name = syn::LitStr::new(service_name, proc_macro2::Span::call_site());
|
||||
|
||||
quote! {
|
||||
impl<T: #server_trait> tonic::transport::ServiceName for #server_service<T> {
|
||||
const NAME: &'static str = #service_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "transport"))]
|
||||
fn generate_transport(
|
||||
_server_service: &syn::Ident,
|
||||
_server_trait: &syn::Ident,
|
||||
_service_name: &str,
|
||||
) -> TokenStream {
|
||||
TokenStream::new()
|
||||
}
|
||||
|
||||
fn generate_methods(service: &Service, proto_path: &str) -> TokenStream {
|
||||
let mut stream = TokenStream::new();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user