feat: add config module with TOML parsing and env var support
Made-with: Cursor
This commit is contained in:
186
src/config.rs
Normal file
186
src/config.rs
Normal file
@@ -0,0 +1,186 @@
|
||||
use std::path::Path;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct BridgeConfig {
|
||||
pub irc: IrcConfig,
|
||||
pub owncast: OwncastConfig,
|
||||
#[serde(default)]
|
||||
pub bridge: BridgeSettings,
|
||||
#[serde(default)]
|
||||
pub control: ControlConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct IrcConfig {
|
||||
pub server: String,
|
||||
#[serde(default = "default_irc_port")]
|
||||
pub port: u16,
|
||||
#[serde(default)]
|
||||
pub tls: bool,
|
||||
#[serde(default = "default_nick")]
|
||||
pub nick: String,
|
||||
pub channel: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct OwncastConfig {
|
||||
pub url: String,
|
||||
#[serde(default = "default_webhook_port")]
|
||||
pub webhook_port: u16,
|
||||
#[serde(default)]
|
||||
pub websocket_enabled: bool,
|
||||
#[serde(default = "default_health_poll_interval")]
|
||||
pub health_poll_interval_secs: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct BridgeSettings {
|
||||
#[serde(default = "default_irc_prefix")]
|
||||
pub irc_prefix: String,
|
||||
#[serde(default = "default_owncast_prefix")]
|
||||
pub owncast_prefix: String,
|
||||
#[serde(default)]
|
||||
pub message_buffer_size: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ControlConfig {
|
||||
#[serde(default = "default_socket_path")]
|
||||
pub socket_path: String,
|
||||
}
|
||||
|
||||
impl BridgeConfig {
|
||||
pub fn load(path: &Path) -> anyhow::Result<Self> {
|
||||
let contents = std::fs::read_to_string(path)?;
|
||||
let config: BridgeConfig = toml::from_str(&contents)?;
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
pub fn owncast_access_token(&self) -> anyhow::Result<String> {
|
||||
std::env::var("OWNCAST_ACCESS_TOKEN")
|
||||
.map_err(|_| anyhow::anyhow!("OWNCAST_ACCESS_TOKEN env var not set"))
|
||||
}
|
||||
}
|
||||
|
||||
fn default_irc_port() -> u16 { 6667 }
|
||||
fn default_nick() -> String { "owncast-bridge".to_string() }
|
||||
fn default_webhook_port() -> u16 { 9078 }
|
||||
fn default_health_poll_interval() -> u64 { 30 }
|
||||
fn default_irc_prefix() -> String { "[IRC]".to_string() }
|
||||
fn default_owncast_prefix() -> String { "[OC]".to_string() }
|
||||
fn default_socket_path() -> String { "/tmp/owncast-irc-bridge.sock".to_string() }
|
||||
|
||||
impl Default for BridgeSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
irc_prefix: default_irc_prefix(),
|
||||
owncast_prefix: default_owncast_prefix(),
|
||||
message_buffer_size: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ControlConfig {
|
||||
fn default() -> Self {
|
||||
Self { socket_path: default_socket_path() }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl BridgeConfig {
|
||||
pub fn default_for_test() -> Self {
|
||||
Self {
|
||||
irc: IrcConfig {
|
||||
server: "localhost".to_string(),
|
||||
port: 6667,
|
||||
tls: false,
|
||||
nick: "test-bot".to_string(),
|
||||
channel: "#test".to_string(),
|
||||
},
|
||||
owncast: OwncastConfig {
|
||||
url: "http://localhost:8080".to_string(),
|
||||
webhook_port: 9078,
|
||||
websocket_enabled: false,
|
||||
health_poll_interval_secs: 30,
|
||||
},
|
||||
bridge: BridgeSettings::default(),
|
||||
control: ControlConfig::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_parse_minimal_config() {
|
||||
let toml_str = r##"
|
||||
[irc]
|
||||
server = "irc.example.com"
|
||||
channel = "#test"
|
||||
|
||||
[owncast]
|
||||
url = "https://owncast.example.com"
|
||||
"##;
|
||||
let config: BridgeConfig = toml::from_str(toml_str).unwrap();
|
||||
assert_eq!(config.irc.server, "irc.example.com");
|
||||
assert_eq!(config.irc.port, 6667);
|
||||
assert_eq!(config.irc.tls, false);
|
||||
assert_eq!(config.irc.nick, "owncast-bridge");
|
||||
assert_eq!(config.irc.channel, "#test");
|
||||
assert_eq!(config.owncast.url, "https://owncast.example.com");
|
||||
assert_eq!(config.owncast.webhook_port, 9078);
|
||||
assert_eq!(config.owncast.websocket_enabled, false);
|
||||
assert_eq!(config.owncast.health_poll_interval_secs, 30);
|
||||
assert_eq!(config.bridge.irc_prefix, "[IRC]");
|
||||
assert_eq!(config.bridge.owncast_prefix, "[OC]");
|
||||
assert_eq!(config.bridge.message_buffer_size, 0);
|
||||
assert_eq!(config.control.socket_path, "/tmp/owncast-irc-bridge.sock");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_full_config() {
|
||||
let toml_str = r##"
|
||||
[irc]
|
||||
server = "irc.example.com"
|
||||
port = 6697
|
||||
tls = true
|
||||
nick = "mybot"
|
||||
channel = "#mychan"
|
||||
|
||||
[owncast]
|
||||
url = "https://oc.example.com"
|
||||
webhook_port = 8888
|
||||
websocket_enabled = true
|
||||
health_poll_interval_secs = 10
|
||||
|
||||
[bridge]
|
||||
irc_prefix = "<IRC>"
|
||||
owncast_prefix = "<OC>"
|
||||
message_buffer_size = 50
|
||||
|
||||
[control]
|
||||
socket_path = "/var/run/bridge.sock"
|
||||
"##;
|
||||
let config: BridgeConfig = toml::from_str(toml_str).unwrap();
|
||||
assert_eq!(config.irc.port, 6697);
|
||||
assert!(config.irc.tls);
|
||||
assert_eq!(config.irc.nick, "mybot");
|
||||
assert_eq!(config.owncast.webhook_port, 8888);
|
||||
assert!(config.owncast.websocket_enabled);
|
||||
assert_eq!(config.bridge.message_buffer_size, 50);
|
||||
assert_eq!(config.control.socket_path, "/var/run/bridge.sock");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_access_token_from_env() {
|
||||
std::env::set_var("OWNCAST_ACCESS_TOKEN", "test-token-123");
|
||||
let config = BridgeConfig::default_for_test();
|
||||
let token = config.owncast_access_token();
|
||||
assert_eq!(token.unwrap(), "test-token-123");
|
||||
std::env::remove_var("OWNCAST_ACCESS_TOKEN");
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
mod config;
|
||||
|
||||
fn main() {
|
||||
println!("owncast-irc-bridge");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user