Hashmap 或类似 Rust 中的可重用异步闭包/函数

问题描述 投票:0回答:0

我想创建一个有四种方法的结构:

new(), handle_interaction(), add_shortcut(), async start_server()

该结构应包含一个 Web 服务器,该服务器使用

async start_server()
启动,这是一个由用户添加的可用快捷方式列表(回调闭包)。

当服务器启动时,我想要一个单一的端点(

/
)然后将接收 JSON 数据。收到json数据后,服务器会判断传入的是哪个交互,并发关闭交互。

我尝试了很多不同的解决方案,我必须说其中很多都包含了我还不熟悉的锈类型和概念。

我现在登陆的代码仍然失败了,是这样的: (我已经用评论突出了错误,只是让你知道什么失败了)

use axum::{
    routing::{get, post},
    http::StatusCode,
    Json, Router,
};
use std::{net::SocketAddr, future::Future, pin::Pin, collections::HashMap};
use tracing::{debug, info, error};
use futures::{FutureExt, future::BoxFuture};


pub struct Interaction {
    r#type: String,
}

#[derive(Default)]
pub struct App {
    router: Router,
    shortcuts: HashMap<String, Box<dyn Fn(Interaction) -> BoxFuture<'static, ()>>>
}

impl App {
    pub fn new() -> Self {
        Self::default()
    }

    async fn handle_interaction(
        &self,
        Json(interaction): Json<Interaction> 
    ) -> StatusCode {
        let t = interaction.r#type.clone();
        debug!("Got shortcut");
        debug!("{t}");

        let closure = self.shortcuts.get(&t).unwrap();
        tokio::task::spawn(closure(interaction));

        StatusCode::OK
    }

    pub fn add_shortcut<C, Fut>(
        mut self, 
        callback_id: &str,
        fun: C,
    ) -> Self 
    where
        Fut: Future<Output = ()> + Send + 'static,
        C: Fn(Interaction) -> Pin<Box<Fut>>,
    {
        self.shortcuts.insert(callback_id.to_string(),  Box::new(move |interaction| Box::pin(fun(interaction))));
        self
    }

    async fn start(self, addr: SocketAddr) {
        let interaction_handler = move |interaction| async move {
            self.handle_interaction(interaction).await
        };

        // ERROR: `interaction_handler` doesn't match axums route-types... Don't know why this is the case either.
        let router = Router::new()
            .route("/", post(interaction_handler));

        debug!("listening on {}", addr);

        axum::Server::bind(&addr)
            .serve(self.router.into_make_service())
            .await
            .unwrap();
    }
}

async fn shortcut1(i: Interaction) {
    println!("Hello, World!");
}

async fn shortcut2(i: Interaction) {
    println!("Hello, Other World!")
}

#[tokio::main]
async fn main() {
    tracing_subscriber::fmt::init();

    // ERROR: `shortcut1` and `shortcut2` doesn't match input type, 
    // and i don't know how to do this properly.
    let app = App::new()
        .add_shortcut("shortcut1", shortcut1)
        .add_shortcut("shortcut2", shortcut2);

    // run our app with hyper
    // `axum::Server` is a re-export of `hyper::Server`
    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
    app.start(addr).await;
}

其中很多是跟踪和错误、chatgpt 和随机文档的结果——我不熟悉 box、pin 和类似的东西。

我也读过 Mutex 或 Arc 可能有助于解决问题,但我也无法让它工作。

我希望这里有人能帮我指明正确的方向!

asynchronous rust closures rust-tokio rust-axum
© www.soinside.com 2019 - 2024. All rights reserved.