strategy_random.go 1.7 KB

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