go-common/app/service/live/zeus/internal/model/matcher.go
2019-04-22 18:49:16 +08:00

81 lines
2.1 KiB
Go

package model
import (
"encoding/json"
"errors"
"fmt"
"go-common/app/service/live/zeus/expr"
"go-common/library/log"
)
type Matcher struct {
Group map[string][]*MatcherBucket `json:"group"`
VariableWhitelist []string `json:"variable_whitelist"`
}
type MatcherBucket struct {
RuleExpr string `json:"expr"`
Extend interface{} `json:"extend"`
expr expr.Expr
variable []string
config string
}
func NewMatcher(config string) (*Matcher, error) {
matcher := &Matcher{}
if err := json.Unmarshal([]byte(config), matcher); err != nil {
return nil, err
}
whitelist := make(map[string]struct{}, len(matcher.VariableWhitelist))
for _, v := range matcher.VariableWhitelist {
whitelist[v] = struct{}{}
}
parser := expr.NewExpressionParser()
for _, bucket := range matcher.Group {
for _, b := range bucket {
if e := parser.Parse(b.RuleExpr); e != nil {
msg := fmt.Sprintf("zeus compile error, rule:%s error:%s", b.RuleExpr, e.Error())
return nil, errors.New(msg)
}
b.expr = parser.GetExpr()
b.variable = parser.GetVariable()
for _, v := range b.variable {
if _, ok := whitelist[v]; !ok {
msg := fmt.Sprintf("zeus check error, rule:%s error: variable %s not in whitelist", b.RuleExpr, v)
return nil, errors.New(msg)
}
}
if config, e := json.Marshal(b.Extend); e != nil {
msg := fmt.Sprintf("zeus parse config error, rule:%s error:%s", b.RuleExpr, e.Error())
return nil, errors.New(msg)
} else {
b.config = string(config)
}
}
}
return matcher, nil
}
func (m *Matcher) Match(group string, env expr.Env) (bool, string, error) {
var bucket []*MatcherBucket
var ok bool
if bucket, ok = m.Group[group]; !ok {
return false, "", errors.New("group not found")
}
isMatch := false
extend := ""
for _, b := range bucket {
result, err := expr.EvalBool(b.expr, env)
if err != nil {
log.Error("zeus eval error, group:%s expr:%s error:%s", group, b.RuleExpr, err.Error())
continue
}
if result {
isMatch = true
extend = b.config
break
}
}
return isMatch, extend, nil
}