package identify import ( "encoding/json" "strconv" "strings" ) // SingleItem Nv和Ov的组合规则: // 1. Nv是什么 || Nv不是什么 // 2. Ov是什么 || Ov不是什么 // // 1与2的布尔运行结果交叉后, 得到4种组合 00, 01, 10, 11. // 一个事件的判断, 就处在[00, 01, 10, 11]的其中, 有一项为nil, 则表示该项直接通过 // 多个事件, 就判断多个[00, 01, 10, 11], 所以得出以下结论: // 针对设备配置如下规则: // // { // "EventName 1": { // "NvIn": [1,2,3,4], // "NvNotIn": [5,6,7,8], // "OvIn": [1,2,3,4], // "OvNotIn": [5,6,7,8], // }, // "EventName 2": { // "NvIn": [1,2,3,4], // "NvNotIn": [5,6,7,8], // "OvNotIn": [5,6,7,8], // }, // ...... // } type SingleItem struct { nv ItemValue // 当前值 ov ItemValue // 上一次的值 rules map[EventName]Rule } func (s *SingleItem) Check(ov, nv ItemValue) EventName { defer func() { s.nv = "" s.ov = "" }() s.nv = nv s.ov = ov for event, rule := range s.rules { if s.check(rule) { return event } } return "" } func (s *SingleItem) checkForMulti(ov, nv ItemValue, rule Rule) bool { if ov == "" || nv == "" { return false } s.ov = ov s.nv = nv defer func() { s.nv = "" s.ov = "" }() var ovIn, ovNotIn, nvIn, nvNotIn = true, true, true, true if rule.OvIn != nil { ovIn = s.ovIn(rule.OvIn) } if rule.OvNotIn != nil { ovNotIn = s.ovNotIn(rule.OvNotIn) } if rule.NvIn != nil { nvIn = s.nvIn(rule.NvIn) } if rule.NvNotIn != nil { nvNotIn = s.nvNotIn(rule.NvNotIn) } return ovIn && ovNotIn && nvIn && nvNotIn } func (s *SingleItem) check(rule Rule) bool { if s.ov == "" || s.nv == "" { return false } var ovIn, ovNotIn, nvIn, nvNotIn = true, true, true, true if rule.OvIn != nil { ovIn = s.ovIn(rule.OvIn) } if rule.OvNotIn != nil { ovNotIn = s.ovNotIn(rule.OvNotIn) } if rule.NvIn != nil { nvIn = s.nvIn(rule.NvIn) } if rule.NvNotIn != nil { nvNotIn = s.nvNotIn(rule.NvNotIn) } return ovIn && ovNotIn && nvIn && nvNotIn } func (s *SingleItem) ovIn(slice []ItemValue) bool { b := true if slice != nil && s.inSlice(slice, s.ov) == false { b = false } return b } func (s *SingleItem) ovNotIn(slice []ItemValue) bool { b := true if slice != nil && s.inSlice(slice, s.ov) == true { b = false } return b } func (s *SingleItem) nvIn(slice []ItemValue) bool { b := true if slice != nil && s.inSlice(slice, s.nv) == false { b = false } return b } func (s *SingleItem) nvNotIn(slice []ItemValue) bool { b := true if slice != nil && s.inSlice(slice, s.nv) == true { b = false } return b } func (s *SingleItem) inSlice(slice []ItemValue, v ItemValue) bool { for _, s2 := range slice { s1 := s.transVar(s2) if s1 == v { return true } // 数字比较 if _, err := strconv.ParseInt(s1, 10, 64); err != nil { return s.compare(s1, v) } } return false } func (s *SingleItem) transVar(v ItemValue) ItemValue { if v == VAR_NV { v = s.nv } if v == VAR_OV { v = s.ov } return v } func (s *SingleItem) compare(r string, v string) bool { if strings.Index(r, "...") > -1 { return s.compareRange(r, v) } else if strings.Index(r, " ") > 1 { return s.compareLogic(r, v) } return false } func (s *SingleItem) compareRange(r string, v string) bool { rl := strings.Split(r, "...") if len(rl) != 2 { return false } var min, max, vi int64 = 0, 0, 0 if tmin, err := strconv.ParseInt(strings.TrimSpace(rl[0]), 10, 64); err == nil { min = tmin } else { return false } if tmax, err := strconv.ParseInt(strings.TrimSpace(rl[1]), 10, 64); err == nil { max = tmax } else { return false } if tvi, err := strconv.ParseInt(strings.TrimSpace(v), 10, 64); err == nil { vi = tvi } else { return false } return min <= vi && vi <= max } func (s *SingleItem) compareLogic(r string, v string) bool { rl := strings.Split(r, " ") if len(rl) != 2 { return false } var ri, vi int64 = 0, 0 if tri, err := strconv.ParseInt(strings.TrimSpace(rl[1]), 10, 64); err == nil { ri = tri } else { return false } if tvi, err := strconv.ParseInt(strings.TrimSpace(v), 10, 64); err == nil { vi = tvi } else { return false } switch rl[0] { case "<": return vi < ri case "<=": return vi <= ri case ">": return vi > ri case ">=": return vi >= ri case "!=": return vi != ri } return false } // NewSingleCheck 生成一个检测对象, 之后调用Check来获得事件名称 func NewSingleCheck(rules map[EventName]Rule) *SingleItem { return &SingleItem{ rules: rules, } } // NewSingleCheck 生成一个检测对象, 之后调用Check来获得事件名称 func newSingleCheckForMultiItem() *SingleItem { return &SingleItem{} } func StepTest(ov, nv, ruleString string) string { rules := make(map[string]Rule) err := json.Unmarshal([]byte(ruleString), &rules) if err != nil { println(err.Error()) } return NewSingleCheck(rules).Check(ov, nv) }