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  }