github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/app/router/strategy_leastping.go (about)

     1  //go:build !confonly
     2  // +build !confonly
     3  
     4  package router
     5  
     6  import (
     7  	"context"
     8  
     9  	core "github.com/v2fly/v2ray-core/v5"
    10  	"github.com/v2fly/v2ray-core/v5/app/observatory"
    11  	"github.com/v2fly/v2ray-core/v5/common"
    12  	"github.com/v2fly/v2ray-core/v5/features"
    13  	"github.com/v2fly/v2ray-core/v5/features/extension"
    14  )
    15  
    16  type LeastPingStrategy struct {
    17  	ctx         context.Context
    18  	observatory extension.Observatory
    19  
    20  	config *StrategyLeastPingConfig
    21  }
    22  
    23  func (l *LeastPingStrategy) GetPrincipleTarget(strings []string) []string {
    24  	return []string{l.PickOutbound(strings)}
    25  }
    26  
    27  func (l *LeastPingStrategy) InjectContext(ctx context.Context) {
    28  	l.ctx = ctx
    29  }
    30  
    31  func (l *LeastPingStrategy) PickOutbound(strings []string) string {
    32  	if l.observatory == nil {
    33  		common.Must(core.RequireFeatures(l.ctx, func(observatory extension.Observatory) error {
    34  			if l.config.ObserverTag != "" {
    35  				l.observatory = common.Must2(observatory.(features.TaggedFeatures).GetFeaturesByTag(l.config.ObserverTag)).(extension.Observatory)
    36  			} else {
    37  				l.observatory = observatory
    38  			}
    39  			return nil
    40  		}))
    41  	}
    42  
    43  	observeReport, err := l.observatory.GetObservation(l.ctx)
    44  	if err != nil {
    45  		newError("cannot get observe report").Base(err).WriteToLog()
    46  		return ""
    47  	}
    48  	outboundsList := outboundList(strings)
    49  	if result, ok := observeReport.(*observatory.ObservationResult); ok {
    50  		status := result.Status
    51  		leastPing := int64(99999999)
    52  		selectedOutboundName := ""
    53  		for _, v := range status {
    54  			if outboundsList.contains(v.OutboundTag) && v.Alive && v.Delay < leastPing {
    55  				selectedOutboundName = v.OutboundTag
    56  				leastPing = v.Delay
    57  			}
    58  		}
    59  		return selectedOutboundName
    60  	}
    61  
    62  	// No way to understand observeReport
    63  	return ""
    64  }
    65  
    66  type outboundList []string
    67  
    68  func (o outboundList) contains(name string) bool {
    69  	for _, v := range o {
    70  		if v == name {
    71  			return true
    72  		}
    73  	}
    74  	return false
    75  }
    76  
    77  func init() {
    78  	common.Must(common.RegisterConfig((*StrategyLeastPingConfig)(nil), nil))
    79  }