Skip to main content

freshblu_server/
config.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize)]
4pub struct ServerConfig {
5    /// HTTP port
6    pub http_port: u16,
7    /// MQTT port
8    pub mqtt_port: u16,
9    /// Database URL (sqlite:freshblu.db or postgresql://...)
10    pub database_url: String,
11    /// Bcrypt pepper for extra token security
12    pub pepper: String,
13    /// Open registration (no auth required to register)
14    pub open_registration: bool,
15    /// Max message size in bytes
16    pub max_message_size: usize,
17    /// Log level
18    pub log_level: String,
19    /// NATS URL (if set, use NatsBus; otherwise LocalBus)
20    pub nats_url: Option<String>,
21    /// Redis URL (if set, enable cache layer and presence)
22    pub redis_url: Option<String>,
23    /// Pod ID for NATS delivery routing (defaults to hostname)
24    pub pod_id: String,
25    /// Rate limit: max requests per window per device
26    pub rate_limit: u64,
27    /// Rate limit window in seconds
28    pub rate_window: u64,
29    /// Server public key (PEM)
30    pub public_key: Option<String>,
31    /// Server private key (PEM)
32    pub private_key: Option<String>,
33}
34
35impl Default for ServerConfig {
36    fn default() -> Self {
37        Self {
38            http_port: 3000,
39            mqtt_port: 1883,
40            database_url: "sqlite:freshblu.db".to_string(),
41            pepper: "change-me-in-production".to_string(),
42            open_registration: true,
43            max_message_size: 1_048_576, // 1MB
44            log_level: "info".to_string(),
45            nats_url: None,
46            redis_url: None,
47            pod_id: gethostname(),
48            rate_limit: 1200,
49            rate_window: 60,
50            public_key: None,
51            private_key: None,
52        }
53    }
54}
55
56impl ServerConfig {
57    pub fn from_env() -> Self {
58        let _ = dotenvy::dotenv();
59        Self {
60            http_port: std::env::var("FRESHBLU_HTTP_PORT")
61                .ok()
62                .and_then(|v| v.parse().ok())
63                .unwrap_or(3000),
64            mqtt_port: std::env::var("FRESHBLU_MQTT_PORT")
65                .ok()
66                .and_then(|v| v.parse().ok())
67                .unwrap_or(1883),
68            database_url: std::env::var("DATABASE_URL")
69                .unwrap_or_else(|_| "sqlite:freshblu.db".to_string()),
70            pepper: std::env::var("FRESHBLU_PEPPER")
71                .unwrap_or_else(|_| "change-me-in-production".to_string()),
72            open_registration: std::env::var("FRESHBLU_OPEN_REGISTRATION")
73                .map(|v| v != "false")
74                .unwrap_or(true),
75            max_message_size: std::env::var("FRESHBLU_MAX_MESSAGE_SIZE")
76                .ok()
77                .and_then(|v| v.parse().ok())
78                .unwrap_or(1_048_576),
79            log_level: std::env::var("RUST_LOG").unwrap_or_else(|_| "info".to_string()),
80            nats_url: std::env::var("NATS_URL").ok(),
81            redis_url: std::env::var("REDIS_URL").ok(),
82            pod_id: std::env::var("POD_ID").unwrap_or_else(|_| gethostname()),
83            rate_limit: std::env::var("FRESHBLU_RATE_LIMIT")
84                .ok()
85                .and_then(|v| v.parse().ok())
86                .unwrap_or(1200),
87            rate_window: std::env::var("FRESHBLU_RATE_WINDOW")
88                .ok()
89                .and_then(|v| v.parse().ok())
90                .unwrap_or(60),
91            public_key: std::env::var("FRESHBLU_PUBLIC_KEY").ok(),
92            private_key: std::env::var("FRESHBLU_PRIVATE_KEY").ok(),
93        }
94    }
95}
96
97fn gethostname() -> String {
98    std::env::var("HOSTNAME").unwrap_or_else(|_| uuid::Uuid::new_v4().to_string()[..8].to_string())
99}