Skip to main content

framework_web_axum/
router.rs

1use crate::AxumContext;
2use crate::context::scope_axum;
3use framework_web::{
4    WebContext, WebError, WebMethod, WebResponse, WebRoute, scope_web, use_web, web_api_iter,
5};
6use futures_util::future::BoxFuture;
7use std::collections::HashMap as Map;
8use std::collections::hash_map::Entry;
9use std::sync::Arc;
10
11/// 包裹路由执行后的异步结果。
12pub type WebRouteResultFuture = BoxFuture<'static, anyhow::Result<WebResponse>>;
13
14/// 路由包装器:在 find 命中 WebRoute 后包裹其运行,用于授权校验、上下文注入等扩展。
15pub type WebRouteWrapper = Arc<dyn Fn(Arc<WebRoute>) -> WebRouteResultFuture + Send + Sync>;
16
17/// 默认包装器:直接执行 route.invoke()。
18fn default_wrapper() -> WebRouteWrapper {
19    Arc::new(|route| Box::pin(async move { Ok(route.invoke().await) }))
20}
21
22/// Web 路由:收集所有已注册的 WebRoute,并按方法与路径查找。
23pub struct WebRouter {
24    routes: Map<WebMethod, Map<String, Arc<WebRoute>>>,
25    wrapper: WebRouteWrapper,
26}
27
28impl WebRouter {
29    pub fn new(wrapper: Option<WebRouteWrapper>) -> Self {
30        let mut routes: Map<WebMethod, Map<String, Arc<WebRoute>>> = Map::new();
31        for route in web_api_iter() {
32            let route = Arc::new(route);
33            match routes.entry(route.method.clone()) {
34                Entry::Occupied(mut methods) => {
35                    methods.get_mut().insert(route.path.clone(), route);
36                }
37                Entry::Vacant(methods) => {
38                    methods.insert(Map::from([(route.path.clone(), route)]));
39                }
40            }
41        }
42        Self {
43            routes,
44            wrapper: wrapper.unwrap_or_else(default_wrapper),
45        }
46    }
47
48    /// 执行当前请求:注入上下文、查找路由、交由包装器运行。
49    pub async fn invoke(
50        &self,
51        web_context: WebContext,
52        axum_context: AxumContext,
53    ) -> anyhow::Result<WebResponse> {
54        let web_context = Arc::new(web_context);
55        let axum_context = Arc::new(axum_context);
56        scope_axum(
57            axum_context,
58            scope_web(web_context, async {
59                let route = self.find().await?;
60                (self.wrapper)(route).await
61            }),
62        )
63        .await
64    }
65
66    /// 按当前请求的方法与路径查找路由。
67    async fn find(&self) -> anyhow::Result<Arc<WebRoute>> {
68        let context = use_web()?;
69        let request = context.request();
70        let path = request.path.trim_matches('/');
71        self.routes
72            .get(&request.method)
73            .and_then(|routes| routes.get(path))
74            .cloned()
75            .ok_or_else(|| WebError::not_found("请求接口不存在").into())
76    }
77}