1pub mod error;
6
7#[cfg(test)]
8mod tests;
9
10pub use error::ConfigError;
11
12use std::env;
13use std::net::IpAddr;
14use std::path::PathBuf;
15
16#[derive(Debug, Clone)]
20pub struct Config {
21 pub port: u16,
23
24 pub bind_addr: IpAddr,
26
27 pub storage_path: PathBuf,
29
30 pub model_path: Option<PathBuf>,
32
33 pub reranker_path: Option<PathBuf>,
35
36 pub qdrant_url: String,
38
39 pub l1_capacity: u64,
41}
42
43pub const DEFAULT_QDRANT_URL: &str = "http://localhost:6334";
45
46impl Default for Config {
47 fn default() -> Self {
48 Self {
49 port: 8080,
50 bind_addr: IpAddr::V4(std::net::Ipv4Addr::new(127, 0, 0, 1)),
51 storage_path: PathBuf::from("./.data"),
52 model_path: None,
53 reranker_path: None,
54 qdrant_url: DEFAULT_QDRANT_URL.to_string(),
55 l1_capacity: 10_000,
56 }
57 }
58}
59
60impl Config {
61 const ENV_PORT: &'static str = "REFLEX_PORT";
62 const ENV_BIND_ADDR: &'static str = "REFLEX_BIND_ADDR";
63 const ENV_STORAGE_PATH: &'static str = "REFLEX_STORAGE_PATH";
64 const ENV_MODEL_PATH: &'static str = "REFLEX_MODEL_PATH";
65 const ENV_RERANKER_PATH: &'static str = "REFLEX_RERANKER_PATH";
66 const ENV_QDRANT_URL: &'static str = "REFLEX_QDRANT_URL";
67 const ENV_L1_CAPACITY: &'static str = "REFLEX_L1_CAPACITY";
68
69 pub fn from_env() -> Result<Self, ConfigError> {
71 let defaults = Self::default();
72
73 let port = Self::parse_port_from_env(defaults.port)?;
74 let bind_addr = Self::parse_bind_addr_from_env(defaults.bind_addr)?;
75 let storage_path = Self::parse_path_from_env(Self::ENV_STORAGE_PATH, defaults.storage_path);
76 let model_path = Self::parse_optional_path_from_env(Self::ENV_MODEL_PATH);
77 let reranker_path = Self::parse_optional_path_from_env(Self::ENV_RERANKER_PATH);
78 let qdrant_url = Self::parse_string_from_env(Self::ENV_QDRANT_URL, defaults.qdrant_url);
79 let l1_capacity = Self::parse_u64_from_env(Self::ENV_L1_CAPACITY, defaults.l1_capacity);
80
81 Ok(Self {
82 port,
83 bind_addr,
84 storage_path,
85 model_path,
86 reranker_path,
87 qdrant_url,
88 l1_capacity,
89 })
90 }
91
92 pub fn validate(&self) -> Result<(), ConfigError> {
94 if self.storage_path.exists() && !self.storage_path.is_dir() {
95 return Err(ConfigError::NotADirectory {
96 path: self.storage_path.clone(),
97 });
98 }
99
100 if let Some(ref path) = self.model_path {
101 if !path.exists() {
102 return Err(ConfigError::PathNotFound { path: path.clone() });
103 }
104 if !path.is_file() {
105 return Err(ConfigError::NotAFile { path: path.clone() });
106 }
107 }
108
109 if let Some(ref path) = self.reranker_path {
110 if !path.exists() {
111 return Err(ConfigError::PathNotFound { path: path.clone() });
112 }
113 if !path.is_dir() {
114 return Err(ConfigError::NotADirectory { path: path.clone() });
115 }
116 }
117
118 Ok(())
119 }
120
121 pub fn socket_addr(&self) -> String {
123 format!("{}:{}", self.bind_addr, self.port)
124 }
125
126 fn parse_port_from_env(default: u16) -> Result<u16, ConfigError> {
127 match env::var(Self::ENV_PORT) {
128 Ok(value) => {
129 let port: u16 = value.parse().map_err(|e| ConfigError::PortParseError {
130 value: value.clone(),
131 source: e,
132 })?;
133
134 if port == 0 {
135 return Err(ConfigError::InvalidPort { value });
136 }
137
138 Ok(port)
139 }
140 Err(_) => Ok(default),
141 }
142 }
143
144 fn parse_bind_addr_from_env(default: IpAddr) -> Result<IpAddr, ConfigError> {
145 match env::var(Self::ENV_BIND_ADDR) {
146 Ok(value) => value
147 .parse()
148 .map_err(|e| ConfigError::InvalidBindAddr { value, source: e }),
149 Err(_) => Ok(default),
150 }
151 }
152
153 fn parse_path_from_env(var_name: &str, default: PathBuf) -> PathBuf {
154 env::var(var_name).map(PathBuf::from).unwrap_or(default)
155 }
156
157 fn parse_optional_path_from_env(var_name: &str) -> Option<PathBuf> {
158 env::var(var_name)
159 .ok()
160 .map(|v| v.trim().to_string())
161 .filter(|v| !v.is_empty())
162 .map(PathBuf::from)
163 }
164
165 fn parse_string_from_env(var_name: &str, default: String) -> String {
166 env::var(var_name).unwrap_or(default)
167 }
168
169 fn parse_u64_from_env(var_name: &str, default: u64) -> u64 {
170 env::var(var_name)
171 .ok()
172 .and_then(|v| v.parse().ok())
173 .unwrap_or(default)
174 }
175}