Feature: add delay history and improve url-test behavior
This commit is contained in:
@ -6,6 +6,7 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/Dreamacro/clash/common/queue"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
)
|
||||
|
||||
@ -32,7 +33,8 @@ func (b *Base) MarshalJSON() ([]byte, error) {
|
||||
|
||||
type Proxy struct {
|
||||
C.ProxyAdapter
|
||||
alive bool
|
||||
history *queue.Queue
|
||||
alive bool
|
||||
}
|
||||
|
||||
func (p *Proxy) Alive() bool {
|
||||
@ -45,8 +47,54 @@ func (p *Proxy) Dial(metadata *C.Metadata) (net.Conn, error) {
|
||||
return conn, err
|
||||
}
|
||||
|
||||
func (p *Proxy) DelayHistory() []C.DelayHistory {
|
||||
queue := p.history.Copy()
|
||||
histories := []C.DelayHistory{}
|
||||
for _, item := range queue {
|
||||
histories = append(histories, item.(C.DelayHistory))
|
||||
}
|
||||
return histories
|
||||
}
|
||||
|
||||
func (p *Proxy) LastDelay() (delay uint16) {
|
||||
head := p.history.First()
|
||||
if head == nil {
|
||||
delay--
|
||||
return
|
||||
}
|
||||
history := head.(C.DelayHistory)
|
||||
if history.Delay == 0 {
|
||||
delay--
|
||||
return
|
||||
}
|
||||
return history.Delay
|
||||
}
|
||||
|
||||
func (p *Proxy) MarshalJSON() ([]byte, error) {
|
||||
inner, err := p.ProxyAdapter.MarshalJSON()
|
||||
if err != nil {
|
||||
return inner, err
|
||||
}
|
||||
|
||||
mapping := map[string]interface{}{}
|
||||
json.Unmarshal(inner, &mapping)
|
||||
mapping["history"] = p.DelayHistory()
|
||||
return json.Marshal(mapping)
|
||||
}
|
||||
|
||||
// URLTest get the delay for the specified URL
|
||||
func (p *Proxy) URLTest(url string) (t int16, err error) {
|
||||
func (p *Proxy) URLTest(url string) (t uint16, err error) {
|
||||
defer func() {
|
||||
record := C.DelayHistory{Time: time.Now()}
|
||||
if err == nil {
|
||||
record.Delay = t
|
||||
}
|
||||
p.history.Put(record)
|
||||
if p.history.Len() > 10 {
|
||||
p.history.Pop()
|
||||
}
|
||||
}()
|
||||
|
||||
addr, err := urlToMetadata(url)
|
||||
if err != nil {
|
||||
return
|
||||
@ -74,10 +122,10 @@ func (p *Proxy) URLTest(url string) (t int16, err error) {
|
||||
return
|
||||
}
|
||||
resp.Body.Close()
|
||||
t = int16(time.Since(start) / time.Millisecond)
|
||||
t = uint16(time.Since(start) / time.Millisecond)
|
||||
return
|
||||
}
|
||||
|
||||
func NewProxy(adapter C.ProxyAdapter) *Proxy {
|
||||
return &Proxy{adapter, true}
|
||||
return &Proxy{adapter, queue.New(10), true}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ func (u *URLTest) Now() string {
|
||||
func (u *URLTest) Dial(metadata *C.Metadata) (net.Conn, error) {
|
||||
a, err := u.fast.Dial(metadata)
|
||||
if err != nil {
|
||||
go u.speedTest()
|
||||
u.fallback()
|
||||
}
|
||||
return a, err
|
||||
}
|
||||
@ -74,6 +74,23 @@ Loop:
|
||||
}
|
||||
}
|
||||
|
||||
func (u *URLTest) fallback() {
|
||||
fast := u.proxies[0]
|
||||
min := fast.LastDelay()
|
||||
for _, proxy := range u.proxies[1:] {
|
||||
if !proxy.Alive() {
|
||||
continue
|
||||
}
|
||||
|
||||
delay := proxy.LastDelay()
|
||||
if delay < min {
|
||||
fast = proxy
|
||||
min = delay
|
||||
}
|
||||
}
|
||||
u.fast = fast
|
||||
}
|
||||
|
||||
func (u *URLTest) speedTest() {
|
||||
if atomic.AddInt32(&u.once, 1) != 1 {
|
||||
return
|
||||
|
Reference in New Issue
Block a user