github.com/igoogolx/clash@v1.19.8/adapter/provider/healthcheck.go (about) 1 package provider 2 3 import ( 4 "context" 5 "time" 6 7 "github.com/igoogolx/clash/common/batch" 8 C "github.com/igoogolx/clash/constant" 9 10 "github.com/samber/lo" 11 "go.uber.org/atomic" 12 ) 13 14 const ( 15 defaultURLTestTimeout = time.Second * 5 16 ) 17 18 type HealthCheckOption struct { 19 URL string 20 Interval uint 21 } 22 23 type HealthCheck struct { 24 url string 25 proxies []C.Proxy 26 interval uint 27 lazy bool 28 lastTouch *atomic.Int64 29 done chan struct{} 30 } 31 32 func (hc *HealthCheck) process() { 33 ticker := time.NewTicker(time.Duration(hc.interval) * time.Second) 34 35 go hc.checkAll() 36 for { 37 select { 38 case <-ticker.C: 39 now := time.Now().Unix() 40 if !hc.lazy || now-hc.lastTouch.Load() < int64(hc.interval) { 41 hc.checkAll() 42 } else { // lazy but still need to check not alive proxies 43 notAliveProxies := lo.Filter(hc.proxies, func(proxy C.Proxy, _ int) bool { 44 return !proxy.Alive() 45 }) 46 if len(notAliveProxies) != 0 { 47 hc.check(notAliveProxies) 48 } 49 } 50 case <-hc.done: 51 ticker.Stop() 52 return 53 } 54 } 55 } 56 57 func (hc *HealthCheck) setProxy(proxies []C.Proxy) { 58 hc.proxies = proxies 59 } 60 61 func (hc *HealthCheck) auto() bool { 62 return hc.interval != 0 63 } 64 65 func (hc *HealthCheck) touch() { 66 hc.lastTouch.Store(time.Now().Unix()) 67 } 68 69 func (hc *HealthCheck) checkAll() { 70 hc.check(hc.proxies) 71 } 72 73 func (hc *HealthCheck) check(proxies []C.Proxy) { 74 b, _ := batch.New(context.Background(), batch.WithConcurrencyNum(10)) 75 for _, proxy := range proxies { 76 p := proxy 77 b.Go(p.Name(), func() (any, error) { 78 ctx, cancel := context.WithTimeout(context.Background(), defaultURLTestTimeout) 79 defer cancel() 80 p.URLTest(ctx, hc.url) 81 return nil, nil 82 }) 83 } 84 b.Wait() 85 } 86 87 func (hc *HealthCheck) close() { 88 hc.done <- struct{}{} 89 } 90 91 func NewHealthCheck(proxies []C.Proxy, url string, interval uint, lazy bool) *HealthCheck { 92 return &HealthCheck{ 93 proxies: proxies, 94 url: url, 95 interval: interval, 96 lazy: lazy, 97 lastTouch: atomic.NewInt64(0), 98 done: make(chan struct{}, 1), 99 } 100 }