Compile Code:
// [[file:../20220725095717-short_url.org::*short-url][short-url:1]]
use std::collections::HashMap;
use std::convert::Infallible;
use std::net::SocketAddr;
use std::sync::Arc;
use std::future::Future;
use async_trait::async_trait;
use hyper::{Body, Request, Response, Server, Method, StatusCode};
use hyper::service::{make_service_fn, service_fn};
use sqlx::{Pool, Database, MySql};
use sqlx::mysql::MySqlPoolOptions;
use route_recognizer::{ Router, Params };
use once_cell::sync::Lazy;
use tokio::runtime::Runtime;
static TOKIO_RT: Lazy<Runtime> = Lazy::new(|| {
tokio::runtime::Runtime::new().unwrap()
});
#[async_trait]
trait Handler: Sync + Send {
async fn invoke(&self, req: Request<Body>, context: Context) -> Result<Response<Body>, Infallible>;
}
#[async_trait]
impl<F: Send + Sync, Fut> Handler for F
where
F: Fn(Request<Body>, Context) -> Fut,
Fut: Future<Output = Result<Response<Body>, Infallible>> + Send,
{
async fn invoke(&self, req: Request<Body>, context: Context) -> Result<Response<Body>, Infallible> {
(self)(req, context).await
}
}
#[tokio::main]
async fn main() {
let mut router: Router<Box<dyn Handler>> = Router::new();
router.add("/", Box::new(home));
let shared_router = Arc::new(router);
// make service for each conn
let make_svc = make_service_fn(move |_conn| {
let captured_router = shared_router.clone();
async move {
Ok::<_, Infallible>(service_fn(move |req| {
let m = captured_router.recognize(req.uri().path()).unwrap();
let handler = m.handler();
handler.invoke(req, Context{ session: None})
}))
}
});
let addr = SocketAddr::from(([127, 0, 0, 1], 8080));
let server = Server::bind(&addr).serve(make_svc);
println!("Listening on http://{}", addr);
server.await;
}
struct Context {
session: Option<HashMap<String, String>>,
}
async fn home(req: Request<Body>, ctx: Context) -> Result<Response<Body>, Infallible> {
Ok(Response::new("short url home page".into()))
}
// short-url:1 ends here
got error:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src/main.rs:53:33
|
53 | ... let m = captured_router.recognize(req.uri().path()).unwrap();
| ^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'_` as defined here...
--> src/main.rs:52:38
|
52 | Ok::<_, Infallible>(service_fn(move |req| {
| ^^^^^^^^^^
note: ...so that closure can access `captured_router`
--> src/main.rs:53:17
|
53 | ... let m = captured_router.recognize(req.uri().path()).unwrap();
| ^^^^^^^^^^^^^^^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `hyper::proto::h2::server::H2Stream<Pin<Box<dyn Future<Output = Result<Response<Body>, Infallible>> + Send>>, Body>` will meet its required lifetime bounds...
--> src/main.rs:63:36
|
63 | let server = Server::bind(&addr).serve(make_svc);
| ^^^^^
note: ...that is required by this bound
--> /Users/fuchengxu/.cargo/registry/src/mirrors.sjtug.sjtu.edu.cn-4f7dbcce21e258a2/hyper-0.14.20/src/server/server.rs:546:12
|
546 | E: ConnStreamExec<<S::Service as HttpService<Body>>::Future, B>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This error confuse me a lot.
What first, the lifetime
refering to? captured_router?
'_
is the lifetime of closure move |req|
?
My understanding is that captured reference must outlive the closure, so closure can access it.
Server::bind(&addr).serve(make_svc);
need service/closure to be static?
If so how to make the closure static?