event_notification/
config.rs1use crate::Error;
2use figment::providers::Format;
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct WebhookConfig {
9 pub endpoint: String,
10 pub auth_token: Option<String>,
11 pub custom_headers: Option<HashMap<String, String>>,
12 pub max_retries: u32,
13 pub timeout: u64,
14}
15
16impl WebhookConfig {
17 pub fn validate(&self) -> Result<(), String> {
19 if self.endpoint.trim().is_empty() {
21 return Err("Webhook endpoint cannot be empty".to_string());
22 }
23
24 if self.timeout == 0 {
26 return Err("Webhook timeout must be greater than 0".to_string());
27 }
28
29 if self.max_retries > 10 {
31 return Err("Maximum retry count cannot exceed 10".to_string());
32 }
33
34 Ok(())
35 }
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct KafkaConfig {
41 pub brokers: String,
42 pub topic: String,
43 pub max_retries: u32,
44 pub timeout: u64,
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize)]
49pub struct MqttConfig {
50 pub broker: String,
51 pub port: u16,
52 pub client_id: String,
53 pub topic: String,
54 pub max_retries: u32,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
59#[serde(tag = "type")]
60pub enum AdapterConfig {
61 Webhook(WebhookConfig),
62 Kafka(KafkaConfig),
63 Mqtt(MqttConfig),
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct HttpProducerConfig {
69 #[serde(default = "default_http_port")]
70 pub port: u16,
71}
72
73impl Default for HttpProducerConfig {
74 fn default() -> Self {
75 Self {
76 port: default_http_port(),
77 }
78 }
79}
80
81fn default_http_port() -> u16 {
82 3000
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct NotificationConfig {
88 #[serde(default = "default_store_path")]
89 pub store_path: String,
90 #[serde(default = "default_channel_capacity")]
91 pub channel_capacity: usize,
92 pub adapters: Vec<AdapterConfig>,
93 #[serde(default)]
94 pub http: HttpProducerConfig,
95}
96
97impl Default for NotificationConfig {
98 fn default() -> Self {
99 Self {
100 store_path: default_store_path(),
101 channel_capacity: default_channel_capacity(),
102 adapters: Vec::new(),
103 http: HttpProducerConfig::default(),
104 }
105 }
106}
107
108impl NotificationConfig {
109 pub fn new() -> Self {
111 Self::default()
112 }
113
114 pub fn from_file(path: &str) -> Result<Self, Error> {
116 let config = figment::Figment::new()
117 .merge(figment::providers::Toml::file(path))
118 .extract()?;
119
120 Ok(config)
121 }
122
123 pub fn load() -> Result<Self, Error> {
125 let figment = figment::Figment::new()
126 .merge(figment::providers::Toml::file("event.toml"))
128 .merge(figment::providers::Yaml::file("event.yaml"))
130 .merge(figment::providers::Env::prefixed("EVENT_NOTIF_"));
132
133 Ok(figment.extract()?)
134 }
135
136 pub fn from_env_file(path: &str) -> Result<Self, Error> {
138 dotenv::from_path(path)
140 .map_err(|e| Error::ConfigError(format!("unable to load env file: {}", e)))?;
141
142 let figment =
144 figment::Figment::new().merge(figment::providers::Env::prefixed("EVENT_NOTIF_"));
145
146 Ok(figment.extract()?)
147 }
148}
149
150fn default_store_path() -> String {
152 std::env::temp_dir()
153 .join("event-notification")
154 .to_string_lossy()
155 .to_string()
156}
157
158fn default_channel_capacity() -> usize {
160 10000 }