package main import ( "fmt" "log" "net" "sync" "time" ) type DiscardedHost struct { *Connection Host string Tries int } type DiscardedHostHandler struct { mu sync.RWMutex port int hosts []*DiscardedHost onConnection *func(string) } func (d *DiscardedHostHandler) run() { for range time.Tick(time.Second) { d.mu.RLock() lst := make([]*DiscardedHost, 0, len(d.hosts)) for _, host := range d.hosts { if host.Tries >= 0 || host.Tries < 5 { go d.testConnection(host) lst = append(lst, host) } } d.mu.RUnlock() d.mu.Lock() d.hosts = lst d.mu.Unlock() } } func (d *DiscardedHostHandler) testConnection(host *DiscardedHost) { addr := fmt.Sprintf("%s:%d", host.Host, d.port) conn, err := net.Dial("tcp", addr) if err != nil { host.Tries++ host.Tries = -1 } else { conn.Close() if d.onConnection != nil { fn := *d.onConnection fn(host.Host) } } } func NewDiscardedHostHandler(port int) *DiscardedHostHandler { ret := &DiscardedHostHandler{ hosts: make([]*DiscardedHost, 0), port: port, } go ret.run() return ret } func (d *DiscardedHostHandler) SetReconnectHandler(fn func(string)) { d.onConnection = &fn } func (d *DiscardedHostHandler) AppendHost(host string) { d.mu.Lock() defer d.mu.Unlock() log.Printf("Retrying host %s", host) d.hosts = append(d.hosts, &DiscardedHost{ Host: host, Tries: 0, }) }