mirror of
https://github.com/v2fly/v2ray-core.git
synced 2025-01-02 07:26:24 -05:00
v5: Health Check & LeastLoad Strategy (rebased from 2c5a714903
)
Some changes will be necessary to integrate it into V2Ray
This commit is contained in:
parent
dde9463275
commit
fa0cf6db26
@ -207,10 +207,16 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
|
|||||||
content = new(session.Content)
|
content = new(session.Content)
|
||||||
ctx = session.ContextWithContent(ctx, content)
|
ctx = session.ContextWithContent(ctx, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handler := session.HandlerFromContext(ctx)
|
||||||
sniffingRequest := content.SniffingRequest
|
sniffingRequest := content.SniffingRequest
|
||||||
switch {
|
switch {
|
||||||
case !sniffingRequest.Enabled:
|
case !sniffingRequest.Enabled:
|
||||||
go d.routedDispatch(ctx, outbound, destination)
|
if handler != nil {
|
||||||
|
go d.targetedDispatch(ctx, outbound, handler.Tag)
|
||||||
|
} else {
|
||||||
|
go d.routedDispatch(ctx, outbound, destination)
|
||||||
|
}
|
||||||
case destination.Network != net.Network_TCP:
|
case destination.Network != net.Network_TCP:
|
||||||
// Only metadata sniff will be used for non tcp connection
|
// Only metadata sniff will be used for non tcp connection
|
||||||
result, err := sniffer(ctx, nil, true)
|
result, err := sniffer(ctx, nil, true)
|
||||||
@ -240,7 +246,11 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
|
|||||||
destination.Address = net.ParseAddress(domain)
|
destination.Address = net.ParseAddress(domain)
|
||||||
ob.Target = destination
|
ob.Target = destination
|
||||||
}
|
}
|
||||||
d.routedDispatch(ctx, outbound, destination)
|
if handler != nil {
|
||||||
|
d.targetedDispatch(ctx, outbound, handler.Tag)
|
||||||
|
} else {
|
||||||
|
d.routedDispatch(ctx, outbound, destination)
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
return inbound, nil
|
return inbound, nil
|
||||||
@ -292,6 +302,25 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool) (Sni
|
|||||||
return contentResult, contentErr
|
return contentResult, contentErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO Pending removal for tagged connection
|
||||||
|
func (d *DefaultDispatcher) targetedDispatch(ctx context.Context, link *transport.Link, tag string) {
|
||||||
|
handler := d.ohm.GetHandler(tag)
|
||||||
|
if handler == nil {
|
||||||
|
newError("outbound handler [", tag, "] not exist").AtError().WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
common.Close(link.Writer)
|
||||||
|
common.Interrupt(link.Reader)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if accessMessage := log.AccessMessageFromContext(ctx); accessMessage != nil {
|
||||||
|
if tag := handler.Tag(); tag != "" {
|
||||||
|
accessMessage.Detour = tag
|
||||||
|
}
|
||||||
|
log.Record(accessMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
handler.Dispatch(ctx, link)
|
||||||
|
}
|
||||||
|
|
||||||
func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination) {
|
func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination) {
|
||||||
var handler outbound.Handler
|
var handler outbound.Handler
|
||||||
|
|
||||||
|
@ -5,8 +5,8 @@ package router
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/v2fly/v2ray-core/v4/features/routing"
|
||||||
|
|
||||||
"github.com/v2fly/v2ray-core/v4/common/dice"
|
|
||||||
"github.com/v2fly/v2ray-core/v4/features/extension"
|
"github.com/v2fly/v2ray-core/v4/features/extension"
|
||||||
"github.com/v2fly/v2ray-core/v4/features/outbound"
|
"github.com/v2fly/v2ray-core/v4/features/outbound"
|
||||||
)
|
)
|
||||||
@ -15,34 +15,37 @@ type BalancingStrategy interface {
|
|||||||
PickOutbound([]string) string
|
PickOutbound([]string) string
|
||||||
}
|
}
|
||||||
|
|
||||||
type RandomStrategy struct{}
|
|
||||||
|
|
||||||
func (s *RandomStrategy) PickOutbound(tags []string) string {
|
|
||||||
n := len(tags)
|
|
||||||
if n == 0 {
|
|
||||||
panic("0 tags")
|
|
||||||
}
|
|
||||||
|
|
||||||
return tags[dice.Roll(n)]
|
|
||||||
}
|
|
||||||
|
|
||||||
type Balancer struct {
|
type Balancer struct {
|
||||||
selectors []string
|
selectors []string
|
||||||
strategy BalancingStrategy
|
strategy routing.BalancingStrategy
|
||||||
ohm outbound.Manager
|
ohm outbound.Manager
|
||||||
|
fallbackTag string
|
||||||
|
|
||||||
|
override overridden
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PickOutbound picks the tag of a outbound
|
||||||
func (b *Balancer) PickOutbound() (string, error) {
|
func (b *Balancer) PickOutbound() (string, error) {
|
||||||
hs, ok := b.ohm.(outbound.HandlerSelector)
|
candidates, err := b.SelectOutbounds()
|
||||||
if !ok {
|
if err != nil {
|
||||||
return "", newError("outbound.Manager is not a HandlerSelector")
|
if b.fallbackTag != "" {
|
||||||
|
newError("fallback to [", b.fallbackTag, "], due to error: ", err).AtInfo().WriteToLog()
|
||||||
|
return b.fallbackTag, nil
|
||||||
|
}
|
||||||
|
return "", err
|
||||||
}
|
}
|
||||||
tags := hs.Select(b.selectors)
|
var tag string
|
||||||
if len(tags) == 0 {
|
if o := b.override.Get(); o != nil {
|
||||||
return "", newError("no available outbounds selected")
|
tag = b.strategy.Pick(o.selects)
|
||||||
|
} else {
|
||||||
|
tag = b.strategy.SelectAndPick(candidates)
|
||||||
}
|
}
|
||||||
tag := b.strategy.PickOutbound(tags)
|
|
||||||
if tag == "" {
|
if tag == "" {
|
||||||
|
if b.fallbackTag != "" {
|
||||||
|
newError("fallback to [", b.fallbackTag, "], due to empty tag returned").AtInfo().WriteToLog()
|
||||||
|
return b.fallbackTag, nil
|
||||||
|
}
|
||||||
|
// will use default handler
|
||||||
return "", newError("balancing strategy returns empty tag")
|
return "", newError("balancing strategy returns empty tag")
|
||||||
}
|
}
|
||||||
return tag, nil
|
return tag, nil
|
||||||
@ -53,3 +56,13 @@ func (b *Balancer) InjectContext(ctx context.Context) {
|
|||||||
contextReceiver.InjectContext(ctx)
|
contextReceiver.InjectContext(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SelectOutbounds select outbounds with selectors of the Balancer
|
||||||
|
func (b *Balancer) SelectOutbounds() ([]string, error) {
|
||||||
|
hs, ok := b.ohm.(outbound.HandlerSelector)
|
||||||
|
if !ok {
|
||||||
|
return nil, newError("outbound.Manager is not a HandlerSelector")
|
||||||
|
}
|
||||||
|
tags := hs.Select(b.selectors)
|
||||||
|
return tags, nil
|
||||||
|
}
|
||||||
|
83
app/router/balancing_override.go
Normal file
83
app/router/balancing_override.go
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
sync "sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/v2fly/v2ray-core/v4/features/outbound"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (b *Balancer) overrideSelecting(selects []string, validity time.Duration) error {
|
||||||
|
if validity <= 0 {
|
||||||
|
b.override.Clear()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
hs, ok := b.ohm.(outbound.HandlerSelector)
|
||||||
|
if !ok {
|
||||||
|
return newError("outbound.Manager is not a HandlerSelector")
|
||||||
|
}
|
||||||
|
tags := hs.Select(selects)
|
||||||
|
if len(tags) == 0 {
|
||||||
|
return newError("no outbound selected")
|
||||||
|
}
|
||||||
|
b.override.Put(tags, time.Now().Add(validity))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OverrideSelecting implements routing.BalancingOverrider
|
||||||
|
func (r *Router) OverrideSelecting(balancer string, selects []string, validity time.Duration) error {
|
||||||
|
var b *Balancer
|
||||||
|
for tag, bl := range r.balancers {
|
||||||
|
if tag == balancer {
|
||||||
|
b = bl
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if b == nil {
|
||||||
|
return newError("balancer '", balancer, "' not found")
|
||||||
|
}
|
||||||
|
err := b.overrideSelecting(selects, validity)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type overriddenSettings struct {
|
||||||
|
selects []string
|
||||||
|
until time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type overridden struct {
|
||||||
|
access sync.RWMutex
|
||||||
|
settings overriddenSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get gets the overridden settings
|
||||||
|
func (o *overridden) Get() *overriddenSettings {
|
||||||
|
o.access.RLock()
|
||||||
|
defer o.access.RUnlock()
|
||||||
|
if len(o.settings.selects) == 0 || time.Now().After(o.settings.until) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &overriddenSettings{
|
||||||
|
selects: o.settings.selects,
|
||||||
|
until: o.settings.until,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put updates the overridden settings
|
||||||
|
func (o *overridden) Put(selects []string, until time.Time) {
|
||||||
|
o.access.Lock()
|
||||||
|
defer o.access.Unlock()
|
||||||
|
o.settings.selects = selects
|
||||||
|
o.settings.until = until
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear clears the overridden settings
|
||||||
|
func (o *overridden) Clear() {
|
||||||
|
o.access.Lock()
|
||||||
|
defer o.access.Unlock()
|
||||||
|
o.settings.selects = nil
|
||||||
|
o.settings.until = time.Time{}
|
||||||
|
}
|
@ -8,6 +8,9 @@ import (
|
|||||||
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
|
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
|
||||||
core "github.com/v2fly/v2ray-core/v4"
|
core "github.com/v2fly/v2ray-core/v4"
|
||||||
"github.com/v2fly/v2ray-core/v4/common"
|
"github.com/v2fly/v2ray-core/v4/common"
|
||||||
"github.com/v2fly/v2ray-core/v4/features/routing"
|
"github.com/v2fly/v2ray-core/v4/features/routing"
|
||||||
@ -73,6 +76,80 @@ func (s *routingServer) SubscribeRoutingStats(request *SubscribeRoutingStatsRequ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *routingServer) GetBalancers(ctx context.Context, request *GetBalancersRequest) (*GetBalancersResponse, error) {
|
||||||
|
h, ok := s.router.(routing.RouterChecker)
|
||||||
|
if !ok {
|
||||||
|
return nil, status.Errorf(codes.Unavailable, "current router is not a health checker")
|
||||||
|
}
|
||||||
|
results, err := h.GetBalancersInfo(request.BalancerTags)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, err.Error())
|
||||||
|
}
|
||||||
|
rsp := &GetBalancersResponse{
|
||||||
|
Balancers: make([]*BalancerMsg, 0),
|
||||||
|
}
|
||||||
|
for _, result := range results {
|
||||||
|
var override *OverrideSelectingMsg
|
||||||
|
if result.Override != nil {
|
||||||
|
override = &OverrideSelectingMsg{
|
||||||
|
Until: result.Override.Until.Local().String(),
|
||||||
|
Selects: result.Override.Selects,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stat := &BalancerMsg{
|
||||||
|
Tag: result.Tag,
|
||||||
|
StrategySettings: result.Strategy.Settings,
|
||||||
|
Titles: result.Strategy.ValueTitles,
|
||||||
|
Override: override,
|
||||||
|
Selects: make([]*OutboundMsg, 0),
|
||||||
|
Others: make([]*OutboundMsg, 0),
|
||||||
|
}
|
||||||
|
for _, item := range result.Strategy.Selects {
|
||||||
|
stat.Selects = append(stat.Selects, &OutboundMsg{
|
||||||
|
Tag: item.Tag,
|
||||||
|
Values: item.Values,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
for _, item := range result.Strategy.Others {
|
||||||
|
stat.Others = append(stat.Others, &OutboundMsg{
|
||||||
|
Tag: item.Tag,
|
||||||
|
Values: item.Values,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
rsp.Balancers = append(rsp.Balancers, stat)
|
||||||
|
}
|
||||||
|
return rsp, nil
|
||||||
|
}
|
||||||
|
func (s *routingServer) CheckBalancers(ctx context.Context, request *CheckBalancersRequest) (*CheckBalancersResponse, error) {
|
||||||
|
h, ok := s.router.(routing.RouterChecker)
|
||||||
|
if !ok {
|
||||||
|
return nil, status.Errorf(codes.Unavailable, "current router is not a health checker")
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
err := h.CheckBalancers(request.BalancerTags)
|
||||||
|
if err != nil {
|
||||||
|
newError("CheckBalancers error:", err).AtInfo().WriteToLog()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return &CheckBalancersResponse{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *routingServer) OverrideSelecting(ctx context.Context, request *OverrideSelectingRequest) (*OverrideSelectingResponse, error) {
|
||||||
|
bo, ok := s.router.(routing.BalancingOverrider)
|
||||||
|
if !ok {
|
||||||
|
return nil, status.Errorf(codes.Unavailable, "current router doesn't support balancing override")
|
||||||
|
}
|
||||||
|
err := bo.OverrideSelecting(
|
||||||
|
request.BalancerTag,
|
||||||
|
request.Selectors,
|
||||||
|
time.Duration(request.Validity),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.InvalidArgument, err.Error())
|
||||||
|
}
|
||||||
|
return &OverrideSelectingResponse{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *routingServer) mustEmbedUnimplementedRoutingServiceServer() {}
|
func (s *routingServer) mustEmbedUnimplementedRoutingServiceServer() {}
|
||||||
|
|
||||||
type service struct {
|
type service struct {
|
||||||
|
@ -293,6 +293,483 @@ func (x *TestRouteRequest) GetPublishResult() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GetBalancersRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
BalancerTags []string `protobuf:"bytes,1,rep,name=balancerTags,proto3" json:"balancerTags,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetBalancersRequest) Reset() {
|
||||||
|
*x = GetBalancersRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_app_router_command_command_proto_msgTypes[3]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetBalancersRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*GetBalancersRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *GetBalancersRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_app_router_command_command_proto_msgTypes[3]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use GetBalancersRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*GetBalancersRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_app_router_command_command_proto_rawDescGZIP(), []int{3}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetBalancersRequest) GetBalancerTags() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.BalancerTags
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type OutboundMsg struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||||
|
Values []string `protobuf:"bytes,2,rep,name=values,proto3" json:"values,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *OutboundMsg) Reset() {
|
||||||
|
*x = OutboundMsg{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_app_router_command_command_proto_msgTypes[4]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *OutboundMsg) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*OutboundMsg) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *OutboundMsg) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_app_router_command_command_proto_msgTypes[4]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use OutboundMsg.ProtoReflect.Descriptor instead.
|
||||||
|
func (*OutboundMsg) Descriptor() ([]byte, []int) {
|
||||||
|
return file_app_router_command_command_proto_rawDescGZIP(), []int{4}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *OutboundMsg) GetTag() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Tag
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *OutboundMsg) GetValues() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Values
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type OverrideSelectingMsg struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Until string `protobuf:"bytes,1,opt,name=until,proto3" json:"until,omitempty"`
|
||||||
|
Selects []string `protobuf:"bytes,2,rep,name=selects,proto3" json:"selects,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *OverrideSelectingMsg) Reset() {
|
||||||
|
*x = OverrideSelectingMsg{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_app_router_command_command_proto_msgTypes[5]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *OverrideSelectingMsg) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*OverrideSelectingMsg) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *OverrideSelectingMsg) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_app_router_command_command_proto_msgTypes[5]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use OverrideSelectingMsg.ProtoReflect.Descriptor instead.
|
||||||
|
func (*OverrideSelectingMsg) Descriptor() ([]byte, []int) {
|
||||||
|
return file_app_router_command_command_proto_rawDescGZIP(), []int{5}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *OverrideSelectingMsg) GetUntil() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Until
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *OverrideSelectingMsg) GetSelects() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Selects
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type BalancerMsg struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||||
|
StrategySettings []string `protobuf:"bytes,2,rep,name=strategySettings,proto3" json:"strategySettings,omitempty"`
|
||||||
|
Titles []string `protobuf:"bytes,4,rep,name=titles,proto3" json:"titles,omitempty"`
|
||||||
|
Override *OverrideSelectingMsg `protobuf:"bytes,5,opt,name=override,proto3" json:"override,omitempty"`
|
||||||
|
Selects []*OutboundMsg `protobuf:"bytes,6,rep,name=selects,proto3" json:"selects,omitempty"`
|
||||||
|
Others []*OutboundMsg `protobuf:"bytes,7,rep,name=others,proto3" json:"others,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *BalancerMsg) Reset() {
|
||||||
|
*x = BalancerMsg{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_app_router_command_command_proto_msgTypes[6]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *BalancerMsg) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*BalancerMsg) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *BalancerMsg) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_app_router_command_command_proto_msgTypes[6]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use BalancerMsg.ProtoReflect.Descriptor instead.
|
||||||
|
func (*BalancerMsg) Descriptor() ([]byte, []int) {
|
||||||
|
return file_app_router_command_command_proto_rawDescGZIP(), []int{6}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *BalancerMsg) GetTag() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Tag
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *BalancerMsg) GetStrategySettings() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.StrategySettings
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *BalancerMsg) GetTitles() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Titles
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *BalancerMsg) GetOverride() *OverrideSelectingMsg {
|
||||||
|
if x != nil {
|
||||||
|
return x.Override
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *BalancerMsg) GetSelects() []*OutboundMsg {
|
||||||
|
if x != nil {
|
||||||
|
return x.Selects
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *BalancerMsg) GetOthers() []*OutboundMsg {
|
||||||
|
if x != nil {
|
||||||
|
return x.Others
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetBalancersResponse struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Balancers []*BalancerMsg `protobuf:"bytes,1,rep,name=balancers,proto3" json:"balancers,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetBalancersResponse) Reset() {
|
||||||
|
*x = GetBalancersResponse{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_app_router_command_command_proto_msgTypes[7]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetBalancersResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*GetBalancersResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *GetBalancersResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_app_router_command_command_proto_msgTypes[7]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use GetBalancersResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*GetBalancersResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_app_router_command_command_proto_rawDescGZIP(), []int{7}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetBalancersResponse) GetBalancers() []*BalancerMsg {
|
||||||
|
if x != nil {
|
||||||
|
return x.Balancers
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type CheckBalancersRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
BalancerTags []string `protobuf:"bytes,1,rep,name=balancerTags,proto3" json:"balancerTags,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CheckBalancersRequest) Reset() {
|
||||||
|
*x = CheckBalancersRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_app_router_command_command_proto_msgTypes[8]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CheckBalancersRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*CheckBalancersRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *CheckBalancersRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_app_router_command_command_proto_msgTypes[8]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use CheckBalancersRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*CheckBalancersRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_app_router_command_command_proto_rawDescGZIP(), []int{8}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CheckBalancersRequest) GetBalancerTags() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.BalancerTags
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type CheckBalancersResponse struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CheckBalancersResponse) Reset() {
|
||||||
|
*x = CheckBalancersResponse{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_app_router_command_command_proto_msgTypes[9]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CheckBalancersResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*CheckBalancersResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *CheckBalancersResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_app_router_command_command_proto_msgTypes[9]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use CheckBalancersResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*CheckBalancersResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_app_router_command_command_proto_rawDescGZIP(), []int{9}
|
||||||
|
}
|
||||||
|
|
||||||
|
type OverrideSelectingRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
BalancerTag string `protobuf:"bytes,1,opt,name=balancerTag,proto3" json:"balancerTag,omitempty"`
|
||||||
|
Selectors []string `protobuf:"bytes,2,rep,name=selectors,proto3" json:"selectors,omitempty"`
|
||||||
|
Validity int64 `protobuf:"varint,3,opt,name=validity,proto3" json:"validity,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *OverrideSelectingRequest) Reset() {
|
||||||
|
*x = OverrideSelectingRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_app_router_command_command_proto_msgTypes[10]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *OverrideSelectingRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*OverrideSelectingRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *OverrideSelectingRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_app_router_command_command_proto_msgTypes[10]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use OverrideSelectingRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*OverrideSelectingRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_app_router_command_command_proto_rawDescGZIP(), []int{10}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *OverrideSelectingRequest) GetBalancerTag() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.BalancerTag
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *OverrideSelectingRequest) GetSelectors() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Selectors
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *OverrideSelectingRequest) GetValidity() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Validity
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type OverrideSelectingResponse struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *OverrideSelectingResponse) Reset() {
|
||||||
|
*x = OverrideSelectingResponse{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_app_router_command_command_proto_msgTypes[11]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *OverrideSelectingResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*OverrideSelectingResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *OverrideSelectingResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_app_router_command_command_proto_msgTypes[11]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use OverrideSelectingResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*OverrideSelectingResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_app_router_command_command_proto_rawDescGZIP(), []int{11}
|
||||||
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@ -302,7 +779,7 @@ type Config struct {
|
|||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
*x = Config{}
|
*x = Config{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_app_router_command_command_proto_msgTypes[3]
|
mi := &file_app_router_command_command_proto_msgTypes[12]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@ -315,7 +792,7 @@ func (x *Config) String() string {
|
|||||||
func (*Config) ProtoMessage() {}
|
func (*Config) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_router_command_command_proto_msgTypes[3]
|
mi := &file_app_router_command_command_proto_msgTypes[12]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@ -328,7 +805,7 @@ func (x *Config) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||||
func (*Config) Descriptor() ([]byte, []int) {
|
func (*Config) Descriptor() ([]byte, []int) {
|
||||||
return file_app_router_command_command_proto_rawDescGZIP(), []int{3}
|
return file_app_router_command_command_proto_rawDescGZIP(), []int{12}
|
||||||
}
|
}
|
||||||
|
|
||||||
var File_app_router_command_command_proto protoreflect.FileDescriptor
|
var File_app_router_command_command_proto protoreflect.FileDescriptor
|
||||||
@ -390,32 +867,110 @@ var file_app_router_command_command_proto_rawDesc = []byte{
|
|||||||
0x28, 0x09, 0x52, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f,
|
0x28, 0x09, 0x52, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f,
|
||||||
0x72, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73,
|
0x72, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73,
|
||||||
0x75, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x50, 0x75, 0x62, 0x6c, 0x69,
|
0x75, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x50, 0x75, 0x62, 0x6c, 0x69,
|
||||||
0x73, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66,
|
0x73, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x39, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x42,
|
||||||
0x69, 0x67, 0x32, 0x89, 0x02, 0x0a, 0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x65,
|
0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
|
||||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x87, 0x01, 0x0a, 0x15, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72,
|
0x22, 0x0a, 0x0c, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x18,
|
||||||
0x69, 0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12,
|
0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54,
|
||||||
0x3b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,
|
0x61, 0x67, 0x73, 0x22, 0x37, 0x0a, 0x0b, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x4d,
|
||||||
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,
|
0x73, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67,
|
0x03, 0x74, 0x61, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02,
|
||||||
0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x76,
|
0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x46, 0x0a, 0x14,
|
||||||
|
0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6e,
|
||||||
|
0x67, 0x4d, 0x73, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x01, 0x20,
|
||||||
|
0x01, 0x28, 0x09, 0x52, 0x05, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65,
|
||||||
|
0x6c, 0x65, 0x63, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x6c,
|
||||||
|
0x65, 0x63, 0x74, 0x73, 0x22, 0xbe, 0x02, 0x0a, 0x0b, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65,
|
||||||
|
0x72, 0x4d, 0x73, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||||
|
0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x2a, 0x0a, 0x10, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65,
|
||||||
|
0x67, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09,
|
||||||
|
0x52, 0x10, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
|
||||||
|
0x67, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03,
|
||||||
|
0x28, 0x09, 0x52, 0x06, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x73, 0x12, 0x4f, 0x0a, 0x08, 0x6f, 0x76,
|
||||||
|
0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x76,
|
||||||
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f,
|
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f,
|
||||||
0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f, 0x75,
|
0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4f, 0x76, 0x65,
|
||||||
0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x00, 0x30, 0x01, 0x12,
|
0x72, 0x72, 0x69, 0x64, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x4d, 0x73,
|
||||||
0x6d, 0x0a, 0x09, 0x54, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x2f, 0x2e, 0x76,
|
0x67, 0x52, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x44, 0x0a, 0x07, 0x73,
|
||||||
|
0x65, 0x6c, 0x65, 0x63, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x76,
|
||||||
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f,
|
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f,
|
||||||
0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x54, 0x65, 0x73,
|
0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4f, 0x75, 0x74,
|
||||||
0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e,
|
0x62, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x73, 0x67, 0x52, 0x07, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74,
|
||||||
|
0x73, 0x12, 0x42, 0x0a, 0x06, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28,
|
||||||
|
0x0b, 0x32, 0x2a, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61,
|
||||||
|
0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
|
||||||
|
0x64, 0x2e, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x73, 0x67, 0x52, 0x06, 0x6f,
|
||||||
|
0x74, 0x68, 0x65, 0x72, 0x73, 0x22, 0x60, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61,
|
||||||
|
0x6e, 0x63, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a,
|
||||||
|
0x09, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
|
||||||
|
0x32, 0x2a, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,
|
||||||
|
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
||||||
|
0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x52, 0x09, 0x62, 0x61,
|
||||||
|
0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x73, 0x22, 0x3b, 0x0a, 0x15, 0x43, 0x68, 0x65, 0x63, 0x6b,
|
||||||
|
0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||||
|
0x12, 0x22, 0x0a, 0x0c, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x67, 0x73,
|
||||||
|
0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72,
|
||||||
|
0x54, 0x61, 0x67, 0x73, 0x22, 0x18, 0x0a, 0x16, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x42, 0x61, 0x6c,
|
||||||
|
0x61, 0x6e, 0x63, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x76,
|
||||||
|
0x0a, 0x18, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74,
|
||||||
|
0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x61,
|
||||||
|
0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
|
0x0b, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x67, 0x12, 0x1c, 0x0a, 0x09,
|
||||||
|
0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52,
|
||||||
|
0x09, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x61,
|
||||||
|
0x6c, 0x69, 0x64, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x76, 0x61,
|
||||||
|
0x6c, 0x69, 0x64, 0x69, 0x74, 0x79, 0x22, 0x1b, 0x0a, 0x19, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69,
|
||||||
|
0x64, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||||
|
0x6e, 0x73, 0x65, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x32, 0x90, 0x05,
|
||||||
|
0x0a, 0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
|
||||||
|
0x12, 0x87, 0x01, 0x0a, 0x15, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x6f,
|
||||||
|
0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x3b, 0x2e, 0x76, 0x32, 0x72,
|
||||||
|
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
||||||
|
0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63,
|
||||||
|
0x72, 0x69, 0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73,
|
||||||
|
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
|
||||||
|
0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e,
|
||||||
|
0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43,
|
||||||
|
0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x00, 0x30, 0x01, 0x12, 0x6d, 0x0a, 0x09, 0x54, 0x65,
|
||||||
|
0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x2f, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
|
||||||
|
0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e,
|
||||||
|
0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x74,
|
||||||
|
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
|
||||||
|
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
|
||||||
|
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67,
|
||||||
|
0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x00, 0x12, 0x79, 0x0a, 0x0c, 0x47, 0x65, 0x74,
|
||||||
|
0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x73, 0x12, 0x32, 0x2e, 0x76, 0x32, 0x72, 0x61,
|
||||||
|
0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||||
|
0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c,
|
||||||
|
0x61, 0x6e, 0x63, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e,
|
||||||
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,
|
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,
|
||||||
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f,
|
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65,
|
||||||
0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x00, 0x42, 0x78,
|
0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||||
0x0a, 0x21, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
|
0x73, 0x65, 0x22, 0x00, 0x12, 0x7f, 0x0a, 0x0e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x42, 0x61, 0x6c,
|
||||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
0x61, 0x6e, 0x63, 0x65, 0x72, 0x73, 0x12, 0x34, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
|
||||||
0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
|
0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63,
|
||||||
0x6d, 0x2f, 0x76, 0x32, 0x66, 0x6c, 0x79, 0x2f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f,
|
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x42, 0x61, 0x6c, 0x61,
|
||||||
0x72, 0x65, 0x2f, 0x76, 0x34, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
|
0x6e, 0x63, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x76,
|
||||||
0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa, 0x02, 0x1d, 0x56, 0x32, 0x52, 0x61, 0x79,
|
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f,
|
||||||
0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72,
|
0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x43, 0x68, 0x65,
|
||||||
0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x63, 0x6b, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||||
|
0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x88, 0x01, 0x0a, 0x11, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69,
|
||||||
|
0x64, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x37, 0x2e, 0x76, 0x32,
|
||||||
|
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75,
|
||||||
|
0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4f, 0x76, 0x65, 0x72,
|
||||||
|
0x72, 0x69, 0x64, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71,
|
||||||
|
0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,
|
||||||
|
0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d,
|
||||||
|
0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x53, 0x65, 0x6c,
|
||||||
|
0x65, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
|
||||||
|
0x42, 0x78, 0x0a, 0x21, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
|
||||||
|
0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f,
|
||||||
|
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
||||||
|
0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x32, 0x66, 0x6c, 0x79, 0x2f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2d,
|
||||||
|
0x63, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x34, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74,
|
||||||
|
0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa, 0x02, 0x1d, 0x56, 0x32, 0x52,
|
||||||
|
0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x52, 0x6f, 0x75, 0x74,
|
||||||
|
0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
||||||
|
0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -430,28 +985,47 @@ func file_app_router_command_command_proto_rawDescGZIP() []byte {
|
|||||||
return file_app_router_command_command_proto_rawDescData
|
return file_app_router_command_command_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_app_router_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
|
var file_app_router_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 14)
|
||||||
var file_app_router_command_command_proto_goTypes = []interface{}{
|
var file_app_router_command_command_proto_goTypes = []interface{}{
|
||||||
(*RoutingContext)(nil), // 0: v2ray.core.app.router.command.RoutingContext
|
(*RoutingContext)(nil), // 0: v2ray.core.app.router.command.RoutingContext
|
||||||
(*SubscribeRoutingStatsRequest)(nil), // 1: v2ray.core.app.router.command.SubscribeRoutingStatsRequest
|
(*SubscribeRoutingStatsRequest)(nil), // 1: v2ray.core.app.router.command.SubscribeRoutingStatsRequest
|
||||||
(*TestRouteRequest)(nil), // 2: v2ray.core.app.router.command.TestRouteRequest
|
(*TestRouteRequest)(nil), // 2: v2ray.core.app.router.command.TestRouteRequest
|
||||||
(*Config)(nil), // 3: v2ray.core.app.router.command.Config
|
(*GetBalancersRequest)(nil), // 3: v2ray.core.app.router.command.GetBalancersRequest
|
||||||
nil, // 4: v2ray.core.app.router.command.RoutingContext.AttributesEntry
|
(*OutboundMsg)(nil), // 4: v2ray.core.app.router.command.OutboundMsg
|
||||||
(net.Network)(0), // 5: v2ray.core.common.net.Network
|
(*OverrideSelectingMsg)(nil), // 5: v2ray.core.app.router.command.OverrideSelectingMsg
|
||||||
|
(*BalancerMsg)(nil), // 6: v2ray.core.app.router.command.BalancerMsg
|
||||||
|
(*GetBalancersResponse)(nil), // 7: v2ray.core.app.router.command.GetBalancersResponse
|
||||||
|
(*CheckBalancersRequest)(nil), // 8: v2ray.core.app.router.command.CheckBalancersRequest
|
||||||
|
(*CheckBalancersResponse)(nil), // 9: v2ray.core.app.router.command.CheckBalancersResponse
|
||||||
|
(*OverrideSelectingRequest)(nil), // 10: v2ray.core.app.router.command.OverrideSelectingRequest
|
||||||
|
(*OverrideSelectingResponse)(nil), // 11: v2ray.core.app.router.command.OverrideSelectingResponse
|
||||||
|
(*Config)(nil), // 12: v2ray.core.app.router.command.Config
|
||||||
|
nil, // 13: v2ray.core.app.router.command.RoutingContext.AttributesEntry
|
||||||
|
(net.Network)(0), // 14: v2ray.core.common.net.Network
|
||||||
}
|
}
|
||||||
var file_app_router_command_command_proto_depIdxs = []int32{
|
var file_app_router_command_command_proto_depIdxs = []int32{
|
||||||
5, // 0: v2ray.core.app.router.command.RoutingContext.Network:type_name -> v2ray.core.common.net.Network
|
14, // 0: v2ray.core.app.router.command.RoutingContext.Network:type_name -> v2ray.core.common.net.Network
|
||||||
4, // 1: v2ray.core.app.router.command.RoutingContext.Attributes:type_name -> v2ray.core.app.router.command.RoutingContext.AttributesEntry
|
13, // 1: v2ray.core.app.router.command.RoutingContext.Attributes:type_name -> v2ray.core.app.router.command.RoutingContext.AttributesEntry
|
||||||
0, // 2: v2ray.core.app.router.command.TestRouteRequest.RoutingContext:type_name -> v2ray.core.app.router.command.RoutingContext
|
0, // 2: v2ray.core.app.router.command.TestRouteRequest.RoutingContext:type_name -> v2ray.core.app.router.command.RoutingContext
|
||||||
1, // 3: v2ray.core.app.router.command.RoutingService.SubscribeRoutingStats:input_type -> v2ray.core.app.router.command.SubscribeRoutingStatsRequest
|
5, // 3: v2ray.core.app.router.command.BalancerMsg.override:type_name -> v2ray.core.app.router.command.OverrideSelectingMsg
|
||||||
2, // 4: v2ray.core.app.router.command.RoutingService.TestRoute:input_type -> v2ray.core.app.router.command.TestRouteRequest
|
4, // 4: v2ray.core.app.router.command.BalancerMsg.selects:type_name -> v2ray.core.app.router.command.OutboundMsg
|
||||||
0, // 5: v2ray.core.app.router.command.RoutingService.SubscribeRoutingStats:output_type -> v2ray.core.app.router.command.RoutingContext
|
4, // 5: v2ray.core.app.router.command.BalancerMsg.others:type_name -> v2ray.core.app.router.command.OutboundMsg
|
||||||
0, // 6: v2ray.core.app.router.command.RoutingService.TestRoute:output_type -> v2ray.core.app.router.command.RoutingContext
|
6, // 6: v2ray.core.app.router.command.GetBalancersResponse.balancers:type_name -> v2ray.core.app.router.command.BalancerMsg
|
||||||
5, // [5:7] is the sub-list for method output_type
|
1, // 7: v2ray.core.app.router.command.RoutingService.SubscribeRoutingStats:input_type -> v2ray.core.app.router.command.SubscribeRoutingStatsRequest
|
||||||
3, // [3:5] is the sub-list for method input_type
|
2, // 8: v2ray.core.app.router.command.RoutingService.TestRoute:input_type -> v2ray.core.app.router.command.TestRouteRequest
|
||||||
3, // [3:3] is the sub-list for extension type_name
|
3, // 9: v2ray.core.app.router.command.RoutingService.GetBalancers:input_type -> v2ray.core.app.router.command.GetBalancersRequest
|
||||||
3, // [3:3] is the sub-list for extension extendee
|
8, // 10: v2ray.core.app.router.command.RoutingService.CheckBalancers:input_type -> v2ray.core.app.router.command.CheckBalancersRequest
|
||||||
0, // [0:3] is the sub-list for field type_name
|
10, // 11: v2ray.core.app.router.command.RoutingService.OverrideSelecting:input_type -> v2ray.core.app.router.command.OverrideSelectingRequest
|
||||||
|
0, // 12: v2ray.core.app.router.command.RoutingService.SubscribeRoutingStats:output_type -> v2ray.core.app.router.command.RoutingContext
|
||||||
|
0, // 13: v2ray.core.app.router.command.RoutingService.TestRoute:output_type -> v2ray.core.app.router.command.RoutingContext
|
||||||
|
7, // 14: v2ray.core.app.router.command.RoutingService.GetBalancers:output_type -> v2ray.core.app.router.command.GetBalancersResponse
|
||||||
|
9, // 15: v2ray.core.app.router.command.RoutingService.CheckBalancers:output_type -> v2ray.core.app.router.command.CheckBalancersResponse
|
||||||
|
11, // 16: v2ray.core.app.router.command.RoutingService.OverrideSelecting:output_type -> v2ray.core.app.router.command.OverrideSelectingResponse
|
||||||
|
12, // [12:17] is the sub-list for method output_type
|
||||||
|
7, // [7:12] is the sub-list for method input_type
|
||||||
|
7, // [7:7] is the sub-list for extension type_name
|
||||||
|
7, // [7:7] is the sub-list for extension extendee
|
||||||
|
0, // [0:7] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_app_router_command_command_proto_init() }
|
func init() { file_app_router_command_command_proto_init() }
|
||||||
@ -497,6 +1071,114 @@ func file_app_router_command_command_proto_init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_app_router_command_command_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
file_app_router_command_command_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*GetBalancersRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_router_command_command_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*OutboundMsg); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_router_command_command_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*OverrideSelectingMsg); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_router_command_command_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*BalancerMsg); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_router_command_command_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*GetBalancersResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_router_command_command_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*CheckBalancersRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_router_command_command_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*CheckBalancersResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_router_command_command_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*OverrideSelectingRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_router_command_command_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*OverrideSelectingResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_router_command_command_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*Config); i {
|
switch v := v.(*Config); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@ -515,7 +1197,7 @@ func file_app_router_command_command_proto_init() {
|
|||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: file_app_router_command_command_proto_rawDesc,
|
RawDescriptor: file_app_router_command_command_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 5,
|
NumMessages: 14,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 1,
|
NumServices: 1,
|
||||||
},
|
},
|
||||||
|
@ -60,10 +60,55 @@ message TestRouteRequest {
|
|||||||
bool PublishResult = 3;
|
bool PublishResult = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message GetBalancersRequest {
|
||||||
|
repeated string balancerTags = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message OutboundMsg {
|
||||||
|
string tag = 1;
|
||||||
|
repeated string values = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message OverrideSelectingMsg {
|
||||||
|
string until = 1;
|
||||||
|
repeated string selects = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BalancerMsg {
|
||||||
|
string tag = 1;
|
||||||
|
repeated string strategySettings = 2;
|
||||||
|
repeated string titles = 4;
|
||||||
|
OverrideSelectingMsg override = 5;
|
||||||
|
repeated OutboundMsg selects = 6;
|
||||||
|
repeated OutboundMsg others = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetBalancersResponse {
|
||||||
|
repeated BalancerMsg balancers = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CheckBalancersRequest {
|
||||||
|
repeated string balancerTags = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CheckBalancersResponse {}
|
||||||
|
|
||||||
|
|
||||||
|
message OverrideSelectingRequest {
|
||||||
|
string balancerTag = 1;
|
||||||
|
repeated string selectors = 2;
|
||||||
|
int64 validity = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message OverrideSelectingResponse {}
|
||||||
|
|
||||||
service RoutingService {
|
service RoutingService {
|
||||||
rpc SubscribeRoutingStats(SubscribeRoutingStatsRequest)
|
rpc SubscribeRoutingStats(SubscribeRoutingStatsRequest)
|
||||||
returns (stream RoutingContext) {}
|
returns (stream RoutingContext) {}
|
||||||
rpc TestRoute(TestRouteRequest) returns (RoutingContext) {}
|
rpc TestRoute(TestRouteRequest) returns (RoutingContext) {}
|
||||||
|
rpc GetBalancers(GetBalancersRequest) returns (GetBalancersResponse) {}
|
||||||
|
rpc CheckBalancers(CheckBalancersRequest) returns (CheckBalancersResponse) {}
|
||||||
|
rpc OverrideSelecting(OverrideSelectingRequest) returns (OverrideSelectingResponse) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
message Config {}
|
message Config {}
|
||||||
|
@ -20,6 +20,9 @@ const _ = grpc.SupportPackageIsVersion7
|
|||||||
type RoutingServiceClient interface {
|
type RoutingServiceClient interface {
|
||||||
SubscribeRoutingStats(ctx context.Context, in *SubscribeRoutingStatsRequest, opts ...grpc.CallOption) (RoutingService_SubscribeRoutingStatsClient, error)
|
SubscribeRoutingStats(ctx context.Context, in *SubscribeRoutingStatsRequest, opts ...grpc.CallOption) (RoutingService_SubscribeRoutingStatsClient, error)
|
||||||
TestRoute(ctx context.Context, in *TestRouteRequest, opts ...grpc.CallOption) (*RoutingContext, error)
|
TestRoute(ctx context.Context, in *TestRouteRequest, opts ...grpc.CallOption) (*RoutingContext, error)
|
||||||
|
GetBalancers(ctx context.Context, in *GetBalancersRequest, opts ...grpc.CallOption) (*GetBalancersResponse, error)
|
||||||
|
CheckBalancers(ctx context.Context, in *CheckBalancersRequest, opts ...grpc.CallOption) (*CheckBalancersResponse, error)
|
||||||
|
OverrideSelecting(ctx context.Context, in *OverrideSelectingRequest, opts ...grpc.CallOption) (*OverrideSelectingResponse, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type routingServiceClient struct {
|
type routingServiceClient struct {
|
||||||
@ -71,12 +74,42 @@ func (c *routingServiceClient) TestRoute(ctx context.Context, in *TestRouteReque
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *routingServiceClient) GetBalancers(ctx context.Context, in *GetBalancersRequest, opts ...grpc.CallOption) (*GetBalancersResponse, error) {
|
||||||
|
out := new(GetBalancersResponse)
|
||||||
|
err := c.cc.Invoke(ctx, "/v2ray.core.app.router.command.RoutingService/GetBalancers", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *routingServiceClient) CheckBalancers(ctx context.Context, in *CheckBalancersRequest, opts ...grpc.CallOption) (*CheckBalancersResponse, error) {
|
||||||
|
out := new(CheckBalancersResponse)
|
||||||
|
err := c.cc.Invoke(ctx, "/v2ray.core.app.router.command.RoutingService/CheckBalancers", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *routingServiceClient) OverrideSelecting(ctx context.Context, in *OverrideSelectingRequest, opts ...grpc.CallOption) (*OverrideSelectingResponse, error) {
|
||||||
|
out := new(OverrideSelectingResponse)
|
||||||
|
err := c.cc.Invoke(ctx, "/v2ray.core.app.router.command.RoutingService/OverrideSelecting", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
// RoutingServiceServer is the server API for RoutingService service.
|
// RoutingServiceServer is the server API for RoutingService service.
|
||||||
// All implementations must embed UnimplementedRoutingServiceServer
|
// All implementations must embed UnimplementedRoutingServiceServer
|
||||||
// for forward compatibility
|
// for forward compatibility
|
||||||
type RoutingServiceServer interface {
|
type RoutingServiceServer interface {
|
||||||
SubscribeRoutingStats(*SubscribeRoutingStatsRequest, RoutingService_SubscribeRoutingStatsServer) error
|
SubscribeRoutingStats(*SubscribeRoutingStatsRequest, RoutingService_SubscribeRoutingStatsServer) error
|
||||||
TestRoute(context.Context, *TestRouteRequest) (*RoutingContext, error)
|
TestRoute(context.Context, *TestRouteRequest) (*RoutingContext, error)
|
||||||
|
GetBalancers(context.Context, *GetBalancersRequest) (*GetBalancersResponse, error)
|
||||||
|
CheckBalancers(context.Context, *CheckBalancersRequest) (*CheckBalancersResponse, error)
|
||||||
|
OverrideSelecting(context.Context, *OverrideSelectingRequest) (*OverrideSelectingResponse, error)
|
||||||
mustEmbedUnimplementedRoutingServiceServer()
|
mustEmbedUnimplementedRoutingServiceServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,6 +123,15 @@ func (UnimplementedRoutingServiceServer) SubscribeRoutingStats(*SubscribeRouting
|
|||||||
func (UnimplementedRoutingServiceServer) TestRoute(context.Context, *TestRouteRequest) (*RoutingContext, error) {
|
func (UnimplementedRoutingServiceServer) TestRoute(context.Context, *TestRouteRequest) (*RoutingContext, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method TestRoute not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method TestRoute not implemented")
|
||||||
}
|
}
|
||||||
|
func (UnimplementedRoutingServiceServer) GetBalancers(context.Context, *GetBalancersRequest) (*GetBalancersResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method GetBalancers not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedRoutingServiceServer) CheckBalancers(context.Context, *CheckBalancersRequest) (*CheckBalancersResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method CheckBalancers not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedRoutingServiceServer) OverrideSelecting(context.Context, *OverrideSelectingRequest) (*OverrideSelectingResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method OverrideSelecting not implemented")
|
||||||
|
}
|
||||||
func (UnimplementedRoutingServiceServer) mustEmbedUnimplementedRoutingServiceServer() {}
|
func (UnimplementedRoutingServiceServer) mustEmbedUnimplementedRoutingServiceServer() {}
|
||||||
|
|
||||||
// UnsafeRoutingServiceServer may be embedded to opt out of forward compatibility for this service.
|
// UnsafeRoutingServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||||
@ -142,6 +184,60 @@ func _RoutingService_TestRoute_Handler(srv interface{}, ctx context.Context, dec
|
|||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _RoutingService_GetBalancers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(GetBalancersRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(RoutingServiceServer).GetBalancers(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/v2ray.core.app.router.command.RoutingService/GetBalancers",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(RoutingServiceServer).GetBalancers(ctx, req.(*GetBalancersRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _RoutingService_CheckBalancers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(CheckBalancersRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(RoutingServiceServer).CheckBalancers(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/v2ray.core.app.router.command.RoutingService/CheckBalancers",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(RoutingServiceServer).CheckBalancers(ctx, req.(*CheckBalancersRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _RoutingService_OverrideSelecting_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(OverrideSelectingRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(RoutingServiceServer).OverrideSelecting(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/v2ray.core.app.router.command.RoutingService/OverrideSelecting",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(RoutingServiceServer).OverrideSelecting(ctx, req.(*OverrideSelectingRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
// RoutingService_ServiceDesc is the grpc.ServiceDesc for RoutingService service.
|
// RoutingService_ServiceDesc is the grpc.ServiceDesc for RoutingService service.
|
||||||
// It's only intended for direct use with grpc.RegisterService,
|
// It's only intended for direct use with grpc.RegisterService,
|
||||||
// and not to be introspected or modified (even as a copy)
|
// and not to be introspected or modified (even as a copy)
|
||||||
@ -153,6 +249,18 @@ var RoutingService_ServiceDesc = grpc.ServiceDesc{
|
|||||||
MethodName: "TestRoute",
|
MethodName: "TestRoute",
|
||||||
Handler: _RoutingService_TestRoute_Handler,
|
Handler: _RoutingService_TestRoute_Handler,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
MethodName: "GetBalancers",
|
||||||
|
Handler: _RoutingService_GetBalancers_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "CheckBalancers",
|
||||||
|
Handler: _RoutingService_CheckBalancers_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "OverrideSelecting",
|
||||||
|
Handler: _RoutingService_OverrideSelecting_Handler,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Streams: []grpc.StreamDesc{
|
Streams: []grpc.StreamDesc{
|
||||||
{
|
{
|
||||||
|
@ -248,7 +248,7 @@ func TestSerivceTestRoute(t *testing.T) {
|
|||||||
TargetTag: &router.RoutingRule_Tag{Tag: "out"},
|
TargetTag: &router.RoutingRule_Tag{Tag: "out"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, mocks.NewDNSClient(mockCtl), mocks.NewOutboundManager(mockCtl)))
|
}, mocks.NewDNSClient(mockCtl), mocks.NewOutboundManager(mockCtl), nil))
|
||||||
|
|
||||||
lis := bufconn.Listen(1024 * 1024)
|
lis := bufconn.Listen(1024 * 1024)
|
||||||
bufDialer := func(context.Context, string) (net.Conn, error) {
|
bufDialer := func(context.Context, string) (net.Conn, error) {
|
||||||
|
@ -157,7 +157,8 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
|
|||||||
return conds, nil
|
return conds, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (br *BalancingRule) Build(ohm outbound.Manager) (*Balancer, error) {
|
// Build builds the balancing rule
|
||||||
|
func (br *BalancingRule) Build(ohm outbound.Manager, dispatcher routing.Dispatcher) (*Balancer, error) {
|
||||||
switch br.Strategy {
|
switch br.Strategy {
|
||||||
case "leastPing":
|
case "leastPing":
|
||||||
return &Balancer{
|
return &Balancer{
|
||||||
@ -165,13 +166,28 @@ func (br *BalancingRule) Build(ohm outbound.Manager) (*Balancer, error) {
|
|||||||
strategy: &LeastPingStrategy{},
|
strategy: &LeastPingStrategy{},
|
||||||
ohm: ohm,
|
ohm: ohm,
|
||||||
}, nil
|
}, nil
|
||||||
|
case "leastLoad":
|
||||||
|
i, err := br.StrategySettings.GetInstance()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
s, ok := i.(*StrategyLeastLoadConfig)
|
||||||
|
if !ok {
|
||||||
|
return nil, newError("not a StrategyLeastLoadConfig").AtError()
|
||||||
|
}
|
||||||
|
leastLoadStrategy := NewLeastLoadStrategy(s, dispatcher)
|
||||||
|
return &Balancer{
|
||||||
|
selectors: br.OutboundSelector,
|
||||||
|
ohm: ohm, fallbackTag: br.FallbackTag,
|
||||||
|
strategy: leastLoadStrategy,
|
||||||
|
}, nil
|
||||||
case "random":
|
case "random":
|
||||||
fallthrough
|
fallthrough
|
||||||
default:
|
default:
|
||||||
return &Balancer{
|
return &Balancer{
|
||||||
selectors: br.OutboundSelector,
|
selectors: br.OutboundSelector,
|
||||||
strategy: &RandomStrategy{},
|
ohm: ohm, fallbackTag: br.FallbackTag,
|
||||||
ohm: ohm,
|
strategy: &RandomStrategy{},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ package router
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
net "github.com/v2fly/v2ray-core/v4/common/net"
|
net "github.com/v2fly/v2ray-core/v4/common/net"
|
||||||
|
serial "github.com/v2fly/v2ray-core/v4/common/serial"
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
@ -131,7 +132,7 @@ func (x Config_DomainStrategy) Number() protoreflect.EnumNumber {
|
|||||||
|
|
||||||
// Deprecated: Use Config_DomainStrategy.Descriptor instead.
|
// Deprecated: Use Config_DomainStrategy.Descriptor instead.
|
||||||
func (Config_DomainStrategy) EnumDescriptor() ([]byte, []int) {
|
func (Config_DomainStrategy) EnumDescriptor() ([]byte, []int) {
|
||||||
return file_app_router_config_proto_rawDescGZIP(), []int{8, 0}
|
return file_app_router_config_proto_rawDescGZIP(), []int{11, 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Domain for routing decision.
|
// Domain for routing decision.
|
||||||
@ -706,9 +707,11 @@ type BalancingRule struct {
|
|||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||||
OutboundSelector []string `protobuf:"bytes,2,rep,name=outbound_selector,json=outboundSelector,proto3" json:"outbound_selector,omitempty"`
|
OutboundSelector []string `protobuf:"bytes,2,rep,name=outbound_selector,json=outboundSelector,proto3" json:"outbound_selector,omitempty"`
|
||||||
Strategy string `protobuf:"bytes,3,opt,name=strategy,proto3" json:"strategy,omitempty"`
|
Strategy string `protobuf:"bytes,3,opt,name=strategy,proto3" json:"strategy,omitempty"`
|
||||||
|
StrategySettings *serial.TypedMessage `protobuf:"bytes,4,opt,name=strategy_settings,json=strategySettings,proto3" json:"strategy_settings,omitempty"`
|
||||||
|
FallbackTag string `protobuf:"bytes,5,opt,name=fallback_tag,json=fallbackTag,proto3" json:"fallback_tag,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *BalancingRule) Reset() {
|
func (x *BalancingRule) Reset() {
|
||||||
@ -764,6 +767,260 @@ func (x *BalancingRule) GetStrategy() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *BalancingRule) GetStrategySettings() *serial.TypedMessage {
|
||||||
|
if x != nil {
|
||||||
|
return x.StrategySettings
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *BalancingRule) GetFallbackTag() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.FallbackTag
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type StrategyWeight struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Regexp bool `protobuf:"varint,1,opt,name=regexp,proto3" json:"regexp,omitempty"`
|
||||||
|
Match string `protobuf:"bytes,2,opt,name=match,proto3" json:"match,omitempty"`
|
||||||
|
Value float32 `protobuf:"fixed32,3,opt,name=value,proto3" json:"value,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StrategyWeight) Reset() {
|
||||||
|
*x = StrategyWeight{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_app_router_config_proto_msgTypes[8]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StrategyWeight) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*StrategyWeight) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *StrategyWeight) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_app_router_config_proto_msgTypes[8]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use StrategyWeight.ProtoReflect.Descriptor instead.
|
||||||
|
func (*StrategyWeight) Descriptor() ([]byte, []int) {
|
||||||
|
return file_app_router_config_proto_rawDescGZIP(), []int{8}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StrategyWeight) GetRegexp() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.Regexp
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StrategyWeight) GetMatch() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Match
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StrategyWeight) GetValue() float32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Value
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type StrategyLeastLoadConfig struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
HealthCheck *HealthPingConfig `protobuf:"bytes,1,opt,name=healthCheck,proto3" json:"healthCheck,omitempty"`
|
||||||
|
// weight settings
|
||||||
|
Costs []*StrategyWeight `protobuf:"bytes,2,rep,name=costs,proto3" json:"costs,omitempty"`
|
||||||
|
// RTT baselines for selecting, int64 values of time.Duration
|
||||||
|
Baselines []int64 `protobuf:"varint,3,rep,packed,name=baselines,proto3" json:"baselines,omitempty"`
|
||||||
|
// expected nodes count to select
|
||||||
|
Expected int32 `protobuf:"varint,4,opt,name=expected,proto3" json:"expected,omitempty"`
|
||||||
|
// max acceptable rtt, filter away high delay nodes. defalut 0
|
||||||
|
MaxRTT int64 `protobuf:"varint,5,opt,name=maxRTT,proto3" json:"maxRTT,omitempty"`
|
||||||
|
// acceptable failure rate
|
||||||
|
Tolerance float32 `protobuf:"fixed32,6,opt,name=tolerance,proto3" json:"tolerance,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StrategyLeastLoadConfig) Reset() {
|
||||||
|
*x = StrategyLeastLoadConfig{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_app_router_config_proto_msgTypes[9]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StrategyLeastLoadConfig) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*StrategyLeastLoadConfig) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *StrategyLeastLoadConfig) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_app_router_config_proto_msgTypes[9]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use StrategyLeastLoadConfig.ProtoReflect.Descriptor instead.
|
||||||
|
func (*StrategyLeastLoadConfig) Descriptor() ([]byte, []int) {
|
||||||
|
return file_app_router_config_proto_rawDescGZIP(), []int{9}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StrategyLeastLoadConfig) GetHealthCheck() *HealthPingConfig {
|
||||||
|
if x != nil {
|
||||||
|
return x.HealthCheck
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StrategyLeastLoadConfig) GetCosts() []*StrategyWeight {
|
||||||
|
if x != nil {
|
||||||
|
return x.Costs
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StrategyLeastLoadConfig) GetBaselines() []int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Baselines
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StrategyLeastLoadConfig) GetExpected() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Expected
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StrategyLeastLoadConfig) GetMaxRTT() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.MaxRTT
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StrategyLeastLoadConfig) GetTolerance() float32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Tolerance
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type HealthPingConfig struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
// destination url, need 204 for success return
|
||||||
|
// default http://www.google.com/gen_204
|
||||||
|
Destination string `protobuf:"bytes,1,opt,name=destination,proto3" json:"destination,omitempty"`
|
||||||
|
// connectivity check url
|
||||||
|
Connectivity string `protobuf:"bytes,2,opt,name=connectivity,proto3" json:"connectivity,omitempty"`
|
||||||
|
// health check interval, int64 values of time.Duration
|
||||||
|
Interval int64 `protobuf:"varint,3,opt,name=interval,proto3" json:"interval,omitempty"`
|
||||||
|
// samplingcount is the amount of recent ping results which are kept for calculation
|
||||||
|
SamplingCount int32 `protobuf:"varint,4,opt,name=samplingCount,proto3" json:"samplingCount,omitempty"`
|
||||||
|
// ping timeout, int64 values of time.Duration
|
||||||
|
Timeout int64 `protobuf:"varint,5,opt,name=timeout,proto3" json:"timeout,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HealthPingConfig) Reset() {
|
||||||
|
*x = HealthPingConfig{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_app_router_config_proto_msgTypes[10]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HealthPingConfig) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*HealthPingConfig) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *HealthPingConfig) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_app_router_config_proto_msgTypes[10]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use HealthPingConfig.ProtoReflect.Descriptor instead.
|
||||||
|
func (*HealthPingConfig) Descriptor() ([]byte, []int) {
|
||||||
|
return file_app_router_config_proto_rawDescGZIP(), []int{10}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HealthPingConfig) GetDestination() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Destination
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HealthPingConfig) GetConnectivity() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Connectivity
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HealthPingConfig) GetInterval() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Interval
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HealthPingConfig) GetSamplingCount() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.SamplingCount
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HealthPingConfig) GetTimeout() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Timeout
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@ -777,7 +1034,7 @@ type Config struct {
|
|||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
*x = Config{}
|
*x = Config{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_app_router_config_proto_msgTypes[8]
|
mi := &file_app_router_config_proto_msgTypes[11]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@ -790,7 +1047,7 @@ func (x *Config) String() string {
|
|||||||
func (*Config) ProtoMessage() {}
|
func (*Config) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_router_config_proto_msgTypes[8]
|
mi := &file_app_router_config_proto_msgTypes[11]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@ -803,7 +1060,7 @@ func (x *Config) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||||
func (*Config) Descriptor() ([]byte, []int) {
|
func (*Config) Descriptor() ([]byte, []int) {
|
||||||
return file_app_router_config_proto_rawDescGZIP(), []int{8}
|
return file_app_router_config_proto_rawDescGZIP(), []int{11}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetDomainStrategy() Config_DomainStrategy {
|
func (x *Config) GetDomainStrategy() Config_DomainStrategy {
|
||||||
@ -842,7 +1099,7 @@ type Domain_Attribute struct {
|
|||||||
func (x *Domain_Attribute) Reset() {
|
func (x *Domain_Attribute) Reset() {
|
||||||
*x = Domain_Attribute{}
|
*x = Domain_Attribute{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_app_router_config_proto_msgTypes[9]
|
mi := &file_app_router_config_proto_msgTypes[12]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@ -855,7 +1112,7 @@ func (x *Domain_Attribute) String() string {
|
|||||||
func (*Domain_Attribute) ProtoMessage() {}
|
func (*Domain_Attribute) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *Domain_Attribute) ProtoReflect() protoreflect.Message {
|
func (x *Domain_Attribute) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_router_config_proto_msgTypes[9]
|
mi := &file_app_router_config_proto_msgTypes[12]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@ -921,143 +1178,187 @@ var file_app_router_config_proto_rawDesc = []byte{
|
|||||||
0x0a, 0x17, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6e,
|
0x0a, 0x17, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6e,
|
||||||
0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x76, 0x32, 0x72, 0x61, 0x79,
|
0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x76, 0x32, 0x72, 0x61, 0x79,
|
||||||
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
|
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
|
||||||
0x1a, 0x15, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x70, 0x6f, 0x72,
|
0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f,
|
||||||
0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f,
|
0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72,
|
||||||
0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f,
|
||||||
0x6f, 0x22, 0xbf, 0x02, 0x0a, 0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x36, 0x0a, 0x04,
|
0x70, 0x6f, 0x72, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d,
|
||||||
0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x76, 0x32, 0x72,
|
0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x70,
|
||||||
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
0x72, 0x6f, 0x74, 0x6f, 0x22, 0xbf, 0x02, 0x0a, 0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12,
|
||||||
0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04,
|
0x36, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e,
|
||||||
0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
|
|
||||||
0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x45, 0x0a, 0x09, 0x61, 0x74,
|
|
||||||
0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e,
|
|
||||||
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,
|
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,
|
||||||
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x41, 0x74, 0x74,
|
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x54, 0x79, 0x70,
|
||||||
0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
|
0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
||||||
0x65, 0x1a, 0x6c, 0x0a, 0x09, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x10,
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x45, 0x0a,
|
||||||
0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
|
0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
|
||||||
0x12, 0x1f, 0x0a, 0x0a, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
|
0x32, 0x27, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,
|
||||||
0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x09, 0x62, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75,
|
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e,
|
||||||
0x65, 0x12, 0x1d, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03,
|
0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69,
|
||||||
0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65,
|
0x62, 0x75, 0x74, 0x65, 0x1a, 0x6c, 0x0a, 0x09, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
|
||||||
0x42, 0x0d, 0x0a, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22,
|
0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
|
||||||
0x32, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x6c, 0x61, 0x69, 0x6e,
|
0x6b, 0x65, 0x79, 0x12, 0x1f, 0x0a, 0x0a, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75,
|
||||||
0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x65, 0x67, 0x65, 0x78, 0x10, 0x01, 0x12, 0x0a, 0x0a,
|
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x09, 0x62, 0x6f, 0x6f, 0x6c, 0x56,
|
||||||
0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x75, 0x6c,
|
0x61, 0x6c, 0x75, 0x65, 0x12, 0x1d, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75,
|
||||||
0x6c, 0x10, 0x03, 0x22, 0x2e, 0x0a, 0x04, 0x43, 0x49, 0x44, 0x52, 0x12, 0x0e, 0x0a, 0x02, 0x69,
|
0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x56, 0x61,
|
||||||
0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x70,
|
0x6c, 0x75, 0x65, 0x42, 0x0d, 0x0a, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x76, 0x61, 0x6c,
|
||||||
0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x70, 0x72, 0x65,
|
0x75, 0x65, 0x22, 0x32, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x6c,
|
||||||
0x66, 0x69, 0x78, 0x22, 0x80, 0x01, 0x0a, 0x05, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x12, 0x21, 0x0a,
|
0x61, 0x69, 0x6e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x65, 0x67, 0x65, 0x78, 0x10, 0x01,
|
||||||
0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20,
|
0x12, 0x0a, 0x0a, 0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04,
|
||||||
0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65,
|
0x46, 0x75, 0x6c, 0x6c, 0x10, 0x03, 0x22, 0x2e, 0x0a, 0x04, 0x43, 0x49, 0x44, 0x52, 0x12, 0x0e,
|
||||||
0x12, 0x2f, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b,
|
0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x16,
|
||||||
0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06,
|
||||||
0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x49, 0x44, 0x52, 0x52, 0x04, 0x63, 0x69, 0x64,
|
0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x80, 0x01, 0x0a, 0x05, 0x47, 0x65, 0x6f, 0x49, 0x50,
|
||||||
0x72, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x5f, 0x6d, 0x61, 0x74,
|
0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65,
|
||||||
0x63, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73,
|
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43,
|
||||||
0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3f, 0x0a, 0x09, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x4c,
|
0x6f, 0x64, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28,
|
||||||
0x69, 0x73, 0x74, 0x12, 0x32, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x03,
|
|
||||||
0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
|
|
||||||
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50,
|
|
||||||
0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x63, 0x0a, 0x07, 0x47, 0x65, 0x6f, 0x53, 0x69,
|
|
||||||
0x74, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f,
|
|
||||||
0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72,
|
|
||||||
0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18,
|
|
||||||
0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
|
|
||||||
0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x44, 0x6f,
|
|
||||||
0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x22, 0x43, 0x0a, 0x0b,
|
|
||||||
0x47, 0x65, 0x6f, 0x53, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x34, 0x0a, 0x05, 0x65,
|
|
||||||
0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x76, 0x32, 0x72,
|
|
||||||
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
|
||||||
0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x53, 0x69, 0x74, 0x65, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72,
|
|
||||||
0x79, 0x22, 0xf1, 0x06, 0x0a, 0x0b, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c,
|
|
||||||
0x65, 0x12, 0x12, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00,
|
|
||||||
0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x25, 0x0a, 0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69,
|
|
||||||
0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0c,
|
|
||||||
0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x12, 0x35, 0x0a, 0x06,
|
|
||||||
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x76,
|
|
||||||
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f,
|
|
||||||
0x75, 0x74, 0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x64, 0x6f, 0x6d,
|
|
||||||
0x61, 0x69, 0x6e, 0x12, 0x33, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x72, 0x18, 0x03, 0x20, 0x03, 0x28,
|
|
||||||
0x0b, 0x32, 0x1b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61,
|
0x0b, 0x32, 0x1b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61,
|
||||||
0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x49, 0x44, 0x52, 0x42, 0x02,
|
0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x49, 0x44, 0x52, 0x52, 0x04,
|
||||||
0x18, 0x01, 0x52, 0x04, 0x63, 0x69, 0x64, 0x72, 0x12, 0x32, 0x0a, 0x05, 0x67, 0x65, 0x6f, 0x69,
|
0x63, 0x69, 0x64, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x5f,
|
||||||
0x70, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
|
0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x72, 0x65, 0x76,
|
||||||
0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e,
|
0x65, 0x72, 0x73, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3f, 0x0a, 0x09, 0x47, 0x65, 0x6f,
|
||||||
0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x43, 0x0a, 0x0a,
|
0x49, 0x50, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x32, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18,
|
||||||
0x70, 0x6f, 0x72, 0x74, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b,
|
0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
|
||||||
0x32, 0x20, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f,
|
0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65,
|
||||||
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e,
|
0x6f, 0x49, 0x50, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x63, 0x0a, 0x07, 0x47, 0x65,
|
||||||
0x67, 0x65, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67,
|
0x6f, 0x53, 0x69, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79,
|
||||||
0x65, 0x12, 0x3c, 0x0a, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x0e,
|
0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x75,
|
||||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,
|
0x6e, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61,
|
||||||
0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72,
|
0x69, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
|
||||||
0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12,
|
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
|
||||||
0x49, 0x0a, 0x0c, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18,
|
0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x22,
|
||||||
0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
|
0x43, 0x0a, 0x0b, 0x47, 0x65, 0x6f, 0x53, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x34,
|
||||||
0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65,
|
0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e,
|
||||||
0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x6e,
|
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,
|
||||||
0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x08, 0x6e, 0x65,
|
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x53, 0x69, 0x74, 0x65, 0x52, 0x05, 0x65,
|
||||||
0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x76,
|
0x6e, 0x74, 0x72, 0x79, 0x22, 0xf1, 0x06, 0x0a, 0x0b, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67,
|
||||||
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
0x52, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||||
0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x08, 0x6e, 0x65,
|
0x09, 0x48, 0x00, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x25, 0x0a, 0x0d, 0x62, 0x61, 0x6c, 0x61,
|
||||||
0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x40, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
|
0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x48,
|
||||||
0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x76, 0x32,
|
0x00, 0x52, 0x0c, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x12,
|
||||||
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75,
|
0x35, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||||
0x74, 0x65, 0x72, 0x2e, 0x43, 0x49, 0x44, 0x52, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x73, 0x6f,
|
0x1d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,
|
||||||
0x75, 0x72, 0x63, 0x65, 0x43, 0x69, 0x64, 0x72, 0x12, 0x3f, 0x0a, 0x0c, 0x73, 0x6f, 0x75, 0x72,
|
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06,
|
||||||
0x63, 0x65, 0x5f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c,
|
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x33, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x72, 0x18, 0x03,
|
||||||
0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,
|
||||||
0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x0b, 0x73, 0x6f,
|
0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x49, 0x44,
|
||||||
0x75, 0x72, 0x63, 0x65, 0x47, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x49, 0x0a, 0x10, 0x73, 0x6f, 0x75,
|
0x52, 0x42, 0x02, 0x18, 0x01, 0x52, 0x04, 0x63, 0x69, 0x64, 0x72, 0x12, 0x32, 0x0a, 0x05, 0x67,
|
||||||
0x72, 0x63, 0x65, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x10, 0x20,
|
0x65, 0x6f, 0x69, 0x70, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x76, 0x32, 0x72,
|
||||||
0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
|
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
||||||
|
0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x12,
|
||||||
|
0x43, 0x0a, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x04, 0x20,
|
||||||
|
0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
|
||||||
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74,
|
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74,
|
||||||
0x4c, 0x69, 0x73, 0x74, 0x52, 0x0e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x6f, 0x72, 0x74,
|
0x52, 0x61, 0x6e, 0x67, 0x65, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x52,
|
||||||
0x4c, 0x69, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x65, 0x6d, 0x61,
|
0x61, 0x6e, 0x67, 0x65, 0x12, 0x3c, 0x0a, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x73,
|
||||||
0x69, 0x6c, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x45, 0x6d,
|
0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
|
||||||
0x61, 0x69, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74,
|
0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e,
|
||||||
0x61, 0x67, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e,
|
0x50, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x69,
|
||||||
0x64, 0x54, 0x61, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
|
0x73, 0x74, 0x12, 0x49, 0x0a, 0x0c, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x6c, 0x69,
|
||||||
0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
|
0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
|
||||||
0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x0f,
|
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74,
|
||||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73,
|
0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x02, 0x18, 0x01,
|
||||||
0x12, 0x25, 0x0a, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68,
|
0x52, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x3a, 0x0a,
|
||||||
0x65, 0x72, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
0x08, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0e, 0x32,
|
||||||
0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x42, 0x0c, 0x0a, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65,
|
0x1e, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
|
||||||
0x74, 0x5f, 0x74, 0x61, 0x67, 0x22, 0x6a, 0x0a, 0x0d, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69,
|
0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52,
|
||||||
0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20,
|
0x08, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x40, 0x0a, 0x0b, 0x73, 0x6f, 0x75,
|
||||||
0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x2b, 0x0a, 0x11, 0x6f, 0x75, 0x74, 0x62,
|
0x72, 0x63, 0x65, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b,
|
||||||
0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20,
|
0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
||||||
0x03, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x65, 0x6c,
|
0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x49, 0x44, 0x52, 0x42, 0x02, 0x18, 0x01, 0x52,
|
||||||
0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
|
0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x69, 0x64, 0x72, 0x12, 0x3f, 0x0a, 0x0c, 0x73,
|
||||||
0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
|
0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x0b, 0x20, 0x03, 0x28,
|
||||||
0x79, 0x22, 0xad, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x55, 0x0a, 0x0f,
|
0x0b, 0x32, 0x1c, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61,
|
||||||
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18,
|
0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52,
|
||||||
0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
|
0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x49, 0x0a, 0x10,
|
||||||
0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6f,
|
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x73, 0x74,
|
||||||
0x6e, 0x66, 0x69, 0x67, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74,
|
0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
|
||||||
0x65, 0x67, 0x79, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74,
|
0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50,
|
||||||
0x65, 0x67, 0x79, 0x12, 0x36, 0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28,
|
0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x0e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50,
|
||||||
0x0b, 0x32, 0x22, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61,
|
0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f,
|
||||||
0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e,
|
0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65,
|
||||||
0x67, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x12, 0x4b, 0x0a, 0x0e, 0x62,
|
0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e,
|
||||||
0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x03, 0x20,
|
0x64, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x62,
|
||||||
0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
|
0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x42, 0x61, 0x6c, 0x61,
|
0x63, 0x6f, 0x6c, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e,
|
0x63, 0x6f, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65,
|
||||||
0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x22, 0x47, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61,
|
0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75,
|
||||||
0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x73,
|
0x74, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6d, 0x61,
|
||||||
0x49, 0x73, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x49, 0x70, 0x10, 0x01, 0x12,
|
0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x6f, 0x6d,
|
||||||
0x10, 0x0a, 0x0c, 0x49, 0x70, 0x49, 0x66, 0x4e, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x10,
|
0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x42, 0x0c, 0x0a, 0x0a, 0x74, 0x61,
|
||||||
0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x70, 0x4f, 0x6e, 0x44, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x10,
|
0x72, 0x67, 0x65, 0x74, 0x5f, 0x74, 0x61, 0x67, 0x22, 0xe2, 0x01, 0x0a, 0x0d, 0x42, 0x61, 0x6c,
|
||||||
0x03, 0x42, 0x60, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
|
0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61,
|
||||||
0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x50, 0x01,
|
0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x2b, 0x0a, 0x11,
|
||||||
0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x32, 0x66,
|
0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f,
|
||||||
0x6c, 0x79, 0x2f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x34,
|
0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e,
|
||||||
0x2f, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0xaa, 0x02, 0x15, 0x56, 0x32,
|
0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x74, 0x72,
|
||||||
0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x52, 0x6f, 0x75,
|
0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x74, 0x72,
|
||||||
0x74, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x53, 0x0a, 0x11, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
|
||||||
|
0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b,
|
||||||
|
0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f,
|
||||||
|
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65,
|
||||||
|
0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x10, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65,
|
||||||
|
0x67, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x61,
|
||||||
|
0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09,
|
||||||
|
0x52, 0x0b, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x54, 0x61, 0x67, 0x22, 0x54, 0x0a,
|
||||||
|
0x0e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12,
|
||||||
|
0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x65, 0x78, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||||
|
0x06, 0x72, 0x65, 0x67, 0x65, 0x78, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68,
|
||||||
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x14, 0x0a,
|
||||||
|
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x02, 0x52, 0x05, 0x76, 0x61,
|
||||||
|
0x6c, 0x75, 0x65, 0x22, 0x91, 0x02, 0x0a, 0x17, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
||||||
|
0x4c, 0x65, 0x61, 0x73, 0x74, 0x4c, 0x6f, 0x61, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
|
||||||
|
0x49, 0x0a, 0x0b, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x01,
|
||||||
|
0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,
|
||||||
|
0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x61,
|
||||||
|
0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0b, 0x68,
|
||||||
|
0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x3b, 0x0a, 0x05, 0x63, 0x6f,
|
||||||
|
0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x76, 0x32, 0x72, 0x61,
|
||||||
|
0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||||
|
0x72, 0x2e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74,
|
||||||
|
0x52, 0x05, 0x63, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x61, 0x73, 0x65, 0x6c,
|
||||||
|
0x69, 0x6e, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x03, 0x52, 0x09, 0x62, 0x61, 0x73, 0x65,
|
||||||
|
0x6c, 0x69, 0x6e, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65,
|
||||||
|
0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65,
|
||||||
|
0x64, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x61, 0x78, 0x52, 0x54, 0x54, 0x18, 0x05, 0x20, 0x01, 0x28,
|
||||||
|
0x03, 0x52, 0x06, 0x6d, 0x61, 0x78, 0x52, 0x54, 0x54, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x6f, 0x6c,
|
||||||
|
0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x02, 0x52, 0x09, 0x74, 0x6f,
|
||||||
|
0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x22, 0xb4, 0x01, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x6c,
|
||||||
|
0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x0a, 0x0b,
|
||||||
|
0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||||
|
0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22,
|
||||||
|
0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x18, 0x02,
|
||||||
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x76, 0x69,
|
||||||
|
0x74, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03,
|
||||||
|
0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x24,
|
||||||
|
0x0a, 0x0d, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18,
|
||||||
|
0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x43,
|
||||||
|
0x6f, 0x75, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18,
|
||||||
|
0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0xad,
|
||||||
|
0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x55, 0x0a, 0x0f, 0x64, 0x6f, 0x6d,
|
||||||
|
0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01,
|
||||||
|
0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
|
||||||
|
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||||
|
0x67, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
||||||
|
0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
||||||
|
0x12, 0x36, 0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22,
|
||||||
|
0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
||||||
|
0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75,
|
||||||
|
0x6c, 0x65, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x12, 0x4b, 0x0a, 0x0e, 0x62, 0x61, 0x6c, 0x61,
|
||||||
|
0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
|
||||||
|
0x32, 0x24, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,
|
||||||
|
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69,
|
||||||
|
0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e,
|
||||||
|
0x67, 0x52, 0x75, 0x6c, 0x65, 0x22, 0x47, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53,
|
||||||
|
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x73, 0x49, 0x73, 0x10,
|
||||||
|
0x00, 0x12, 0x09, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x49, 0x70, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c,
|
||||||
|
0x49, 0x70, 0x49, 0x66, 0x4e, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x10, 0x02, 0x12, 0x0e,
|
||||||
|
0x0a, 0x0a, 0x49, 0x70, 0x4f, 0x6e, 0x44, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x10, 0x03, 0x42, 0x60,
|
||||||
|
0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
|
||||||
|
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x50, 0x01, 0x5a, 0x29, 0x67,
|
||||||
|
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x32, 0x66, 0x6c, 0x79, 0x2f,
|
||||||
|
0x76, 0x32, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x34, 0x2f, 0x61, 0x70,
|
||||||
|
0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0xaa, 0x02, 0x15, 0x56, 0x32, 0x52, 0x61, 0x79,
|
||||||
|
0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72,
|
||||||
|
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -1073,28 +1374,32 @@ func file_app_router_config_proto_rawDescGZIP() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var file_app_router_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
var file_app_router_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
||||||
var file_app_router_config_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
var file_app_router_config_proto_msgTypes = make([]protoimpl.MessageInfo, 13)
|
||||||
var file_app_router_config_proto_goTypes = []interface{}{
|
var file_app_router_config_proto_goTypes = []interface{}{
|
||||||
(Domain_Type)(0), // 0: v2ray.core.app.router.Domain.Type
|
(Domain_Type)(0), // 0: v2ray.core.app.router.Domain.Type
|
||||||
(Config_DomainStrategy)(0), // 1: v2ray.core.app.router.Config.DomainStrategy
|
(Config_DomainStrategy)(0), // 1: v2ray.core.app.router.Config.DomainStrategy
|
||||||
(*Domain)(nil), // 2: v2ray.core.app.router.Domain
|
(*Domain)(nil), // 2: v2ray.core.app.router.Domain
|
||||||
(*CIDR)(nil), // 3: v2ray.core.app.router.CIDR
|
(*CIDR)(nil), // 3: v2ray.core.app.router.CIDR
|
||||||
(*GeoIP)(nil), // 4: v2ray.core.app.router.GeoIP
|
(*GeoIP)(nil), // 4: v2ray.core.app.router.GeoIP
|
||||||
(*GeoIPList)(nil), // 5: v2ray.core.app.router.GeoIPList
|
(*GeoIPList)(nil), // 5: v2ray.core.app.router.GeoIPList
|
||||||
(*GeoSite)(nil), // 6: v2ray.core.app.router.GeoSite
|
(*GeoSite)(nil), // 6: v2ray.core.app.router.GeoSite
|
||||||
(*GeoSiteList)(nil), // 7: v2ray.core.app.router.GeoSiteList
|
(*GeoSiteList)(nil), // 7: v2ray.core.app.router.GeoSiteList
|
||||||
(*RoutingRule)(nil), // 8: v2ray.core.app.router.RoutingRule
|
(*RoutingRule)(nil), // 8: v2ray.core.app.router.RoutingRule
|
||||||
(*BalancingRule)(nil), // 9: v2ray.core.app.router.BalancingRule
|
(*BalancingRule)(nil), // 9: v2ray.core.app.router.BalancingRule
|
||||||
(*Config)(nil), // 10: v2ray.core.app.router.Config
|
(*StrategyWeight)(nil), // 10: v2ray.core.app.router.StrategyWeight
|
||||||
(*Domain_Attribute)(nil), // 11: v2ray.core.app.router.Domain.Attribute
|
(*StrategyLeastLoadConfig)(nil), // 11: v2ray.core.app.router.StrategyLeastLoadConfig
|
||||||
(*net.PortRange)(nil), // 12: v2ray.core.common.net.PortRange
|
(*HealthPingConfig)(nil), // 12: v2ray.core.app.router.HealthPingConfig
|
||||||
(*net.PortList)(nil), // 13: v2ray.core.common.net.PortList
|
(*Config)(nil), // 13: v2ray.core.app.router.Config
|
||||||
(*net.NetworkList)(nil), // 14: v2ray.core.common.net.NetworkList
|
(*Domain_Attribute)(nil), // 14: v2ray.core.app.router.Domain.Attribute
|
||||||
(net.Network)(0), // 15: v2ray.core.common.net.Network
|
(*net.PortRange)(nil), // 15: v2ray.core.common.net.PortRange
|
||||||
|
(*net.PortList)(nil), // 16: v2ray.core.common.net.PortList
|
||||||
|
(*net.NetworkList)(nil), // 17: v2ray.core.common.net.NetworkList
|
||||||
|
(net.Network)(0), // 18: v2ray.core.common.net.Network
|
||||||
|
(*serial.TypedMessage)(nil), // 19: v2ray.core.common.serial.TypedMessage
|
||||||
}
|
}
|
||||||
var file_app_router_config_proto_depIdxs = []int32{
|
var file_app_router_config_proto_depIdxs = []int32{
|
||||||
0, // 0: v2ray.core.app.router.Domain.type:type_name -> v2ray.core.app.router.Domain.Type
|
0, // 0: v2ray.core.app.router.Domain.type:type_name -> v2ray.core.app.router.Domain.Type
|
||||||
11, // 1: v2ray.core.app.router.Domain.attribute:type_name -> v2ray.core.app.router.Domain.Attribute
|
14, // 1: v2ray.core.app.router.Domain.attribute:type_name -> v2ray.core.app.router.Domain.Attribute
|
||||||
3, // 2: v2ray.core.app.router.GeoIP.cidr:type_name -> v2ray.core.app.router.CIDR
|
3, // 2: v2ray.core.app.router.GeoIP.cidr:type_name -> v2ray.core.app.router.CIDR
|
||||||
4, // 3: v2ray.core.app.router.GeoIPList.entry:type_name -> v2ray.core.app.router.GeoIP
|
4, // 3: v2ray.core.app.router.GeoIPList.entry:type_name -> v2ray.core.app.router.GeoIP
|
||||||
2, // 4: v2ray.core.app.router.GeoSite.domain:type_name -> v2ray.core.app.router.Domain
|
2, // 4: v2ray.core.app.router.GeoSite.domain:type_name -> v2ray.core.app.router.Domain
|
||||||
@ -1102,21 +1407,24 @@ var file_app_router_config_proto_depIdxs = []int32{
|
|||||||
2, // 6: v2ray.core.app.router.RoutingRule.domain:type_name -> v2ray.core.app.router.Domain
|
2, // 6: v2ray.core.app.router.RoutingRule.domain:type_name -> v2ray.core.app.router.Domain
|
||||||
3, // 7: v2ray.core.app.router.RoutingRule.cidr:type_name -> v2ray.core.app.router.CIDR
|
3, // 7: v2ray.core.app.router.RoutingRule.cidr:type_name -> v2ray.core.app.router.CIDR
|
||||||
4, // 8: v2ray.core.app.router.RoutingRule.geoip:type_name -> v2ray.core.app.router.GeoIP
|
4, // 8: v2ray.core.app.router.RoutingRule.geoip:type_name -> v2ray.core.app.router.GeoIP
|
||||||
12, // 9: v2ray.core.app.router.RoutingRule.port_range:type_name -> v2ray.core.common.net.PortRange
|
15, // 9: v2ray.core.app.router.RoutingRule.port_range:type_name -> v2ray.core.common.net.PortRange
|
||||||
13, // 10: v2ray.core.app.router.RoutingRule.port_list:type_name -> v2ray.core.common.net.PortList
|
16, // 10: v2ray.core.app.router.RoutingRule.port_list:type_name -> v2ray.core.common.net.PortList
|
||||||
14, // 11: v2ray.core.app.router.RoutingRule.network_list:type_name -> v2ray.core.common.net.NetworkList
|
17, // 11: v2ray.core.app.router.RoutingRule.network_list:type_name -> v2ray.core.common.net.NetworkList
|
||||||
15, // 12: v2ray.core.app.router.RoutingRule.networks:type_name -> v2ray.core.common.net.Network
|
18, // 12: v2ray.core.app.router.RoutingRule.networks:type_name -> v2ray.core.common.net.Network
|
||||||
3, // 13: v2ray.core.app.router.RoutingRule.source_cidr:type_name -> v2ray.core.app.router.CIDR
|
3, // 13: v2ray.core.app.router.RoutingRule.source_cidr:type_name -> v2ray.core.app.router.CIDR
|
||||||
4, // 14: v2ray.core.app.router.RoutingRule.source_geoip:type_name -> v2ray.core.app.router.GeoIP
|
4, // 14: v2ray.core.app.router.RoutingRule.source_geoip:type_name -> v2ray.core.app.router.GeoIP
|
||||||
13, // 15: v2ray.core.app.router.RoutingRule.source_port_list:type_name -> v2ray.core.common.net.PortList
|
16, // 15: v2ray.core.app.router.RoutingRule.source_port_list:type_name -> v2ray.core.common.net.PortList
|
||||||
1, // 16: v2ray.core.app.router.Config.domain_strategy:type_name -> v2ray.core.app.router.Config.DomainStrategy
|
19, // 16: v2ray.core.app.router.BalancingRule.strategy_settings:type_name -> v2ray.core.common.serial.TypedMessage
|
||||||
8, // 17: v2ray.core.app.router.Config.rule:type_name -> v2ray.core.app.router.RoutingRule
|
12, // 17: v2ray.core.app.router.StrategyLeastLoadConfig.healthCheck:type_name -> v2ray.core.app.router.HealthPingConfig
|
||||||
9, // 18: v2ray.core.app.router.Config.balancing_rule:type_name -> v2ray.core.app.router.BalancingRule
|
10, // 18: v2ray.core.app.router.StrategyLeastLoadConfig.costs:type_name -> v2ray.core.app.router.StrategyWeight
|
||||||
19, // [19:19] is the sub-list for method output_type
|
1, // 19: v2ray.core.app.router.Config.domain_strategy:type_name -> v2ray.core.app.router.Config.DomainStrategy
|
||||||
19, // [19:19] is the sub-list for method input_type
|
8, // 20: v2ray.core.app.router.Config.rule:type_name -> v2ray.core.app.router.RoutingRule
|
||||||
19, // [19:19] is the sub-list for extension type_name
|
9, // 21: v2ray.core.app.router.Config.balancing_rule:type_name -> v2ray.core.app.router.BalancingRule
|
||||||
19, // [19:19] is the sub-list for extension extendee
|
22, // [22:22] is the sub-list for method output_type
|
||||||
0, // [0:19] is the sub-list for field type_name
|
22, // [22:22] is the sub-list for method input_type
|
||||||
|
22, // [22:22] is the sub-list for extension type_name
|
||||||
|
22, // [22:22] is the sub-list for extension extendee
|
||||||
|
0, // [0:22] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_app_router_config_proto_init() }
|
func init() { file_app_router_config_proto_init() }
|
||||||
@ -1222,7 +1530,7 @@ func file_app_router_config_proto_init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_app_router_config_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
|
file_app_router_config_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*Config); i {
|
switch v := v.(*StrategyWeight); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
case 1:
|
case 1:
|
||||||
@ -1234,6 +1542,42 @@ func file_app_router_config_proto_init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_app_router_config_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
|
file_app_router_config_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*StrategyLeastLoadConfig); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_router_config_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*HealthPingConfig); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_router_config_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*Config); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_router_config_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*Domain_Attribute); i {
|
switch v := v.(*Domain_Attribute); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@ -1250,7 +1594,7 @@ func file_app_router_config_proto_init() {
|
|||||||
(*RoutingRule_Tag)(nil),
|
(*RoutingRule_Tag)(nil),
|
||||||
(*RoutingRule_BalancingTag)(nil),
|
(*RoutingRule_BalancingTag)(nil),
|
||||||
}
|
}
|
||||||
file_app_router_config_proto_msgTypes[9].OneofWrappers = []interface{}{
|
file_app_router_config_proto_msgTypes[12].OneofWrappers = []interface{}{
|
||||||
(*Domain_Attribute_BoolValue)(nil),
|
(*Domain_Attribute_BoolValue)(nil),
|
||||||
(*Domain_Attribute_IntValue)(nil),
|
(*Domain_Attribute_IntValue)(nil),
|
||||||
}
|
}
|
||||||
@ -1260,7 +1604,7 @@ func file_app_router_config_proto_init() {
|
|||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: file_app_router_config_proto_rawDesc,
|
RawDescriptor: file_app_router_config_proto_rawDesc,
|
||||||
NumEnums: 2,
|
NumEnums: 2,
|
||||||
NumMessages: 10,
|
NumMessages: 13,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
},
|
},
|
||||||
|
@ -6,6 +6,7 @@ option go_package = "github.com/v2fly/v2ray-core/v4/app/router";
|
|||||||
option java_package = "com.v2ray.core.app.router";
|
option java_package = "com.v2ray.core.app.router";
|
||||||
option java_multiple_files = true;
|
option java_multiple_files = true;
|
||||||
|
|
||||||
|
import "common/serial/typed_message.proto";
|
||||||
import "common/net/port.proto";
|
import "common/net/port.proto";
|
||||||
import "common/net/network.proto";
|
import "common/net/network.proto";
|
||||||
|
|
||||||
@ -128,6 +129,42 @@ message BalancingRule {
|
|||||||
string tag = 1;
|
string tag = 1;
|
||||||
repeated string outbound_selector = 2;
|
repeated string outbound_selector = 2;
|
||||||
string strategy = 3;
|
string strategy = 3;
|
||||||
|
v2ray.core.common.serial.TypedMessage strategy_settings = 4;
|
||||||
|
string fallback_tag = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message StrategyWeight {
|
||||||
|
bool regexp = 1;
|
||||||
|
string match = 2;
|
||||||
|
float value =3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message StrategyLeastLoadConfig {
|
||||||
|
HealthPingConfig healthCheck = 1;
|
||||||
|
// weight settings
|
||||||
|
repeated StrategyWeight costs = 2;
|
||||||
|
// RTT baselines for selecting, int64 values of time.Duration
|
||||||
|
repeated int64 baselines = 3;
|
||||||
|
// expected nodes count to select
|
||||||
|
int32 expected = 4;
|
||||||
|
// max acceptable rtt, filter away high delay nodes. defalut 0
|
||||||
|
int64 maxRTT = 5;
|
||||||
|
// acceptable failure rate
|
||||||
|
float tolerance = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
message HealthPingConfig {
|
||||||
|
// destination url, need 204 for success return
|
||||||
|
// default http://www.google.com/gen_204
|
||||||
|
string destination = 1;
|
||||||
|
// connectivity check url
|
||||||
|
string connectivity = 2;
|
||||||
|
// health check interval, int64 values of time.Duration
|
||||||
|
int64 interval = 3;
|
||||||
|
// samplingcount is the amount of recent ping results which are kept for calculation
|
||||||
|
int32 samplingCount = 4;
|
||||||
|
// ping timeout, int64 values of time.Duration
|
||||||
|
int64 timeout = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Config {
|
message Config {
|
||||||
|
231
app/router/healthping.go
Normal file
231
app/router/healthping.go
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
sync "sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/v2fly/v2ray-core/v4/common/dice"
|
||||||
|
"github.com/v2fly/v2ray-core/v4/features/routing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HealthPingSettings holds settings for health Checker
|
||||||
|
type HealthPingSettings struct {
|
||||||
|
Destination string `json:"destination"`
|
||||||
|
Connectivity string `json:"connectivity"`
|
||||||
|
Interval time.Duration `json:"interval"`
|
||||||
|
SamplingCount int `json:"sampling"`
|
||||||
|
Timeout time.Duration `json:"timeout"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// HealthPing is the health checker for balancers
|
||||||
|
type HealthPing struct {
|
||||||
|
access sync.Mutex
|
||||||
|
ticker *time.Ticker
|
||||||
|
dispatcher routing.Dispatcher
|
||||||
|
|
||||||
|
Settings *HealthPingSettings
|
||||||
|
Results map[string]*HealthPingRTTS
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHealthPing creates a new HealthPing with settings
|
||||||
|
func NewHealthPing(config *HealthPingConfig, dispatcher routing.Dispatcher) *HealthPing {
|
||||||
|
settings := &HealthPingSettings{}
|
||||||
|
if config != nil {
|
||||||
|
settings = &HealthPingSettings{
|
||||||
|
Connectivity: strings.TrimSpace(config.Connectivity),
|
||||||
|
Destination: strings.TrimSpace(config.Destination),
|
||||||
|
Interval: time.Duration(config.Interval),
|
||||||
|
SamplingCount: int(config.SamplingCount),
|
||||||
|
Timeout: time.Duration(config.Timeout),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if settings.Destination == "" {
|
||||||
|
settings.Destination = "http://www.google.com/gen_204"
|
||||||
|
}
|
||||||
|
if settings.Interval == 0 {
|
||||||
|
settings.Interval = time.Duration(1) * time.Minute
|
||||||
|
} else if settings.Interval < 10 {
|
||||||
|
newError("health check interval is too small, 10s is applied").AtWarning().WriteToLog()
|
||||||
|
settings.Interval = time.Duration(10) * time.Second
|
||||||
|
}
|
||||||
|
if settings.SamplingCount <= 0 {
|
||||||
|
settings.SamplingCount = 10
|
||||||
|
}
|
||||||
|
if settings.Timeout <= 0 {
|
||||||
|
// results are saved after all health pings finish,
|
||||||
|
// a larger timeout could possibly makes checks run longer
|
||||||
|
settings.Timeout = time.Duration(5) * time.Second
|
||||||
|
}
|
||||||
|
return &HealthPing{
|
||||||
|
dispatcher: dispatcher,
|
||||||
|
Settings: settings,
|
||||||
|
Results: nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartScheduler implements the HealthChecker
|
||||||
|
func (h *HealthPing) StartScheduler(selector func() ([]string, error)) {
|
||||||
|
if h.ticker != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
interval := h.Settings.Interval * time.Duration(h.Settings.SamplingCount)
|
||||||
|
ticker := time.NewTicker(interval)
|
||||||
|
h.ticker = ticker
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
go func() {
|
||||||
|
tags, err := selector()
|
||||||
|
if err != nil {
|
||||||
|
newError("error select outbounds for scheduled health check: ", err).AtWarning().WriteToLog()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
h.doCheck(tags, interval, h.Settings.SamplingCount)
|
||||||
|
h.Cleanup(tags)
|
||||||
|
}()
|
||||||
|
_, ok := <-ticker.C
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// StopScheduler implements the HealthChecker
|
||||||
|
func (h *HealthPing) StopScheduler() {
|
||||||
|
h.ticker.Stop()
|
||||||
|
h.ticker = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check implements the HealthChecker
|
||||||
|
func (h *HealthPing) Check(tags []string) error {
|
||||||
|
if len(tags) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
newError("perform one-time health check for tags ", tags).AtInfo().WriteToLog()
|
||||||
|
h.doCheck(tags, 0, 1)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type rtt struct {
|
||||||
|
handler string
|
||||||
|
value time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// doCheck performs the 'rounds' amount checks in given 'duration'. You should make
|
||||||
|
// sure all tags are valid for current balancer
|
||||||
|
func (h *HealthPing) doCheck(tags []string, duration time.Duration, rounds int) {
|
||||||
|
count := len(tags) * rounds
|
||||||
|
if count == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ch := make(chan *rtt, count)
|
||||||
|
// rtts := make(map[string][]time.Duration)
|
||||||
|
for _, tag := range tags {
|
||||||
|
handler := tag
|
||||||
|
client := newPingClient(
|
||||||
|
h.Settings.Destination,
|
||||||
|
h.Settings.Timeout,
|
||||||
|
handler,
|
||||||
|
h.dispatcher,
|
||||||
|
)
|
||||||
|
for i := 0; i < rounds; i++ {
|
||||||
|
delay := time.Duration(0)
|
||||||
|
if duration > 0 {
|
||||||
|
delay = time.Duration(dice.Roll(int(duration)))
|
||||||
|
}
|
||||||
|
time.AfterFunc(delay, func() {
|
||||||
|
newError("checking ", handler).AtDebug().WriteToLog()
|
||||||
|
delay, err := client.MeasureDelay()
|
||||||
|
if err == nil {
|
||||||
|
ch <- &rtt{
|
||||||
|
handler: handler,
|
||||||
|
value: delay,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !h.checkConnectivity() {
|
||||||
|
newError("network is down").AtWarning().WriteToLog()
|
||||||
|
ch <- &rtt{
|
||||||
|
handler: handler,
|
||||||
|
value: 0,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
newError(fmt.Sprintf(
|
||||||
|
"error ping %s with %s: %s",
|
||||||
|
h.Settings.Destination,
|
||||||
|
handler,
|
||||||
|
err,
|
||||||
|
)).AtWarning().WriteToLog()
|
||||||
|
ch <- &rtt{
|
||||||
|
handler: handler,
|
||||||
|
value: rttFailed,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
rtt := <-ch
|
||||||
|
if rtt.value > 0 {
|
||||||
|
// should not put results when network is down
|
||||||
|
h.PutResult(rtt.handler, rtt.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PutResult put a ping rtt to results
|
||||||
|
func (h *HealthPing) PutResult(tag string, rtt time.Duration) {
|
||||||
|
h.access.Lock()
|
||||||
|
defer h.access.Unlock()
|
||||||
|
if h.Results == nil {
|
||||||
|
h.Results = make(map[string]*HealthPingRTTS)
|
||||||
|
}
|
||||||
|
r, ok := h.Results[tag]
|
||||||
|
if !ok {
|
||||||
|
// validity is 2 times to sampling period, since the check are
|
||||||
|
// distributed in the time line randomly, in extreme cases,
|
||||||
|
// previous checks are distributed on the left, and latters
|
||||||
|
// on the right
|
||||||
|
validity := h.Settings.Interval * time.Duration(h.Settings.SamplingCount) * 2
|
||||||
|
r = NewHealthPingResult(h.Settings.SamplingCount, validity)
|
||||||
|
h.Results[tag] = r
|
||||||
|
}
|
||||||
|
r.Put(rtt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup removes results of removed handlers,
|
||||||
|
// tags should be all valid tags of the Balancer now
|
||||||
|
func (h *HealthPing) Cleanup(tags []string) {
|
||||||
|
h.access.Lock()
|
||||||
|
defer h.access.Unlock()
|
||||||
|
for tag := range h.Results {
|
||||||
|
found := false
|
||||||
|
for _, v := range tags {
|
||||||
|
if tag == v {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
delete(h.Results, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkConnectivity checks the network connectivity, it returns
|
||||||
|
// true if network is good or "connectivity check url" not set
|
||||||
|
func (h *HealthPing) checkConnectivity() bool {
|
||||||
|
if h.Settings.Connectivity == "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
tester := newDirectPingClient(
|
||||||
|
h.Settings.Connectivity,
|
||||||
|
h.Settings.Timeout,
|
||||||
|
)
|
||||||
|
if _, err := tester.MeasureDelay(); err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
143
app/router/healthping_result.go
Normal file
143
app/router/healthping_result.go
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HealthPingStats is the statistics of HealthPingRTTS
|
||||||
|
type HealthPingStats struct {
|
||||||
|
All int
|
||||||
|
Fail int
|
||||||
|
Deviation time.Duration
|
||||||
|
Average time.Duration
|
||||||
|
Max time.Duration
|
||||||
|
Min time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// HealthPingRTTS holds ping rtts for health Checker
|
||||||
|
type HealthPingRTTS struct {
|
||||||
|
idx int
|
||||||
|
cap int
|
||||||
|
validity time.Duration
|
||||||
|
rtts []*pingRTT
|
||||||
|
|
||||||
|
lastUpdateAt time.Time
|
||||||
|
stats *HealthPingStats
|
||||||
|
}
|
||||||
|
|
||||||
|
type pingRTT struct {
|
||||||
|
time time.Time
|
||||||
|
value time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHealthPingResult returns a *HealthPingResult with specified capacity
|
||||||
|
func NewHealthPingResult(cap int, validity time.Duration) *HealthPingRTTS {
|
||||||
|
return &HealthPingRTTS{cap: cap, validity: validity}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get gets statistics of the HealthPingRTTS
|
||||||
|
func (h *HealthPingRTTS) Get() *HealthPingStats {
|
||||||
|
return h.getStatistics()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWithCache get statistics and write cache for next call
|
||||||
|
// Make sure use Mutex.Lock() before calling it, RWMutex.RLock()
|
||||||
|
// is not an option since it writes cache
|
||||||
|
func (h *HealthPingRTTS) GetWithCache() *HealthPingStats {
|
||||||
|
lastPutAt := h.rtts[h.idx].time
|
||||||
|
now := time.Now()
|
||||||
|
if h.stats == nil || h.lastUpdateAt.Before(lastPutAt) || h.findOutdated(now) >= 0 {
|
||||||
|
h.stats = h.getStatistics()
|
||||||
|
h.lastUpdateAt = now
|
||||||
|
}
|
||||||
|
return h.stats
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put puts a new rtt to the HealthPingResult
|
||||||
|
func (h *HealthPingRTTS) Put(d time.Duration) {
|
||||||
|
if h.rtts == nil {
|
||||||
|
h.rtts = make([]*pingRTT, h.cap)
|
||||||
|
for i := 0; i < h.cap; i++ {
|
||||||
|
h.rtts[i] = &pingRTT{}
|
||||||
|
}
|
||||||
|
h.idx = -1
|
||||||
|
}
|
||||||
|
h.idx = h.calcIndex(1)
|
||||||
|
now := time.Now()
|
||||||
|
h.rtts[h.idx].time = now
|
||||||
|
h.rtts[h.idx].value = d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HealthPingRTTS) calcIndex(step int) int {
|
||||||
|
idx := h.idx
|
||||||
|
idx += step
|
||||||
|
if idx >= h.cap {
|
||||||
|
idx %= h.cap
|
||||||
|
}
|
||||||
|
return idx
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HealthPingRTTS) getStatistics() *HealthPingStats {
|
||||||
|
stats := &HealthPingStats{}
|
||||||
|
stats.Fail = 0
|
||||||
|
stats.Max = 0
|
||||||
|
stats.Min = rttFailed
|
||||||
|
sum := time.Duration(0)
|
||||||
|
cnt := 0
|
||||||
|
validRTTs := make([]time.Duration, 0)
|
||||||
|
for _, rtt := range h.rtts {
|
||||||
|
switch {
|
||||||
|
case rtt.value == 0 || time.Since(rtt.time) > h.validity:
|
||||||
|
continue
|
||||||
|
case rtt.value == rttFailed:
|
||||||
|
stats.Fail++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cnt++
|
||||||
|
sum += rtt.value
|
||||||
|
validRTTs = append(validRTTs, rtt.value)
|
||||||
|
if stats.Max < rtt.value {
|
||||||
|
stats.Max = rtt.value
|
||||||
|
}
|
||||||
|
if stats.Min > rtt.value {
|
||||||
|
stats.Min = rtt.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stats.All = cnt + stats.Fail
|
||||||
|
if cnt == 0 {
|
||||||
|
stats.Min = 0
|
||||||
|
return stats
|
||||||
|
}
|
||||||
|
stats.Average = time.Duration(int(sum) / cnt)
|
||||||
|
var std float64
|
||||||
|
if cnt < 2 {
|
||||||
|
// no enough data for standard deviation, we assume it's half of the average rtt
|
||||||
|
// if we don't do this, standard deviation of 1 round tested nodes is 0, will always
|
||||||
|
// selected before 2 or more rounds tested nodes
|
||||||
|
std = float64(stats.Average / 2)
|
||||||
|
} else {
|
||||||
|
variance := float64(0)
|
||||||
|
for _, rtt := range validRTTs {
|
||||||
|
variance += math.Pow(float64(rtt-stats.Average), 2)
|
||||||
|
}
|
||||||
|
std = math.Sqrt(variance / float64(cnt))
|
||||||
|
}
|
||||||
|
stats.Deviation = time.Duration(std)
|
||||||
|
return stats
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HealthPingRTTS) findOutdated(now time.Time) int {
|
||||||
|
for i := h.cap - 1; i < 2*h.cap; i++ {
|
||||||
|
// from oldest to latest
|
||||||
|
idx := h.calcIndex(i)
|
||||||
|
validity := h.rtts[idx].time.Add(h.validity)
|
||||||
|
if h.lastUpdateAt.After(validity) {
|
||||||
|
return idx
|
||||||
|
}
|
||||||
|
if validity.Before(now) {
|
||||||
|
return idx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
106
app/router/healthping_result_test.go
Normal file
106
app/router/healthping_result_test.go
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
package router_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
reflect "reflect"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/v2fly/v2ray-core/v4/app/router"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHealthPingResults(t *testing.T) {
|
||||||
|
rtts := []int64{60, 140, 60, 140, 60, 60, 140, 60, 140}
|
||||||
|
hr := router.NewHealthPingResult(4, time.Hour)
|
||||||
|
for _, rtt := range rtts {
|
||||||
|
hr.Put(time.Duration(rtt))
|
||||||
|
}
|
||||||
|
rttFailed := time.Duration(math.MaxInt64)
|
||||||
|
expected := &router.HealthPingStats{
|
||||||
|
All: 4,
|
||||||
|
Fail: 0,
|
||||||
|
Deviation: 40,
|
||||||
|
Average: 100,
|
||||||
|
Max: 140,
|
||||||
|
Min: 60,
|
||||||
|
}
|
||||||
|
actual := hr.Get()
|
||||||
|
if !reflect.DeepEqual(expected, actual) {
|
||||||
|
t.Errorf("expected: %v, actual: %v", expected, actual)
|
||||||
|
}
|
||||||
|
hr.Put(rttFailed)
|
||||||
|
hr.Put(rttFailed)
|
||||||
|
expected.Fail = 2
|
||||||
|
actual = hr.Get()
|
||||||
|
if !reflect.DeepEqual(expected, actual) {
|
||||||
|
t.Errorf("failed half-failures test, expected: %v, actual: %v", expected, actual)
|
||||||
|
}
|
||||||
|
hr.Put(rttFailed)
|
||||||
|
hr.Put(rttFailed)
|
||||||
|
expected = &router.HealthPingStats{
|
||||||
|
All: 4,
|
||||||
|
Fail: 4,
|
||||||
|
Deviation: 0,
|
||||||
|
Average: 0,
|
||||||
|
Max: 0,
|
||||||
|
Min: 0,
|
||||||
|
}
|
||||||
|
actual = hr.Get()
|
||||||
|
if !reflect.DeepEqual(expected, actual) {
|
||||||
|
t.Errorf("failed all-failures test, expected: %v, actual: %v", expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHealthPingResultsIgnoreOutdated(t *testing.T) {
|
||||||
|
rtts := []int64{60, 140, 60, 140}
|
||||||
|
hr := router.NewHealthPingResult(4, time.Duration(10)*time.Millisecond)
|
||||||
|
for i, rtt := range rtts {
|
||||||
|
if i == 2 {
|
||||||
|
// wait for previous 2 outdated
|
||||||
|
time.Sleep(time.Duration(10) * time.Millisecond)
|
||||||
|
}
|
||||||
|
hr.Put(time.Duration(rtt))
|
||||||
|
}
|
||||||
|
hr.Get()
|
||||||
|
expected := &router.HealthPingStats{
|
||||||
|
All: 2,
|
||||||
|
Fail: 0,
|
||||||
|
Deviation: 40,
|
||||||
|
Average: 100,
|
||||||
|
Max: 140,
|
||||||
|
Min: 60,
|
||||||
|
}
|
||||||
|
actual := hr.Get()
|
||||||
|
if !reflect.DeepEqual(expected, actual) {
|
||||||
|
t.Errorf("failed 'half-outdated' test, expected: %v, actual: %v", expected, actual)
|
||||||
|
}
|
||||||
|
// wait for all outdated
|
||||||
|
time.Sleep(time.Duration(10) * time.Millisecond)
|
||||||
|
expected = &router.HealthPingStats{
|
||||||
|
All: 0,
|
||||||
|
Fail: 0,
|
||||||
|
Deviation: 0,
|
||||||
|
Average: 0,
|
||||||
|
Max: 0,
|
||||||
|
Min: 0,
|
||||||
|
}
|
||||||
|
actual = hr.Get()
|
||||||
|
if !reflect.DeepEqual(expected, actual) {
|
||||||
|
t.Errorf("failed 'outdated / not-tested' test, expected: %v, actual: %v", expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
hr.Put(time.Duration(60))
|
||||||
|
expected = &router.HealthPingStats{
|
||||||
|
All: 1,
|
||||||
|
Fail: 0,
|
||||||
|
// 1 sample, std=0.5rtt
|
||||||
|
Deviation: 30,
|
||||||
|
Average: 60,
|
||||||
|
Max: 60,
|
||||||
|
Min: 60,
|
||||||
|
}
|
||||||
|
actual = hr.Get()
|
||||||
|
if !reflect.DeepEqual(expected, actual) {
|
||||||
|
t.Errorf("expected: %v, actual: %v", expected, actual)
|
||||||
|
}
|
||||||
|
}
|
81
app/router/ping.go
Normal file
81
app/router/ping.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/v2fly/v2ray-core/v4/common/net"
|
||||||
|
"github.com/v2fly/v2ray-core/v4/common/session"
|
||||||
|
"github.com/v2fly/v2ray-core/v4/features/routing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type pingClient struct {
|
||||||
|
destination string
|
||||||
|
httpClient *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPingClient(destination string, timeout time.Duration, handler string, dispatcher routing.Dispatcher) *pingClient {
|
||||||
|
return &pingClient{
|
||||||
|
destination: destination,
|
||||||
|
httpClient: newHTTPClient(handler, dispatcher, timeout),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDirectPingClient(destination string, timeout time.Duration) *pingClient {
|
||||||
|
return &pingClient{
|
||||||
|
destination: destination,
|
||||||
|
httpClient: &http.Client{Timeout: timeout},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newHTTPClient(handler string, dispatcher routing.Dispatcher, timeout time.Duration) *http.Client {
|
||||||
|
tr := &http.Transport{
|
||||||
|
DisableKeepAlives: true,
|
||||||
|
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
dest, err := net.ParseDestination(network + ":" + addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
h := &session.Handler{
|
||||||
|
Tag: handler,
|
||||||
|
}
|
||||||
|
ctx = session.ContextWithHandler(ctx, h)
|
||||||
|
link, err := dispatcher.Dispatch(ctx, dest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return net.NewConnection(
|
||||||
|
net.ConnectionInputMulti(link.Writer),
|
||||||
|
net.ConnectionOutputMulti(link.Reader),
|
||||||
|
), nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return &http.Client{
|
||||||
|
Transport: tr,
|
||||||
|
Timeout: timeout,
|
||||||
|
// don't follow redirect
|
||||||
|
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||||
|
return http.ErrUseLastResponse
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MeasureDelay returns the delay time of the request to dest
|
||||||
|
func (s *pingClient) MeasureDelay() (time.Duration, error) {
|
||||||
|
if s.httpClient == nil {
|
||||||
|
panic("pingClient no initialized")
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest(http.MethodHead, s.destination, nil)
|
||||||
|
if err != nil {
|
||||||
|
return rttFailed, err
|
||||||
|
}
|
||||||
|
start := time.Now()
|
||||||
|
resp, err := s.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return rttFailed, err
|
||||||
|
}
|
||||||
|
// don't wait for body
|
||||||
|
resp.Body.Close()
|
||||||
|
return time.Since(start), nil
|
||||||
|
}
|
@ -29,13 +29,13 @@ type Route struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Init initializes the Router.
|
// Init initializes the Router.
|
||||||
func (r *Router) Init(ctx context.Context, config *Config, d dns.Client, ohm outbound.Manager) error {
|
func (r *Router) Init(ctx context.Context, config *Config, d dns.Client, ohm outbound.Manager, dispatcher routing.Dispatcher) error {
|
||||||
r.domainStrategy = config.DomainStrategy
|
r.domainStrategy = config.DomainStrategy
|
||||||
r.dns = d
|
r.dns = d
|
||||||
|
|
||||||
r.balancers = make(map[string]*Balancer, len(config.BalancingRule))
|
r.balancers = make(map[string]*Balancer, len(config.BalancingRule))
|
||||||
for _, rule := range config.BalancingRule {
|
for _, rule := range config.BalancingRule {
|
||||||
balancer, err := rule.Build(ohm)
|
balancer, err := rule.Build(ohm, dispatcher)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -113,12 +113,26 @@ func (r *Router) pickRouteInternal(ctx routing.Context) (*Rule, routing.Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start implements common.Runnable.
|
// Start implements common.Runnable.
|
||||||
func (*Router) Start() error {
|
func (r *Router) Start() error {
|
||||||
|
for _, b := range r.balancers {
|
||||||
|
checker, ok := b.strategy.(routing.HealthChecker)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
checker.StartScheduler(b.SelectOutbounds)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close implements common.Closable.
|
// Close implements common.Closable.
|
||||||
func (*Router) Close() error {
|
func (r *Router) Close() error {
|
||||||
|
for _, b := range r.balancers {
|
||||||
|
checker, ok := b.strategy.(routing.HealthChecker)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
checker.StopScheduler()
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,8 +154,8 @@ func (r *Route) GetOutboundTag() string {
|
|||||||
func init() {
|
func init() {
|
||||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||||
r := new(Router)
|
r := new(Router)
|
||||||
if err := core.RequireFeatures(ctx, func(d dns.Client, ohm outbound.Manager) error {
|
if err := core.RequireFeatures(ctx, func(d dns.Client, ohm outbound.Manager, dispatcher routing.Dispatcher) error {
|
||||||
return r.Init(ctx, config.(*Config), d, ohm)
|
return r.Init(ctx, config.(*Config), d, ohm, dispatcher)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
118
app/router/router_health.go
Normal file
118
app/router/router_health.go
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/v2fly/v2ray-core/v4/features/routing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CheckHanlders implements routing.RouterChecker.
|
||||||
|
func (r *Router) CheckHanlders(tags []string) error {
|
||||||
|
errs := make([]error, 0)
|
||||||
|
for _, b := range r.balancers {
|
||||||
|
checker, ok := b.strategy.(routing.HealthChecker)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
all, err := b.SelectOutbounds()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ts := getCheckTags(tags, all)
|
||||||
|
err = checker.Check(ts)
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(errs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return getCollectError(errs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCheckTags(tags, all []string) []string {
|
||||||
|
ts := make([]string, 0)
|
||||||
|
for _, t := range tags {
|
||||||
|
if findSliceIndex(all, t) >= 0 && findSliceIndex(ts, t) < 0 {
|
||||||
|
ts = append(ts, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ts
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckBalancers implements routing.RouterChecker.
|
||||||
|
func (r *Router) CheckBalancers(tags []string) error {
|
||||||
|
errs := make([]error, 0)
|
||||||
|
for t, b := range r.balancers {
|
||||||
|
if len(tags) > 0 && findSliceIndex(tags, t) < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
checker, ok := b.strategy.(routing.HealthChecker)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
tags, err := b.SelectOutbounds()
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
err = checker.Check(tags)
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(errs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return getCollectError(errs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCollectError(errs []error) error {
|
||||||
|
sb := new(strings.Builder)
|
||||||
|
sb.WriteString("collect errors:\n")
|
||||||
|
for _, err := range errs {
|
||||||
|
sb.WriteString(" * ")
|
||||||
|
sb.WriteString(err.Error())
|
||||||
|
sb.WriteString("\n")
|
||||||
|
}
|
||||||
|
return errors.New(sb.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBalancersInfo implements routing.RouterChecker.
|
||||||
|
func (r *Router) GetBalancersInfo(tags []string) (resp []*routing.BalancerInfo, err error) {
|
||||||
|
resp = make([]*routing.BalancerInfo, 0)
|
||||||
|
for t, b := range r.balancers {
|
||||||
|
if len(tags) > 0 && findSliceIndex(tags, t) < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
all, err := b.SelectOutbounds()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var override *routing.BalancingOverrideInfo
|
||||||
|
if o := b.override.Get(); o != nil {
|
||||||
|
override = &routing.BalancingOverrideInfo{
|
||||||
|
Until: o.until,
|
||||||
|
Selects: o.selects,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stat := &routing.BalancerInfo{
|
||||||
|
Tag: t,
|
||||||
|
Override: override,
|
||||||
|
Strategy: b.strategy.GetInformation(all),
|
||||||
|
}
|
||||||
|
resp = append(resp, stat)
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func findSliceIndex(slice []string, find string) int {
|
||||||
|
index := -1
|
||||||
|
for i, v := range slice {
|
||||||
|
if find == v {
|
||||||
|
index = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return index
|
||||||
|
}
|
@ -9,6 +9,7 @@ import (
|
|||||||
. "github.com/v2fly/v2ray-core/v4/app/router"
|
. "github.com/v2fly/v2ray-core/v4/app/router"
|
||||||
"github.com/v2fly/v2ray-core/v4/common"
|
"github.com/v2fly/v2ray-core/v4/common"
|
||||||
"github.com/v2fly/v2ray-core/v4/common/net"
|
"github.com/v2fly/v2ray-core/v4/common/net"
|
||||||
|
serial "github.com/v2fly/v2ray-core/v4/common/serial"
|
||||||
"github.com/v2fly/v2ray-core/v4/common/session"
|
"github.com/v2fly/v2ray-core/v4/common/session"
|
||||||
"github.com/v2fly/v2ray-core/v4/features/outbound"
|
"github.com/v2fly/v2ray-core/v4/features/outbound"
|
||||||
routing_session "github.com/v2fly/v2ray-core/v4/features/routing/session"
|
routing_session "github.com/v2fly/v2ray-core/v4/features/routing/session"
|
||||||
@ -43,7 +44,7 @@ func TestSimpleRouter(t *testing.T) {
|
|||||||
common.Must(r.Init(context.TODO(), config, mockDNS, &mockOutboundManager{
|
common.Must(r.Init(context.TODO(), config, mockDNS, &mockOutboundManager{
|
||||||
Manager: mockOhm,
|
Manager: mockOhm,
|
||||||
HandlerSelector: mockHs,
|
HandlerSelector: mockHs,
|
||||||
}))
|
}, nil))
|
||||||
|
|
||||||
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("v2fly.org"), 80)})
|
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("v2fly.org"), 80)})
|
||||||
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
|
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
|
||||||
@ -84,7 +85,7 @@ func TestSimpleBalancer(t *testing.T) {
|
|||||||
common.Must(r.Init(context.TODO(), config, mockDNS, &mockOutboundManager{
|
common.Must(r.Init(context.TODO(), config, mockDNS, &mockOutboundManager{
|
||||||
Manager: mockOhm,
|
Manager: mockOhm,
|
||||||
HandlerSelector: mockHs,
|
HandlerSelector: mockHs,
|
||||||
}))
|
}, nil))
|
||||||
|
|
||||||
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("v2fly.org"), 80)})
|
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("v2fly.org"), 80)})
|
||||||
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
|
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
|
||||||
@ -94,6 +95,52 @@ func TestSimpleBalancer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLeastLoadBalancer(t *testing.T) {
|
||||||
|
config := &Config{
|
||||||
|
Rule: []*RoutingRule{
|
||||||
|
{
|
||||||
|
TargetTag: &RoutingRule_BalancingTag{
|
||||||
|
BalancingTag: "balance",
|
||||||
|
},
|
||||||
|
Networks: []net.Network{net.Network_TCP},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
BalancingRule: []*BalancingRule{
|
||||||
|
{
|
||||||
|
Tag: "balance",
|
||||||
|
OutboundSelector: []string{"test-"},
|
||||||
|
Strategy: "leastLoad",
|
||||||
|
StrategySettings: serial.ToTypedMessage(&StrategyLeastLoadConfig{
|
||||||
|
HealthCheck: nil,
|
||||||
|
Baselines: nil,
|
||||||
|
Expected: 1,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
mockCtl := gomock.NewController(t)
|
||||||
|
defer mockCtl.Finish()
|
||||||
|
|
||||||
|
mockDNS := mocks.NewDNSClient(mockCtl)
|
||||||
|
mockOhm := mocks.NewOutboundManager(mockCtl)
|
||||||
|
mockHs := mocks.NewOutboundHandlerSelector(mockCtl)
|
||||||
|
|
||||||
|
mockHs.EXPECT().Select(gomock.Eq([]string{"test-"})).Return([]string{"test1"})
|
||||||
|
|
||||||
|
r := new(Router)
|
||||||
|
common.Must(r.Init(context.TODO(), config, mockDNS, &mockOutboundManager{
|
||||||
|
Manager: mockOhm,
|
||||||
|
HandlerSelector: mockHs,
|
||||||
|
}, nil))
|
||||||
|
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("v2ray.com"), 80)})
|
||||||
|
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
|
||||||
|
common.Must(err)
|
||||||
|
if tag := route.GetOutboundTag(); tag != "test1" {
|
||||||
|
t.Error("expect tag 'test1', bug actually ", tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestIPOnDemand(t *testing.T) {
|
func TestIPOnDemand(t *testing.T) {
|
||||||
config := &Config{
|
config := &Config{
|
||||||
DomainStrategy: Config_IpOnDemand,
|
DomainStrategy: Config_IpOnDemand,
|
||||||
@ -119,7 +166,7 @@ func TestIPOnDemand(t *testing.T) {
|
|||||||
mockDNS.EXPECT().LookupIP(gomock.Eq("v2fly.org")).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes()
|
mockDNS.EXPECT().LookupIP(gomock.Eq("v2fly.org")).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes()
|
||||||
|
|
||||||
r := new(Router)
|
r := new(Router)
|
||||||
common.Must(r.Init(context.TODO(), config, mockDNS, nil))
|
common.Must(r.Init(context.TODO(), config, mockDNS, nil, nil))
|
||||||
|
|
||||||
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("v2fly.org"), 80)})
|
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("v2fly.org"), 80)})
|
||||||
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
|
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
|
||||||
@ -154,7 +201,7 @@ func TestIPIfNonMatchDomain(t *testing.T) {
|
|||||||
mockDNS.EXPECT().LookupIP(gomock.Eq("v2fly.org")).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes()
|
mockDNS.EXPECT().LookupIP(gomock.Eq("v2fly.org")).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes()
|
||||||
|
|
||||||
r := new(Router)
|
r := new(Router)
|
||||||
common.Must(r.Init(context.TODO(), config, mockDNS, nil))
|
common.Must(r.Init(context.TODO(), config, mockDNS, nil, nil))
|
||||||
|
|
||||||
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("v2fly.org"), 80)})
|
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("v2fly.org"), 80)})
|
||||||
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
|
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
|
||||||
@ -188,7 +235,7 @@ func TestIPIfNonMatchIP(t *testing.T) {
|
|||||||
mockDNS := mocks.NewDNSClient(mockCtl)
|
mockDNS := mocks.NewDNSClient(mockCtl)
|
||||||
|
|
||||||
r := new(Router)
|
r := new(Router)
|
||||||
common.Must(r.Init(context.TODO(), config, mockDNS, nil))
|
common.Must(r.Init(context.TODO(), config, mockDNS, nil, nil))
|
||||||
|
|
||||||
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.LocalHostIP, 80)})
|
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.LocalHostIP, 80)})
|
||||||
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
|
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
|
||||||
|
322
app/router/strategy_leastload.go
Normal file
322
app/router/strategy_leastload.go
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/v2fly/v2ray-core/v4/common/dice"
|
||||||
|
"github.com/v2fly/v2ray-core/v4/features/routing"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
rttFailed = time.Duration(math.MaxInt64 - iota)
|
||||||
|
rttUntested
|
||||||
|
rttUnqualified
|
||||||
|
)
|
||||||
|
|
||||||
|
// LeastLoadStrategy represents a random balancing strategy
|
||||||
|
type LeastLoadStrategy struct {
|
||||||
|
*HealthPing
|
||||||
|
|
||||||
|
settings *StrategyLeastLoadConfig
|
||||||
|
costs *WeightManager
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLeastLoadStrategy creates a new LeastLoadStrategy with settings
|
||||||
|
func NewLeastLoadStrategy(settings *StrategyLeastLoadConfig, dispatcher routing.Dispatcher) *LeastLoadStrategy {
|
||||||
|
return &LeastLoadStrategy{
|
||||||
|
HealthPing: NewHealthPing(settings.HealthCheck, dispatcher),
|
||||||
|
settings: settings,
|
||||||
|
costs: NewWeightManager(
|
||||||
|
settings.Costs, 1,
|
||||||
|
func(value, cost float64) float64 {
|
||||||
|
return value * math.Pow(cost, 0.5)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// node is a minimal copy of HealthCheckResult
|
||||||
|
// we don't use HealthCheckResult directly because
|
||||||
|
// it may change by health checker during routing
|
||||||
|
type node struct {
|
||||||
|
Tag string
|
||||||
|
CountAll int
|
||||||
|
CountFail int
|
||||||
|
RTTAverage time.Duration
|
||||||
|
RTTDeviation time.Duration
|
||||||
|
RTTDeviationCost time.Duration
|
||||||
|
|
||||||
|
applied time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInformation implements the routing.BalancingStrategy.
|
||||||
|
func (s *LeastLoadStrategy) GetInformation(tags []string) *routing.StrategyInfo {
|
||||||
|
qualified, others := s.getNodes(tags, time.Duration(s.settings.MaxRTT))
|
||||||
|
selects := s.selectLeastLoad(qualified)
|
||||||
|
// append qualified but not selected outbounds to others
|
||||||
|
others = append(others, qualified[len(selects):]...)
|
||||||
|
leastloadSort(others)
|
||||||
|
titles, sl := s.getNodesInfo(selects)
|
||||||
|
_, ot := s.getNodesInfo(others)
|
||||||
|
return &routing.StrategyInfo{
|
||||||
|
Settings: s.getSettings(),
|
||||||
|
ValueTitles: titles,
|
||||||
|
Selects: sl,
|
||||||
|
Others: ot,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectAndPick implements the routing.BalancingStrategy.
|
||||||
|
func (s *LeastLoadStrategy) SelectAndPick(candidates []string) string {
|
||||||
|
qualified, _ := s.getNodes(candidates, time.Duration(s.settings.MaxRTT))
|
||||||
|
selects := s.selectLeastLoad(qualified)
|
||||||
|
count := len(selects)
|
||||||
|
if count == 0 {
|
||||||
|
// goes to fallbackTag
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return selects[dice.Roll(count)].Tag
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pick implements the routing.BalancingStrategy.
|
||||||
|
func (s *LeastLoadStrategy) Pick(candidates []string) string {
|
||||||
|
count := len(candidates)
|
||||||
|
if count == 0 {
|
||||||
|
// goes to fallbackTag
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return candidates[dice.Roll(count)]
|
||||||
|
}
|
||||||
|
|
||||||
|
// selectLeastLoad selects nodes according to Baselines and Expected Count.
|
||||||
|
//
|
||||||
|
// The strategy always improves network response speed, not matter which mode below is configurated.
|
||||||
|
// But they can still have different priorities.
|
||||||
|
//
|
||||||
|
// 1. Bandwidth priority: no Baseline + Expected Count > 0.: selects `Expected Count` of nodes.
|
||||||
|
// (one if Expected Count <= 0)
|
||||||
|
//
|
||||||
|
// 2. Bandwidth priority advanced: Baselines + Expected Count > 0.
|
||||||
|
// Select `Expected Count` amount of nodes, and also those near them according to baselines.
|
||||||
|
// In other words, it selects according to different Baselines, until one of them matches
|
||||||
|
// the Expected Count, if no Baseline matches, Expected Count applied.
|
||||||
|
//
|
||||||
|
// 3. Speed priority: Baselines + `Expected Count <= 0`.
|
||||||
|
// go through all baselines until find selects, if not, select none. Used in combination
|
||||||
|
// with 'balancer.fallbackTag', it means: selects qualified nodes or use the fallback.
|
||||||
|
func (s *LeastLoadStrategy) selectLeastLoad(nodes []*node) []*node {
|
||||||
|
if len(nodes) == 0 {
|
||||||
|
newError("least load: no qualified outbound").AtInfo().WriteToLog()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
expected := int(s.settings.Expected)
|
||||||
|
availableCount := len(nodes)
|
||||||
|
if expected > availableCount {
|
||||||
|
return nodes
|
||||||
|
}
|
||||||
|
|
||||||
|
if expected <= 0 {
|
||||||
|
expected = 1
|
||||||
|
}
|
||||||
|
if len(s.settings.Baselines) == 0 {
|
||||||
|
return nodes[:expected]
|
||||||
|
}
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
// go through all base line until find expected selects
|
||||||
|
for _, b := range s.settings.Baselines {
|
||||||
|
baseline := time.Duration(b)
|
||||||
|
for i := 0; i < availableCount; i++ {
|
||||||
|
if nodes[i].applied > baseline {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
count = i + 1
|
||||||
|
}
|
||||||
|
// don't continue if find expected selects
|
||||||
|
if count >= expected {
|
||||||
|
newError("applied baseline: ", baseline).AtDebug().WriteToLog()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if s.settings.Expected > 0 && count < expected {
|
||||||
|
count = expected
|
||||||
|
}
|
||||||
|
return nodes[:count]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LeastLoadStrategy) getNodes(candidates []string, maxRTT time.Duration) ([]*node, []*node) {
|
||||||
|
s.access.Lock()
|
||||||
|
defer s.access.Unlock()
|
||||||
|
results := s.Results
|
||||||
|
qualified := make([]*node, 0)
|
||||||
|
unqualified := make([]*node, 0)
|
||||||
|
failed := make([]*node, 0)
|
||||||
|
untested := make([]*node, 0)
|
||||||
|
others := make([]*node, 0)
|
||||||
|
for _, tag := range candidates {
|
||||||
|
r, ok := results[tag]
|
||||||
|
if !ok {
|
||||||
|
untested = append(untested, &node{
|
||||||
|
Tag: tag,
|
||||||
|
RTTDeviationCost: 0,
|
||||||
|
RTTDeviation: 0,
|
||||||
|
RTTAverage: 0,
|
||||||
|
applied: rttUntested,
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
stats := r.Get()
|
||||||
|
node := &node{
|
||||||
|
Tag: tag,
|
||||||
|
RTTDeviationCost: time.Duration(s.costs.Apply(tag, float64(stats.Deviation))),
|
||||||
|
RTTDeviation: stats.Deviation,
|
||||||
|
RTTAverage: stats.Average,
|
||||||
|
CountAll: stats.All,
|
||||||
|
CountFail: stats.Fail,
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case stats.All == 0:
|
||||||
|
node.applied = rttUntested
|
||||||
|
untested = append(untested, node)
|
||||||
|
case maxRTT > 0 && stats.Average > maxRTT:
|
||||||
|
node.applied = rttUnqualified
|
||||||
|
unqualified = append(unqualified, node)
|
||||||
|
case float64(stats.Fail)/float64(stats.All) > float64(s.settings.Tolerance):
|
||||||
|
node.applied = rttFailed
|
||||||
|
if stats.All-stats.Fail == 0 {
|
||||||
|
// no good, put them after has-good nodes
|
||||||
|
node.RTTDeviationCost = rttFailed
|
||||||
|
node.RTTDeviation = rttFailed
|
||||||
|
node.RTTAverage = rttFailed
|
||||||
|
}
|
||||||
|
failed = append(failed, node)
|
||||||
|
default:
|
||||||
|
node.applied = node.RTTDeviationCost
|
||||||
|
qualified = append(qualified, node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(qualified) > 0 {
|
||||||
|
leastloadSort(qualified)
|
||||||
|
others = append(others, unqualified...)
|
||||||
|
others = append(others, untested...)
|
||||||
|
others = append(others, failed...)
|
||||||
|
} else {
|
||||||
|
qualified = untested
|
||||||
|
others = append(others, unqualified...)
|
||||||
|
others = append(others, failed...)
|
||||||
|
}
|
||||||
|
return qualified, others
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LeastLoadStrategy) getSettings() []string {
|
||||||
|
settings := make([]string, 0)
|
||||||
|
sb := new(strings.Builder)
|
||||||
|
for i, b := range s.settings.Baselines {
|
||||||
|
if i > 0 {
|
||||||
|
sb.WriteByte(' ')
|
||||||
|
}
|
||||||
|
sb.WriteString(time.Duration(b).String())
|
||||||
|
}
|
||||||
|
baselines := sb.String()
|
||||||
|
if baselines == "" {
|
||||||
|
baselines = "none"
|
||||||
|
}
|
||||||
|
maxRTT := time.Duration(s.settings.MaxRTT).String()
|
||||||
|
if s.settings.MaxRTT == 0 {
|
||||||
|
maxRTT = "none"
|
||||||
|
}
|
||||||
|
settings = append(settings, fmt.Sprintf(
|
||||||
|
"leastload, expected: %d, baselines: %s, max rtt: %s, tolerance: %.2f",
|
||||||
|
s.settings.Expected,
|
||||||
|
baselines,
|
||||||
|
maxRTT,
|
||||||
|
s.settings.Tolerance,
|
||||||
|
))
|
||||||
|
settings = append(settings, fmt.Sprintf(
|
||||||
|
"health ping, interval: %s, sampling: %d, timeout: %s, destination: %s",
|
||||||
|
s.HealthPing.Settings.Interval,
|
||||||
|
s.HealthPing.Settings.SamplingCount,
|
||||||
|
s.HealthPing.Settings.Timeout,
|
||||||
|
s.HealthPing.Settings.Destination,
|
||||||
|
))
|
||||||
|
return settings
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LeastLoadStrategy) getNodesInfo(nodes []*node) ([]string, []*routing.OutboundInfo) {
|
||||||
|
titles := []string{" ", "RTT STD+C ", "RTT STD. ", "RTT Avg. ", "Hit ", "Cost "}
|
||||||
|
hasCost := len(s.settings.Costs) > 0
|
||||||
|
if !hasCost {
|
||||||
|
titles = []string{" ", "RTT STD. ", "RTT Avg. ", "Hit "}
|
||||||
|
}
|
||||||
|
items := make([]*routing.OutboundInfo, 0)
|
||||||
|
for _, node := range nodes {
|
||||||
|
item := &routing.OutboundInfo{
|
||||||
|
Tag: node.Tag,
|
||||||
|
}
|
||||||
|
var status string
|
||||||
|
cost := fmt.Sprintf("%.2f", s.costs.Get(node.Tag))
|
||||||
|
switch node.applied {
|
||||||
|
case rttFailed:
|
||||||
|
status = "x"
|
||||||
|
case rttUntested:
|
||||||
|
status = "?"
|
||||||
|
case rttUnqualified:
|
||||||
|
status = ">"
|
||||||
|
default:
|
||||||
|
status = "OK"
|
||||||
|
}
|
||||||
|
if hasCost {
|
||||||
|
item.Values = []string{
|
||||||
|
status,
|
||||||
|
durationString(node.RTTDeviationCost),
|
||||||
|
durationString(node.RTTDeviation),
|
||||||
|
durationString(node.RTTAverage),
|
||||||
|
fmt.Sprintf("%d/%d", node.CountAll-node.CountFail, node.CountAll),
|
||||||
|
cost,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
item.Values = []string{
|
||||||
|
status,
|
||||||
|
durationString(node.RTTDeviation),
|
||||||
|
durationString(node.RTTAverage),
|
||||||
|
fmt.Sprintf("%d/%d", node.CountAll-node.CountFail, node.CountAll),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items = append(items, item)
|
||||||
|
}
|
||||||
|
return titles, items
|
||||||
|
}
|
||||||
|
|
||||||
|
func durationString(d time.Duration) string {
|
||||||
|
if d <= 0 || d > time.Hour {
|
||||||
|
return "-"
|
||||||
|
}
|
||||||
|
return d.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func leastloadSort(nodes []*node) {
|
||||||
|
sort.Slice(nodes, func(i, j int) bool {
|
||||||
|
left := nodes[i]
|
||||||
|
right := nodes[j]
|
||||||
|
if left.applied != right.applied {
|
||||||
|
return left.applied < right.applied
|
||||||
|
}
|
||||||
|
if left.RTTDeviationCost != right.RTTDeviationCost {
|
||||||
|
return left.RTTDeviationCost < right.RTTDeviationCost
|
||||||
|
}
|
||||||
|
if left.RTTAverage != right.RTTAverage {
|
||||||
|
return left.RTTAverage < right.RTTAverage
|
||||||
|
}
|
||||||
|
if left.CountFail != right.CountFail {
|
||||||
|
return left.CountFail < right.CountFail
|
||||||
|
}
|
||||||
|
if left.CountAll != right.CountAll {
|
||||||
|
return left.CountAll > right.CountAll
|
||||||
|
}
|
||||||
|
return left.Tag < right.Tag
|
||||||
|
})
|
||||||
|
}
|
177
app/router/strategy_leastload_test.go
Normal file
177
app/router/strategy_leastload_test.go
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSelectLeastLoad(t *testing.T) {
|
||||||
|
settings := &StrategyLeastLoadConfig{
|
||||||
|
HealthCheck: &HealthPingConfig{
|
||||||
|
SamplingCount: 10,
|
||||||
|
},
|
||||||
|
Expected: 1,
|
||||||
|
MaxRTT: int64(time.Millisecond * time.Duration(800)),
|
||||||
|
}
|
||||||
|
strategy := NewLeastLoadStrategy(settings, nil)
|
||||||
|
// std 40
|
||||||
|
strategy.PutResult("a", time.Millisecond*time.Duration(60))
|
||||||
|
strategy.PutResult("a", time.Millisecond*time.Duration(140))
|
||||||
|
strategy.PutResult("a", time.Millisecond*time.Duration(60))
|
||||||
|
strategy.PutResult("a", time.Millisecond*time.Duration(140))
|
||||||
|
// std 60
|
||||||
|
strategy.PutResult("b", time.Millisecond*time.Duration(40))
|
||||||
|
strategy.PutResult("b", time.Millisecond*time.Duration(160))
|
||||||
|
strategy.PutResult("b", time.Millisecond*time.Duration(40))
|
||||||
|
strategy.PutResult("b", time.Millisecond*time.Duration(160))
|
||||||
|
// std 0, but >MaxRTT
|
||||||
|
strategy.PutResult("c", time.Millisecond*time.Duration(1000))
|
||||||
|
strategy.PutResult("c", time.Millisecond*time.Duration(1000))
|
||||||
|
strategy.PutResult("c", time.Millisecond*time.Duration(1000))
|
||||||
|
strategy.PutResult("c", time.Millisecond*time.Duration(1000))
|
||||||
|
expected := "a"
|
||||||
|
actual := strategy.SelectAndPick([]string{"a", "b", "c", "untested"})
|
||||||
|
if actual != expected {
|
||||||
|
t.Errorf("expected: %v, actual: %v", expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSelectLeastLoadWithCost(t *testing.T) {
|
||||||
|
settings := &StrategyLeastLoadConfig{
|
||||||
|
HealthCheck: &HealthPingConfig{
|
||||||
|
SamplingCount: 10,
|
||||||
|
},
|
||||||
|
Costs: []*StrategyWeight{
|
||||||
|
{Match: "a", Value: 9},
|
||||||
|
},
|
||||||
|
Expected: 1,
|
||||||
|
}
|
||||||
|
strategy := NewLeastLoadStrategy(settings, nil)
|
||||||
|
// std 40, std+c 120
|
||||||
|
strategy.PutResult("a", time.Millisecond*time.Duration(60))
|
||||||
|
strategy.PutResult("a", time.Millisecond*time.Duration(140))
|
||||||
|
strategy.PutResult("a", time.Millisecond*time.Duration(60))
|
||||||
|
strategy.PutResult("a", time.Millisecond*time.Duration(140))
|
||||||
|
// std 60
|
||||||
|
strategy.PutResult("b", time.Millisecond*time.Duration(40))
|
||||||
|
strategy.PutResult("b", time.Millisecond*time.Duration(160))
|
||||||
|
strategy.PutResult("b", time.Millisecond*time.Duration(40))
|
||||||
|
strategy.PutResult("b", time.Millisecond*time.Duration(160))
|
||||||
|
expected := "b"
|
||||||
|
actual := strategy.SelectAndPick([]string{"a", "b", "untested"})
|
||||||
|
if actual != expected {
|
||||||
|
t.Errorf("expected: %v, actual: %v", expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSelectLeastExpected(t *testing.T) {
|
||||||
|
strategy := &LeastLoadStrategy{
|
||||||
|
settings: &StrategyLeastLoadConfig{
|
||||||
|
Baselines: nil,
|
||||||
|
Expected: 3,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
nodes := []*node{
|
||||||
|
{Tag: "a", applied: 100},
|
||||||
|
{Tag: "b", applied: 200},
|
||||||
|
{Tag: "c", applied: 300},
|
||||||
|
{Tag: "d", applied: 350},
|
||||||
|
}
|
||||||
|
expected := 3
|
||||||
|
ns := strategy.selectLeastLoad(nodes)
|
||||||
|
if len(ns) != expected {
|
||||||
|
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func TestSelectLeastExpected2(t *testing.T) {
|
||||||
|
strategy := &LeastLoadStrategy{
|
||||||
|
settings: &StrategyLeastLoadConfig{
|
||||||
|
Baselines: nil,
|
||||||
|
Expected: 3,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
nodes := []*node{
|
||||||
|
{Tag: "a", applied: 100},
|
||||||
|
{Tag: "b", applied: 200},
|
||||||
|
}
|
||||||
|
expected := 2
|
||||||
|
ns := strategy.selectLeastLoad(nodes)
|
||||||
|
if len(ns) != expected {
|
||||||
|
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func TestSelectLeastExpectedAndBaselines(t *testing.T) {
|
||||||
|
strategy := &LeastLoadStrategy{
|
||||||
|
settings: &StrategyLeastLoadConfig{
|
||||||
|
Baselines: []int64{200, 300, 400},
|
||||||
|
Expected: 3,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
nodes := []*node{
|
||||||
|
{Tag: "a", applied: 100},
|
||||||
|
{Tag: "b", applied: 200},
|
||||||
|
{Tag: "c", applied: 250},
|
||||||
|
{Tag: "d", applied: 300},
|
||||||
|
{Tag: "e", applied: 310},
|
||||||
|
}
|
||||||
|
expected := 4
|
||||||
|
ns := strategy.selectLeastLoad(nodes)
|
||||||
|
if len(ns) != expected {
|
||||||
|
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func TestSelectLeastExpectedAndBaselines2(t *testing.T) {
|
||||||
|
strategy := &LeastLoadStrategy{
|
||||||
|
settings: &StrategyLeastLoadConfig{
|
||||||
|
Baselines: []int64{200, 300, 400},
|
||||||
|
Expected: 3,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
nodes := []*node{
|
||||||
|
{Tag: "a", applied: 500},
|
||||||
|
{Tag: "b", applied: 600},
|
||||||
|
{Tag: "c", applied: 700},
|
||||||
|
{Tag: "d", applied: 800},
|
||||||
|
{Tag: "e", applied: 900},
|
||||||
|
}
|
||||||
|
expected := 3
|
||||||
|
ns := strategy.selectLeastLoad(nodes)
|
||||||
|
if len(ns) != expected {
|
||||||
|
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func TestSelectLeastLoadBaselines(t *testing.T) {
|
||||||
|
strategy := &LeastLoadStrategy{
|
||||||
|
settings: &StrategyLeastLoadConfig{
|
||||||
|
Baselines: []int64{200, 400, 600},
|
||||||
|
Expected: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
nodes := []*node{
|
||||||
|
{Tag: "a", applied: 100},
|
||||||
|
{Tag: "b", applied: 200},
|
||||||
|
{Tag: "c", applied: 300},
|
||||||
|
}
|
||||||
|
expected := 2
|
||||||
|
ns := strategy.selectLeastLoad(nodes)
|
||||||
|
if len(ns) != expected {
|
||||||
|
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func TestSelectLeastLoadBaselinesNoQualified(t *testing.T) {
|
||||||
|
strategy := &LeastLoadStrategy{
|
||||||
|
settings: &StrategyLeastLoadConfig{
|
||||||
|
Baselines: []int64{200, 400, 600},
|
||||||
|
Expected: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
nodes := []*node{
|
||||||
|
{Tag: "a", applied: 800},
|
||||||
|
{Tag: "b", applied: 1000},
|
||||||
|
}
|
||||||
|
expected := 0
|
||||||
|
ns := strategy.selectLeastLoad(nodes)
|
||||||
|
if len(ns) != expected {
|
||||||
|
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ package router
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/v2fly/v2ray-core/v4/features/routing"
|
||||||
|
|
||||||
core "github.com/v2fly/v2ray-core/v4"
|
core "github.com/v2fly/v2ray-core/v4"
|
||||||
"github.com/v2fly/v2ray-core/v4/app/observatory"
|
"github.com/v2fly/v2ray-core/v4/app/observatory"
|
||||||
@ -17,6 +18,20 @@ type LeastPingStrategy struct {
|
|||||||
observatory extension.Observatory
|
observatory extension.Observatory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO Fix PlaceHolder
|
||||||
|
|
||||||
|
func (l *LeastPingStrategy) Pick(candidates []string) string {
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LeastPingStrategy) SelectAndPick(candidates []string) string {
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LeastPingStrategy) GetInformation(tags []string) *routing.StrategyInfo {
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
||||||
func (l *LeastPingStrategy) InjectContext(ctx context.Context) {
|
func (l *LeastPingStrategy) InjectContext(ctx context.Context) {
|
||||||
l.ctx = ctx
|
l.ctx = ctx
|
||||||
}
|
}
|
||||||
|
38
app/router/strategy_random.go
Normal file
38
app/router/strategy_random.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/v2fly/v2ray-core/v4/common/dice"
|
||||||
|
"github.com/v2fly/v2ray-core/v4/features/routing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RandomStrategy represents a random balancing strategy
|
||||||
|
type RandomStrategy struct{}
|
||||||
|
|
||||||
|
// GetInformation implements the routing.BalancingStrategy.
|
||||||
|
func (s *RandomStrategy) GetInformation(tags []string) *routing.StrategyInfo {
|
||||||
|
items := make([]*routing.OutboundInfo, 0)
|
||||||
|
for _, tag := range tags {
|
||||||
|
items = append(items, &routing.OutboundInfo{Tag: tag})
|
||||||
|
}
|
||||||
|
return &routing.StrategyInfo{
|
||||||
|
Settings: []string{"random"},
|
||||||
|
ValueTitles: nil,
|
||||||
|
Selects: items,
|
||||||
|
Others: nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectAndPick implements the routing.BalancingStrategy.
|
||||||
|
func (s *RandomStrategy) SelectAndPick(candidates []string) string {
|
||||||
|
return s.Pick(candidates)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pick implements the routing.BalancingStrategy.
|
||||||
|
func (s *RandomStrategy) Pick(candidates []string) string {
|
||||||
|
count := len(candidates)
|
||||||
|
if count == 0 {
|
||||||
|
// goes to fallbackTag
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return candidates[dice.Roll(count)]
|
||||||
|
}
|
85
app/router/weight.go
Normal file
85
app/router/weight.go
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type weightScaler func(value, weight float64) float64
|
||||||
|
|
||||||
|
var numberFinder = regexp.MustCompile(`\d+(\.\d+)?`)
|
||||||
|
|
||||||
|
// NewWeightManager creates a new WeightManager with settings
|
||||||
|
func NewWeightManager(s []*StrategyWeight, defaultWeight float64, scaler weightScaler) *WeightManager {
|
||||||
|
return &WeightManager{
|
||||||
|
settings: s,
|
||||||
|
cache: make(map[string]float64),
|
||||||
|
scaler: scaler,
|
||||||
|
defaultWeight: defaultWeight,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WeightManager manages weights for specific settings
|
||||||
|
type WeightManager struct {
|
||||||
|
settings []*StrategyWeight
|
||||||
|
cache map[string]float64
|
||||||
|
scaler weightScaler
|
||||||
|
defaultWeight float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get get the weight of specified tag
|
||||||
|
func (s *WeightManager) Get(tag string) float64 {
|
||||||
|
weight, ok := s.cache[tag]
|
||||||
|
if ok {
|
||||||
|
return weight
|
||||||
|
}
|
||||||
|
weight = s.findValue(tag)
|
||||||
|
s.cache[tag] = weight
|
||||||
|
return weight
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply applies weight to the value
|
||||||
|
func (s *WeightManager) Apply(tag string, value float64) float64 {
|
||||||
|
return s.scaler(value, s.Get(tag))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *WeightManager) findValue(tag string) float64 {
|
||||||
|
for _, w := range s.settings {
|
||||||
|
matched := s.getMatch(tag, w.Match, w.Regexp)
|
||||||
|
if matched == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if w.Value > 0 {
|
||||||
|
return float64(w.Value)
|
||||||
|
}
|
||||||
|
// auto weight from matched
|
||||||
|
numStr := numberFinder.FindString(matched)
|
||||||
|
if numStr == "" {
|
||||||
|
return s.defaultWeight
|
||||||
|
}
|
||||||
|
weight, err := strconv.ParseFloat(numStr, 64)
|
||||||
|
if err != nil {
|
||||||
|
newError("unexpected error from ParseFloat: ", err).AtError().WriteToLog()
|
||||||
|
return s.defaultWeight
|
||||||
|
}
|
||||||
|
return weight
|
||||||
|
}
|
||||||
|
return s.defaultWeight
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *WeightManager) getMatch(tag, find string, isRegexp bool) string {
|
||||||
|
if !isRegexp {
|
||||||
|
idx := strings.Index(tag, find)
|
||||||
|
if idx < 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return find
|
||||||
|
}
|
||||||
|
r, err := regexp.Compile(find)
|
||||||
|
if err != nil {
|
||||||
|
newError("invalid regexp: ", find, "err: ", err).AtError().WriteToLog()
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return r.FindString(tag)
|
||||||
|
}
|
60
app/router/weight_test.go
Normal file
60
app/router/weight_test.go
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package router_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/v2fly/v2ray-core/v4/app/router"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWeight(t *testing.T) {
|
||||||
|
manager := router.NewWeightManager(
|
||||||
|
[]*router.StrategyWeight{
|
||||||
|
{
|
||||||
|
Match: "x5",
|
||||||
|
Value: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Match: "x8",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Regexp: true,
|
||||||
|
Match: `\bx0+(\.\d+)?\b`,
|
||||||
|
Value: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Regexp: true,
|
||||||
|
Match: `\bx\d+(\.\d+)?\b`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
1, func(v, w float64) float64 {
|
||||||
|
return v * w
|
||||||
|
},
|
||||||
|
)
|
||||||
|
tags := []string{
|
||||||
|
"node name, x5, and more",
|
||||||
|
"node name, x8",
|
||||||
|
"node name, x15",
|
||||||
|
"node name, x0100, and more",
|
||||||
|
"node name, x10.1",
|
||||||
|
"node name, x00.1, and more",
|
||||||
|
}
|
||||||
|
// test weight
|
||||||
|
expected := []float64{100, 8, 15, 100, 10.1, 1}
|
||||||
|
actual := make([]float64, 0)
|
||||||
|
for _, tag := range tags {
|
||||||
|
actual = append(actual, manager.Get(tag))
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(expected, actual) {
|
||||||
|
t.Errorf("expected: %v, actual: %v", expected, actual)
|
||||||
|
}
|
||||||
|
// test scale
|
||||||
|
expected2 := []float64{1000, 80, 150, 1000, 101, 10}
|
||||||
|
actual2 := make([]float64, 0)
|
||||||
|
for _, tag := range tags {
|
||||||
|
actual2 = append(actual2, manager.Apply(tag, 10))
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(expected2, actual2) {
|
||||||
|
t.Errorf("expected2: %v, actual2: %v", expected2, actual2)
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,7 @@ const (
|
|||||||
muxPreferedSessionKey
|
muxPreferedSessionKey
|
||||||
sockoptSessionKey
|
sockoptSessionKey
|
||||||
trackedConnectionErrorKey
|
trackedConnectionErrorKey
|
||||||
|
handlerSessionKey
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContextWithID returns a new context with the given ID.
|
// ContextWithID returns a new context with the given ID.
|
||||||
@ -132,3 +133,16 @@ func SubmitOutboundErrorToOriginator(ctx context.Context, err error) {
|
|||||||
func TrackedConnectionError(ctx context.Context, tracker TrackedRequestErrorFeedback) context.Context {
|
func TrackedConnectionError(ctx context.Context, tracker TrackedRequestErrorFeedback) context.Context {
|
||||||
return context.WithValue(ctx, trackedConnectionErrorKey, tracker)
|
return context.WithValue(ctx, trackedConnectionErrorKey, tracker)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ContextWithHandler returns a new context with handler
|
||||||
|
func ContextWithHandler(ctx context.Context, handler *Handler) context.Context {
|
||||||
|
return context.WithValue(ctx, handlerSessionKey, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandlerFromContext returns handler config in this context, or nil if not
|
||||||
|
func HandlerFromContext(ctx context.Context) *Handler {
|
||||||
|
if handler, ok := ctx.Value(handlerSessionKey).(*Handler); ok {
|
||||||
|
return handler
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -78,6 +78,12 @@ type Sockopt struct {
|
|||||||
Mark int32
|
Mark int32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handler is the handler setting for dispatching.
|
||||||
|
type Handler struct {
|
||||||
|
// Tag of outbound handler.
|
||||||
|
Tag string
|
||||||
|
}
|
||||||
|
|
||||||
// SetAttribute attachs additional string attributes to content.
|
// SetAttribute attachs additional string attributes to content.
|
||||||
func (c *Content) SetAttribute(name string, value string) {
|
func (c *Content) SetAttribute(name string, value string) {
|
||||||
if c.Attributes == nil {
|
if c.Attributes == nil {
|
||||||
|
51
features/routing/health.go
Normal file
51
features/routing/health.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package routing
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// HealthChecker is the interface for health checkers
|
||||||
|
type HealthChecker interface {
|
||||||
|
// StartScheduler starts the check scheduler
|
||||||
|
StartScheduler(selector func() ([]string, error))
|
||||||
|
// StopScheduler stops the check scheduler
|
||||||
|
StopScheduler()
|
||||||
|
// Check start the health checking for given tags.
|
||||||
|
Check(tags []string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// OutboundInfo holds information of an outbound
|
||||||
|
type OutboundInfo struct {
|
||||||
|
Tag string // Tag of the outbound
|
||||||
|
Values []string // Information of the outbound, which can be different between strategies, like health ping RTT
|
||||||
|
}
|
||||||
|
|
||||||
|
// StrategyInfo holds strategy running information, like selected handlers and others
|
||||||
|
type StrategyInfo struct {
|
||||||
|
Settings []string // Strategy settings
|
||||||
|
ValueTitles []string // Value titles of OutboundInfo.Values
|
||||||
|
Selects []*OutboundInfo // Selects of the strategy
|
||||||
|
Others []*OutboundInfo // Other outbounds
|
||||||
|
}
|
||||||
|
|
||||||
|
// BalancingOverrideInfo holds balancing overridden information
|
||||||
|
type BalancingOverrideInfo struct {
|
||||||
|
Until time.Time
|
||||||
|
Selects []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// BalancerInfo holds information of a balancer
|
||||||
|
type BalancerInfo struct {
|
||||||
|
Tag string // Tag of the balancer
|
||||||
|
Override *BalancingOverrideInfo
|
||||||
|
Strategy *StrategyInfo // Strategy and its running information
|
||||||
|
}
|
||||||
|
|
||||||
|
// RouterChecker represents a router that is able to perform checks for its balancers, and get statistics.
|
||||||
|
type RouterChecker interface {
|
||||||
|
// CheckHanlders performs a health check for specified outbound hanlders.
|
||||||
|
CheckHanlders(tags []string) error
|
||||||
|
// CheckBalancers performs health checks for specified balancers,
|
||||||
|
// if not specified, check them all.
|
||||||
|
CheckBalancers(tags []string) error
|
||||||
|
// GetBalancersInfo get health info of specific balancer, if balancer not specified, get all
|
||||||
|
GetBalancersInfo(tags []string) ([]*BalancerInfo, error)
|
||||||
|
}
|
22
features/routing/strategy.go
Normal file
22
features/routing/strategy.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package routing
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// BalancingStrategy is the interface for balancing strategies
|
||||||
|
type BalancingStrategy interface {
|
||||||
|
// Pick pick one outbound from candidates. Unlike the SelectAndPick(),
|
||||||
|
// it skips the select procedure (select all & pick one).
|
||||||
|
Pick(candidates []string) string
|
||||||
|
// SelectAndPick selects qualified nodes from candidates then pick one.
|
||||||
|
SelectAndPick(candidates []string) string
|
||||||
|
// GetInformation gets information of the strategy
|
||||||
|
GetInformation(tags []string) *StrategyInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
// BalancingOverrider is the interface of those who can override
|
||||||
|
// the selecting of its balancers
|
||||||
|
type BalancingOverrider interface {
|
||||||
|
// OverrideSelecting overrides the selects of specified balancer, for 'validity'
|
||||||
|
// duration of time.
|
||||||
|
OverrideSelecting(balancer string, selects []string, validity time.Duration) error
|
||||||
|
}
|
2
go.sum
2
go.sum
@ -238,6 +238,8 @@ github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je4
|
|||||||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
|
github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM=
|
||||||
|
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
|
||||||
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
|
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
|
||||||
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
|
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
|
||||||
github.com/pires/go-proxyproto v0.6.0 h1:cLJUPnuQdiNf7P/wbeOKmM1khVdaMgTFDLj8h9ZrVYk=
|
github.com/pires/go-proxyproto v0.6.0 h1:cLJUPnuQdiNf7P/wbeOKmM1khVdaMgTFDLj8h9ZrVYk=
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
loggerservice "github.com/v2fly/v2ray-core/v4/app/log/command"
|
loggerservice "github.com/v2fly/v2ray-core/v4/app/log/command"
|
||||||
observatoryservice "github.com/v2fly/v2ray-core/v4/app/observatory/command"
|
observatoryservice "github.com/v2fly/v2ray-core/v4/app/observatory/command"
|
||||||
handlerservice "github.com/v2fly/v2ray-core/v4/app/proxyman/command"
|
handlerservice "github.com/v2fly/v2ray-core/v4/app/proxyman/command"
|
||||||
|
routerservice "github.com/v2fly/v2ray-core/v4/app/router/command"
|
||||||
statsservice "github.com/v2fly/v2ray-core/v4/app/stats/command"
|
statsservice "github.com/v2fly/v2ray-core/v4/app/stats/command"
|
||||||
"github.com/v2fly/v2ray-core/v4/common/serial"
|
"github.com/v2fly/v2ray-core/v4/common/serial"
|
||||||
)
|
)
|
||||||
@ -37,6 +38,8 @@ func (c *APIConfig) Build() (*commander.Config, error) {
|
|||||||
services = append(services, serial.ToTypedMessage(&statsservice.Config{}))
|
services = append(services, serial.ToTypedMessage(&statsservice.Config{}))
|
||||||
case "observatoryservice":
|
case "observatoryservice":
|
||||||
services = append(services, serial.ToTypedMessage(&observatoryservice.Config{}))
|
services = append(services, serial.ToTypedMessage(&observatoryservice.Config{}))
|
||||||
|
case "routingservice":
|
||||||
|
services = append(services, serial.ToTypedMessage(&routerservice.Config{}))
|
||||||
default:
|
default:
|
||||||
if !strings.HasPrefix(s, "#") {
|
if !strings.HasPrefix(s, "#") {
|
||||||
continue
|
continue
|
||||||
|
@ -3,10 +3,12 @@ package conf
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/v2fly/v2ray-core/v4/app/router"
|
"github.com/v2fly/v2ray-core/v4/app/router"
|
||||||
"github.com/v2fly/v2ray-core/v4/common/platform"
|
"github.com/v2fly/v2ray-core/v4/common/platform"
|
||||||
|
"github.com/v2fly/v2ray-core/v4/common/serial"
|
||||||
"github.com/v2fly/v2ray-core/v4/infra/conf/cfgcommon"
|
"github.com/v2fly/v2ray-core/v4/infra/conf/cfgcommon"
|
||||||
"github.com/v2fly/v2ray-core/v4/infra/conf/geodata"
|
"github.com/v2fly/v2ray-core/v4/infra/conf/geodata"
|
||||||
rule2 "github.com/v2fly/v2ray-core/v4/infra/conf/rule"
|
rule2 "github.com/v2fly/v2ray-core/v4/infra/conf/rule"
|
||||||
@ -24,11 +26,13 @@ type StrategyConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type BalancingRule struct {
|
type BalancingRule struct {
|
||||||
Tag string `json:"tag"`
|
Tag string `json:"tag"`
|
||||||
Selectors cfgcommon.StringList `json:"selector"`
|
Selectors cfgcommon.StringList `json:"selector"`
|
||||||
Strategy StrategyConfig `json:"strategy"`
|
Strategy StrategyConfig `json:"strategy"`
|
||||||
|
FallbackTag string `json:"fallbackTag"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build builds the balancing rule
|
||||||
func (r *BalancingRule) Build() (*router.BalancingRule, error) {
|
func (r *BalancingRule) Build() (*router.BalancingRule, error) {
|
||||||
if r.Tag == "" {
|
if r.Tag == "" {
|
||||||
return nil, newError("empty balancer tag")
|
return nil, newError("empty balancer tag")
|
||||||
@ -40,17 +44,38 @@ func (r *BalancingRule) Build() (*router.BalancingRule, error) {
|
|||||||
var strategy string
|
var strategy string
|
||||||
switch strings.ToLower(r.Strategy.Type) {
|
switch strings.ToLower(r.Strategy.Type) {
|
||||||
case strategyRandom, "":
|
case strategyRandom, "":
|
||||||
|
r.Strategy.Type = strategyRandom
|
||||||
strategy = strategyRandom
|
strategy = strategyRandom
|
||||||
|
case strategyLeastLoad:
|
||||||
|
strategy = strategyLeastLoad
|
||||||
case strategyLeastPing:
|
case strategyLeastPing:
|
||||||
strategy = "leastPing"
|
strategy = "leastPing"
|
||||||
default:
|
default:
|
||||||
return nil, newError("unknown balancing strategy: " + r.Strategy.Type)
|
return nil, newError("unknown balancing strategy: " + r.Strategy.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
settings := []byte("{}")
|
||||||
|
if r.Strategy.Settings != nil {
|
||||||
|
settings = ([]byte)(*r.Strategy.Settings)
|
||||||
|
}
|
||||||
|
rawConfig, err := strategyConfigLoader.LoadWithID(settings, r.Strategy.Type)
|
||||||
|
if err != nil {
|
||||||
|
return nil, newError("failed to parse to strategy config.").Base(err)
|
||||||
|
}
|
||||||
|
var ts proto.Message
|
||||||
|
if builder, ok := rawConfig.(Buildable); ok {
|
||||||
|
ts, err = builder.Build()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &router.BalancingRule{
|
return &router.BalancingRule{
|
||||||
Tag: r.Tag,
|
|
||||||
OutboundSelector: []string(r.Selectors),
|
|
||||||
Strategy: strategy,
|
Strategy: strategy,
|
||||||
|
StrategySettings: serial.ToTypedMessage(ts),
|
||||||
|
FallbackTag: r.FallbackTag,
|
||||||
|
OutboundSelector: r.Selectors,
|
||||||
|
Tag: r.Tag,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,85 @@
|
|||||||
package conf
|
package conf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
"github.com/v2fly/v2ray-core/v4/app/router"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
strategyRandom string = "random"
|
strategyRandom string = "random"
|
||||||
|
strategyLeastLoad string = "leastload"
|
||||||
strategyLeastPing string = "leastping"
|
strategyLeastPing string = "leastping"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
strategyConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{
|
||||||
|
strategyRandom: func() interface{} { return new(strategyEmptyConfig) },
|
||||||
|
strategyLeastLoad: func() interface{} { return new(strategyLeastLoadConfig) },
|
||||||
|
}, "type", "settings")
|
||||||
|
)
|
||||||
|
|
||||||
|
type strategyEmptyConfig struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *strategyEmptyConfig) Build() (proto.Message, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type strategyLeastLoadConfig struct {
|
||||||
|
// note the time values of the HealthCheck holds is not
|
||||||
|
// 'time.Duration' but plain number, sice they were parsed
|
||||||
|
// directly from json
|
||||||
|
HealthCheck *router.HealthPingSettings `json:"healthCheck,omitempty"`
|
||||||
|
// weight settings
|
||||||
|
Costs []*router.StrategyWeight `json:"costs,omitempty"`
|
||||||
|
// ping rtt baselines (ms)
|
||||||
|
Baselines []int `json:"baselines,omitempty"`
|
||||||
|
// expected nodes count to select
|
||||||
|
Expected int32 `json:"expected,omitempty"`
|
||||||
|
// max acceptable rtt (ms), filter away high delay nodes. defalut 0
|
||||||
|
MaxRTT int `json:"maxRTT,omitempty"`
|
||||||
|
// acceptable failure rate
|
||||||
|
Tolerance float64 `json:"tolerance,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build implements Buildable.
|
||||||
|
func (v *strategyLeastLoadConfig) Build() (proto.Message, error) {
|
||||||
|
config := &router.StrategyLeastLoadConfig{
|
||||||
|
HealthCheck: &router.HealthPingConfig{},
|
||||||
|
}
|
||||||
|
if v.HealthCheck != nil {
|
||||||
|
config.HealthCheck = &router.HealthPingConfig{
|
||||||
|
Destination: v.HealthCheck.Destination,
|
||||||
|
Connectivity: v.HealthCheck.Connectivity,
|
||||||
|
Interval: int64(v.HealthCheck.Interval * time.Second),
|
||||||
|
Timeout: int64(v.HealthCheck.Timeout * time.Second),
|
||||||
|
SamplingCount: int32(v.HealthCheck.SamplingCount),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config.Costs = v.Costs
|
||||||
|
config.Tolerance = float32(v.Tolerance)
|
||||||
|
if config.Tolerance < 0 {
|
||||||
|
config.Tolerance = 0
|
||||||
|
}
|
||||||
|
if config.Tolerance > 1 {
|
||||||
|
config.Tolerance = 1
|
||||||
|
}
|
||||||
|
config.Expected = v.Expected
|
||||||
|
if config.Expected < 0 {
|
||||||
|
config.Expected = 0
|
||||||
|
}
|
||||||
|
config.MaxRTT = int64(time.Duration(v.MaxRTT) * time.Millisecond)
|
||||||
|
if config.MaxRTT < 0 {
|
||||||
|
config.MaxRTT = 0
|
||||||
|
}
|
||||||
|
config.Baselines = make([]int64, 0)
|
||||||
|
for _, b := range v.Baselines {
|
||||||
|
if b <= 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
config.Baselines = append(config.Baselines, int64(time.Duration(b)*time.Millisecond))
|
||||||
|
}
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
@ -3,12 +3,14 @@ package conf_test
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
_ "unsafe"
|
_ "unsafe"
|
||||||
|
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
|
|
||||||
"github.com/v2fly/v2ray-core/v4/app/router"
|
"github.com/v2fly/v2ray-core/v4/app/router"
|
||||||
"github.com/v2fly/v2ray-core/v4/common/net"
|
"github.com/v2fly/v2ray-core/v4/common/net"
|
||||||
|
"github.com/v2fly/v2ray-core/v4/common/serial"
|
||||||
. "github.com/v2fly/v2ray-core/v4/infra/conf"
|
. "github.com/v2fly/v2ray-core/v4/infra/conf"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -68,6 +70,34 @@ func TestRouterConfig(t *testing.T) {
|
|||||||
{
|
{
|
||||||
"tag": "b1",
|
"tag": "b1",
|
||||||
"selector": ["test"]
|
"selector": ["test"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tag": "b2",
|
||||||
|
"selector": ["test"],
|
||||||
|
"strategy": {
|
||||||
|
"type": "leastload",
|
||||||
|
"settings": {
|
||||||
|
"healthCheck": {
|
||||||
|
"interval": 300,
|
||||||
|
"sampling": 2,
|
||||||
|
"timeout": 3,
|
||||||
|
"destination": "dest",
|
||||||
|
"connectivity": "conn"
|
||||||
|
},
|
||||||
|
"costs": [
|
||||||
|
{
|
||||||
|
"regexp": true,
|
||||||
|
"match": "\\d+(\\.\\d+)",
|
||||||
|
"value": 5
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"baselines": [400, 600],
|
||||||
|
"expected": 6,
|
||||||
|
"maxRTT": 1000,
|
||||||
|
"tolerance": 0.5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fallbackTag": "fall"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}`,
|
}`,
|
||||||
@ -80,6 +110,35 @@ func TestRouterConfig(t *testing.T) {
|
|||||||
OutboundSelector: []string{"test"},
|
OutboundSelector: []string{"test"},
|
||||||
Strategy: "random",
|
Strategy: "random",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Tag: "b2",
|
||||||
|
OutboundSelector: []string{"test"},
|
||||||
|
Strategy: "leastload",
|
||||||
|
StrategySettings: serial.ToTypedMessage(&router.StrategyLeastLoadConfig{
|
||||||
|
HealthCheck: &router.HealthPingConfig{
|
||||||
|
Interval: int64(time.Duration(300) * time.Second),
|
||||||
|
SamplingCount: 2,
|
||||||
|
Timeout: int64(time.Duration(3) * time.Second),
|
||||||
|
Destination: "dest",
|
||||||
|
Connectivity: "conn",
|
||||||
|
},
|
||||||
|
Costs: []*router.StrategyWeight{
|
||||||
|
{
|
||||||
|
Regexp: true,
|
||||||
|
Match: "\\d+(\\.\\d+)",
|
||||||
|
Value: 5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Baselines: []int64{
|
||||||
|
int64(time.Duration(400) * time.Millisecond),
|
||||||
|
int64(time.Duration(600) * time.Millisecond),
|
||||||
|
},
|
||||||
|
Expected: 6,
|
||||||
|
MaxRTT: int64(time.Duration(1000) * time.Millisecond),
|
||||||
|
Tolerance: 0.5,
|
||||||
|
}),
|
||||||
|
FallbackTag: "fall",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Rule: []*router.RoutingRule{
|
Rule: []*router.RoutingRule{
|
||||||
{
|
{
|
||||||
|
@ -15,6 +15,9 @@ var CmdAPI = &base.Command{
|
|||||||
cmdGetStats,
|
cmdGetStats,
|
||||||
cmdQueryStats,
|
cmdQueryStats,
|
||||||
cmdSysStats,
|
cmdSysStats,
|
||||||
|
cmdBalancerCheck,
|
||||||
|
cmdBalancerInfo,
|
||||||
|
cmdBalancerOverride,
|
||||||
cmdAddInbounds,
|
cmdAddInbounds,
|
||||||
cmdAddOutbounds,
|
cmdAddOutbounds,
|
||||||
cmdRemoveInbounds,
|
cmdRemoveInbounds,
|
||||||
|
47
main/commands/all/api/balancer_check.go
Normal file
47
main/commands/all/api/balancer_check.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
routerService "github.com/v2fly/v2ray-core/v4/app/router/command"
|
||||||
|
"github.com/v2fly/v2ray-core/v4/main/commands/base"
|
||||||
|
)
|
||||||
|
|
||||||
|
var cmdBalancerCheck = &base.Command{
|
||||||
|
CustomFlags: true,
|
||||||
|
UsageLine: "{{.Exec}} api bc [--server=127.0.0.1:8080] [balancer]...",
|
||||||
|
Short: "balancer health check",
|
||||||
|
Long: `
|
||||||
|
Perform instant health checks for specific balancers. If no
|
||||||
|
balancer tag specified, check all balancers.
|
||||||
|
|
||||||
|
> Make sure you have "RoutingService" set in "config.api.services"
|
||||||
|
of server config.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
|
||||||
|
-s, -server
|
||||||
|
The API server address. Default 127.0.0.1:8080
|
||||||
|
|
||||||
|
-t, -timeout
|
||||||
|
Timeout seconds to call API. Default 3
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 balancer1 balancer2
|
||||||
|
`,
|
||||||
|
Run: executeBalancerCheck,
|
||||||
|
}
|
||||||
|
|
||||||
|
func executeBalancerCheck(cmd *base.Command, args []string) {
|
||||||
|
setSharedFlags(cmd)
|
||||||
|
cmd.Flag.Parse(args)
|
||||||
|
|
||||||
|
conn, ctx, close := dialAPIServer()
|
||||||
|
defer close()
|
||||||
|
|
||||||
|
client := routerService.NewRoutingServiceClient(conn)
|
||||||
|
r := &routerService.CheckBalancersRequest{BalancerTags: cmd.Flag.Args()}
|
||||||
|
_, err := client.CheckBalancers(ctx, r)
|
||||||
|
if err != nil {
|
||||||
|
base.Fatalf("failed to perform balancer health checks: %s", err)
|
||||||
|
}
|
||||||
|
}
|
122
main/commands/all/api/balancer_info.go
Normal file
122
main/commands/all/api/balancer_info.go
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
routerService "github.com/v2fly/v2ray-core/v4/app/router/command"
|
||||||
|
"github.com/v2fly/v2ray-core/v4/main/commands/base"
|
||||||
|
)
|
||||||
|
|
||||||
|
var cmdBalancerInfo = &base.Command{
|
||||||
|
CustomFlags: true,
|
||||||
|
UsageLine: "{{.Exec}} api bi [--server=127.0.0.1:8080] [balancer]...",
|
||||||
|
Short: "balancer information",
|
||||||
|
Long: `
|
||||||
|
Get information of specified balancers, including health, strategy
|
||||||
|
and selecting. If no balancer tag specified, get information of
|
||||||
|
all balancers.
|
||||||
|
|
||||||
|
> Make sure you have "RoutingService" set in "config.api.services"
|
||||||
|
of server config.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
|
||||||
|
-s, -server
|
||||||
|
The API server address. Default 127.0.0.1:8080
|
||||||
|
|
||||||
|
-t, -timeout
|
||||||
|
Timeout seconds to call API. Default 3
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 balancer1 balancer2
|
||||||
|
`,
|
||||||
|
Run: executeBalancerInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
func executeBalancerInfo(cmd *base.Command, args []string) {
|
||||||
|
setSharedFlags(cmd)
|
||||||
|
cmd.Flag.Parse(args)
|
||||||
|
|
||||||
|
conn, ctx, close := dialAPIServer()
|
||||||
|
defer close()
|
||||||
|
|
||||||
|
client := routerService.NewRoutingServiceClient(conn)
|
||||||
|
r := &routerService.GetBalancersRequest{BalancerTags: cmd.Flag.Args()}
|
||||||
|
resp, err := client.GetBalancers(ctx, r)
|
||||||
|
if err != nil {
|
||||||
|
base.Fatalf("failed to get health information: %s", err)
|
||||||
|
}
|
||||||
|
sort.Slice(resp.Balancers, func(i, j int) bool {
|
||||||
|
return resp.Balancers[i].Tag < resp.Balancers[j].Tag
|
||||||
|
})
|
||||||
|
for _, b := range resp.Balancers {
|
||||||
|
showBalancerInfo(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func showBalancerInfo(b *routerService.BalancerMsg) {
|
||||||
|
sb := new(strings.Builder)
|
||||||
|
// Balancer
|
||||||
|
sb.WriteString(fmt.Sprintf("Balancer: %s\n", b.Tag))
|
||||||
|
// Strategy
|
||||||
|
sb.WriteString(" - Strategy:\n")
|
||||||
|
for _, v := range b.StrategySettings {
|
||||||
|
sb.WriteString(fmt.Sprintf(" %s\n", v))
|
||||||
|
}
|
||||||
|
// Override
|
||||||
|
if b.Override != nil {
|
||||||
|
sb.WriteString(" - Selecting Override:\n")
|
||||||
|
until := fmt.Sprintf("until: %s", b.Override.Until)
|
||||||
|
writeRow(sb, 0, nil, nil, until)
|
||||||
|
for i, s := range b.Override.Selects {
|
||||||
|
writeRow(sb, i+1, nil, nil, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
formats := getColumnFormats(b.Titles)
|
||||||
|
// Selects
|
||||||
|
sb.WriteString(" - Selects:\n")
|
||||||
|
writeRow(sb, 0, b.Titles, formats, "Tag")
|
||||||
|
for i, o := range b.Selects {
|
||||||
|
writeRow(sb, i+1, o.Values, formats, o.Tag)
|
||||||
|
}
|
||||||
|
// Others
|
||||||
|
scnt := len(b.Selects)
|
||||||
|
if len(b.Others) > 0 {
|
||||||
|
sb.WriteString(" - Others:\n")
|
||||||
|
writeRow(sb, 0, b.Titles, formats, "Tag")
|
||||||
|
for i, o := range b.Others {
|
||||||
|
writeRow(sb, scnt+i+1, o.Values, formats, o.Tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os.Stdout.WriteString(sb.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func getColumnFormats(titles []string) []string {
|
||||||
|
w := make([]string, len(titles))
|
||||||
|
for i, t := range titles {
|
||||||
|
w[i] = fmt.Sprintf("%%-%ds ", len(t))
|
||||||
|
}
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeRow(sb *strings.Builder, index int, values, formats []string, tag string) {
|
||||||
|
if index == 0 {
|
||||||
|
// title line
|
||||||
|
sb.WriteString(" ")
|
||||||
|
} else {
|
||||||
|
sb.WriteString(fmt.Sprintf(" %-4d", index))
|
||||||
|
}
|
||||||
|
for i, v := range values {
|
||||||
|
format := "%-14s"
|
||||||
|
if i < len(formats) {
|
||||||
|
format = formats[i]
|
||||||
|
}
|
||||||
|
sb.WriteString(fmt.Sprintf(format, v))
|
||||||
|
}
|
||||||
|
sb.WriteString(tag)
|
||||||
|
sb.WriteByte('\n')
|
||||||
|
}
|
87
main/commands/all/api/balancer_override.go
Normal file
87
main/commands/all/api/balancer_override.go
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
routerService "github.com/v2fly/v2ray-core/v4/app/router/command"
|
||||||
|
"github.com/v2fly/v2ray-core/v4/main/commands/base"
|
||||||
|
)
|
||||||
|
|
||||||
|
var cmdBalancerOverride = &base.Command{
|
||||||
|
CustomFlags: true,
|
||||||
|
UsageLine: "{{.Exec}} api bo [--server=127.0.0.1:8080] <-b balancer> selectors...",
|
||||||
|
Short: "balancer select override",
|
||||||
|
Long: `
|
||||||
|
Override a balancer's selecting in a duration of time.
|
||||||
|
|
||||||
|
> Make sure you have "RoutingService" set in "config.api.services"
|
||||||
|
of server config.
|
||||||
|
|
||||||
|
Once a balancer's selecting is overridden:
|
||||||
|
|
||||||
|
- The selectors of the balancer won't apply.
|
||||||
|
- The strategy of the balancer stops selecting qualified nodes
|
||||||
|
according to its settings, doing only the final pick.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
|
||||||
|
-r, -remove
|
||||||
|
Remove the overridden
|
||||||
|
|
||||||
|
-b, -balancer
|
||||||
|
Tag of the balancer. Required
|
||||||
|
|
||||||
|
-v, -validity
|
||||||
|
Time minutes of the validity of overridden. Default 60
|
||||||
|
|
||||||
|
-s, -server
|
||||||
|
The API server address. Default 127.0.0.1:8080
|
||||||
|
|
||||||
|
-t, -timeout
|
||||||
|
Timeout seconds to call API. Default 3
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 -b balancer selector1 selector2
|
||||||
|
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 -b balancer -r
|
||||||
|
`,
|
||||||
|
Run: executeBalancerOverride,
|
||||||
|
}
|
||||||
|
|
||||||
|
func executeBalancerOverride(cmd *base.Command, args []string) {
|
||||||
|
var (
|
||||||
|
balancer string
|
||||||
|
validity int64
|
||||||
|
remove bool
|
||||||
|
)
|
||||||
|
cmd.Flag.StringVar(&balancer, "b", "", "")
|
||||||
|
cmd.Flag.StringVar(&balancer, "balancer", "", "")
|
||||||
|
cmd.Flag.Int64Var(&validity, "v", 60, "")
|
||||||
|
cmd.Flag.Int64Var(&validity, "validity", 60, "")
|
||||||
|
cmd.Flag.BoolVar(&remove, "r", false, "")
|
||||||
|
cmd.Flag.BoolVar(&remove, "remove", false, "")
|
||||||
|
setSharedFlags(cmd)
|
||||||
|
cmd.Flag.Parse(args)
|
||||||
|
|
||||||
|
if balancer == "" {
|
||||||
|
base.Fatalf("balancer tag not specified")
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, ctx, close := dialAPIServer()
|
||||||
|
defer close()
|
||||||
|
|
||||||
|
v := int64(0)
|
||||||
|
if !remove {
|
||||||
|
v = int64(time.Duration(validity) * time.Minute)
|
||||||
|
}
|
||||||
|
client := routerService.NewRoutingServiceClient(conn)
|
||||||
|
r := &routerService.OverrideSelectingRequest{
|
||||||
|
BalancerTag: balancer,
|
||||||
|
Selectors: cmd.Flag.Args(),
|
||||||
|
Validity: v,
|
||||||
|
}
|
||||||
|
_, err := client.OverrideSelecting(ctx, r)
|
||||||
|
if err != nil {
|
||||||
|
base.Fatalf("failed to perform balancer health checks: %s", err)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user