I'm writing a function fn run_grpc_server<S, L>(service: S, layer: L) -> Result<(), String>
where I need to provide generic parameter for protobuf service S
and tower layer L
, so I can build the GRPC server combining them.
To illustrate, I modify the example https://github.com/hyperium/tonic/blob/master/examples/src/tower/server.rs as follows:
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let greeter = MyGreeter::default();
// The stack of middleware that our service will be wrapped in
let layer = tower::ServiceBuilder::new()
// Apply middleware from tower
.timeout(Duration::from_secs(30))
// Apply our own middleware
.layer(MyMiddlewareLayer::default())
// Interceptors can be also be applied as middleware
.layer(tonic::service::interceptor(intercept))
.into_inner();
run_grpc_server(greeter, layer).await;
Ok(())
}
pub async fn run_grpc_server<S, L>(service: S, layer: L) -> Result<(), String>
where
S: hello_world::greeter_server::Greeter,
L: Clone, // not sure what other constraints to put here? Something with tower::Layer<?>
{
let addr = "[::1]:50051".parse().unwrap();
Server::builder()
.layer(layer)
.add_service(GreeterServer::new(service))
.serve(addr)
.await
.map_err(|e| e.to_string())
}
This fails to compile even though the original layer
in main
is not changed and is now provided as generic parameter L
.
The compilation error is:
error[E0277]: the trait bound `L: Layer<Routes>` is not satisfied
--> src/server.rs:63:10
|
63 | .serve(addr)
| ^^^^^ the trait `Layer<Routes>` is not implemented for `L`
|
= note: required for `Stack<L, Identity>` to implement `Layer<Routes>`
help: consider further restricting this bound
|
56 | L: Clone + tower::Layer<tonic::transport::server::Routes>,
| ++++++++++++++++++++++++++++++++++++++++++++++++
What changes are needed for run_grpc_server
to accept layer
as parameter of generic type L
?
Adding compiler suggestion L: Clone + tower::Layer<tonic::transport::server::Routes>
doesnt fix the issue but surfaces many more errors