You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
121 lines
2.8 KiB
121 lines
2.8 KiB
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
|
|
}
|
|
}
|