1use crate::jobs::{Job, JobID};
22use crate::utils::defaults::DEFAULT_TEXT_ITEM;
23use crate::utils::types::RUMString;
24use askama::PrimitiveType;
25use axum::extract::State;
26use phf::OrderedMap;
27pub use phf_macros::phf_ordered_map as rumtk_create_const_ordered_map;
28use rumtk_core::net::tcp::SafeLock;
29use rumtk_core::pipelines::pipeline_types::RUMCommandLine;
30use rumtk_core::serde::{RUMDeJson, RUMSerJson};
31use rumtk_core::strings::RUMStringConversions;
32use rumtk_core::types::RUMID;
33use rumtk_core::types::{RUMHashMap, RUMOrderedMap};
34use rumtk_core::{rumtk_generate_id, rumtk_new_lock};
35
36pub type TextMap = RUMOrderedMap<RUMString, RUMString>;
37pub type NestedTextMap = RUMOrderedMap<RUMString, TextMap>;
38pub type NestedNestedTextMap = RUMOrderedMap<RUMString, NestedTextMap>;
39pub type RootNestedNestedTextMap = RUMOrderedMap<RUMString, NestedNestedTextMap>;
40
41pub type ConstTextMap = OrderedMap<&'static str, &'static str>;
42pub type ConstNestedTextMap = OrderedMap<&'static str, &'static ConstTextMap>;
43pub type ConstNestedNestedTextMap = OrderedMap<&'static str, &'static ConstNestedTextMap>;
44
45pub type PipelineGroup = RUMHashMap<RUMString, RUMCommandLine>;
46
47#[derive(RUMSerJson, RUMDeJson, PartialEq, Debug, Clone, Default)]
48pub struct HeaderConf {
49 pub logo_source: Option<RUMString>,
50 pub logo_size: RUMString,
51 pub disable_navlinks: bool,
52 pub disable_logo: bool,
53}
54
55#[derive(RUMSerJson, RUMDeJson, PartialEq, Debug, Clone, Default)]
56pub struct FooterConf {
57 pub socials_list: RUMString,
58 pub disable_contact_button: bool,
59}
60
61#[derive(RUMSerJson, RUMDeJson, PartialEq, Debug, Clone, Default)]
62pub struct PipelineConf {
63 pub settings: Option<TextMap>,
64 pub data_templates: Option<NestedTextMap>,
65 pub targets: Option<TextMap>,
66 pub categories: Option<RUMHashMap<RUMString, PipelineGroup>>
67}
68
69impl PipelineConf {
70 pub fn get_settings(&self) -> Option<&TextMap> {
71 self.settings.as_ref()
72 }
73
74 pub fn get_pipeline_category(&self, pipeline_category: &str) -> Option<&PipelineGroup> {
75 match self.categories {
76 Some(ref categories) => {
77 match categories.get(pipeline_category) {
78 Some(pipelines) => Some(pipelines),
79 None => None
80 }
81 }
82 None => None,
83 }
84 }
85 pub fn get_available_pipeline_names(&self) -> Vec<&RUMString> {
86 match self.targets.as_ref() {
87 Some(group) => {
88 let mut keys = group.keys().collect::<Vec<&RUMString>>();
89 keys.sort_unstable();
90 keys
91 },
92 None => vec![]
93 }
94 }
95 pub fn get_pipeline(&self, pipeline_category: &str, pipeline_name: &str) -> RUMCommandLine {
96 match self.get_pipeline_category(pipeline_category) {
97 Some(group) => match group.get(pipeline_name) {
98 Some(pipeline) => pipeline.to_owned(),
99 None => RUMCommandLine::new()
100 },
101 None => RUMCommandLine::new()
102 }
103 }
104
105 pub fn get_target(&self, profile: &str) -> RUMString {
106 match self.targets.as_ref() {
107 Some(targets) => match targets.get(profile) {
108 Some(pipeline) => pipeline.to_owned(),
109 None => RUMString::default()
110 },
111 None => RUMString::default()
112 }
113 }
114
115 pub fn get_template(&self, name: &str) -> Option<&TextMap> {
116 match self.data_templates.as_ref() {
117 Some(templates) => templates.get(name),
118 None => None
119 }
120 }
121
122 pub fn get_available_data_templates(&self) -> Vec<&RUMString> {
123 match self.data_templates.as_ref() {
124 Some(group) => {
125 let mut keys = group.keys().collect::<Vec<&RUMString>>();
126 keys.sort_unstable();
127 keys
128 },
129 None => vec![]
130 }
131 }
132}
133
134#[derive(RUMSerJson, RUMDeJson, PartialEq, Debug, Clone, Default)]
142pub struct AppConf {
143 pub title: RUMString,
144 pub description: RUMString,
145 pub company: RUMString,
146 pub copyright: RUMString,
147 pub lang: RUMString,
148 pub theme: RUMString,
149 pub custom_css: bool,
150 pub header_conf: HeaderConf,
151 pub footer_conf: FooterConf,
152
153 strings: RootNestedNestedTextMap,
154 config: NestedNestedTextMap,
155 pipelines: PipelineConf,
156 }
158
159impl AppConf {
160 pub fn update_site_info(
161 &mut self,
162 title: RUMString,
163 description: RUMString,
164 company: RUMString,
165 copyright: RUMString,
166 ) {
167 if !title.is_empty() {
168 self.title = title;
169 }
170 if !company.is_empty() {
171 self.company = company;
172 }
173 if !description.is_empty() {
174 self.description = description;
175 }
176 if !copyright.is_empty() {
177 self.copyright = copyright;
178 }
179 }
180
181 pub fn get_pipelines(&self) -> &PipelineConf {
182 &self.pipelines
183 }
184
185 pub fn get_text(&self, item: &str) -> NestedTextMap {
186 match self.strings.get(&self.lang) {
187 Some(l) => match l.get(item) {
188 Some(i) => i.clone(),
189 None => NestedTextMap::default(),
190 },
191 None => NestedTextMap::default(),
192 }
193 }
194
195 pub fn get_section(&self, section: &str) -> TextMap {
196 match self.config.get(&self.lang) {
197 Some(l) => match l.get(section) {
198 Some(i) => i.clone(),
199 None => self.get_default_item(section),
200 },
201 None => self.get_default_item(section),
202 }
203 }
204
205 pub fn get_default_item(&self, section: &str) -> TextMap {
206 match self.config.get(DEFAULT_TEXT_ITEM) {
207 Some(l) => match l.get(section) {
208 Some(i) => i.clone(),
209 None => TextMap::default(),
210 },
211 None => TextMap::default(),
212 }
213 }
214}
215
216pub type ClipboardID = RUMString;
217#[derive(Default, Debug, Clone)]
223pub struct AppState {
224 config: AppConf,
225 clipboard: NestedTextMap,
226 jobs: RUMHashMap<RUMID, Job>,
227}
228
229pub type SharedAppState = SafeLock<AppState>;
230
231impl AppState {
232 pub fn new() -> AppState {
233 AppState {
234 config: AppConf::default(),
235 clipboard: NestedTextMap::default(),
236 jobs: RUMHashMap::default(),
237 }
238 }
239
240 pub fn new_safe() -> SharedAppState {
241 rumtk_new_lock!(AppState::new())
242 }
243
244 pub fn from_safe(conf: AppConf) -> SharedAppState {
245 rumtk_new_lock!(AppState::from(conf))
246 }
247
248 pub fn get_config(&self) -> &AppConf {
249 &self.config
250 }
251
252 pub fn get_config_mut(&mut self) -> &mut AppConf {
253 &mut self.config
254 }
255
256 pub fn has_clipboard(&self, id: &ClipboardID) -> bool {
257 self.clipboard.contains_key(id)
258 }
259
260 pub fn has_job(&self, id: &JobID) -> bool {
261 self.jobs.contains_key(id)
262 }
263
264 pub fn push_job_result(&mut self, id: &JobID, job: Job) {
265 self.jobs.insert(id.clone(), job);
266 }
267
268 pub fn push_to_clipboard(&mut self, data: TextMap) -> ClipboardID {
269 let clipboard_id = rumtk_generate_id!().to_string();
270 self.clipboard.insert(clipboard_id.clone(), data);
271 clipboard_id
272 }
273
274 pub fn request_clipboard_slice(&mut self) -> ClipboardID {
275 let clipboard_id = rumtk_generate_id!().to_string();
276 self.clipboard
277 .insert(clipboard_id.clone(), TextMap::default());
278 clipboard_id
279 }
280
281 pub fn pop_job(&mut self, id: &RUMID) -> Option<Job> {
282 self.jobs.remove(id)
283 }
284
285 pub fn pop_clipboard(&mut self, id: &ClipboardID) -> Option<TextMap> {
286 self.clipboard.shift_remove(id)
287 }
288}
289
290impl From<AppConf> for AppState {
291 fn from(config: AppConf) -> Self {
292 AppState {
293 config,
294 clipboard: NestedTextMap::default(),
295 jobs: RUMHashMap::default(),
296 }
297 }
298}
299
300pub type RouterAppState = State<SharedAppState>;
301
302#[macro_export]
345macro_rules! rumtk_web_load_conf {
346 ( $args:expr ) => {{
347 use $crate::defaults::{DEFAULT_APP_CONFIG};
348 rumtk_web_load_conf!($args, DEFAULT_APP_CONFIG)
349 }};
350 ( $args:expr, $path:expr ) => {{
351 use rumtk_core::rumtk_deserialize;
352 use rumtk_core::strings::RUMStringConversions;
353 use rumtk_core::types::RUMHashMap;
354 use $crate::AppConf;
355 use std::fs;
356
357 use $crate::rumtk_web_save_conf;
358 use $crate::utils::{AppState, TextMap};
359
360 let json = match fs::read_to_string($path) {
361 Ok(json) => json,
362 Err(err) => rumtk_web_save_conf!($path),
363 };
364
365 let mut conf: AppConf = match rumtk_deserialize!(&json) {
366 Ok(conf) => conf,
367 Err(err) => panic!(
368 "The App config file in {} does not meet the expected structure. \
369 See the documentation for more information. Error: {}\n{}",
370 $path, err, json
371 ),
372 };
373 conf.update_site_info(
374 $args.title.clone(),
375 $args.description.clone(),
376 $args.company.clone(),
377 $args.copyright.clone(),
378 );
379 AppState::from_safe(conf)
380 }};
381}
382
383#[macro_export]
415macro_rules! rumtk_web_save_conf {
416 ( ) => {{
417 $crate::utils::defaults::DEFAULT_APP_CONFIG;
418 rumtk_web_save_conf!(DEFAULT_APP_CONFIG)
419 }};
420 ( $path:expr ) => {{
421 use rumtk_core::rumtk_serialize;
422 use rumtk_core::strings::RUMStringConversions;
423 use std::fs;
424 use $crate::utils::AppConf;
425
426 let json = rumtk_serialize!(&AppConf::default()).unwrap_or_default();
427 fs::write($path, &json);
428 json
429 }};
430}
431
432#[macro_export]
437macro_rules! rumtk_web_get_config_string {
438 ( $conf:expr, $item:expr ) => {{
439 use $crate::rumtk_web_get_config;
440 use $crate::AppConf;
441 rumtk_web_get_config!($conf).get_text($item)
442 }};
443}
444
445#[macro_export]
451macro_rules! rumtk_web_get_config_section {
452 ( $conf:expr, $item:expr ) => {{
453 use $crate::rumtk_web_get_config;
454 use $crate::AppConf;
455 rumtk_web_get_config!($conf).get_section($item)
456 }};
457}
458
459#[macro_export]
477macro_rules! rumtk_web_get_pipelines {
478 ( $conf:expr ) => {{
479 use $crate::rumtk_web_get_config;
480 use $crate::AppConf;
481 rumtk_web_get_config!($conf).get_pipelines()
482 }};
483}
484
485#[macro_export]
503macro_rules! rumtk_web_get_config {
504 ( $state:expr ) => {{
505 use rumtk_core::{rumtk_lock_read};
506 rumtk_lock_read!($state.clone()).get_config()
507 }};
508}
509
510#[macro_export]
532macro_rules! rumtk_web_set_config {
533 ( $state:expr ) => {{
534 use rumtk_core::rumtk_lock_write;
535 rumtk_lock_write!($state.clone()).get_config_mut()
536 }};
537}
538
539#[macro_export]
558macro_rules! rumtk_web_modify_state {
559 ( $state:expr ) => {{
560 use rumtk_core::rumtk_lock_write;
561 rumtk_lock_write!($state.clone())
562 }};
563}
564
565pub const DEFAULT_TEXT: fn() -> RUMString = || RUMString::default();
569pub const DEFAULT_TEXTMAP: fn() -> TextMap = || TextMap::default();
570pub const DEFAULT_NESTEDTEXTMAP: fn() -> NestedTextMap = || NestedTextMap::default();
571pub const DEFAULT_NESTEDNESTEDTEXTMAP: fn() -> NestedNestedTextMap =
572 || NestedNestedTextMap::default();