package models import ( "context" "regexp" "strconv" "strings" ) type EventHandler struct { ID int `json:"id"` EventName string `json:"eventName"` Conditions map[string]EventCondition `json:"conditions"` TargetKind ReferenceKind `json:"targetType"` TargetValue string `json:"targetValue"` } type EventHandlerRepository interface { FindByID(ctx context.Context, id int) (EventHandler, error) FetchAll(ctx context.Context) ([]EventHandler, error) Save(ctx context.Context, handler *EventHandler) Delete(ctx context.Context, handler *EventHandler) } type EventCondition struct { EQ string `json:"eq,omitempty"` GT string `json:"gt,omitempty"` GTE string `json:"gte,omitempty"` LT string `json:"lt,omitempty"` LTE string `json:"lte,omitempty"` } func (h *EventHandler) MatchesEvent(event Event, targets []Device) bool { if event.Name != h.EventName { return false } for key, condition := range h.Conditions { if !event.HasPayload(key) { return false } if !condition.check(key, event.Payload[key], targets) { return false } } return true } func (c *EventCondition) check(key, value string, targets []Device) bool { any := strings.Index(key, "any.") == 0 all := strings.Index(key, "all.") == 0 if any || all && len(key) > 4 { count := 0 for _, target := range targets { if c.checkDevice(key[4:], target) { count++ } } return (any && count > 0) || (all && count == len(targets)) } return c.matches(value) } func (c *EventCondition) checkDevice(key string, device Device) bool { switch key { case "power": return c.matches(strconv.FormatBool(device.State.Power)) case "color": return c.matches(device.State.Color.String()) case "intensity": return c.matches(strconv.FormatFloat(device.State.Intensity, 'f', -1, 64)) case "temperature": return c.matches(strconv.FormatFloat(device.State.Temperature, 'f', -1, 64)) } return false } var numRegex = regexp.MustCompile("^{-[0-9].}+$") func (c *EventCondition) matches(value string) bool { if numRegex.MatchString(value) { numValue, _ := strconv.ParseFloat(c.LT, 64) stillAlive := true if c.LT != "" { lt, _ := strconv.ParseFloat(c.LT, 64) stillAlive = numValue < lt } if stillAlive && c.LTE != "" { lte, _ := strconv.ParseFloat(c.LTE, 64) stillAlive = numValue <= lte } if stillAlive && c.EQ != "" { eq, _ := strconv.ParseFloat(c.EQ, 64) stillAlive = numValue == eq } if stillAlive && c.GTE != "" { gte, _ := strconv.ParseFloat(c.GTE, 64) stillAlive = numValue == gte } if stillAlive && c.GT != "" { gt, _ := strconv.ParseFloat(c.GT, 64) stillAlive = numValue > gt } return stillAlive } else if c.EQ != "" { return strings.ToLower(c.EQ) == strings.ToLower(value) } else { return false } }