Add config validation and dashboard
Add YAML config loading with validation, env overrides for secrets, and a web dashboard exposing health, stats, and recent events.
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
module main
|
||||
|
||||
import net.http
|
||||
import time
|
||||
import sources
|
||||
|
||||
pub struct NtfyClient {
|
||||
pub mut:
|
||||
base_url string
|
||||
auth_token string
|
||||
logger Logger
|
||||
}
|
||||
|
||||
pub fn new_ntfy_client(cfg ServerConfig, logger Logger) NtfyClient {
|
||||
return NtfyClient{
|
||||
base_url: cfg.url.trim_right('/')
|
||||
auth_token: cfg.auth_token
|
||||
logger: logger
|
||||
}
|
||||
}
|
||||
|
||||
fn join_tags(tags []string) string {
|
||||
return tags.join(',')
|
||||
}
|
||||
|
||||
// publish sends an event to the Ntfy server with exponential backoff retry (3 attempts).
|
||||
pub fn (c NtfyClient) publish(event sources.Event) ! {
|
||||
url := '${c.base_url}/${event.topic}'
|
||||
mut header := http.Header{}
|
||||
header.add_custom('Content-Type', 'text/plain')!
|
||||
header.add_custom('X-Priority', event.priority.str())!
|
||||
if event.tags.len > 0 {
|
||||
header.add_custom('X-Tags', join_tags(event.tags))!
|
||||
}
|
||||
if c.auth_token != '' {
|
||||
header.add(.authorization, 'Bearer ${c.auth_token}')
|
||||
}
|
||||
|
||||
c.logger.debug('ntfy', 'publish',
|
||||
'POST ${url} priority=${event.priority} tags=${join_tags(event.tags)}')
|
||||
|
||||
// Retry with exponential backoff: 3 attempts, 1s / 2s / 4s delays
|
||||
mut last_err := error('unknown')
|
||||
for attempt := 1; attempt <= 3; attempt++ {
|
||||
resp := http.fetch(http.FetchConfig{
|
||||
url: url
|
||||
method: .post
|
||||
header: header
|
||||
data: event.message
|
||||
}) or {
|
||||
last_err = err
|
||||
if attempt < 3 {
|
||||
delay := time.second * (1 << (attempt - 1))
|
||||
c.logger.warn('ntfy', 'publish',
|
||||
'attempt ${attempt}/3 failed: ${err}, retrying in ${delay}')
|
||||
time.sleep(delay)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if resp.status_code >= 200 && resp.status_code < 300 {
|
||||
c.logger.debug('ntfy', 'publish', 'success ${resp.status_code}')
|
||||
return
|
||||
}
|
||||
|
||||
last_err = error('ntfy returned ${resp.status_code}: ${resp.body}')
|
||||
if attempt < 3 {
|
||||
delay := time.second * (1 << (attempt - 1))
|
||||
c.logger.warn('ntfy', 'publish',
|
||||
'attempt ${attempt}/3 failed: ${last_err}, retrying in ${delay}')
|
||||
time.sleep(delay)
|
||||
}
|
||||
}
|
||||
|
||||
return last_err
|
||||
}
|
||||
Reference in New Issue
Block a user