Feature: add interval url test for load-balance

This commit is contained in:
Dreamacro 2019-03-28 19:00:41 +08:00
parent d3b280a7e5
commit 18f885a92a
3 changed files with 57 additions and 8 deletions

View file

@ -43,7 +43,9 @@ func (p *Proxy) Alive() bool {
func (p *Proxy) Dial(metadata *C.Metadata) (net.Conn, error) { func (p *Proxy) Dial(metadata *C.Metadata) (net.Conn, error) {
conn, err := p.ProxyAdapter.Dial(metadata) conn, err := p.ProxyAdapter.Dial(metadata)
p.alive = err == nil if err != nil {
p.alive = false
}
return conn, err return conn, err
} }
@ -89,6 +91,7 @@ func (p *Proxy) MarshalJSON() ([]byte, error) {
// URLTest get the delay for the specified URL // URLTest get the delay for the specified URL
func (p *Proxy) URLTest(url string) (t uint16, err error) { func (p *Proxy) URLTest(url string) (t uint16, err error) {
defer func() { defer func() {
p.alive = err == nil
record := C.DelayHistory{Time: time.Now()} record := C.DelayHistory{Time: time.Now()}
if err == nil { if err == nil {
record.Delay = t record.Delay = t

View file

@ -4,6 +4,8 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"net" "net"
"sync"
"time"
"github.com/Dreamacro/clash/common/murmur3" "github.com/Dreamacro/clash/common/murmur3"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
@ -15,6 +17,9 @@ type LoadBalance struct {
*Base *Base
proxies []C.Proxy proxies []C.Proxy
maxRetry int maxRetry int
rawURL string
interval time.Duration
done chan struct{}
} }
func getKey(metadata *C.Metadata) string { func getKey(metadata *C.Metadata) string {
@ -62,6 +67,38 @@ func (lb *LoadBalance) Dial(metadata *C.Metadata) (net.Conn, error) {
return lb.proxies[0].Dial(metadata) return lb.proxies[0].Dial(metadata)
} }
func (lb *LoadBalance) Destroy() {
lb.done <- struct{}{}
}
func (lb *LoadBalance) validTest() {
wg := sync.WaitGroup{}
wg.Add(len(lb.proxies))
for _, p := range lb.proxies {
go func(p C.Proxy) {
p.URLTest(lb.rawURL)
wg.Done()
}(p)
}
wg.Wait()
}
func (lb *LoadBalance) loop() {
tick := time.NewTicker(lb.interval)
go lb.validTest()
Loop:
for {
select {
case <-tick.C:
go lb.validTest()
case <-lb.done:
break Loop
}
}
}
func (lb *LoadBalance) MarshalJSON() ([]byte, error) { func (lb *LoadBalance) MarshalJSON() ([]byte, error) {
var all []string var all []string
for _, proxy := range lb.proxies { for _, proxy := range lb.proxies {
@ -76,19 +113,28 @@ func (lb *LoadBalance) MarshalJSON() ([]byte, error) {
type LoadBalanceOption struct { type LoadBalanceOption struct {
Name string `proxy:"name"` Name string `proxy:"name"`
Proxies []string `proxy:"proxies"` Proxies []string `proxy:"proxies"`
URL string `proxy:"url"`
Interval int `proxy:"interval"`
} }
func NewLoadBalance(name string, proxies []C.Proxy) (*LoadBalance, error) { func NewLoadBalance(option LoadBalanceOption, proxies []C.Proxy) (*LoadBalance, error) {
if len(proxies) == 0 { if len(proxies) == 0 {
return nil, errors.New("Provide at least one proxy") return nil, errors.New("Provide at least one proxy")
} }
return &LoadBalance{ interval := time.Duration(option.Interval) * time.Second
lb := &LoadBalance{
Base: &Base{ Base: &Base{
name: name, name: option.Name,
tp: C.LoadBalance, tp: C.LoadBalance,
}, },
proxies: proxies, proxies: proxies,
maxRetry: 3, maxRetry: 3,
}, nil rawURL: option.URL,
interval: interval,
done: make(chan struct{}),
}
go lb.loop()
return lb, nil
} }

View file

@ -302,7 +302,7 @@ func parseProxies(cfg *rawConfig) (map[string]C.Proxy, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("ProxyGroup %s: %s", groupName, err.Error()) return nil, fmt.Errorf("ProxyGroup %s: %s", groupName, err.Error())
} }
group, err = adapters.NewLoadBalance(loadBalanceOption.Name, ps) group, err = adapters.NewLoadBalance(*loadBalanceOption, ps)
} }
if err != nil { if err != nil {
return nil, fmt.Errorf("Proxy %s: %s", groupName, err.Error()) return nil, fmt.Errorf("Proxy %s: %s", groupName, err.Error())