如何在将变量移动到 warp 的 .then() 过滤器之前克隆它?

How do I clone a variable before moving it into warp's .then() filter?

我有以下代码片段:

async fn server(config: crate::Config) {
    println!("Building server");
    let key = hmac::Key::new(hmac::HMAC_SHA256, config.docusign.hmac_key.as_bytes());
    let webhook = warp::path("webhook")
        .and(warp::post())
        .and(warp::body::content_length_limit(4194304))
        .and(warp::header::headers_cloned())
        .and(warp::body::bytes())
        .then(|headers: HeaderMap, bytes: Bytes| async move {
            match verify_msg(&key, &headers, &bytes) {
                Ok(_) => {
                    println!("Message is Valid!");
                    process_msg(bytes).await.into_response()
                }
                Err(string) => {
                    println!("{string}");
                    warp::reply::with_status(warp::reply(), http::StatusCode::UNAUTHORIZED)
                        .into_response()
                }
            }
        });

    warp::serve(webhook)
        .tls()
        .cert_path("cert/cert.pem")
        .key_path("cert/key.pem")
        .run(([0, 0, 0, 0], 443))
        .await;

    println!("Shutting down Server");
}

这给了我一个错误:

expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
this closure implements `FnOnce`, not `Fn`rustc(E0525)
server.rs(20, 4): the requirement to implement `Fn` derives from here
server.rs(20, 9): this closure implements `FnOnce`, not `Fn`
server.rs(21, 22): closure is `FnOnce` because it moves the variable `key` out of its environment

这是有道理的,我正在使用 key 变量并将其移出环境。我想不通的是如何在不移动密钥的情况下让这个异步闭包工作?我试过像这样克隆它:match verify_msg(&key.clone(), &headers, &bytes) 但它仍然不起作用。我想这是有道理的,因为变量仍然在闭包中被引用。那么,如何在移动之前克隆密钥?

我能够让它与 .map() 和常规(非异步)闭包一起工作,但是 process_msg() 函数是异步的,所以我认为这行不通。

编辑: @t56k 的回答让我走上了正确的轨道,但效果并不理想。朝着将异步块放入闭包的方向前进并遵循编译器的建议最终让我得到了这个:

async fn server(config: crate::Config) {
    println!("Building server");
    let key = hmac::Key::new(hmac::HMAC_SHA256, config.docusign.hmac_key.as_bytes());
    let webhook = warp::path("webhook")
        .and(warp::post())
        .and(warp::body::content_length_limit(4194304))
        .and(warp::header::headers_cloned())
        .and(warp::body::bytes())
        .then(move |headers: HeaderMap, bytes: Bytes| {
            let key = key.clone();
            async move {
                match verify_msg(&key, &headers, &bytes) {
                    Ok(_) => {
                        println!("Message is Valid!");
                        process_msg(bytes).await.into_response()
                    }
                    Err(string) => {
                        println!("{string}");
                        warp::reply::with_status(warp::reply(), http::StatusCode::UNAUTHORIZED)
                            .into_response()
                    }
                }
            }
        });

    warp::serve(webhook)
        .tls()
        .cert_path("cert/cert.pem")
        .key_path("cert/key.pem")
        .run(([0, 0, 0, 0], 443))
        .await;

    println!("Shutting down Server");
}

由于某些原因,即使我使用 move 关键字,它也能完美运行。我想我只能移动 key 如果它不在 async 块内?无论如何,我的问题已经解决了,但如果有人能解释为什么这有效,我会很乐意接受它。

这对于您的用例未经测试,但您可以 .clone() move 之前的内容以允许它们访问。

.and_then(|headers: HeaderMap, bytes: Bytes| async {
    let key = key.clone();

    move {
        match verify_msg(key, &headers, &bytes) {
            // ...
        }
    }
});