Go backend that drives kernel WireGuard over netlink (wireguard-go as the fallback), nftables NAT with MSS clamping, forwarding and buffer sysctls, SQLite for peers, users, sessions, traffic history and the audit log. React console: dashboard with live rates and usage history, peer management with QR codes and .conf downloads, disconnect, session reset, key rotation, expiry, client-supplied keys, settings, users with admin and viewer roles, two-factor authentication with recovery codes, audit log. Docker image on Alpine with compose files for bridged and host networking, CI and GHCR publish workflows, performance notes.
61 lines
1.2 KiB
Go
61 lines
1.2 KiB
Go
package engine
|
|
|
|
import (
|
|
"encoding/json"
|
|
"sync"
|
|
)
|
|
|
|
// Event is one server-sent event.
|
|
type Event struct {
|
|
Name string
|
|
Data []byte
|
|
}
|
|
|
|
// Hub fans events out to every open dashboard. A subscriber that cannot keep
|
|
// up loses events rather than stalling the collector; the next status
|
|
// snapshot carries the full picture anyway.
|
|
type Hub struct {
|
|
mu sync.Mutex
|
|
subs map[chan Event]struct{}
|
|
}
|
|
|
|
// NewHub returns an empty hub.
|
|
func NewHub() *Hub { return &Hub{subs: map[chan Event]struct{}{}} }
|
|
|
|
// Subscribe returns a channel of events and a function to leave.
|
|
func (h *Hub) Subscribe() (<-chan Event, func()) {
|
|
ch := make(chan Event, 16)
|
|
h.mu.Lock()
|
|
h.subs[ch] = struct{}{}
|
|
h.mu.Unlock()
|
|
return ch, func() {
|
|
h.mu.Lock()
|
|
delete(h.subs, ch)
|
|
h.mu.Unlock()
|
|
}
|
|
}
|
|
|
|
// Publish encodes v as JSON and sends it to every subscriber.
|
|
func (h *Hub) Publish(name string, v any) {
|
|
data, err := json.Marshal(v)
|
|
if err != nil {
|
|
return
|
|
}
|
|
ev := Event{Name: name, Data: data}
|
|
h.mu.Lock()
|
|
defer h.mu.Unlock()
|
|
for ch := range h.subs {
|
|
select {
|
|
case ch <- ev:
|
|
default:
|
|
}
|
|
}
|
|
}
|
|
|
|
// Subscribers is how many dashboards are listening.
|
|
func (h *Hub) Subscribers() int {
|
|
h.mu.Lock()
|
|
defer h.mu.Unlock()
|
|
return len(h.subs)
|
|
}
|