I've been trying the following
Relevant imports and code shown
use std::sync::{Arc, Mutex};
use std::thread;
use hyper::rt::{self, Future, Stream};
use hyper::service::service_fn;
use hyper::{Body, Request, Response, Server, StatusCode};
pub struct ChallengeState;
pub struct ChallengeResponse;
type BoxFut<'a> = Box<Future<Item = Response<Body>, Error = hyper::Error> + Send + 'a>;
fn handle_challengeproof<'a>(
req: Request<Body>,
challenge: &Arc<Mutex<ChallengeState>>,
) -> BoxFut<'a> {
let resp = req.into_body().concat2().map(move |body| {
let challenge_lock = challenge.lock().unwrap();
Response::builder()
.status(StatusCode::OK)
.body(Body::from("test"))
.unwrap()
});
Box::new(resp)
}
fn handle<'a>(
req: Request<Body>,
challenge: &Arc<Mutex<ChallengeState>>,
) -> BoxFut<'a> {
handle_challengeproof(req, challenge)
}
pub fn run_listener(
challenge: Arc<Mutex<ChallengeState>>,
) -> thread::JoinHandle<()> {
let addr = ([127, 0, 0, 1], 9999).into();
let listener_service = move || {
let challenge = Arc::clone(&challenge);
service_fn(move |req: Request<Body>| {
handle(req, &challenge)
})
};
let server = Server::bind(&addr)
.serve(listener_service)
.map_err(|_| () );
thread::spawn(move || {
rt::run(server);
})
}
I've been trying to avoid an extra clone of Arc by passing a reference to the handle method but can't seem to get around this. Avoiding the lifetime on handle() got a different error regarding futures asking for static lifetime.
Code updated with only relevant stuff # https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=10ea31450e88a122455006760d7fcdd1
The whole point of an Arc is that it counts how many references there are, which happens when it is cloned. Passing around references to an Arc defeats the point.
Instead of passing references, pass the Arc itself. So handle's signature becomes:
fn handle<'a>(
req: Request<Body>,
challenge: Arc<Mutex<ChallengeState>>,
) -> BoxFut<'a>
Passing the Arc by references from the closure isn't possible because you would be referencing something that immediately goes out of scope. Instead, move the Arc into handle:
let listener_service = move || {
service_fn(move |req: Request<Body>| handle(req, challenge))
};
Related
I've been doing rust for just short while but didn't much struggle until this issue.
I want to authenticate each request, and make returned value (from auth service) available inside requests.
I've read implementing FromRequest for the struct returned by auth server should make it available.
But I have issues implementing it correctly. It requires extract and from_request functions both returning self, and if I understand it a little correctly, extract is being called the first, so I should set it somewhere in request extensions, and get it from there inside from_request. I have following code:
impl FromRequest for CustomClaim {
type Error = actix_web::Error;
type Future = std::pin::Pin<Box<dyn std::future::Future<Output = Result<Self, Self::Error>>>>;
fn extract(req: &HttpRequest) -> Self::Future {
let auth_header = req
.headers()
.get("Authorization")
.unwrap()
.to_str()
.unwrap()
.to_owned();
let boxed_future = Box::pin(async move {
let claim_future = get_claim(&auth_header).await;
claim_future
});
req.extensions_mut().insert(boxed_future);
boxed_future
}
fn from_request(req: &HttpRequest, payload: &mut actix_web::dev::Payload) -> Self::Future {
let boxed_future = req.extensions().get::<Self::Future>().unwrap();
boxed_future
}
}
async fn get_claim(auth_header: &str) -> Result<CustomClaim, actix_web::Error>
But from_request doesn't compile because it returns a reference (error message: mismatched types expected struct `Pin\<Box\<(dyn futures::Future\<Output = Result\<auth::CustomClaim, actix_web::Error\>\> + 'static)\>\>`found reference`&Pin\<Box\<dyn futures::Future\<Output = Result\<auth::CustomClaim, actix_web::Error\>\>\>\>` )
Doing .clone() doesn't help because clone is not implemented on that future type so it still returns a reference. Can I implement clone for the future? Is my approach wrong?
Ok so I feel little dumb but the answer is - you (or I) don't need the extract function. Only from_request is required.
So solution is, move the code from extract function to from_request, omit extract, and don't set anything on the request:
impl FromRequest for CustomClaim {
type Error = actix_web::Error;
type Future = std::pin::Pin<Box<dyn std::future::Future<Output = Result<Self, Self::Error>>>>;
fn from_request(req: &HttpRequest, _payload: &mut actix_web::dev::Payload) -> Self::Future {
let auth_header = req
.headers()
.get("Authorization")
.unwrap()
.to_str()
.unwrap()
.to_owned();
Box::pin(async move {
let claim_future = get_claim(&auth_header).await;
claim_future
})
}
}
Then it's possible to add a parameter in authenticated handlers:
#[post("/authed-post")]
async fn authed_post(
_req: HttpRequest,
claim: CustomClaim,
// ...
) -> impl Responder
In my browser application, two closures access data stored in a Rc<RefCell<T>>. One closure mutably borrows the data, while the other immutably borrows it. The two closures are invoked independently of one another, and this will occasionally result in a BorrowError or BorrowMutError.
Here is my attempt at an MWE, though it uses a future to artificially inflate the likelihood of the error occurring:
use std::cell::RefCell;
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
use std::task::{Context, Poll, Waker};
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsValue;
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
pub fn log(s: &str);
#[wasm_bindgen(js_name = setTimeout)]
fn set_timeout(closure: &Closure<dyn FnMut()>, millis: u32) -> i32;
#[wasm_bindgen(js_name = setInterval)]
fn set_interval(closure: &Closure<dyn FnMut()>, millis: u32) -> i32;
}
pub struct Counter(u32);
#[wasm_bindgen(start)]
pub async fn main() -> Result<(), JsValue> {
console_error_panic_hook::set_once();
let counter = Rc::new(RefCell::new(Counter(0)));
let counter_clone = counter.clone();
let log_closure = Closure::wrap(Box::new(move || {
let c = counter_clone.borrow();
log(&c.0.to_string());
}) as Box<dyn FnMut()>);
set_interval(&log_closure, 1000);
log_closure.forget();
let counter_clone = counter.clone();
let increment_closure = Closure::wrap(Box::new(move || {
let counter_clone = counter_clone.clone();
wasm_bindgen_futures::spawn_local(async move {
let mut c = counter_clone.borrow_mut();
// In reality this future would be replaced by some other
// time-consuming operation manipulating the borrowed data
SleepFuture::new(5000).await;
c.0 += 1;
});
}) as Box<dyn FnMut()>);
set_timeout(&increment_closure, 3000);
increment_closure.forget();
Ok(())
}
struct SleepSharedState {
waker: Option<Waker>,
completed: bool,
closure: Option<Closure<dyn FnMut()>>,
}
struct SleepFuture {
shared_state: Rc<RefCell<SleepSharedState>>,
}
impl Future for SleepFuture {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut shared_state = self.shared_state.borrow_mut();
if shared_state.completed {
Poll::Ready(())
} else {
shared_state.waker = Some(cx.waker().clone());
Poll::Pending
}
}
}
impl SleepFuture {
fn new(duration: u32) -> Self {
let shared_state = Rc::new(RefCell::new(SleepSharedState {
waker: None,
completed: false,
closure: None,
}));
let state_clone = shared_state.clone();
let closure = Closure::wrap(Box::new(move || {
let mut state = state_clone.borrow_mut();
state.completed = true;
if let Some(waker) = state.waker.take() {
waker.wake();
}
}) as Box<dyn FnMut()>);
set_timeout(&closure, duration);
shared_state.borrow_mut().closure = Some(closure);
SleepFuture { shared_state }
}
}
panicked at 'already mutably borrowed: BorrowError'
The error makes sense, but how should I go about resolving it?
My current solution is to have the closures use try_borrow or try_borrow_mut, and if unsuccessful, use setTimeout for an arbitrary amount of time before attempting to borrow again.
Think about this problem independently of Rust's borrow semantics. You have a long-running operation that's updating some shared state.
How would you do it if you were using threads? You would put the shared state behind a lock. RefCell is like a lock except that you can't block on unlocking it — but you can emulate blocking by using some kind of message-passing to wake up the reader.
How would you do it if you were using pure JavaScript? You don't automatically have anything like RefCell, so either:
The state can be safely read while the operation is still ongoing (in a concurrency-not-parallelism sense): in this case, emulate that by not holding a single RefMut (result of borrow_mut()) alive across an await boundary.
The state is not safe to be read: you'd either write something lock-like as described above, or perhaps arrange so that it's only written once when the operation is done, and until then, the long-running operation has its own private state not shared with the rest of the application (so there can be no BorrowError conflicts).
Think about what your application actually needs and pick a suitable solution. Implementing any of these solutions will most likely involve having additional interior-mutable objects used for communication.
I need a simple hyper server that serves a single request and then exits. This is my code so far, I believe that all I need is a way to get tx into hello, so I can use tx.send(()) and it should work the way I want it. However, I can't quite work out a way to do that without having the compiler yell at me.
use std::convert::Infallible;
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server};
async fn hello(_: Request<Body>) -> Result<Response<Body>, Infallible> {
Ok(Response::new(Body::from("Hello World!")))
}
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let (tx, rx) = tokio::sync::oneshot::channel::<()>();
let make_svc = make_service_fn(|_conn| {
async { Ok::<_, Infallible>(service_fn(hello)) }
});
let addr = ([127, 0, 0, 1], 3000).into();
let server = Server::bind(&addr).serve(make_svc);
println!("Listening on http://{}", addr);
let graceful = server.with_graceful_shutdown(async {
rx.await.ok();
});
graceful.await?;
Ok(())
}
Rust playground
Relevant crates:
tokio = { version = "0.2", features = ["full"] }
hyper = "0.13.7"
Since How to share mutable state for a Hyper handler? and How to share mutable state for a Hyper handler?, the hyper API has changed and I am unable to compile the code when edited to work with the current version.
A straightforward solution would be to use global state for this, made possible by tokio's Mutex type, like so:
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server};
use lazy_static::lazy_static;
use std::convert::Infallible;
use std::sync::Arc;
use tokio::sync::oneshot::Sender;
use tokio::sync::Mutex;
lazy_static! {
/// Channel used to send shutdown signal - wrapped in an Option to allow
/// it to be taken by value (since oneshot channels consume themselves on
/// send) and an Arc<Mutex> to allow it to be safely shared between threads
static ref SHUTDOWN_TX: Arc<Mutex<Option<Sender<()>>>> = <_>::default();
}
async fn hello(_: Request<Body>) -> Result<Response<Body>, Infallible> {
// Attempt to send a shutdown signal, if one hasn't already been sent
if let Some(tx) = SHUTDOWN_TX.lock().await.take() {
let _ = tx.send(());
}
Ok(Response::new(Body::from("Hello World!")))
}
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let (tx, rx) = tokio::sync::oneshot::channel::<()>();
SHUTDOWN_TX.lock().await.replace(tx);
let make_svc = make_service_fn(|_conn| async { Ok::<_, Infallible>(service_fn(hello)) });
let addr = ([127, 0, 0, 1], 3000).into();
let server = Server::bind(&addr).serve(make_svc);
println!("Listening on http://{}", addr);
let graceful = server.with_graceful_shutdown(async {
rx.await.ok();
});
graceful.await?;
Ok(())
}
In this version of the code, we store the sender half of the shutdown signal channel in a global variable protected by a mutex lock, and then attempt to consume the channel to send the signal on every request.
Been learning rust and having a problem with lifetime when passing conn to the request_handler. I get an error saying
error[E0312]: lifetime of reference outlives lifetime of borrowed content...
--> src/main.rs:33:70
|
33 | let request_handler = |req: Request<Body>| async { request_handler(conn, req).await };
| ^^^^
|
= note: ...the reference is valid for the static lifetime...
but I am not sure how to handle lifetimes with closures and why/how it is static. I have a loose understanding of lifetimes and borrowing but this seems like a more complex case. I also would just not use a closure, but the return type of one of the closures has a type that is not exported by the hyper crate, so i don't know how i would create a fn without being able to declare the return type.
Also I can confirm if i remove passing conn i can get everything to work, but I want to use the conn object in the request_handler.
use hyper::server::conn::AddrStream;
use hyper::service::make_service_fn;
use hyper::Version;
use hyper::{Body, Error, Method, Request, Response, Server};
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
mod http_models;
mod utils;
use hyper::service::service_fn;
async fn request_handler(
conn: &'static AddrStream,
req: Request<Body>,
) -> Result<Response<Body>, hyper::Error> {
println!("req: {:?}", req);
if req.method() == Method::CONNECT {
println!("Connect")
}
let res: Response<Body> = Response::builder()
.status(200)
.version(Version::HTTP_11)
.body(Body::empty())
.unwrap();
return Ok(res);
}
#[tokio::main]
async fn main() -> Result<(), Error> {
let ip = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
let addr = SocketAddr::new(ip, 1337);
//let client = Client::new();
let make_service = make_service_fn(|conn: &AddrStream| async {
let request_handler = |req: Request<Body>| async { request_handler(conn, req).await };
let service = service_fn(request_handler);
Ok::<_, Error>(service)
});
let server = Server::bind(&addr).serve(make_service);
println!("Listening on http://{}", addr);
if let Err(e) = server.await {
eprintln!("server error: {}", e);
}
Ok(())
}
The conn argument of the closure passed to make_service_fn only lives as long as the closure body, but the return value of the closure (Ok(service)) references it. The closure must have the type FnMut(&Target) -> impl Future, which means it sadly is not permitted to return a value that references its argument.
The only solution is to copy/clone whatever you need from conn while setting up your request handler, since you cannot keep a reference to it once the closure returns.
I'm stuck trying to share (read-only) data structures across async helpers. What I'm trying to accomplish is create a Hyper server where I pre-generate some data that can be used by all request handlers.
Here is the example from the Hyper getting started guide, extended with what I'm trying to do:
#[tokio::main]
async fn main() {
let address = SocketAddr::from(([127, 0, 0, 1], 3000));
let pages = generate_static_pages();
let make_service = make_service_fn(|_conn| async move {
Ok::<_, Infallible>(service_fn(|req: Request<Body>| async move {
serve(pages, req)
}))
});
let server = Server::bind(&address).serve(make_service);
if let Err(error) = server.await {
eprintln!("server error: {}", error);
}
}
In my case, generate_static_pages() returns a HashMap<&'static str, Bytes> with pre-generated pages. Unfortunately, this hash map cannot be generated at compile-time, because that would make things a lot easier. Now, I struggle because pages cannot be borrowed by the closures: "cannot move out of pages, a captured variable in an FnMut closure"
I tried to pass a reference, but that didn't work because Rust cannot infer the variable to live long enough for the closure to use. I then tried to use .clone() but that doesn't work because it would be called on the variable after it is moved, which it can't. Finally, I tried wrapping in an Arc, but that doesn't solve it, basically because of the same reason.
What would you advice me to do? Thanks!
If you only want immutable references to the pages then you should be able to use the lazy_static crate. lazy_static lets you initialize static variables at runtime - it's quite useful!
Your code would end up looking something like:
use lazy_static::lazy_static;
lazy_static! {
static ref PAGES: HashMap<&'static str, Bytes> = generate_static_pages();
}
#[tokio::main]
async fn main() {
let address = SocketAddr::from(([127, 0, 0, 1], 3000));
let make_service = make_service_fn(|_conn| async move {
Ok::<_, Infallible>(service_fn(|req: Request<Body>| async move {
serve(&PAGES, req)
}))
});
let server = Server::bind(&address).serve(make_service);
if let Err(error) = server.await {
eprintln!("server error: {}", error);
}
}
Also, here's another lazy_static example.