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

View file

@ -4,6 +4,8 @@ import (
"encoding/json"
"errors"
"net"
"sync"
"time"
"github.com/Dreamacro/clash/common/murmur3"
C "github.com/Dreamacro/clash/constant"
@ -15,6 +17,9 @@ type LoadBalance struct {
*Base
proxies []C.Proxy
maxRetry int
rawURL string
interval time.Duration
done chan struct{}
}
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)
}
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) {
var all []string
for _, proxy := range lb.proxies {
@ -74,21 +111,30 @@ func (lb *LoadBalance) MarshalJSON() ([]byte, error) {
}
type LoadBalanceOption struct {
Name string `proxy:"name"`
Proxies []string `proxy:"proxies"`
Name string `proxy:"name"`
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 {
return nil, errors.New("Provide at least one proxy")
}
return &LoadBalance{
interval := time.Duration(option.Interval) * time.Second
lb := &LoadBalance{
Base: &Base{
name: name,
name: option.Name,
tp: C.LoadBalance,
},
proxies: proxies,
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 {
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 {
return nil, fmt.Errorf("Proxy %s: %s", groupName, err.Error())