Skip to main content

manabrew_server/
config.rs

1const DEFAULT_CAPTURE_MAX_GB: u64 = 20;
2/// Fixed rather than ephemeral: a client that learns it from config rather
3/// than from mDNS needs it to survive a restart.
4const DEFAULT_ART_PORT: u16 = 9528;
5
6const BYTES_PER_GB: u64 = 1024 * 1024 * 1024;
7
8pub struct ServerConfig {
9    pub host: String,
10    pub port: u16,
11    pub health_port: u16,
12    pub max_rooms: usize,
13    pub server_key: String,
14    pub official_key: Option<String>,
15    pub events_dir: Option<String>,
16    pub capture_dir: Option<String>,
17    pub capture_max_gb: u64,
18    pub deck_hub_enabled: bool,
19    pub hub_deck_plays_url: Option<String>,
20    pub hub_deck_plays_token: Option<String>,
21    pub hub_jwks_url: Option<String>,
22    /// Where this relay keeps card art. Set it and the relay serves
23    /// `/scryfall-img/` for everyone on the network, which is the point of
24    /// running one: nobody else has to hold 8GB of images.
25    pub art_dir: Option<String>,
26    pub art_port: u16,
27    /// An absolute url, for a deployment behind a proxy where the port this
28    /// binds is not the one a client reaches. On a LAN nobody sets this: the
29    /// mDNS record already carries the port and the client already knows the
30    /// host it connected to.
31    pub art_base_url: Option<String>,
32    /// Answer mDNS, so four desktops on a network find this box without anyone
33    /// typing its address.
34    pub lan_advertise: bool,
35}
36
37impl ServerConfig {
38    pub fn from_env() -> Self {
39        ServerConfig {
40            host: std::env::var("FORGE_HOST").unwrap_or_else(|_| "0.0.0.0".into()),
41            port: std::env::var("FORGE_PORT")
42                .ok()
43                .and_then(|p| p.parse().ok())
44                .unwrap_or(9443),
45            health_port: std::env::var("FORGE_HEALTH_PORT")
46                .ok()
47                .and_then(|p| p.parse().ok())
48                .unwrap_or(9444),
49            max_rooms: std::env::var("FORGE_MAX_ROOMS")
50                .ok()
51                .and_then(|r| r.parse().ok())
52                .unwrap_or(100),
53            server_key: std::env::var("MANABREW_SERVER_KEY").unwrap_or_else(|_| "forge".into()),
54            official_key: std::env::var("SECRET_MANABREW_KEY")
55                .ok()
56                .filter(|key| !key.is_empty()),
57            events_dir: std::env::var("MANABREW_EVENTS_DIR")
58                .ok()
59                .filter(|dir| !dir.is_empty()),
60            capture_dir: std::env::var("MANABREW_GAME_CAPTURE_DIR")
61                .ok()
62                .filter(|dir| !dir.is_empty()),
63            capture_max_gb: std::env::var("MANABREW_GAME_CAPTURE_MAX_GB")
64                .ok()
65                .and_then(|gb| gb.parse().ok())
66                .unwrap_or(DEFAULT_CAPTURE_MAX_GB),
67            deck_hub_enabled: std::env::var("DECK_HUB").ok().is_some_and(|value| {
68                matches!(
69                    value.to_ascii_lowercase().as_str(),
70                    "1" | "true" | "yes" | "on"
71                )
72            }),
73            hub_deck_plays_url: std::env::var("MANABREW_HUB_DECK_PLAYS_URL")
74                .ok()
75                .filter(|url| !url.is_empty()),
76            hub_deck_plays_token: std::env::var("MANABREW_HUB_DECK_PLAYS_TOKEN")
77                .ok()
78                .filter(|token| !token.is_empty()),
79            hub_jwks_url: std::env::var("MANABREW_HUB_JWKS_URL")
80                .ok()
81                .filter(|url| !url.is_empty()),
82            art_dir: std::env::var("MANABREW_ART_DIR")
83                .ok()
84                .filter(|dir| !dir.is_empty()),
85            art_port: std::env::var("MANABREW_ART_PORT")
86                .ok()
87                .and_then(|port| port.parse().ok())
88                .unwrap_or(DEFAULT_ART_PORT),
89            art_base_url: std::env::var("MANABREW_ART_BASE_URL")
90                .ok()
91                .filter(|url| !url.is_empty()),
92            lan_advertise: std::env::var("MANABREW_LAN_ADVERTISE")
93                .map(|value| {
94                    matches!(
95                        value.to_ascii_lowercase().as_str(),
96                        "1" | "true" | "yes" | "on"
97                    )
98                })
99                .unwrap_or(false),
100        }
101    }
102
103    pub fn capture_max_bytes(&self) -> u64 {
104        self.capture_max_gb.saturating_mul(BYTES_PER_GB)
105    }
106}