github.com/xtls/xray-core@v1.8.12-0.20240518155711-3168d27b0bdb/app/router/strategy_random.go (about)

     1  package router
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/xtls/xray-core/app/observatory"
     7  	"github.com/xtls/xray-core/common"
     8  	"github.com/xtls/xray-core/common/dice"
     9  	"github.com/xtls/xray-core/core"
    10  	"github.com/xtls/xray-core/features/extension"
    11  )
    12  
    13  // RandomStrategy represents a random balancing strategy
    14  type RandomStrategy struct{
    15  	FallbackTag string
    16  
    17  	ctx         context.Context
    18  	observatory extension.Observatory
    19  }
    20  
    21  func (s *RandomStrategy) InjectContext(ctx context.Context) {
    22  	s.ctx = ctx
    23  }
    24  
    25  func (s *RandomStrategy) GetPrincipleTarget(strings []string) []string {
    26  	return strings
    27  }
    28  
    29  func (s *RandomStrategy) PickOutbound(candidates []string) string {
    30  	if len(s.FallbackTag) > 0 && s.observatory == nil {
    31  		common.Must(core.RequireFeatures(s.ctx, func(observatory extension.Observatory) error {
    32  			s.observatory = observatory
    33  			return nil
    34  		}))
    35  	}
    36  	if s.observatory != nil {
    37  		observeReport, err := s.observatory.GetObservation(s.ctx)
    38  		if err == nil {
    39  			aliveTags := make([]string, 0)
    40  			if result, ok := observeReport.(*observatory.ObservationResult); ok {
    41  				status := result.Status
    42  				statusMap := make(map[string]*observatory.OutboundStatus)
    43  				for _, outboundStatus := range status {
    44  					statusMap[outboundStatus.OutboundTag] = outboundStatus
    45  				}
    46  				for _, candidate := range candidates {
    47  					if outboundStatus, found := statusMap[candidate]; found {
    48  						if outboundStatus.Alive {
    49  							aliveTags = append(aliveTags, candidate)
    50  						}
    51  					} else {
    52  						// unfound candidate is considered alive
    53  						aliveTags = append(aliveTags, candidate)
    54  					}
    55  				}
    56  				candidates = aliveTags
    57  			}
    58  		}
    59  	}
    60  
    61  	count := len(candidates)
    62  	if count == 0 {
    63  		// goes to fallbackTag
    64  		return ""
    65  	}
    66  	return candidates[dice.Roll(count)]
    67  }