freifunkmanager/runtime/ping.go

113 lines
2.3 KiB
Go

package runtime
import (
"net"
"sync"
"time"
"github.com/FreifunkBremen/yanic/lib/duration"
"github.com/digineo/go-ping"
"github.com/jinzhu/gorm"
log "github.com/sirupsen/logrus"
"github.com/FreifunkBremen/freifunkmanager/data"
)
type PingerConfig struct {
Enable bool `toml:"enable"`
Every duration.Duration `toml:"every"`
Timeout duration.Duration `toml:"timeout"`
Count int `toml:"count"`
}
type Pinger struct {
db *gorm.DB
config *PingerConfig
blacklistFor time.Duration
sendResult func(*data.PingResult)
stop bool
wg sync.WaitGroup
p *ping.Pinger
}
func NewPinger(db *gorm.DB, config *PingerConfig, blacklistFor time.Duration, sendResult func(*data.PingResult)) (*Pinger, error) {
ping, err := ping.New("", "::")
if err != nil {
return nil, err
}
return &Pinger{
db: db,
config: config,
blacklistFor: blacklistFor,
sendResult: sendResult,
stop: false,
p: ping,
}, nil
}
func (pinger *Pinger) Start() {
pinger.wg.Add(1)
timer := time.NewTimer(pinger.config.Every.Duration)
for !pinger.stop {
select {
case <-timer.C:
pinger.run()
timer.Reset(pinger.config.Every.Duration)
}
}
timer.Stop()
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.config.Timeout.Duration, pinger.config.Count)
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)
}