rws_proxy/traffic/
config.rs1use std::path::PathBuf;
4
5pub const RWS_CONFIG_TRAFFIC_ENABLED: &str = "RWS_CONFIG_TRAFFIC_ENABLED";
6pub const RWS_CONFIG_TRAFFIC_RETENTION_DAYS: &str = "RWS_CONFIG_TRAFFIC_RETENTION_DAYS";
7pub const RWS_CONFIG_TRAFFIC_PERSIST: &str = "RWS_CONFIG_TRAFFIC_PERSIST";
8pub const RWS_CONFIG_TRAFFIC_EXCLUDE: &str = "RWS_CONFIG_TRAFFIC_EXCLUDE";
9pub const RWS_CONFIG_TRAFFIC_GEO_DB: &str = "RWS_CONFIG_TRAFFIC_GEO_DB";
10pub const RWS_CONFIG_TRAFFIC_SCRIPT: &str = "RWS_CONFIG_TRAFFIC_SCRIPT";
11pub const RWS_CONFIG_TRAFFIC_GOALS: &str = "RWS_CONFIG_TRAFFIC_GOALS";
12pub const RWS_CONFIG_TRAFFIC_DATABASE_URL_ENV: &str = "RWS_CONFIG_TRAFFIC_DATABASE_URL_ENV";
13pub const RWS_CONFIG_TRAFFIC_HOSTING_NETWORKS: &str = "RWS_CONFIG_TRAFFIC_HOSTING_NETWORKS";
14pub const RWS_CONFIG_TRAFFIC_APPS: &str = "RWS_CONFIG_TRAFFIC_APPS";
15pub const RWS_CONFIG_TRAFFIC_OWNER_NETWORKS: &str = "RWS_CONFIG_TRAFFIC_OWNER_NETWORKS";
16pub const RWS_CONFIG_TRAFFIC_PROBE_ADDRESSES: &str = "RWS_CONFIG_TRAFFIC_PROBE_ADDRESSES";
17
18fn read(key: &str) -> String {
19 std::env::var(key).unwrap_or_default().trim().to_string()
20}
21
22pub fn enabled_setting() -> Option<bool> {
25 match read(RWS_CONFIG_TRAFFIC_ENABLED).to_ascii_lowercase().as_str() {
26 "" => None,
27 "false" | "0" | "no" | "off" => Some(false),
28 _ => Some(true),
29 }
30}
31
32pub fn retention_days() -> u64 {
34 read(RWS_CONFIG_TRAFFIC_RETENTION_DAYS).parse::<u64>().ok().filter(|d| *d >= 1).map_or(30, |d| d.min(90))
35}
36
37pub fn exclude() -> Vec<String> {
40 let value = std::env::var(RWS_CONFIG_TRAFFIC_EXCLUDE);
41 match value {
42 Ok(v) => v.split(',').map(str::trim).filter(|p| !p.is_empty()).map(str::to_string).collect(),
43 Err(_) => ["/healthz", "/readyz", "/metrics"].iter().map(|p| p.to_string()).collect(),
44 }
45}
46
47pub fn persist_path() -> Option<PathBuf> {
52 let value = read(RWS_CONFIG_TRAFFIC_PERSIST);
53 if value.eq_ignore_ascii_case("off") {
54 return None;
55 }
56 if !value.is_empty() {
57 return Some(PathBuf::from(value));
58 }
59 [crate::entry_point::Config::RWS_CONFIG_ACME_CERT_PATH, crate::entry_point::Config::RWS_CONFIG_TLS_CERT_FILE]
60 .iter()
61 .map(|key| read(key))
62 .find(|path| !path.is_empty())
63 .and_then(|cert| PathBuf::from(cert).parent().map(|dir| dir.join("traffic.json")))
64}
65
66pub fn geo_db() -> Option<PathBuf> {
69 let value = read(RWS_CONFIG_TRAFFIC_GEO_DB);
70 (!value.is_empty()).then(|| PathBuf::from(value))
71}
72
73pub fn script() -> bool {
76 matches!(read(RWS_CONFIG_TRAFFIC_SCRIPT).to_ascii_lowercase().as_str(), "true" | "1" | "yes" | "on")
77}
78
79pub fn hosting_networks() -> bool {
83 !matches!(read(RWS_CONFIG_TRAFFIC_HOSTING_NETWORKS).to_ascii_lowercase().as_str(), "false" | "0" | "no" | "off")
84}
85
86pub const MAX_GOALS: usize = 32;
88
89pub fn goals() -> Vec<String> {
93 read(RWS_CONFIG_TRAFFIC_GOALS).split(',').map(str::trim).filter(|g| !g.is_empty()).take(MAX_GOALS).map(str::to_string).collect()
94}
95
96pub fn database_url() -> Option<String> {
101 let name = read(RWS_CONFIG_TRAFFIC_DATABASE_URL_ENV);
102 if name.is_empty() {
103 return None;
104 }
105 std::env::var(&name).ok().map(|v| v.trim().to_string()).filter(|v| !v.is_empty())
106}
107
108fn list(key: &str) -> Vec<String> {
109 read(key).split(',').map(str::trim).filter(|v| !v.is_empty()).map(str::to_string).collect()
110}
111
112pub fn apps() -> Vec<String> {
116 list(RWS_CONFIG_TRAFFIC_APPS)
117}
118
119pub fn owner_networks() -> Vec<String> {
122 list(RWS_CONFIG_TRAFFIC_OWNER_NETWORKS)
123}
124
125pub fn probe_addresses() -> bool {
129 matches!(read(RWS_CONFIG_TRAFFIC_PROBE_ADDRESSES).to_ascii_lowercase().as_str(), "true" | "1" | "yes" | "on")
130}