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