Hi,
I am new to rust and i am trying to use tokio tower to build a Service.
My goal is to have sort of "build" method which will return a Service. The build method will allow me to stack additional tower layers as needed (within the build) and a user of the function just needs to call build() to get the service where he can do the usual ready() ... call(req).await to get the value.
Problems:
(1) tower::Service
aspects a signature of the sort async fn handle(req: Request) -> Response
. With a struct method - how do/can i convert a async fn handle(**&mut self**, req: Request) -> Response
to that expected by tower?
(2) how to have the build function return the right Service type?
(3) i keep running into unsatisfied traits relating to Service & ServiceExt and i have no clue how to resolve these. Is there a way to approach this problem?
Thanks for any help and advice
My sample code is below:
use std::future::Future;
use std::pin::Pin;
use tower::{ServiceBuilder, Service, ServiceExt};
#[derive(Debug, Clone)]
pub struct A {
val: String,
}
pub type Request = String;
pub type Response = String;
pub type Error = anyhow::Error;
pub type ResponseResult = Result<String, Error>;
pub type ResponseFuture = Pin<Box<dyn Future<Output = ResponseResult> + Send + 'static>>;
impl A {
pub fn new(val: String) -> Self { Self { val } }
// problem-1: how to convert this to `async fn call(req: Request) -> Response` expected by tower?
pub async fn call(&mut self, req: String) -> ResponseFuture {
let mut val = self.val.clone();
Box::pin( async move { Ok( val + &req ) })
}
// how to have a fn build up a Service and return it?
pub fn build_service(&mut self) -> impl Service<Request> // See (Error-A) below
{
let mut svc = ServiceBuilder::new();
let mut svc = svc.service_fn( move |req| {
self.call(req);
});
svc
}
}
#[tokio::main]
async fn main() {
// tried this by commenting out build_service() above
// and got (Error-B)
let mut a = A{val: "hi".to_string()};
let mut svc = ServiceBuilder::new();
let mut svc = svc.service_fn( move |req|{
a.call(req);
});
let r = svc.ready().await.unwrap().call("test".to_string()).await.unwrap();
println!("r={}", r);
}
Errors Encountered
// ERRORS:
// ------
(Error-A)
error[E0277]: `()` is not a future
--> src/trytowerbuild.rs:26:40
|
26 | pub fn build_service(&mut self) -> impl Service<Request> {
| ^^^^^^^^^^^^^^^^^^^^^ `()` is not a future
|
= help: the trait `std::future::Future` is not implemented for `()`
= note: required because of the requirements on the impl of `Service<String>` for `ServiceFn<[closure@src/trytowerbuild.rs:28:39: 30:10]>`
// (Error-B)
error[E0599]: the method `ready` exists for struct `ServiceFn<[closure@src/trytowerbuild.rs:42:35: 44:6]>`, but its trait bounds were not satisfied
--> src/trytowerbuild.rs:46:17
|
46 | let r = svc.ready().await.unwrap().call("test".to_string()).await.unwrap();
| ^^^^^ method cannot be called on `ServiceFn<[closure@src/trytowerbuild.rs:42:35: 44:6]>` due to unsatisfied trait bounds
|
::: /Users/globalflea/.cargo/registry/src/github.com-1ecc6299db9ec823/tower-0.4.8/src/util/service_fn.rs:54:1
|
54 | pub struct ServiceFn<T> {
| -----------------------
| |
| doesn't satisfy `_: Service<_>`
| doesn't satisfy `_: ServiceExt<_>`
|
= note: the following trait bounds were not satisfied:
`ServiceFn<[closure@src/trytowerbuild.rs:42:35: 44:6]>: Service<_>`
which is required by `ServiceFn<[closure@src/trytowerbuild.rs:42:35: 44:6]>: ServiceExt<_>`