mirror of https://github.com/XTLS/Xray-core
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
92 lines
2.0 KiB
92 lines
2.0 KiB
package router |
|
|
|
import ( |
|
"context" |
|
"regexp" |
|
"strconv" |
|
"strings" |
|
"sync" |
|
|
|
"github.com/xtls/xray-core/common/errors" |
|
) |
|
|
|
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 |
|
mu sync.Mutex |
|
} |
|
|
|
// Get get the weight of specified tag |
|
func (s *WeightManager) Get(tag string) float64 { |
|
s.mu.Lock() |
|
defer s.mu.Unlock() |
|
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 { |
|
errors.LogError(context.Background(), "unexpected error from ParseFloat: ", err) |
|
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 { |
|
errors.LogError(context.Background(), "invalid regexp: ", find, "err: ", err) |
|
return "" |
|
} |
|
return r.FindString(tag) |
|
}
|
|
|