use crate::jobs::{Job, JobID};
use crate::utils::defaults::DEFAULT_TEXT_ITEM;
use crate::utils::types::RUMString;
use askama::PrimitiveType;
use axum::extract::State;
use phf::OrderedMap;
pub use phf_macros::phf_ordered_map as rumtk_create_const_ordered_map;
use rumtk_core::net::tcp::SafeLock;
use rumtk_core::pipelines::pipeline_types::RUMCommandLine;
use rumtk_core::strings::RUMStringConversions;
use rumtk_core::types::{RUMDeserialize, RUMSerialize, RUMID};
use rumtk_core::types::{RUMHashMap, RUMOrderedMap};
use rumtk_core::{rumtk_generate_id, rumtk_new_lock};
pub type TextMap = RUMOrderedMap<RUMString, RUMString>;
pub type NestedTextMap = RUMOrderedMap<RUMString, TextMap>;
pub type NestedNestedTextMap = RUMOrderedMap<RUMString, NestedTextMap>;
pub type RootNestedNestedTextMap = RUMOrderedMap<RUMString, NestedNestedTextMap>;
pub type ConstTextMap = OrderedMap<&'static str, &'static str>;
pub type ConstNestedTextMap = OrderedMap<&'static str, &'static ConstTextMap>;
pub type ConstNestedNestedTextMap = OrderedMap<&'static str, &'static ConstNestedTextMap>;
pub type PipelineGroup = RUMHashMap<RUMString, RUMCommandLine>;
#[derive(RUMSerialize, RUMDeserialize, PartialEq, Debug, Clone, Default)]
pub struct HeaderConf {
pub logo_source: Option<RUMString>,
pub logo_size: RUMString,
pub disable_navlinks: bool,
pub disable_logo: bool,
}
#[derive(RUMSerialize, RUMDeserialize, PartialEq, Debug, Clone, Default)]
pub struct FooterConf {
pub socials_list: RUMString,
pub disable_contact_button: bool,
}
#[derive(RUMSerialize, RUMDeserialize, PartialEq, Debug, Clone, Default)]
pub struct PipelineConf {
pub settings: Option<TextMap>,
pub data_templates: Option<NestedTextMap>,
pub targets: Option<TextMap>,
pub categories: Option<RUMHashMap<RUMString, PipelineGroup>>
}
impl PipelineConf {
pub fn get_settings(&self) -> Option<&TextMap> {
self.settings.as_ref()
}
pub fn get_pipeline_category(&self, pipeline_category: &str) -> Option<&PipelineGroup> {
match self.categories {
Some(ref categories) => {
match categories.get(pipeline_category) {
Some(pipelines) => Some(pipelines),
None => None
}
}
None => None,
}
}
pub fn get_available_pipeline_names(&self) -> Vec<&RUMString> {
match self.targets.as_ref() {
Some(group) => {
let mut keys = group.keys().collect::<Vec<&RUMString>>();
keys.sort_unstable();
keys
},
None => vec![]
}
}
pub fn get_pipeline(&self, pipeline_category: &str, pipeline_name: &str) -> RUMCommandLine {
match self.get_pipeline_category(pipeline_category) {
Some(group) => match group.get(pipeline_name) {
Some(pipeline) => pipeline.to_owned(),
None => RUMCommandLine::new()
},
None => RUMCommandLine::new()
}
}
pub fn get_target(&self, profile: &str) -> RUMString {
match self.targets.as_ref() {
Some(targets) => match targets.get(profile) {
Some(pipeline) => pipeline.to_owned(),
None => RUMString::default()
},
None => RUMString::default()
}
}
pub fn get_template(&self, name: &str) -> Option<&TextMap> {
match self.data_templates.as_ref() {
Some(templates) => templates.get(name),
None => None
}
}
pub fn get_available_data_templates(&self) -> Vec<&RUMString> {
match self.data_templates.as_ref() {
Some(group) => {
let mut keys = group.keys().collect::<Vec<&RUMString>>();
keys.sort_unstable();
keys
},
None => vec![]
}
}
}
#[derive(RUMSerialize, RUMDeserialize, PartialEq, Debug, Clone, Default)]
pub struct AppConf {
pub title: RUMString,
pub description: RUMString,
pub company: RUMString,
pub copyright: RUMString,
pub lang: RUMString,
pub theme: RUMString,
pub custom_css: bool,
pub header_conf: HeaderConf,
pub footer_conf: FooterConf,
strings: RootNestedNestedTextMap,
config: NestedNestedTextMap,
pipelines: PipelineConf,
}
impl AppConf {
pub fn update_site_info(
&mut self,
title: RUMString,
description: RUMString,
company: RUMString,
copyright: RUMString,
) {
if !title.is_empty() {
self.title = title;
}
if !company.is_empty() {
self.company = company;
}
if !description.is_empty() {
self.description = description;
}
if !copyright.is_empty() {
self.copyright = copyright;
}
}
pub fn get_pipelines(&self) -> &PipelineConf {
&self.pipelines
}
pub fn get_text(&self, item: &str) -> NestedTextMap {
match self.strings.get(&self.lang) {
Some(l) => match l.get(item) {
Some(i) => i.clone(),
None => NestedTextMap::default(),
},
None => NestedTextMap::default(),
}
}
pub fn get_section(&self, section: &str) -> TextMap {
match self.config.get(&self.lang) {
Some(l) => match l.get(section) {
Some(i) => i.clone(),
None => self.get_default_item(section),
},
None => self.get_default_item(section),
}
}
pub fn get_default_item(&self, section: &str) -> TextMap {
match self.config.get(DEFAULT_TEXT_ITEM) {
Some(l) => match l.get(section) {
Some(i) => i.clone(),
None => TextMap::default(),
},
None => TextMap::default(),
}
}
}
pub type ClipboardID = RUMString;
#[derive(Default, Debug, Clone)]
pub struct AppState {
config: AppConf,
clipboard: NestedTextMap,
jobs: RUMHashMap<RUMID, Job>,
}
pub type SharedAppState = SafeLock<AppState>;
impl AppState {
pub fn new() -> AppState {
AppState {
config: AppConf::default(),
clipboard: NestedTextMap::default(),
jobs: RUMHashMap::default(),
}
}
pub fn new_safe() -> SharedAppState {
rumtk_new_lock!(AppState::new())
}
pub fn from_safe(conf: AppConf) -> SharedAppState {
rumtk_new_lock!(AppState::from(conf))
}
pub fn get_config(&self) -> &AppConf {
&self.config
}
pub fn get_config_mut(&mut self) -> &mut AppConf {
&mut self.config
}
pub fn has_clipboard(&self, id: &ClipboardID) -> bool {
self.clipboard.contains_key(id)
}
pub fn has_job(&self, id: &JobID) -> bool {
self.jobs.contains_key(id)
}
pub fn push_job_result(&mut self, id: &JobID, job: Job) {
self.jobs.insert(id.clone(), job);
}
pub fn push_to_clipboard(&mut self, data: TextMap) -> ClipboardID {
let clipboard_id = rumtk_generate_id!().to_rumstring();
self.clipboard.insert(clipboard_id.clone(), data);
clipboard_id
}
pub fn request_clipboard_slice(&mut self) -> ClipboardID {
let clipboard_id = rumtk_generate_id!().to_rumstring();
self.clipboard
.insert(clipboard_id.clone(), TextMap::default());
clipboard_id
}
pub fn pop_job(&mut self, id: &RUMID) -> Option<Job> {
self.jobs.remove(id)
}
pub fn pop_clipboard(&mut self, id: &ClipboardID) -> Option<TextMap> {
self.clipboard.shift_remove(id)
}
}
impl From<AppConf> for AppState {
fn from(config: AppConf) -> Self {
AppState {
config,
clipboard: NestedTextMap::default(),
jobs: RUMHashMap::default(),
}
}
}
pub type RouterAppState = State<SharedAppState>;
#[macro_export]
macro_rules! rumtk_web_load_conf {
( $args:expr ) => {{
use $crate::defaults::{DEFAULT_APP_CONFIG};
rumtk_web_load_conf!($args, DEFAULT_APP_CONFIG)
}};
( $args:expr, $path:expr ) => {{
use rumtk_core::rumtk_deserialize;
use rumtk_core::strings::RUMStringConversions;
use rumtk_core::types::RUMHashMap;
use $crate::AppConf;
use std::fs;
use $crate::rumtk_web_save_conf;
use $crate::utils::{AppState, TextMap};
let json = match fs::read_to_string($path) {
Ok(json) => json,
Err(err) => rumtk_web_save_conf!($path),
};
let mut conf: AppConf = match rumtk_deserialize!(json) {
Ok(conf) => conf,
Err(err) => panic!(
"The App config file in {} does not meet the expected structure. \
See the documentation for more information. Error: {}\n{}",
$path, err, json
),
};
conf.update_site_info(
$args.title.clone(),
$args.description.clone(),
$args.company.clone(),
$args.copyright.clone(),
);
AppState::from_safe(conf)
}};
}
#[macro_export]
macro_rules! rumtk_web_save_conf {
( ) => {{
$crate::utils::defaults::DEFAULT_APP_CONFIG;
rumtk_web_save_conf!(DEFAULT_APP_CONFIG)
}};
( $path:expr ) => {{
use rumtk_core::rumtk_serialize;
use rumtk_core::strings::RUMStringConversions;
use std::fs;
use $crate::utils::AppConf;
let json = rumtk_serialize!(AppConf::default(), true).unwrap_or_default();
fs::write($path, &json);
json
}};
}
#[macro_export]
macro_rules! rumtk_web_get_config_string {
( $conf:expr, $item:expr ) => {{
use $crate::rumtk_web_get_config;
use $crate::AppConf;
rumtk_web_get_config!($conf).get_text($item)
}};
}
#[macro_export]
macro_rules! rumtk_web_get_config_section {
( $conf:expr, $item:expr ) => {{
use $crate::rumtk_web_get_config;
use $crate::AppConf;
rumtk_web_get_config!($conf).get_section($item)
}};
}
#[macro_export]
macro_rules! rumtk_web_get_pipelines {
( $conf:expr ) => {{
use $crate::rumtk_web_get_config;
use $crate::AppConf;
rumtk_web_get_config!($conf).get_pipelines()
}};
}
#[macro_export]
macro_rules! rumtk_web_get_config {
( $state:expr ) => {{
use rumtk_core::{rumtk_lock_read};
rumtk_lock_read!($state.clone()).get_config()
}};
}
#[macro_export]
macro_rules! rumtk_web_set_config {
( $state:expr ) => {{
use rumtk_core::rumtk_lock_write;
rumtk_lock_write!($state.clone()).get_config_mut()
}};
}
#[macro_export]
macro_rules! rumtk_web_modify_state {
( $state:expr ) => {{
use rumtk_core::rumtk_lock_write;
rumtk_lock_write!($state.clone())
}};
}
pub const DEFAULT_TEXT: fn() -> RUMString = || RUMString::default();
pub const DEFAULT_TEXTMAP: fn() -> TextMap = || TextMap::default();
pub const DEFAULT_NESTEDTEXTMAP: fn() -> NestedTextMap = || NestedTextMap::default();
pub const DEFAULT_NESTEDNESTEDTEXTMAP: fn() -> NestedNestedTextMap =
|| NestedNestedTextMap::default();