1use crate::utils::defaults::DEFAULT_TEXT_ITEM;
22use crate::utils::types::RUMString;
23use axum::extract::State;
24use phf::OrderedMap;
25pub use phf_macros::phf_ordered_map as rumtk_create_const_ordered_map;
26use serde::{Deserialize, Serialize};
27use std::collections::HashMap;
28use std::sync::{Arc, Mutex};
29
30pub type TextMap = HashMap<RUMString, RUMString>;
31pub type NestedTextMap = HashMap<RUMString, TextMap>;
32pub type NestedNestedTextMap = HashMap<RUMString, NestedTextMap>;
33pub type RootNestedNestedTextMap = HashMap<RUMString, NestedNestedTextMap>;
34pub type RootRootNestedNestedTextMap = HashMap<RUMString, RootNestedNestedTextMap>;
35
36pub type ConstTextMap = OrderedMap<&'static str, &'static str>;
37pub type ConstNestedTextMap = OrderedMap<&'static str, &'static ConstTextMap>;
38pub type ConstNestedNestedTextMap = OrderedMap<&'static str, &'static ConstNestedTextMap>;
39
40#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
48pub struct AppConf {
49 pub title: RUMString,
50 pub description: RUMString,
51 pub copyright: RUMString,
52 pub lang: RUMString,
53 pub theme: RUMString,
54 pub custom_css: bool,
55
56 strings: RootRootNestedNestedTextMap,
57 config: NestedNestedTextMap,
58 }
60
61impl AppConf {
62 pub fn update_site_info(
63 &mut self,
64 title: RUMString,
65 description: RUMString,
66 copyright: RUMString,
67 ) {
68 if !title.is_empty() {
69 self.title = title;
70 }
71 if !description.is_empty() {
72 self.description = description;
73 }
74 if !copyright.is_empty() {
75 self.copyright = copyright;
76 }
77 }
78
79 pub fn get_text(&self, item: &str) -> NestedNestedTextMap {
80 match self.strings.get(&self.lang) {
81 Some(l) => match l.get(item) {
82 Some(i) => i.clone(),
83 None => NestedNestedTextMap::default(),
84 },
85 None => NestedNestedTextMap::default(),
86 }
87 }
88
89 pub fn get_conf(&self, section: &str) -> TextMap {
90 match self.config.get(section) {
91 Some(l) => match l.get(&self.lang) {
92 Some(i) => i.clone(),
93 None => match l.get(DEFAULT_TEXT_ITEM) {
94 Some(i) => i.clone(),
95 None => TextMap::default(),
96 },
97 },
98 None => TextMap::default(),
99 }
100 }
101}
102
103pub type SharedAppConf = Arc<Mutex<AppConf>>;
104pub type RouterAppConf = State<Arc<Mutex<AppConf>>>;
105
106#[macro_export]
107macro_rules! rumtk_web_load_conf {
108 ( $args:expr ) => {{ rumtk_web_load_conf!($args, "./app.json") }};
109 ( $args:expr, $path:expr ) => {{
110 use rumtk_core::rumtk_deserialize;
111 use std::fs::read_to_string;
112 use std::sync::{Arc, Mutex};
113 use $crate::utils::AppConf;
114 let json = match read_to_string($path) {
115 Ok(json) => json,
116 Err(err) => panic!(
117 "The App config file in {} is either missing or cannot be loaded because {}",
118 $path, err
119 ),
120 };
121 let mut conf: AppConf = match rumtk_deserialize!(json) {
122 Ok(conf) => conf,
123 Err(err) => panic!(
124 "The App config file in {} does not meet the expected structure. \
125 See the documentation for more information. Error: {}\n{}",
126 $path, err, json
127 ),
128 };
129 conf.update_site_info(
130 $args.title.clone(),
131 $args.description.clone(),
132 $args.copyright.clone(),
133 );
134 Arc::new(Mutex::new(conf))
135 }};
136}
137
138#[macro_export]
139macro_rules! rumtk_web_get_string {
140 ( $conf:expr, $item:expr ) => {{
141 let owned_state = $conf.lock().expect("Lock failure");
142 owned_state.get_text($item)
143 }};
144}
145
146#[macro_export]
147macro_rules! rumtk_web_get_conf {
148 ( $conf:expr, $item:expr ) => {{
149 let owned_state = $conf.lock().expect("Lock failure");
150 owned_state.get_conf($item)
151 }};
152}
153
154pub const DEFAULT_TEXT: fn() -> RUMString = || RUMString::default();
158pub const DEFAULT_TEXTMAP: fn() -> TextMap = || TextMap::default();
159pub const DEFAULT_NESTEDTEXTMAP: fn() -> NestedTextMap = || NestedTextMap::default();
160pub const DEFAULT_NESTEDNESTEDTEXTMAP: fn() -> NestedNestedTextMap =
161 || NestedNestedTextMap::default();