yozefu_app/configuration/
global_config.rs1use std::{
4 fs,
5 path::{Path, PathBuf},
6};
7
8use indexmap::IndexMap;
9use itertools::Itertools;
10use lib::Error;
11use serde::{Deserialize, Serialize};
12
13use crate::{
14 APPLICATION_NAME,
15 configuration::{ClusterConfig, ConsumerConfig},
16};
17
18use super::cluster_config::SchemaRegistryConfig;
19
20const EXAMPLE_PROMPTS: &[&str] = &[
21 r#"timestamp between "2 hours ago" and "1 hour ago" limit 100 from beginning"#,
22 r#"offset > 100000 and value contains "music" limit 10"#,
23 r#"key == "ABC" and timestamp >= "2 days ago""#,
24];
25
26#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone, Default)]
27#[cfg_attr(test, derive(schemars::JsonSchema))]
28pub enum TimestampFormat {
29 #[default]
30 DateTime,
31 Ago,
32}
33
34#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)]
36#[cfg_attr(test, derive(schemars::JsonSchema))]
37pub struct GlobalConfig {
38 #[serde(skip)]
40 pub path: PathBuf,
41 #[serde(default = "default_url_template")]
43 pub default_url_template: String,
44 pub initial_query: String,
46 #[serde(default = "default_theme")]
48 pub theme: String,
49 pub highlighter_theme: Option<String>,
51 pub clusters: IndexMap<String, ClusterConfig>,
53 #[serde(default)]
54 pub consumer: ConsumerConfig,
56 pub default_kafka_config: IndexMap<String, String>,
58 pub history: Vec<String>,
60 #[serde(default = "default_show_shortcuts")]
62 pub show_shortcuts: bool,
63 #[serde(default = "default_export_directory")]
64 pub export_directory: PathBuf,
65 pub log_file: Option<PathBuf>,
67 #[serde(default = "TimestampFormat::default")]
69 pub timestamp_format: TimestampFormat,
70}
71
72fn default_url_template() -> String {
73 "http://localhost/cluster/{topic}/{partition}/{offset}".to_string()
74}
75
76fn default_export_directory() -> PathBuf {
77 PathBuf::from(format!("./{APPLICATION_NAME}-exports"))
78}
79
80fn default_theme() -> String {
81 if cfg!(target_os = "windows") {
82 "dark".to_string()
83 } else {
84 "light".to_string()
85 }
86}
87
88fn default_show_shortcuts() -> bool {
89 true
90}
91
92impl GlobalConfig {
93 pub fn new(path: &Path) -> Self {
94 Self {
95 path: path.to_path_buf(),
96 default_url_template: default_url_template(),
97 history: EXAMPLE_PROMPTS
98 .iter()
99 .map(|e| (*e).to_string())
100 .collect_vec(),
101 initial_query: "from end - 10".to_string(),
102 clusters: IndexMap::default(),
103 default_kafka_config: IndexMap::default(),
104 theme: default_theme(),
105 highlighter_theme: None,
106 show_shortcuts: true,
107 export_directory: default_export_directory(),
108 consumer: ConsumerConfig::default(),
109 log_file: None,
110 timestamp_format: TimestampFormat::default(),
111 }
112 }
113
114 pub fn read(file: &Path) -> Result<Self, Error> {
116 let content = fs::read_to_string(file);
117 if let Err(e) = &content {
118 return Err(Error::Error(format!(
119 "Failed to read the configuration file {:?}: {}",
120 file.display(),
121 e
122 )));
123 }
124
125 let content = content.unwrap();
126 let mut config: Self = serde_json::from_str(&content).map_err(|e| {
127 Error::Error(format!(
128 "Failed to parse the configuration file {:?}: {}",
129 file.display(),
130 e
131 ))
132 })?;
133 config.path = file.to_path_buf();
134 Ok(config)
135 }
136
137 pub fn log_file(&self) -> Option<PathBuf> {
139 self.log_file.clone()
140 }
141
142 pub fn url_template_of(&self, cluster: &str) -> String {
144 self.clusters
145 .get(cluster)
146 .and_then(|e| e.url_template.clone())
147 .unwrap_or(self.default_url_template.clone())
148 }
149
150 pub(crate) fn consumer_config_of(&self, cluster: &str) -> ConsumerConfig {
152 self.clusters
153 .get(cluster)
154 .and_then(|e| e.consumer.clone())
155 .unwrap_or(self.consumer.clone())
156 }
157
158 pub fn schema_registry_config_of(&self, cluster: &str) -> Option<SchemaRegistryConfig> {
160 self.clusters
161 .get(cluster.trim())
162 .and_then(|config| config.schema_registry.clone())
163 }
164}
165
166#[test]
167fn generate_json_schema_for_global_config() {
168 use schemars::schema_for;
169 let mut schema = schema_for!(GlobalConfig);
170 schema.insert("$id".into(), "https://raw.githubusercontent.com/MAIF/yozefu/refs/heads/main/docs/json-schemas/global-config.json".into());
171 fs::write(
172 PathBuf::from(env!("CARGO_MANIFEST_DIR"))
173 .parent()
174 .unwrap()
175 .parent()
176 .unwrap()
177 .join("docs")
178 .join("json-schemas")
179 .join("global-config.json"),
180 serde_json::to_string_pretty(&schema).unwrap(),
181 )
182 .unwrap();
183}