feat: support merging multiple subscriptions
This commit is contained in:
82
internal/automation/ratefilter.go
Normal file
82
internal/automation/ratefilter.go
Normal file
@ -0,0 +1,82 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user