systemprompt_models/config/
mod.rs1use std::path::PathBuf;
10use std::sync::OnceLock;
11use systemprompt_traits::ConfigProvider;
12
13use crate::auth::JwtAudience;
14use crate::profile::{ContentNegotiationConfig, SecurityHeadersConfig, TrustedIssuer};
15
16mod environment;
17mod paths;
18mod rate_limits;
19mod validation;
20mod verbosity;
21
22pub use environment::Environment;
23pub use paths::PathNotConfiguredError;
24pub use rate_limits::RateLimitConfig;
25pub use validation::{
26 format_path_errors, validate_optional_path, validate_postgres_url, validate_profile_paths,
27 validate_required_optional_path, validate_required_path,
28};
29pub use verbosity::VerbosityLevel;
30
31static CONFIG: OnceLock<Config> = OnceLock::new();
32
33pub const DEFAULT_MAX_CONCURRENT_STREAMS: usize = 256;
35
36#[must_use]
39pub fn default_instance_id() -> String {
40 std::env::var("HOSTNAME")
41 .ok()
42 .filter(|h| !h.trim().is_empty())
43 .unwrap_or_else(|| format!("instance-{}", uuid::Uuid::new_v4().simple()))
44}
45
46#[derive(Debug, Clone)]
47pub struct Config {
48 pub instance_id: String,
49 pub max_concurrent_streams: usize,
50 pub sitename: String,
51 pub database_type: String,
52 pub database_url: String,
53 pub database_write_url: Option<String>,
54 pub github_link: String,
55 pub github_token: Option<String>,
56 pub system_path: String,
57 pub services_path: String,
58 pub bin_path: String,
59 pub skills_path: String,
60 pub settings_path: String,
61 pub content_config_path: String,
62 pub geoip_database_path: Option<String>,
63 pub web_path: String,
64 pub web_config_path: String,
65 pub web_metadata_path: String,
66 pub host: String,
67 pub port: u16,
68 pub api_server_url: String,
69 pub api_internal_url: String,
70 pub api_external_url: String,
71 pub jwt_issuer: String,
72 pub jwt_access_token_expiration: i64,
73 pub jwt_refresh_token_expiration: i64,
74 pub jwt_audiences: Vec<JwtAudience>,
75 pub allowed_resource_audiences: Vec<String>,
76 pub trusted_issuers: Vec<TrustedIssuer>,
77 pub signing_key_path: PathBuf,
78 pub use_https: bool,
79 pub rate_limits: RateLimitConfig,
80 pub cors_allowed_origins: Vec<String>,
81 pub trusted_proxies: Vec<String>,
82 pub is_cloud: bool,
83 pub content_negotiation: ContentNegotiationConfig,
84 pub security_headers: SecurityHeadersConfig,
85 pub allow_registration: bool,
86 pub system_admin_username: String,
87}
88
89impl Config {
90 pub fn is_initialized() -> bool {
91 CONFIG.get().is_some()
92 }
93
94 pub fn get() -> Result<&'static Self, crate::errors::ConfigError> {
95 CONFIG
96 .get()
97 .ok_or(crate::errors::ConfigError::NotInitialized)
98 }
99
100 pub fn install(config: Self) -> Result<(), Box<Self>> {
101 CONFIG.set(config).map_err(Box::new)
102 }
103
104 pub fn logs_path(&self) -> String {
105 format!("{}/logs", self.system_path)
106 }
107}
108
109impl ConfigProvider for Config {
110 fn get(&self, key: &str) -> Option<String> {
111 match key {
112 "database_type" => Some(self.database_type.clone()),
113 "database_url" => Some(self.database_url.clone()),
114 "database_write_url" => self.database_write_url.clone(),
115 "host" => Some(self.host.clone()),
116 "port" => Some(self.port.to_string()),
117 "system_path" => Some(self.system_path.clone()),
118 "services_path" => Some(self.services_path.clone()),
119 "bin_path" => Some(self.bin_path.clone()),
120 "skills_path" => Some(self.skills_path.clone()),
121 "settings_path" => Some(self.settings_path.clone()),
122 "content_config_path" => Some(self.content_config_path.clone()),
123 "web_path" => Some(self.web_path.clone()),
124 "web_config_path" => Some(self.web_config_path.clone()),
125 "web_metadata_path" => Some(self.web_metadata_path.clone()),
126 "sitename" => Some(self.sitename.clone()),
127 "github_link" => Some(self.github_link.clone()),
128 "github_token" => self.github_token.clone(),
129 "api_server_url" => Some(self.api_server_url.clone()),
130 "api_external_url" => Some(self.api_external_url.clone()),
131 "jwt_issuer" => Some(self.jwt_issuer.clone()),
132 "is_cloud" => Some(self.is_cloud.to_string()),
133 "instance_id" => Some(self.instance_id.clone()),
134 "max_concurrent_streams" => Some(self.max_concurrent_streams.to_string()),
135 _ => None,
136 }
137 }
138
139 fn database_url(&self) -> &str {
140 &self.database_url
141 }
142
143 fn database_write_url(&self) -> Option<&str> {
144 self.database_write_url.as_deref()
145 }
146
147 fn system_path(&self) -> &str {
148 &self.system_path
149 }
150
151 fn api_port(&self) -> u16 {
152 self.port
153 }
154
155 fn as_any(&self) -> &dyn std::any::Any {
156 self
157 }
158}