You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

264 lines
5.5 KiB
Go

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package matcher
import (
"encoding/json"
"reflect"
"strings"
ctxpkg "github.com/noahlann/nnet/pkg/context"
routerpkg "github.com/noahlann/nnet/pkg/router"
)
// FrameDataMatcher 帧数据匹配器
type FrameDataMatcher struct {
path string
operator string
value interface{}
priority int
}
// NewFrameDataMatcher 创建帧数据匹配器
func NewFrameDataMatcher(path, operator string, value interface{}) routerpkg.Matcher {
return &FrameDataMatcher{
path: path,
operator: operator,
value: value,
priority: 150, // 帧数据匹配优先级低于帧头匹配
}
}
// WithPriority 设置优先级
func (m *FrameDataMatcher) WithPriority(priority int) *FrameDataMatcher {
m.priority = priority
return m
}
// Match 匹配帧数据
func (m *FrameDataMatcher) Match(input routerpkg.MatchInput, ctx ctxpkg.Context) bool {
var parsedData interface{}
if input.Data != nil {
parsedData = input.Data
} else if len(input.DataBytes) > 0 {
var jsonData map[string]interface{}
if err := json.Unmarshal(input.DataBytes, &jsonData); err != nil {
return false
}
parsedData = jsonData
} else if len(input.Raw) > 0 {
var jsonData map[string]interface{}
if err := json.Unmarshal(input.Raw, &jsonData); err != nil {
return false
}
parsedData = jsonData
} else if req := ctx.Request(); req != nil {
if req.Data() != nil {
parsedData = req.Data()
} else if len(req.DataBytes()) > 0 {
var jsonData map[string]interface{}
if err := json.Unmarshal(req.DataBytes(), &jsonData); err != nil {
return false
}
parsedData = jsonData
}
}
if parsedData == nil {
return false
}
// 根据路径提取值
fieldValue := m.extractValue(parsedData, m.path)
if fieldValue == nil {
return false
}
return m.compare(fieldValue, m.value, m.operator)
}
// extractValue 从数据中提取值(支持点号分隔的路径,如 "user.id"
func (m *FrameDataMatcher) extractValue(data interface{}, path string) interface{} {
if path == "" {
return data
}
parts := strings.Split(path, ".")
current := data
for _, part := range parts {
switch v := current.(type) {
case map[string]interface{}:
current = v[part]
if current == nil {
return nil
}
default:
// 使用反射获取字段值
rv := reflect.ValueOf(current)
if rv.Kind() == reflect.Ptr {
rv = rv.Elem()
}
if rv.Kind() != reflect.Struct {
return nil
}
field := rv.FieldByName(part)
if !field.IsValid() {
return nil
}
current = field.Interface()
}
}
return current
}
// compare 比较值与FrameHeaderMatcher相同的逻辑
func (m *FrameDataMatcher) compare(actual, expected interface{}, operator string) bool {
switch operator {
case "==":
return reflect.DeepEqual(actual, expected)
case "!=":
return !reflect.DeepEqual(actual, expected)
case ">":
return m.greaterThan(actual, expected)
case "<":
return m.lessThan(actual, expected)
case ">=":
return m.greaterThan(actual, expected) || reflect.DeepEqual(actual, expected)
case "<=":
return m.lessThan(actual, expected) || reflect.DeepEqual(actual, expected)
case "in":
return m.in(actual, expected)
case "contains":
return m.contains(actual, expected)
default:
return false
}
}
// greaterThan 大于比较
func (m *FrameDataMatcher) greaterThan(a, b interface{}) bool {
switch av := a.(type) {
case int:
if bv, ok := b.(int); ok {
return av > bv
}
case int32:
if bv, ok := b.(int32); ok {
return av > bv
}
case int64:
if bv, ok := b.(int64); ok {
return av > bv
}
case uint8:
if bv, ok := b.(uint8); ok {
return av > bv
}
case uint32:
if bv, ok := b.(uint32); ok {
return av > bv
}
case uint64:
if bv, ok := b.(uint64); ok {
return av > bv
}
case float64:
if bv, ok := b.(float64); ok {
return av > bv
}
}
return false
}
// lessThan 小于比较
func (m *FrameDataMatcher) lessThan(a, b interface{}) bool {
switch av := a.(type) {
case int:
if bv, ok := b.(int); ok {
return av < bv
}
case int32:
if bv, ok := b.(int32); ok {
return av < bv
}
case int64:
if bv, ok := b.(int64); ok {
return av < bv
}
case uint8:
if bv, ok := b.(uint8); ok {
return av < bv
}
case uint32:
if bv, ok := b.(uint32); ok {
return av < bv
}
case uint64:
if bv, ok := b.(uint64); ok {
return av < bv
}
case float64:
if bv, ok := b.(float64); ok {
return av < bv
}
}
return false
}
// in 检查是否在列表中
func (m *FrameDataMatcher) in(value, list interface{}) bool {
listValue := reflect.ValueOf(list)
if listValue.Kind() != reflect.Slice {
return false
}
for i := 0; i < listValue.Len(); i++ {
if reflect.DeepEqual(value, listValue.Index(i).Interface()) {
return true
}
}
return false
}
// contains 检查是否包含
func (m *FrameDataMatcher) contains(container, item interface{}) bool {
// 字符串包含
if str, ok := container.(string); ok {
if itemStr, ok := item.(string); ok {
return strings.Contains(str, itemStr)
}
}
// 数组/切片包含
containerValue := reflect.ValueOf(container)
if containerValue.Kind() == reflect.Slice {
for i := 0; i < containerValue.Len(); i++ {
if reflect.DeepEqual(item, containerValue.Index(i).Interface()) {
return true
}
}
}
return false
}
// Priority 获取优先级
func (m *FrameDataMatcher) Priority() int {
return m.priority
}
// Path 获取路径
func (m *FrameDataMatcher) Path() string {
return m.path
}
// Operator 获取操作符
func (m *FrameDataMatcher) Operator() string {
return m.operator
}
// Value 获取匹配值
func (m *FrameDataMatcher) Value() interface{} {
return m.value
}