package automation import ( "fmt" "regexp" "strconv" ) // buildRateFilterGroups implements the "rate-filters" ssm feature: for each // rule, extract a rate from each candidate proxy's original name via // rule.Pattern's first capture group, keep those satisfying // "rate rule.Operator rule.Value", and append a new proxy-group containing // them. Proxies whose name doesn't match Pattern at all are excluded. // Returns one error per rule with an invalid pattern/operator; other rules // still run. func buildRateFilterGroups(finalConfig map[string]interface{}, rules []RateFilterRule, proxies []ProxyRef) []error { var errs []error for _, rule := range rules { re, err := regexp.Compile(rule.Pattern) if err != nil { errs = append(errs, fmt.Errorf("rate-filter '%s': invalid pattern %q: %w", rule.Name, rule.Pattern, err)) continue } cmp, err := comparator(rule.Operator) if err != nil { errs = append(errs, fmt.Errorf("rate-filter '%s': %w", rule.Name, err)) continue } candidates := matchProxies(proxies, rule.Match) names := make([]interface{}, 0, len(candidates)) for _, p := range candidates { m := re.FindStringSubmatch(p.OriginalName) if len(m) < 2 { continue } rate, err := strconv.ParseFloat(m[1], 64) if err != nil { continue } if cmp(rate, rule.Value) { names = append(names, p.DisplayName) } } if len(names) == 0 { fmt.Printf("ℹ️ ssm: rate-filter '%s' matched 0 proxies\n", rule.Name) } group := map[string]interface{}{ "name": rule.Name, "type": defaultString(rule.Type, "select"), "proxies": names, } for k, v := range rule.Extra { group[k] = v } appendProxyGroup(finalConfig, group) } return errs } func comparator(op string) (func(a, b float64) bool, error) { switch op { case "<": return func(a, b float64) bool { return a < b }, nil case "<=": return func(a, b float64) bool { return a <= b }, nil case ">": return func(a, b float64) bool { return a > b }, nil case ">=": return func(a, b float64) bool { return a >= b }, nil case "==", "=": return func(a, b float64) bool { return a == b }, nil case "!=": return func(a, b float64) bool { return a != b }, nil default: return nil, fmt.Errorf("unknown operator %q (expected <, <=, >, >=, ==, !=)", op) } }