Skip to content

Commit 2d11f47

Browse files
committed
feat: impl dynamic load configuration
1 parent 59d77f8 commit 2d11f47

File tree

8 files changed

+963
-16
lines changed

8 files changed

+963
-16
lines changed

src/config.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::config_loader;
12
use crate::error::{CliError, Result};
23
use std::env;
34
use std::path::PathBuf;
@@ -29,9 +30,21 @@ impl Default for Config {
2930
}
3031

3132
impl Config {
32-
/// Creates a new configuration instance from environment variables
33+
/// Creates a new configuration instance from dynamic config loader
34+
/// or falls back to environment variables if that fails
3335
pub fn new() -> Self {
34-
let mut config = Self::default();
36+
// Try to load configuration dynamically, fall back to default if it fails
37+
let mut config = config_loader::load_config()
38+
.map(config_loader::to_app_config)
39+
.unwrap_or_else(|e| {
40+
eprintln!(
41+
"\x1b[31m Warning: Failed to load dynamic configuration: {}. Using default configuration.\x1b[0m",
42+
e
43+
);
44+
Self::default()
45+
});
46+
47+
// Allow environment variables to override config
3548
config.load_from_env();
3649
config
3750
}

src/config_loader/config_parser.rs

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
use std::fs;
2+
use std::path::{Path, PathBuf};
3+
use std::str::FromStr;
4+
5+
use crate::config_loader::DorisConfig;
6+
use crate::config_loader::process_detector;
7+
use crate::error::{CliError, Result};
8+
9+
// Common configuration keys
10+
const LOG_DIR_KEY: &str = "LOG_DIR";
11+
const PRIORITY_NETWORKS_KEY: &str = "priority_networks";
12+
const META_SERVICE_KEY: &str = "meta_service_endpoint";
13+
14+
/// Parse BE configuration
15+
pub fn parse_be_config() -> Result<DorisConfig> {
16+
let (install_dir, jdk_path) = process_detector::get_be_paths()?;
17+
let conf_dir = install_dir.join("conf");
18+
let be_conf_path = process_detector::get_be_config_path()?;
19+
20+
process_detector::verify_config_file(&be_conf_path)?;
21+
22+
let content = fs::read_to_string(&be_conf_path)
23+
.map_err(|e| CliError::ConfigError(format!("Failed to read BE config file: {}", e)))?;
24+
25+
let install_dir_clone = install_dir.clone();
26+
27+
let mut config = DorisConfig {
28+
install_dir,
29+
conf_dir,
30+
jdk_path,
31+
..DorisConfig::default()
32+
};
33+
34+
parse_config_content(&content, &mut config, &install_dir_clone)?;
35+
36+
Ok(config)
37+
}
38+
39+
/// Parse FE configuration
40+
pub fn parse_fe_config() -> Result<DorisConfig> {
41+
let (install_dir, jdk_path) = process_detector::get_fe_paths()?;
42+
let conf_dir = install_dir.join("conf");
43+
let fe_conf_path = process_detector::get_fe_config_path()?;
44+
45+
process_detector::verify_config_file(&fe_conf_path)?;
46+
47+
let content = fs::read_to_string(&fe_conf_path)
48+
.map_err(|e| CliError::ConfigError(format!("Failed to read FE config file: {}", e)))?;
49+
50+
let mut config = DorisConfig {
51+
install_dir,
52+
conf_dir,
53+
jdk_path,
54+
..DorisConfig::default()
55+
};
56+
57+
parse_fe_config_content(&content, &mut config)?;
58+
59+
Ok(config)
60+
}
61+
62+
/// Parse BE config content
63+
fn parse_config_content(content: &str, config: &mut DorisConfig, install_dir: &Path) -> Result<()> {
64+
for line in content.lines() {
65+
let line = line.trim();
66+
67+
if line.starts_with('#') || line.is_empty() {
68+
continue;
69+
}
70+
71+
// Parse LOG_DIR
72+
if line.starts_with(LOG_DIR_KEY) {
73+
if let Some(log_dir) = extract_value(line) {
74+
// Handle variable substitution, e.g., ${DORIS_HOME}/log
75+
if log_dir.contains("${DORIS_HOME}") {
76+
let replaced =
77+
log_dir.replace("${DORIS_HOME}", install_dir.to_str().unwrap_or(""));
78+
config.log_dir = PathBuf::from(replaced);
79+
} else {
80+
config.log_dir = PathBuf::from(log_dir);
81+
}
82+
}
83+
}
84+
85+
// Parse ports and network config
86+
parse_key_value(line, "be_port", &mut config.be_port)?;
87+
parse_key_value(line, "brpc_port", &mut config.brpc_port)?;
88+
parse_key_value(
89+
line,
90+
"heartbeat_service_port",
91+
&mut config.heartbeat_service_port,
92+
)?;
93+
parse_key_value(line, "webserver_port", &mut config.webserver_port)?;
94+
parse_key_value(line, PRIORITY_NETWORKS_KEY, &mut config.priority_networks)?;
95+
parse_key_value(line, META_SERVICE_KEY, &mut config.meta_service_endpoint)?;
96+
}
97+
98+
Ok(())
99+
}
100+
101+
/// Extract value from a key=value or key = value line
102+
fn extract_value(line: &str) -> Option<String> {
103+
let parts: Vec<&str> = if line.contains('=') {
104+
line.splitn(2, '=').collect()
105+
} else if line.contains(" = ") {
106+
line.splitn(2, " = ").collect()
107+
} else {
108+
return None;
109+
};
110+
111+
if parts.len() == 2 {
112+
Some(parts[1].trim().trim_matches('"').to_string())
113+
} else {
114+
None
115+
}
116+
}
117+
118+
/// Parse FE config content
119+
fn parse_fe_config_content(content: &str, config: &mut DorisConfig) -> Result<()> {
120+
for line in content.lines() {
121+
let line = line.trim();
122+
123+
if line.starts_with('#') || line.is_empty() {
124+
continue;
125+
}
126+
127+
// Parse LOG_DIR
128+
if line.starts_with(LOG_DIR_KEY) {
129+
if let Some(log_dir) = extract_value(line) {
130+
config.log_dir = PathBuf::from(log_dir);
131+
}
132+
}
133+
134+
// Parse ports and network config
135+
parse_key_value(line, "http_port", &mut config.http_port)?;
136+
parse_key_value(line, "rpc_port", &mut config.rpc_port)?;
137+
parse_key_value(line, "query_port", &mut config.query_port)?;
138+
parse_key_value(line, "edit_log_port", &mut config.edit_log_port)?;
139+
parse_key_value(line, "cloud_http_port", &mut config.cloud_http_port)?;
140+
parse_key_value(line, PRIORITY_NETWORKS_KEY, &mut config.priority_networks)?;
141+
parse_key_value(line, META_SERVICE_KEY, &mut config.meta_service_endpoint)?;
142+
143+
// Parse metadata directory
144+
if line.starts_with("meta_dir") {
145+
if let Some(meta_dir) = extract_value(line) {
146+
config.meta_dir = Some(PathBuf::from(meta_dir));
147+
}
148+
}
149+
}
150+
151+
Ok(())
152+
}
153+
154+
/// Generic key-value parser
155+
fn parse_key_value<T: FromStr>(line: &str, key: &str, value: &mut Option<T>) -> Result<()> {
156+
if line.starts_with(key) && (line.contains('=') || line.contains(" = ")) {
157+
if let Some(val_str) = extract_value(line) {
158+
if let Ok(parsed_val) = val_str.parse::<T>() {
159+
*value = Some(parsed_val);
160+
}
161+
}
162+
}
163+
Ok(())
164+
}

0 commit comments

Comments
 (0)