rumtk_web/utils/
matcher.rs

1/*
2 * rumtk attempts to implement HL7 and medical protocols for interoperability in medicine.
3 * This toolkit aims to be reliable, simple, performant, and standards compliant.
4 * Copyright (C) 2025  Luis M. Santos, M.D.
5 * Copyright (C) 2025  Nick Stephenson
6 * Copyright (C) 2025  Ethan Dixon
7 * Copyright (C) 2025  MedicalMasses L.L.C.
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 */
23use crate::components::app_shell::app_shell;
24use crate::utils::defaults::DEFAULT_ROBOT_TXT;
25use crate::utils::types::SharedAppState;
26use crate::utils::{HTMLResult, RUMString};
27use crate::{
28    rumtk_web_get_api_endpoint, rumtk_web_get_component, RUMWebData, RUMWebResponse, RouterForm,
29    URLParams,
30};
31use axum::body::Body;
32use axum::http::Response;
33use axum::response::{Html, IntoResponse};
34use tracing::error;
35
36pub async fn default_robots_matcher(
37    _path: Vec<RUMString>,
38    _params: RUMWebData,
39    _state: SharedAppState,
40) -> HTMLResult {
41    Ok(RUMWebResponse::GetResponse(Html::<String>::from(
42        String::from(DEFAULT_ROBOT_TXT),
43    )))
44}
45
46pub async fn default_page_matcher(
47    path: Vec<RUMString>,
48    params: RUMWebData,
49    state: SharedAppState,
50) -> HTMLResult {
51    let path_components = match path.first() {
52        Some(x) => x.split('/').collect::<Vec<&str>>(),
53        None => Vec::new(),
54    };
55
56    // Do not minify the page. we saved 0.3KB but transfer went from 5ms to 45ms
57    app_shell(&path_components, &params, state)
58}
59
60pub async fn default_api_matcher(
61    path: RUMString,
62    params: RUMWebData,
63    form: RouterForm,
64    state: SharedAppState,
65) -> HTMLResult {
66    let api_endpoint = rumtk_web_get_api_endpoint!(&path);
67    api_endpoint(&path, &params, form, state)
68}
69
70pub async fn default_component_matcher(
71    path: Vec<RUMString>,
72    params: RUMWebData,
73    state: SharedAppState,
74) -> HTMLResult {
75    let path_components = match path.first() {
76        Some(x) => x.split('/').collect::<Vec<&str>>(),
77        None => Vec::new(),
78    };
79
80    let component = match path_components.first() {
81        Some(component) => component,
82        None => return Err(RUMString::from("Missing component name to fetch!")),
83    };
84
85    let component = rumtk_web_get_component!(component);
86
87    component(&path_components[1..], &params, state)
88}
89
90pub fn match_maker(match_response: HTMLResult) -> Response<Body> {
91    match match_response {
92        Ok(res) => res.into_response(),
93        Err(e) => {
94            error!("{}", e);
95            Html(String::default()).into_response()
96        }
97    }
98}
99
100#[macro_export]
101macro_rules! rumtk_web_fetch {
102    ( $matcher:expr ) => {{
103        use axum::extract::{Path, Query, State};
104        use axum::response::{Html, Response};
105        use $crate::matcher::match_maker;
106        use $crate::utils::types::{RouterAppState, RouterComponents, RouterForm, RouterParams};
107
108        async |Path(path_params): RouterComponents,
109               Query(params): RouterParams,
110               State(state): RouterAppState,
111               Multipart: RouterForm|
112               -> Response {
113            let r = $matcher(path_params, params, state).await;
114            match_maker(r)
115        }
116    }};
117}
118
119#[macro_export]
120macro_rules! rumtk_web_api_process {
121    ( $matcher:expr ) => {{
122        use axum::extract::{Multipart, Path, Query, State};
123        use axum::response::{Html, Response};
124        use $crate::matcher::match_maker;
125        use $crate::utils::types::{RouterAPIPath, RouterAppState, RouterForm, RouterParams};
126
127        async |Path(path_params): RouterAPIPath,
128               Query(params): RouterParams,
129               State(state): RouterAppState,
130               form: RouterForm|
131               -> Response {
132            let r = $matcher(path_params, params, form, state).await;
133            match_maker(r)
134        }
135    }};
136}