asknothingx2_util/api/
setup.rs1use std::{
2 sync::{Arc, OnceLock, RwLock},
3 time::Duration,
4};
5
6use reqwest::Client;
7use tracing::{debug, info, warn};
8
9use super::{error::ConfigError, AppType, Config};
10
11static GLOBAL_CLIENT: OnceLock<Client> = OnceLock::new();
12static GLOBAL_CONFIG: OnceLock<Arc<RwLock<Config>>> = OnceLock::new();
13static GLOBAL_APP_TYPE: OnceLock<AppType> = OnceLock::new();
14
15pub fn get_global_client_or_default() -> &'static Client {
16 GLOBAL_CLIENT.get_or_init(|| {
17 warn!(
18 client_type = "default_web_app",
19 suggestion = "setup::web_apps()",
20 "HTTP client auto-initialized with default configuration"
21 );
22
23 Config::for_web_apps()
24 .build_client()
25 .expect("Failed to create default HTTP client")
26 })
27}
28
29fn initialize_global_client(config: Config) -> Result<(), ConfigError> {
30 let client = config.build_client()?;
31 let app_type = config.app_type;
32
33 GLOBAL_CLIENT
34 .set(client)
35 .map_err(|_| ConfigError::AlreadyConfigured {
36 message: "HTTP client has already been configured".to_string(),
37 })?;
38
39 GLOBAL_APP_TYPE
40 .set(config.app_type)
41 .map_err(|_| ConfigError::AlreadyConfigured {
42 message: "App type has already been set".to_string(),
43 })?;
44
45 let config_arc = Arc::new(RwLock::new(config));
46 GLOBAL_CONFIG
47 .set(config_arc)
48 .map_err(|_| ConfigError::AlreadyConfigured {
49 message: "Configuration has already been set".to_string(),
50 })?;
51
52 info!("HTTP client initialized for app type: {:?}", app_type);
53 Ok(())
54}
55
56fn detect_app_type_from_env() -> AppType {
57 match std::env::var("APP_TYPE")
58 .unwrap_or_else(|_| "web".to_string())
59 .to_lowercase()
60 .as_str()
61 {
62 "cli" | "command" | "script" => AppType::Cli,
63 "web" | "api" | "service" => AppType::Web,
64 "production" | "prod" | "enterprise" => AppType::Production,
65 "development" | "dev" | "test" | "testing" => AppType::Development,
66 "gateway" | "proxy" | "loadbalancer" => AppType::Gateway,
67 "scraping" | "crawler" | "scraper" => AppType::Scraping,
68 _ => AppType::Web,
69 }
70}
71
72fn apply_env_overrides(config: &mut Config) {
73 if let Ok(timeout) = std::env::var("HTTP_TIMEOUT_SECONDS") {
74 if let Ok(seconds) = timeout.parse::<u64>() {
75 config.request_timeout = Duration::from_secs(seconds);
76 }
77 }
78
79 if let Ok(proxy) = std::env::var("HTTP_PROXY") {
80 debug!("Applied HTTP proxy override: {}", proxy);
81 config.proxy_url = Some(proxy);
82 }
83
84 if let Ok(user_agent) = std::env::var("HTTP_USER_AGENT") {
85 debug!("Applied user agent override: {}", user_agent);
86 config.user_agent = user_agent;
87 }
88}
89
90pub fn is_configured() -> bool {
91 GLOBAL_CLIENT.get().is_some()
92}
93
94pub fn current_app_type() -> Option<AppType> {
95 GLOBAL_APP_TYPE.get().copied()
96}
97
98pub fn current_configuration() -> Option<Config> {
99 Some(GLOBAL_CONFIG.get()?.read().ok()?.clone())
100}
101
102pub fn update_global_config<F>(updater: F) -> Result<(), ConfigError>
103where
104 F: FnOnce(&mut Config),
105{
106 let config_arc = GLOBAL_CONFIG.get().ok_or(ConfigError::NotInitialized)?;
107 let mut config = config_arc
108 .write()
109 .map_err(|_| ConfigError::ConfigurationLocked)?;
110 updater(&mut config);
111 debug!("Configuration updated successfully");
112 Ok(())
113}
114
115pub fn app_type(app_type: AppType) -> Result<(), ConfigError> {
116 match app_type {
117 AppType::Cli => cli_tools(),
118 AppType::Web => web_apps(),
119 AppType::Production => production(),
120 AppType::Development => development(),
121 AppType::Gateway => api_gateway(),
122 AppType::Scraping => web_scraping(),
123 }
124}
125
126pub fn cli_tools() -> Result<(), ConfigError> {
127 let config = Config::for_cli_tools();
128 initialize_global_client(config)
129}
130
131pub fn web_apps() -> Result<(), ConfigError> {
132 let config = Config::for_web_apps();
133 initialize_global_client(config)
134}
135
136pub fn production() -> Result<(), ConfigError> {
137 let config = Config::for_production();
138 initialize_global_client(config)
139}
140
141pub fn development() -> Result<(), ConfigError> {
142 let config = Config::for_development();
143 initialize_global_client(config)
144}
145
146pub fn api_gateway() -> Result<(), ConfigError> {
147 let config = Config::for_api_gateway();
148 initialize_global_client(config)
149}
150
151pub fn web_scraping() -> Result<(), ConfigError> {
152 let config = Config::for_web_scraping();
153 initialize_global_client(config)
154}
155
156pub fn automatically() -> Result<(), ConfigError> {
157 let app_type = detect_app_type_from_env();
158
159 let mut config = match app_type {
160 AppType::Cli => Config::for_cli_tools(),
161 AppType::Web => Config::for_web_apps(),
162 AppType::Production => Config::for_production(),
163 AppType::Development => Config::for_development(),
164 AppType::Gateway => Config::for_api_gateway(),
165 AppType::Scraping => Config::for_web_scraping(),
166 };
167
168 apply_env_overrides(&mut config);
169 initialize_global_client(config)
170}