weight.go 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. package router
  2. import (
  3. "regexp"
  4. "strconv"
  5. "strings"
  6. )
  7. type weightScaler func(value, weight float64) float64
  8. var numberFinder = regexp.MustCompile(`\d+(\.\d+)?`)
  9. // NewWeightManager creates a new WeightManager with settings
  10. func NewWeightManager(s []*StrategyWeight, defaultWeight float64, scaler weightScaler) *WeightManager {
  11. return &WeightManager{
  12. settings: s,
  13. cache: make(map[string]float64),
  14. scaler: scaler,
  15. defaultWeight: defaultWeight,
  16. }
  17. }
  18. // WeightManager manages weights for specific settings
  19. type WeightManager struct {
  20. settings []*StrategyWeight
  21. cache map[string]float64
  22. scaler weightScaler
  23. defaultWeight float64
  24. }
  25. // Get gets the weight of specified tag
  26. func (s *WeightManager) Get(tag string) float64 {
  27. weight, ok := s.cache[tag]
  28. if ok {
  29. return weight
  30. }
  31. weight = s.findValue(tag)
  32. s.cache[tag] = weight
  33. return weight
  34. }
  35. // Apply applies weight to the value
  36. func (s *WeightManager) Apply(tag string, value float64) float64 {
  37. return s.scaler(value, s.Get(tag))
  38. }
  39. func (s *WeightManager) findValue(tag string) float64 {
  40. for _, w := range s.settings {
  41. matched := s.getMatch(tag, w.Match, w.Regexp)
  42. if matched == "" {
  43. continue
  44. }
  45. if w.Value > 0 {
  46. return float64(w.Value)
  47. }
  48. // auto weight from matched
  49. numStr := numberFinder.FindString(matched)
  50. if numStr == "" {
  51. return s.defaultWeight
  52. }
  53. weight, err := strconv.ParseFloat(numStr, 64)
  54. if err != nil {
  55. newError("unexpected error from ParseFloat: ", err).AtError().WriteToLog()
  56. return s.defaultWeight
  57. }
  58. return weight
  59. }
  60. return s.defaultWeight
  61. }
  62. func (s *WeightManager) getMatch(tag, find string, isRegexp bool) string {
  63. if !isRegexp {
  64. idx := strings.Index(tag, find)
  65. if idx < 0 {
  66. return ""
  67. }
  68. return find
  69. }
  70. r, err := regexp.Compile(find)
  71. if err != nil {
  72. newError("invalid regexp: ", find, "err: ", err).AtError().WriteToLog()
  73. return ""
  74. }
  75. return r.FindString(tag)
  76. }