Files
ntfy-bridge/docker_watcher.v
bruno 1a4808f5f7
CI / test (push) Has been cancelled
feat: v0.6.0 — ACLs multi-utilisateurs + Plugin system
**ACLs (Access Control Lists):**
- Ajout du type AclConfig dans sources/event.v (allowed_ips CIDR + allowed_tokens)
- Chaque source webhook (Gitea, Uptime Kuma, Cron, Generic) supporte les ACLs
- Validation IP via X-Forwarded-For / X-Real-IP avant HMAC
- Validation Bearer token via Authorization header
- Tests: 7 tests ACL (IP exact, CIDR, parse IPv4, ACL vide, IP+token combiné)

**Plugin system:**
- sources/plugin.v: runner exécutable externe, stdout JSON → Event
- Exit 0 = publish, exit ≠ 0 = skip. Timeout configurable
- Plugin loop dans server.v (goroutine, toutes les 60s)
- Example: scripts/example-plugin-disk.sh (vérifie espace disque)

**Docs:**
- README.md: ajout source Plugin + section Features complète
- ARCHITECTURE.md: flux Plugin, flux ACL, endpoints /metrics /api/silence
- ROADMAP.md: Phase 5 → 8/8 complet, ajout v0.6.0
- ntfy-bridge.example.yaml: sections ACLs et Plugins commentées
- Version bump: 0.5.0 → 0.6.0
2026-08-04 22:25:48 -04:00

76 lines
1.6 KiB
V

module main
import time
$if linux || macos {
import net.unix
import os
import sources
}
fn (mut app App) docker_watch_loop() {
$if linux || macos {
for {
for src in app.cfg.sources.docker {
for host in src.hosts {
app.watch_docker_host(src, host)
}
}
time.sleep(10 * time.second)
}
} $else {
app.logger.warn('docker', 'watch',
'Docker socket watching is only supported on Linux/macOS')
for {
time.sleep(60 * time.second)
}
}
}
$if linux || macos {
fn (mut app App) watch_docker_host(src sources.DockerSource, host string) {
socket_path := host.replace('unix://', '')
if !os.exists(socket_path) {
app.logger.warn('docker', 'watch', 'socket not found: ${socket_path}')
return
}
mut conn := unix.connect_stream(socket_path) or {
app.logger.warn('docker', 'watch', 'failed to connect to ${socket_path}: ${err}')
return
}
defer {
conn.close() or {}
}
filters := build_docker_filters(src.events)
request := 'GET /events?filters=${filters} HTTP/1.1\r\nHost: localhost\r\n\r\n'
conn.write_string(request) or {
app.logger.warn('docker', 'watch', 'write error: ${err}')
return
}
mut buf := []u8{len: 4096}
for {
read := conn.read(mut buf) or { break }
if read <= 0 {
break
}
lines := buf[..read].bytestr().split_into_lines()
for line in lines {
if line.starts_with('{') {
event := sources.transform_docker_event(line, src, host) or { continue }
app.publish(event)
}
}
}
}
fn build_docker_filters(events []string) string {
mut parts := []string{}
for event in events {
parts << '"${event}":true'
}
return '{' + parts.join(',') + '}'
}
}