Skip to content

Commit

Permalink
Feature: support proxy-group in relay (#597)
Browse files Browse the repository at this point in the history
  • Loading branch information
duament authored May 7, 2020
1 parent b979ff0 commit 752f87a
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 22 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ proxies:
# skip-cert-verify: true

proxy-groups:
# relay chains the proxies. proxies shall not contain a proxy-group. No UDP support.
# relay chains the proxies. proxies shall not contain a relay. No UDP support.
# Traffic: clash <-> http <-> vmess <-> ss1 <-> ss2 <-> Internet
- name: "relay"
type: relay
Expand Down
4 changes: 4 additions & 0 deletions adapters/outbound/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ func (b *Base) Addr() string {
return b.addr
}

func (b *Base) Unwrap(metadata *C.Metadata) C.Proxy {
return nil
}

func NewBase(name string, addr string, tp C.AdapterType, udp bool) *Base {
return &Base{name, addr, tp, udp}
}
Expand Down
5 changes: 5 additions & 0 deletions adapters/outboundgroup/fallback.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ func (f *Fallback) MarshalJSON() ([]byte, error) {
})
}

func (f *Fallback) Unwrap(metadata *C.Metadata) C.Proxy {
proxy := f.findAliveProxy()
return proxy
}

func (f *Fallback) proxies() []C.Proxy {
elm, _, _ := f.single.Do(func() (interface{}, error) {
return getProvidersProxies(f.providers), nil
Expand Down
33 changes: 15 additions & 18 deletions adapters/outboundgroup/loadbalance.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,9 @@ func (lb *LoadBalance) DialContext(ctx context.Context, metadata *C.Metadata) (c
}
}()

key := uint64(murmur3.Sum32([]byte(getKey(metadata))))
proxies := lb.proxies()
buckets := int32(len(proxies))
for i := 0; i < lb.maxRetry; i, key = i+1, key+1 {
idx := jumpHash(key, buckets)
proxy := proxies[idx]
if proxy.Alive() {
c, err = proxy.DialContext(ctx, metadata)
return
}
}
c, err = proxies[0].DialContext(ctx, metadata)
proxy := lb.Unwrap(metadata)

c, err = proxy.DialContext(ctx, metadata)
return
}

Expand All @@ -81,22 +72,28 @@ func (lb *LoadBalance) DialUDP(metadata *C.Metadata) (pc C.PacketConn, err error
}
}()

proxy := lb.Unwrap(metadata)

return proxy.DialUDP(metadata)
}

func (lb *LoadBalance) SupportUDP() bool {
return true
}

func (lb *LoadBalance) Unwrap(metadata *C.Metadata) C.Proxy {
key := uint64(murmur3.Sum32([]byte(getKey(metadata))))
proxies := lb.proxies()
buckets := int32(len(proxies))
for i := 0; i < lb.maxRetry; i, key = i+1, key+1 {
idx := jumpHash(key, buckets)
proxy := proxies[idx]
if proxy.Alive() {
return proxy.DialUDP(metadata)
return proxy
}
}

return proxies[0].DialUDP(metadata)
}

func (lb *LoadBalance) SupportUDP() bool {
return true
return proxies[0]
}

func (lb *LoadBalance) proxies() []C.Proxy {
Expand Down
20 changes: 17 additions & 3 deletions adapters/outboundgroup/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type Relay struct {
}

func (r *Relay) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn, error) {
proxies := r.proxies()
proxies := r.proxies(metadata)
if len(proxies) == 0 {
return nil, errors.New("Proxy does not exist")
}
Expand Down Expand Up @@ -58,7 +58,7 @@ func (r *Relay) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn,

func (r *Relay) MarshalJSON() ([]byte, error) {
var all []string
for _, proxy := range r.proxies() {
for _, proxy := range r.rawProxies() {
all = append(all, proxy.Name())
}
return json.Marshal(map[string]interface{}{
Expand All @@ -67,14 +67,28 @@ func (r *Relay) MarshalJSON() ([]byte, error) {
})
}

func (r *Relay) proxies() []C.Proxy {
func (r *Relay) rawProxies() []C.Proxy {
elm, _, _ := r.single.Do(func() (interface{}, error) {
return getProvidersProxies(r.providers), nil
})

return elm.([]C.Proxy)
}

func (r *Relay) proxies(metadata *C.Metadata) []C.Proxy {
proxies := r.rawProxies()

for n, proxy := range proxies {
subproxy := proxy.Unwrap(metadata)
for subproxy != nil {
proxies[n] = subproxy
subproxy = subproxy.Unwrap(metadata)
}
}

return proxies
}

func NewRelay(name string, providers []provider.ProxyProvider) *Relay {
return &Relay{
Base: outbound.NewBase(name, "", C.Relay, false),
Expand Down
4 changes: 4 additions & 0 deletions adapters/outboundgroup/selector.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ func (s *Selector) Set(name string) error {
return errors.New("Proxy does not exist")
}

func (s *Selector) Unwrap(metadata *C.Metadata) C.Proxy {
return s.selectedProxy()
}

func (s *Selector) selectedProxy() C.Proxy {
elm, _, _ := s.single.Do(func() (interface{}, error) {
proxies := getProvidersProxies(s.providers)
Expand Down
4 changes: 4 additions & 0 deletions adapters/outboundgroup/urltest.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ func (u *URLTest) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
return pc, err
}

func (u *URLTest) Unwrap(metadata *C.Metadata) C.Proxy {
return u.fast()
}

func (u *URLTest) proxies() []C.Proxy {
elm, _, _ := u.single.Do(func() (interface{}, error) {
return getProvidersProxies(u.providers), nil
Expand Down
2 changes: 2 additions & 0 deletions constant/adapters.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ type ProxyAdapter interface {
SupportUDP() bool
MarshalJSON() ([]byte, error)
Addr() string
// Unwrap extracts the proxy from a proxy-group. It returns nil when nothing to extract.
Unwrap(metadata *Metadata) Proxy
}

type DelayHistory struct {
Expand Down

0 comments on commit 752f87a

Please sign in to comment.