From aa2917b1a0412d5cd5eb4acef71d643072d5a67e Mon Sep 17 00:00:00 2001 From: Martin/Geno Date: Mon, 3 Jun 2019 15:38:46 +0200 Subject: [PATCH] Add backend pinger --- data/ping_result.go | 6 +++ main.go | 6 +++ runtime/ping.go | 104 ++++++++++++++++++++++++++++++++++++++++++++ websocket/send.go | 5 ++- 4 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 data/ping_result.go create mode 100644 runtime/ping.go diff --git a/data/ping_result.go b/data/ping_result.go new file mode 100644 index 0000000..b6225d2 --- /dev/null +++ b/data/ping_result.go @@ -0,0 +1,6 @@ +package data + +type PingResult struct { + True []string `json:"true"` + False []string `json:"false"` +} \ No newline at end of file diff --git a/main.go b/main.go index 25f1af0..0d9b30d 100644 --- a/main.go +++ b/main.go @@ -56,6 +56,12 @@ func main() { ws := websocket.NewWebsocketServer(config.Secret, config.SSHIPAddressPrefix, db, config.BlacklistFor.Duration, nodesYanic) yanic := runtime.NewYanicDB(db, sshmanager, config.BlacklistFor.Duration, ws.SendNode, ws.SendStats, config.SSHIPAddressPrefix) + + pinger, err := runtime.NewPinger(db, config.BlacklistFor.Duration, ws.SendPing) + if err != nil { + log.Panic(err) + } + go pinger.Start() if config.YanicEnable { if duration := config.YanicSynchronize.Duration; duration > 0 { diff --git a/runtime/ping.go b/runtime/ping.go new file mode 100644 index 0000000..16dd48c --- /dev/null +++ b/runtime/ping.go @@ -0,0 +1,104 @@ +package runtime + +import ( + "net" + "time" + "sync" + + log "github.com/sirupsen/logrus" + "github.com/digineo/go-ping" + "github.com/jinzhu/gorm" + + "github.com/FreifunkBremen/freifunkmanager/data" +) + +type Pinger struct { + db *gorm.DB + blacklistFor time.Duration + sendResult func(*data.PingResult) + + stop bool + wg sync.WaitGroup + + p *ping.Pinger + pingTimeout time.Duration + pingCount int +} + +func NewPinger(db *gorm.DB, blacklistFor time.Duration, sendResult func(*data.PingResult)) (*Pinger, error) { + ping, err := ping.New("", "::") + if err != nil { + return nil, err + } + + return &Pinger{ + db: db, + blacklistFor: blacklistFor, + sendResult: sendResult, + + stop: false, + + p: ping, + pingTimeout: time.Duration(time.Second), + pingCount: 2, + }, nil +} + +func (pinger *Pinger) Start() { + pinger.wg.Add(1) + for !pinger.stop { + pinger.run() + } + pinger.wg.Done() +} + +func (pinger *Pinger) Stop() { + pinger.stop = true + pinger.wg.Wait() +} + +func (pinger *Pinger) run() { + result := &data.PingResult{} + now := time.Now() + + count := 0 + var nodes []*Node + + pinger.db.Find(&nodes).Count(&count) + + wg := sync.WaitGroup{} + wg.Add(count) + + for _, node := range nodes { + go func(n *Node) { + defer wg.Done() + if n.Blacklist.After(now.Add(-pinger.blacklistFor)) { + return + } + + addr, err := net.ResolveIPAddr("ip6", n.Address) + if err != nil { + return + } + + _, err = pinger.p.PingAttempts(addr, pinger.pingTimeout, pinger.pingCount) + + if err == nil { + result.True = append(result.True, n.NodeID) + } else { + result.False = append(result.False, n.NodeID) + } + + }(node) + } + wg.Wait() + + log.WithFields(map[string]interface{}{ + "count": count, + "count_skipped": count - (len(result.True) + len(result.False)), + "count_false": len(result.False), + "count_true": len(result.True), + }).Debug("pinger complete") + + pinger.sendResult(result) +} \ No newline at end of file diff --git a/websocket/send.go b/websocket/send.go index 65f694e..bf36245 100644 --- a/websocket/send.go +++ b/websocket/send.go @@ -6,6 +6,7 @@ import ( yanicRuntime "github.com/FreifunkBremen/yanic/runtime" "github.com/FreifunkBremen/freifunkmanager/runtime" + "github.com/FreifunkBremen/freifunkmanager/data" ) func (ws *WebsocketServer) SendNode(node *runtime.Node) { @@ -15,9 +16,9 @@ func (ws *WebsocketServer) SendNode(node *runtime.Node) { func (ws *WebsocketServer) SendStats(data *yanicRuntime.GlobalStats) { ws.ws.SendAll(&wsLib.Message{Subject: MessageTypeStats, Body: data}) } -func (ws *WebsocketServer) SendPing(data interface{}) { +func (ws *WebsocketServer) SendPing(pResult *data.PingResult) { var sessions []*Session - msg := &wsLib.Message{Subject: MessageTypePing, Body: data} + msg := &wsLib.Message{Subject: MessageTypePing, Body: pResult} ws.db.Find(&sessions) for _, session := range sessions {