This commit is contained in:
jdl
2026-06-10 19:17:55 +02:00
parent db78964033
commit f89f5d5083
7 changed files with 260 additions and 65 deletions

View File

@@ -21,6 +21,7 @@ type HubPoller struct {
vpnNet netip.Prefix
hubURL string
apiKey string
statePath string // where the network state cache is persisted
addCh chan<- HubPeer
removeCh chan<- wgtypes.Key
known map[wgtypes.Key]int64 // pubKey → last seen version
@@ -30,6 +31,7 @@ func NewHubPoller(
selfVPNIP netip.Addr,
vpnNet netip.Prefix,
hubURL, apiKey string,
statePath string,
addCh chan<- HubPeer,
removeCh chan<- wgtypes.Key,
) (*HubPoller, error) {
@@ -44,6 +46,7 @@ func NewHubPoller(
vpnNet: vpnNet,
hubURL: u.String(),
apiKey: apiKey,
statePath: statePath,
addCh: addCh,
removeCh: removeCh,
known: make(map[wgtypes.Key]int64),
@@ -51,6 +54,14 @@ func NewHubPoller(
}
func (hp *HubPoller) Run() {
// Prime from the on-disk cache before reaching the hub, so the peer
// configures WireGuard from its last known state even if the hub is down.
// known starts empty, so this emits every cached peer as an add and seeds
// the version map; the first real poll then emits only deltas.
if state, err := loadNetworkState(hp.statePath); err == nil {
hp.apply(state)
}
hp.poll()
for range time.Tick(hubPollInterval) {
hp.poll()
@@ -90,10 +101,19 @@ func (hp *HubPoller) poll() {
return
}
hp.apply(state)
// Persist only when the state actually changed, to avoid needless writes
// on every poll.
if hp.apply(state) {
if err := saveNetworkState(hp.statePath, state); err != nil {
log.Printf("[HubPoller] save state: %v", err)
}
}
}
func (hp *HubPoller) apply(state m.NetworkState) {
// apply diffs state against the known versions, emitting add events for new or
// changed peers and remove events for peers that disappeared. It returns true
// if anything changed.
func (hp *HubPoller) apply(state m.NetworkState) (changed bool) {
seen := make(map[wgtypes.Key]struct{}, len(hp.known))
netAddr := hp.vpnNet.Addr().As4()
@@ -122,14 +142,18 @@ func (hp *HubPoller) apply(state m.NetworkState) {
}
hp.known[pubKey] = p.Version
hp.addCh <- hubPeerFrom(pubKey, vpnIP, p)
changed = true
}
for key := range hp.known {
if _, ok := seen[key]; !ok {
delete(hp.known, key)
hp.removeCh <- key
changed = true
}
}
return changed
}
func hubPeerFrom(pubKey wgtypes.Key, vpnIP netip.Addr, p *m.Peer) HubPeer {