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

4 years ago
  1. package models
  2. import (
  3. "context"
  4. "regexp"
  5. "strconv"
  6. "strings"
  7. )
  8. type EventHandler struct {
  9. ID int `json:"id"`
  10. EventName string `json:"eventName"`
  11. Conditions map[string]EventCondition `json:"conditions"`
  12. TargetKind ReferenceKind `json:"targetType"`
  13. TargetValue string `json:"targetValue"`
  14. }
  15. type EventHandlerRepository interface {
  16. FindByID(ctx context.Context, id int) (EventHandler, error)
  17. FetchAll(ctx context.Context) ([]EventHandler, error)
  18. Save(ctx context.Context, handler *EventHandler)
  19. Delete(ctx context.Context, handler *EventHandler)
  20. }
  21. type EventCondition struct {
  22. EQ string `json:"eq,omitempty"`
  23. GT string `json:"gt,omitempty"`
  24. GTE string `json:"gte,omitempty"`
  25. LT string `json:"lt,omitempty"`
  26. LTE string `json:"lte,omitempty"`
  27. }
  28. func (h *EventHandler) MatchesEvent(event Event, targets []Device) bool {
  29. if event.Name != h.EventName {
  30. return false
  31. }
  32. for key, condition := range h.Conditions {
  33. if !event.HasPayload(key) {
  34. return false
  35. }
  36. if !condition.check(key, event.Payload[key], targets) {
  37. return false
  38. }
  39. }
  40. return true
  41. }
  42. func (c *EventCondition) check(key, value string, targets []Device) bool {
  43. any := strings.Index(key, "any.") == 0
  44. all := strings.Index(key, "all.") == 0
  45. if any || all && len(key) > 4 {
  46. count := 0
  47. for _, target := range targets {
  48. if c.checkDevice(key[4:], target) {
  49. count++
  50. }
  51. }
  52. return (any && count > 0) || (all && count == len(targets))
  53. }
  54. return c.matches(value)
  55. }
  56. func (c *EventCondition) checkDevice(key string, device Device) bool {
  57. switch key {
  58. case "power":
  59. return c.matches(strconv.FormatBool(device.State.Power))
  60. case "color":
  61. return c.matches(device.State.Color.String())
  62. case "intensity":
  63. return c.matches(strconv.Itoa(device.State.Intensity))
  64. case "temperature":
  65. return c.matches(strconv.Itoa(device.State.Temperature))
  66. }
  67. return false
  68. }
  69. var numRegex = regexp.MustCompile("^{-[0-9].}+$")
  70. func (c *EventCondition) matches(value string) bool {
  71. if numRegex.MatchString(value) {
  72. numValue, _ := strconv.ParseFloat(c.LT, 64)
  73. stillAlive := true
  74. if c.LT != "" {
  75. lt, _ := strconv.ParseFloat(c.LT, 64)
  76. stillAlive = numValue < lt
  77. }
  78. if stillAlive && c.LTE != "" {
  79. lte, _ := strconv.ParseFloat(c.LTE, 64)
  80. stillAlive = numValue <= lte
  81. }
  82. if stillAlive && c.EQ != "" {
  83. eq, _ := strconv.ParseFloat(c.EQ, 64)
  84. stillAlive = numValue == eq
  85. }
  86. if stillAlive && c.GTE != "" {
  87. gte, _ := strconv.ParseFloat(c.GTE, 64)
  88. stillAlive = numValue == gte
  89. }
  90. if stillAlive && c.GT != "" {
  91. gt, _ := strconv.ParseFloat(c.GT, 64)
  92. stillAlive = numValue > gt
  93. }
  94. return stillAlive
  95. } else if c.EQ != "" {
  96. return strings.ToLower(c.EQ) == strings.ToLower(value)
  97. } else {
  98. return false
  99. }
  100. }