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.

195 lines
5.0 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
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. OneShot bool `json:"oneShot"`
  13. Priority int `json:"priority"`
  14. TargetKind ReferenceKind `json:"targetKind"`
  15. TargetValue string `json:"targetValue"`
  16. Actions EventAction `json:"actions"`
  17. }
  18. type EventHandlerRepository interface {
  19. FindByID(ctx context.Context, id int) (*EventHandler, error)
  20. FetchAll(ctx context.Context) ([]EventHandler, error)
  21. Save(ctx context.Context, handler *EventHandler) error
  22. Delete(ctx context.Context, handler *EventHandler) error
  23. }
  24. type EventCondition struct {
  25. EQ string `json:"eq,omitempty"`
  26. GT string `json:"gt,omitempty"`
  27. GTE string `json:"gte,omitempty"`
  28. LT string `json:"lt,omitempty"`
  29. LTE string `json:"lte,omitempty"`
  30. }
  31. type EventHandlerUpdate struct {
  32. SetEventName *string `json:"setEventName"`
  33. SetPriority *int `json:"setPriority"`
  34. SetTargetKind *ReferenceKind `json:"setTargetKind"`
  35. SetTargetValue *string `json:"setTargetValue"`
  36. SetConditions map[string]EventCondition `json:"setConditions"`
  37. PatchConditions map[string]*EventCondition `json:"patchConditions"`
  38. SetActions *EventAction `json:"setActions"`
  39. }
  40. func (h *EventHandler) ApplyUpdate(update EventHandlerUpdate) {
  41. if update.SetEventName != nil {
  42. h.EventName = *update.SetEventName
  43. }
  44. if update.SetPriority != nil {
  45. h.Priority = *update.SetPriority
  46. }
  47. if update.SetTargetKind != nil {
  48. h.TargetKind = *update.SetTargetKind
  49. }
  50. if update.SetTargetValue != nil {
  51. h.TargetValue = *update.SetTargetValue
  52. }
  53. if update.SetActions != nil {
  54. h.Actions = *update.SetActions
  55. }
  56. if update.SetConditions != nil {
  57. h.Conditions = update.SetConditions
  58. }
  59. if update.PatchConditions != nil {
  60. if h.Conditions == nil {
  61. h.Conditions = make(map[string]EventCondition)
  62. }
  63. for key, value := range update.PatchConditions {
  64. if value == nil {
  65. delete(h.Conditions, key)
  66. } else {
  67. h.Conditions[key] = *value
  68. }
  69. }
  70. }
  71. }
  72. func (h *EventHandler) MatchesEvent(event Event, targets []Device) bool {
  73. if event.Name != h.EventName {
  74. return false
  75. }
  76. for key, condition := range h.Conditions {
  77. if !strings.ContainsRune(key, '.') && !event.HasPayload(key) {
  78. return false
  79. }
  80. if !condition.check(key, event.Payload[key], targets) {
  81. return false
  82. }
  83. }
  84. return true
  85. }
  86. func (c *EventCondition) check(key, value string, targets []Device) bool {
  87. any := strings.HasPrefix(key, "any.")
  88. all := strings.HasPrefix(key, "all.")
  89. if any || all {
  90. count := 0
  91. for _, target := range targets {
  92. if c.checkDevice(key[4:], target) {
  93. count++
  94. }
  95. }
  96. return (any && count > 0) || (all && count == len(targets))
  97. }
  98. return c.matches(value)
  99. }
  100. func (c *EventCondition) checkDevice(key string, device Device) bool {
  101. switch key {
  102. case "power":
  103. return c.matches(strconv.FormatBool(device.State.Power))
  104. case "color":
  105. return c.matches(device.State.Color.String())
  106. case "intensity":
  107. return c.matches(strconv.FormatFloat(device.State.Intensity, 'f', -1, 64))
  108. case "temperature":
  109. return c.matches(strconv.FormatFloat(device.State.Temperature, 'f', -1, 64))
  110. }
  111. return false
  112. }
  113. var numRegex = regexp.MustCompile("^{-[0-9].}+$")
  114. func (c *EventCondition) matches(value string) bool {
  115. if numRegex.MatchString(value) {
  116. numValue, _ := strconv.ParseFloat(c.LT, 64)
  117. stillAlive := true
  118. if c.LT != "" {
  119. lt, _ := strconv.ParseFloat(c.LT, 64)
  120. stillAlive = numValue < lt
  121. }
  122. if stillAlive && c.LTE != "" {
  123. lte, _ := strconv.ParseFloat(c.LTE, 64)
  124. stillAlive = numValue <= lte
  125. }
  126. if stillAlive && c.EQ != "" {
  127. eq, _ := strconv.ParseFloat(c.EQ, 64)
  128. stillAlive = numValue == eq
  129. }
  130. if stillAlive && c.GTE != "" {
  131. gte, _ := strconv.ParseFloat(c.GTE, 64)
  132. stillAlive = numValue == gte
  133. }
  134. if stillAlive && c.GT != "" {
  135. gt, _ := strconv.ParseFloat(c.GT, 64)
  136. stillAlive = numValue > gt
  137. }
  138. return stillAlive
  139. } else if c.EQ != "" {
  140. return strings.ToLower(c.EQ) == strings.ToLower(value)
  141. } else {
  142. return false
  143. }
  144. }
  145. type EventAction struct {
  146. SetPower *bool `json:"setPower"`
  147. SetColor *string `json:"setColor"`
  148. SetIntensity *float64 `json:"setIntensity"`
  149. AddIntensity *float64 `json:"addIntensity"`
  150. FireEvent *Event `json:"fireEvent"`
  151. }
  152. func (action *EventAction) Apply(other EventAction) {
  153. if action.SetPower == nil {
  154. action.SetPower = other.SetPower
  155. }
  156. if action.SetColor == nil {
  157. action.SetColor = other.SetColor
  158. }
  159. if action.SetIntensity == nil && other.SetIntensity != nil {
  160. action.SetIntensity = other.SetIntensity
  161. }
  162. if action.AddIntensity == nil && action.SetIntensity == nil {
  163. action.AddIntensity = other.AddIntensity
  164. }
  165. if action.FireEvent == nil {
  166. action.FireEvent = other.FireEvent
  167. }
  168. }