use std::{
collections::HashMap,
net::{IpAddr, Ipv4Addr, SocketAddr},
time::Duration,
};
use secrecy::SecretString;
#[derive(Debug, Clone)]
pub struct AuthKeyEntry {
pub role: String,
}
#[derive(Debug, Clone)]
pub struct ProxyConfig {
pub listen: SocketAddr,
pub max_body_size: usize,
pub upstream_read_timeout: Duration,
pub upstream_connect_timeout: Duration,
pub proxy_api_key: Option<SecretString>,
pub proxy_token: Option<SecretString>,
pub proxy_auth_keys: HashMap<String, AuthKeyEntry>,
}
impl Default for ProxyConfig {
fn default() -> Self {
Self {
listen: SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8787),
max_body_size: 16 * 1024 * 1024, upstream_read_timeout: Duration::from_secs(600),
upstream_connect_timeout: Duration::from_secs(10),
proxy_api_key: None,
proxy_token: None,
proxy_auth_keys: HashMap::new(),
}
}
}
impl ProxyConfig {
#[must_use]
pub fn new(listen: SocketAddr) -> Self {
Self {
listen,
..Default::default()
}
}
#[must_use]
pub fn has_auth(&self) -> bool {
self.proxy_api_key.is_some()
|| self.proxy_token.is_some()
|| !self.proxy_auth_keys.is_empty()
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
#[test]
fn test_default_config_values() {
let config = ProxyConfig::default();
assert_eq!(config.max_body_size, 16 * 1024 * 1024);
assert_eq!(config.upstream_read_timeout, Duration::from_secs(600));
assert_eq!(config.upstream_connect_timeout, Duration::from_secs(10));
assert!(!config.has_auth());
}
#[test]
fn test_has_auth_with_api_key() {
let config = ProxyConfig {
proxy_api_key: Some(SecretString::new("sk-test".into())),
..Default::default()
};
assert!(config.has_auth());
}
#[test]
fn test_has_auth_with_token() {
let config = ProxyConfig {
proxy_token: Some(SecretString::new("token-test".into())),
..Default::default()
};
assert!(config.has_auth());
}
#[test]
fn test_has_auth_with_role_mapping() {
let config = ProxyConfig {
proxy_auth_keys: HashMap::from([(
"sk-test".into(),
AuthKeyEntry {
role: "coder".into(),
},
)]),
..Default::default()
};
assert!(config.has_auth());
}
}