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.

173 lines
5.1 KiB

1 year ago
  1. package uistate
  2. import (
  3. "git.aiterp.net/lucifer3/server/device"
  4. "git.aiterp.net/lucifer3/server/effects"
  5. "git.aiterp.net/lucifer3/server/events"
  6. "git.aiterp.net/lucifer3/server/internal/color"
  7. "git.aiterp.net/lucifer3/server/internal/gentools"
  8. "git.aiterp.net/lucifer3/server/services/script"
  9. "github.com/google/uuid"
  10. "strings"
  11. )
  12. type Data struct {
  13. Devices map[string]Device `json:"devices"`
  14. Assignments map[uuid.UUID]Assignment `json:"assignments"`
  15. Scripts map[string][]script.Line `json:"scripts"`
  16. }
  17. func (d *Data) WithPatch(patches ...Patch) Data {
  18. newData := d.Copy()
  19. for _, patch := range patches {
  20. if patch.Device != nil {
  21. pd := d.ensureDevice(patch.Device.ID)
  22. gentools.ApplyUpdate(&pd.Name, patch.Device.Name)
  23. gentools.ApplyUpdatePtr(&pd.HWState, patch.Device.HWState)
  24. gentools.ApplyUpdatePtr(&pd.HWMetadata, patch.Device.HWMetadata)
  25. gentools.ApplyUpdatePtr(&pd.DesiredState, patch.Device.DesiredState)
  26. gentools.ApplyUpdatePtr(&pd.Assignment, patch.Device.Assignment)
  27. gentools.ApplyUpdatePtr(&pd.ActiveColorRGB, patch.Device.ActiveColorRGB)
  28. gentools.ApplyUpdatePtr(&pd.DesiredColorRGB, patch.Device.DesiredColorRGB)
  29. if patch.Device.AddAlias != nil {
  30. ptr := device.Pointer{ID: "dummy", Aliases: pd.Aliases}
  31. ptr.AddAlias(*patch.Device.AddAlias)
  32. if strings.HasPrefix(*patch.Device.AddAlias, "lucifer:name:") {
  33. pd.Name = (*patch.Device.AddAlias)[len("lucifer:name:"):]
  34. }
  35. if strings.HasPrefix(*patch.Device.AddAlias, "lucifer:icon:") {
  36. pd.Icon = (*patch.Device.AddAlias)[len("lucifer:icon:"):]
  37. }
  38. pd.Aliases = ptr.Aliases
  39. }
  40. if patch.Device.RemoveAlias != nil {
  41. for i, alias := range pd.Aliases {
  42. if alias == *patch.Device.RemoveAlias {
  43. pd.Aliases = append(pd.Aliases[:i], pd.Aliases[i+1:]...)
  44. }
  45. }
  46. }
  47. if patch.Device.HWMetadata != nil {
  48. hasIconAlias := false
  49. for _, a := range pd.Aliases {
  50. if strings.HasPrefix(a, "lucifer:icon") {
  51. hasIconAlias = true
  52. break
  53. }
  54. }
  55. if !hasIconAlias {
  56. pd.Icon = patch.Device.HWMetadata.Icon
  57. }
  58. }
  59. if patch.Device.ClearAssignment {
  60. pd.Assignment = nil
  61. }
  62. if patch.Device.ClearActiveColorRGB {
  63. pd.ActiveColorRGB = nil
  64. }
  65. if patch.Device.Sensors != nil {
  66. if patch.Device.Sensors.LastMotion != nil {
  67. pd.Sensors.LastMotion = gentools.ShallowCopy(patch.Device.Sensors.LastMotion)
  68. }
  69. if patch.Device.Sensors.Temperature != nil {
  70. pd.Sensors.Temperature = gentools.ShallowCopy(patch.Device.Sensors.Temperature)
  71. }
  72. }
  73. if patch.Device.Delete {
  74. delete(newData.Devices, pd.ID)
  75. } else {
  76. newData.Devices[pd.ID] = pd
  77. }
  78. }
  79. if patch.Assignment != nil {
  80. pa := d.ensureAssignment(patch.Assignment.ID)
  81. gentools.ApplyUpdatePtr(&pa.Effect, patch.Assignment.Effect)
  82. if patch.Assignment.AddDeviceID != nil {
  83. pa.DeviceIDs = append(pa.DeviceIDs[:0:0], pa.DeviceIDs...)
  84. pa.DeviceIDs = append(pa.DeviceIDs, *patch.Assignment.AddDeviceID)
  85. }
  86. if patch.Assignment.RemoveDeviceID != nil {
  87. for i, id := range pa.DeviceIDs {
  88. if id == *patch.Assignment.RemoveDeviceID {
  89. pa.DeviceIDs = append(pa.DeviceIDs[:0:0], pa.DeviceIDs...)
  90. pa.DeviceIDs[i] = ""
  91. break
  92. }
  93. }
  94. }
  95. if patch.Assignment.Variables != nil {
  96. pa.Variables = gentools.CopyMap(patch.Assignment.Variables)
  97. }
  98. if patch.Assignment.Delete {
  99. delete(newData.Assignments, pa.ID)
  100. } else {
  101. newData.Assignments[pa.ID] = pa
  102. }
  103. }
  104. if patch.Script != nil {
  105. newData.Scripts[patch.Script.Name] = patch.Script.Lines
  106. }
  107. }
  108. return newData
  109. }
  110. func (d *Data) Copy() Data {
  111. return Data{
  112. Devices: gentools.CopyMap(d.Devices),
  113. Assignments: gentools.CopyMap(d.Assignments),
  114. Scripts: gentools.CopyMap(d.Scripts),
  115. }
  116. }
  117. func (d *Data) ensureDevice(id string) Device {
  118. if device, ok := d.Devices[id]; ok {
  119. return device
  120. } else {
  121. return Device{ID: id}
  122. }
  123. }
  124. func (d *Data) ensureAssignment(id uuid.UUID) Assignment {
  125. if assignment, ok := d.Assignments[id]; ok {
  126. return assignment
  127. } else {
  128. return Assignment{ID: id}
  129. }
  130. }
  131. type Device struct {
  132. ID string `json:"id"`
  133. Name string `json:"name"`
  134. HWMetadata *events.HardwareMetadata `json:"hwMetadata"`
  135. HWState *events.HardwareState `json:"hwState"`
  136. DesiredColorRGB *color.RGB `json:"desiredColorRgb"`
  137. ActiveColorRGB *color.RGB `json:"activeColorRgb"`
  138. DesiredState *device.State `json:"desiredState"`
  139. Aliases []string `json:"aliases"`
  140. Assignment *uuid.UUID `json:"assignment"`
  141. Sensors DeviceSensors `json:"sensors"`
  142. Icon string `json:"icon"`
  143. }
  144. type DeviceSensors struct {
  145. LastMotion *float64 `json:"lastMotion,omitempty"`
  146. Temperature *float64 `json:"temperature,omitempty"`
  147. }
  148. type Assignment struct {
  149. ID uuid.UUID `json:"id"`
  150. DeviceIDs []string `json:"deviceIds"`
  151. Effect *effects.Serializable `json:"effect"`
  152. Variables map[string]float64 `json:"variables"`
  153. }