From 5a61749328ae46dce6e5f43638a2d85f1f852015 Mon Sep 17 00:00:00 2001 From: Shelikhoo Date: Thu, 8 Apr 2021 20:55:25 +0100 Subject: [PATCH] add least balancing strategy --- app/router/balancing.go | 8 ++++ app/router/config.proto | 1 + app/router/router.go | 4 +- app/router/strategy_leastping.go | 57 +++++++++++++++++++++++++++ features/extension/contextreceiver.go | 7 ++++ features/extension/observatory.go | 2 + 6 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 app/router/strategy_leastping.go create mode 100644 features/extension/contextreceiver.go diff --git a/app/router/balancing.go b/app/router/balancing.go index 53088b6de..6b313eb09 100644 --- a/app/router/balancing.go +++ b/app/router/balancing.go @@ -3,7 +3,10 @@ package router import ( + "context" + "github.com/v2fly/v2ray-core/v4/common/dice" + "github.com/v2fly/v2ray-core/v4/features/extension" "github.com/v2fly/v2ray-core/v4/features/outbound" ) @@ -44,3 +47,8 @@ func (b *Balancer) PickOutbound() (string, error) { } return tag, nil } +func (b *Balancer) InjectContext(ctx context.Context) { + if contextReceiver, ok := b.strategy.(extension.ContextReceiver); ok { + contextReceiver.InjectContext(ctx) + } +} diff --git a/app/router/config.proto b/app/router/config.proto index 1d80b2294..13cc19909 100644 --- a/app/router/config.proto +++ b/app/router/config.proto @@ -127,6 +127,7 @@ message RoutingRule { message BalancingRule { string tag = 1; repeated string outbound_selector = 2; + string strategy = 3; } message Config { diff --git a/app/router/router.go b/app/router/router.go index 45626585c..b67737a93 100644 --- a/app/router/router.go +++ b/app/router/router.go @@ -31,7 +31,7 @@ type Route struct { } // Init initializes the Router. -func (r *Router) Init(config *Config, d dns.Client, ohm outbound.Manager) error { +func (r *Router) Init(ctx context.Context, config *Config, d dns.Client, ohm outbound.Manager) error { r.domainStrategy = config.DomainStrategy r.dns = d @@ -142,7 +142,7 @@ func init() { common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { r := new(Router) if err := core.RequireFeatures(ctx, func(d dns.Client, ohm outbound.Manager) error { - return r.Init(config.(*Config), d, ohm) + return r.Init(ctx, config.(*Config), d, ohm) }); err != nil { return nil, err } diff --git a/app/router/strategy_leastping.go b/app/router/strategy_leastping.go new file mode 100644 index 000000000..e4244abfe --- /dev/null +++ b/app/router/strategy_leastping.go @@ -0,0 +1,57 @@ +package router + +import ( + "context" + + core "github.com/v2fly/v2ray-core/v4" + "github.com/v2fly/v2ray-core/v4/app/observatory" + "github.com/v2fly/v2ray-core/v4/common" + "github.com/v2fly/v2ray-core/v4/features/extension" +) + +type LeastPingStrategy struct { + ctx context.Context + observatory extension.Observatory +} + +func (l *LeastPingStrategy) InjectContext(ctx context.Context) { + common.Must(core.RequireFeatures(ctx, func(observatory extension.Observatory) error { + l.observatory = observatory + return nil + })) + l.ctx = ctx +} + +func (l *LeastPingStrategy) PickOutbound(strings []string) string { + observeReport, err := l.observatory.GetObservation(l.ctx) + if err != nil { + newError("cannot get observe report").Base(err).WriteToLog() + return "" + } + outboundsList := outboundList(strings) + if result, ok := observeReport.(*observatory.ObservationResult); ok { + status := result.Status + leastPing := int64(99999999) + selectedOutboundName := "" + for _, v := range status { + if outboundsList.contains(v.OutboundTag) && v.Alive && v.Delay < leastPing { + selectedOutboundName = v.OutboundTag + } + } + return selectedOutboundName + } + + //No way to understand observeReport + return "" +} + +type outboundList []string + +func (o outboundList) contains(name string) bool { + for _, v := range o { + if v == name { + return true + } + } + return false +} diff --git a/features/extension/contextreceiver.go b/features/extension/contextreceiver.go new file mode 100644 index 000000000..2d3394796 --- /dev/null +++ b/features/extension/contextreceiver.go @@ -0,0 +1,7 @@ +package extension + +import "context" + +type ContextReceiver interface { + InjectContext(ctx context.Context) +} diff --git a/features/extension/observatory.go b/features/extension/observatory.go index ca3bc751c..3c0d1a308 100644 --- a/features/extension/observatory.go +++ b/features/extension/observatory.go @@ -2,7 +2,9 @@ package extension import ( "context" + "github.com/golang/protobuf/proto" + "github.com/v2fly/v2ray-core/v4/features" )