0

我有以下代码片段:

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?无论如何,我的问题已经解决了,但如果有人能解释为什么这样做我很乐意接受。

4

1 回答 1

0

这对于您的用例未经测试,但您可以.clone()move允许他们访问之前进行操作。

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

    move {
        match verify_msg(key, &headers, &bytes) {
            // ...
        }
    }
});
于 2022-02-20T20:35:33.057 回答