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::form_data::compile_form_data;
26use crate::utils::types::SharedAppState;
27use crate::utils::{HTMLResult, RUMString};
28use crate::{
29    rumtk_web_get_api_endpoint, rumtk_web_get_component, RUMWebData, RUMWebResponse, RouterForm,
30    URLParams,
31};
32use axum::body::Body;
33use axum::http::Response;
34use axum::response::{Html, IntoResponse};
35use tracing::error;
36
37pub async fn default_robots_matcher(
38    _path: Vec<RUMString>,
39    _params: RUMWebData,
40    _state: SharedAppState,
41) -> HTMLResult {
42    Ok(RUMWebResponse::GetResponse(Html::<String>::from(
43        String::from(DEFAULT_ROBOT_TXT),
44    )))
45}
46
47pub async fn default_page_matcher(
48    path: Vec<RUMString>,
49    params: RUMWebData,
50    state: SharedAppState,
51) -> HTMLResult {
52    let path_components = match path.first() {
53        Some(x) => x.split('/').collect::<Vec<&str>>(),
54        None => Vec::new(),
55    };
56
57    // Do not minify the page. we saved 0.3KB but transfer went from 5ms to 45ms
58    app_shell(&path_components, &params, state)
59}
60
61pub async fn default_api_matcher(
62    path: RUMString,
63    params: RUMWebData,
64    mut form: RouterForm,
65    state: SharedAppState,
66) -> HTMLResult {
67    let form_data = compile_form_data(&mut form).await?;
68    let api_endpoint = rumtk_web_get_api_endpoint!(&path);
69    api_endpoint(path, params, form_data, state)
70}
71
72pub async fn default_component_matcher(
73    path: Vec<RUMString>,
74    params: RUMWebData,
75    state: SharedAppState,
76) -> HTMLResult {
77    let path_components = match path.first() {
78        Some(x) => x.split('/').collect::<Vec<&str>>(),
79        None => Vec::new(),
80    };
81
82    let component = match path_components.first() {
83        Some(component) => component,
84        None => return Err(RUMString::from("Missing component name to fetch!")),
85    };
86
87    let component = rumtk_web_get_component!(component);
88
89    component(&path_components[1..], &params, state)
90}
91
92pub fn match_maker(match_response: HTMLResult) -> Response<Body> {
93    match match_response {
94        Ok(res) => res.into_response(),
95        Err(e) => {
96            error!("{}", e);
97            Html(String::default()).into_response()
98        }
99    }
100}
101
102#[macro_export]
103macro_rules! rumtk_web_fetch {
104    ( $matcher:expr ) => {{
105        use axum::extract::{Path, Query, State};
106        use axum::response::{Html, Response};
107        use $crate::matcher::match_maker;
108        use $crate::utils::types::{RouterAppState, RouterComponents, RouterForm, RouterParams};
109
110        async |Path(path_params): RouterComponents,
111               Query(params): RouterParams,
112               State(state): RouterAppState|
113               -> Response {
114            let r = $matcher(path_params, params, state).await;
115            match_maker(r)
116        }
117    }};
118}
119
120#[macro_export]
121macro_rules! rumtk_web_api_process {
122    ( $matcher:expr ) => {{
123        use axum::extract::{Multipart, Path, Query, State};
124        use axum::response::{Html, Response};
125        use $crate::matcher::match_maker;
126        use $crate::utils::types::{RouterAPIPath, RouterAppState, RouterForm, RouterParams};
127
128        async |Path(path_params): RouterAPIPath,
129               Query(params): RouterParams,
130               State(state): RouterAppState,
131               mut form: RouterForm|
132               -> Response {
133            let r = $matcher(path_params, params, form, state).await;
134            match_maker(r)
135        }
136    }};
137}