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.

245 lines
5.1 KiB

  1. package api
  2. import (
  3. "context"
  4. "git.aiterp.net/lucifer/new-server/app/config"
  5. "git.aiterp.net/lucifer/new-server/models"
  6. "github.com/gin-gonic/gin"
  7. "golang.org/x/sync/errgroup"
  8. "log"
  9. "time"
  10. )
  11. func fetchDevices(ctx context.Context, fetchStr string) ([]models.Device, error) {
  12. kind, value := models.ParseFetchString(fetchStr)
  13. return config.DeviceRepository().FetchByReference(ctx, kind, value)
  14. }
  15. func Devices(r gin.IRoutes) {
  16. r.GET("", handler(func(c *gin.Context) (interface{}, error) {
  17. return config.DeviceRepository().FetchByReference(ctxOf(c), models.RKAll, "")
  18. }))
  19. r.GET("/:fetch", handler(func(c *gin.Context) (interface{}, error) {
  20. return fetchDevices(ctxOf(c), c.Param("fetch"))
  21. }))
  22. r.PUT("", handler(func(c *gin.Context) (interface{}, error) {
  23. var body []struct {
  24. Fetch string `json:"fetch"`
  25. SetState models.NewDeviceState `json:"setState"`
  26. }
  27. err := parseBody(c, &body)
  28. if err != nil {
  29. return nil, err
  30. }
  31. set := make(map[int]bool)
  32. changed := make([]models.Device, 0, 64)
  33. for _, job := range body {
  34. devices, err := fetchDevices(ctxOf(c), job.Fetch)
  35. if err != nil {
  36. return nil, err
  37. }
  38. if len(devices) == 0 {
  39. return []models.Device{}, nil
  40. }
  41. for i := range devices {
  42. if set[devices[i].ID] {
  43. continue
  44. }
  45. err := devices[i].SetState(job.SetState)
  46. if err != nil {
  47. return nil, err
  48. }
  49. set[devices[i].ID] = true
  50. changed = append(changed, devices[i])
  51. }
  52. }
  53. config.PublishChannel <- changed
  54. go func() {
  55. for _, device := range changed {
  56. err := config.DeviceRepository().Save(context.Background(), &device, models.SMState)
  57. if err != nil {
  58. log.Println("Failed to save device for state:", err)
  59. continue
  60. }
  61. }
  62. }()
  63. return changed, nil
  64. }))
  65. r.PUT("/:fetch", handler(func(c *gin.Context) (interface{}, error) {
  66. update := models.DeviceUpdate{}
  67. err := parseBody(c, &update)
  68. if err != nil {
  69. return nil, err
  70. }
  71. devices, err := fetchDevices(ctxOf(c), c.Param("fetch"))
  72. if err != nil {
  73. return nil, err
  74. }
  75. if len(devices) == 0 {
  76. return []models.Device{}, nil
  77. }
  78. for i := range devices {
  79. devices[i].ApplyUpdate(update)
  80. err := config.DeviceRepository().Save(context.Background(), &devices[i], models.SMProperties)
  81. if err != nil {
  82. log.Println("Failed to save device for state:", err)
  83. continue
  84. }
  85. }
  86. return devices, nil
  87. }))
  88. r.PUT("/:fetch/state", handler(func(c *gin.Context) (interface{}, error) {
  89. state := models.NewDeviceState{}
  90. err := parseBody(c, &state)
  91. if err != nil {
  92. return nil, err
  93. }
  94. devices, err := fetchDevices(ctxOf(c), c.Param("fetch"))
  95. if err != nil {
  96. return nil, err
  97. }
  98. if len(devices) == 0 {
  99. return []models.Device{}, nil
  100. }
  101. for i := range devices {
  102. err := devices[i].SetState(state)
  103. if err != nil {
  104. return nil, err
  105. }
  106. }
  107. config.PublishChannel <- devices
  108. go func() {
  109. for _, device := range devices {
  110. err := config.DeviceRepository().Save(context.Background(), &device, models.SMState)
  111. if err != nil {
  112. log.Println("Failed to save device for state:", err)
  113. continue
  114. }
  115. }
  116. }()
  117. return devices, nil
  118. }))
  119. r.PUT("/:fetch/tags", handler(func(c *gin.Context) (interface{}, error) {
  120. var body struct {
  121. Add []string `json:"add"`
  122. Remove []string `json:"remove"`
  123. }
  124. err := parseBody(c, &body)
  125. if err != nil {
  126. return nil, err
  127. }
  128. devices, err := fetchDevices(ctxOf(c), c.Param("fetch"))
  129. if err != nil {
  130. return nil, err
  131. }
  132. if len(devices) == 0 {
  133. return []models.Device{}, nil
  134. }
  135. for i := range devices {
  136. device := &devices[i]
  137. for _, tag := range body.Add {
  138. found := false
  139. for _, tag2 := range device.Tags {
  140. if tag == tag2 {
  141. found = true
  142. break
  143. }
  144. }
  145. if !found {
  146. device.Tags = append(device.Tags, tag)
  147. }
  148. }
  149. for _, tag := range body.Remove {
  150. index := -1
  151. for i, tag2 := range device.Tags {
  152. if tag == tag2 {
  153. index = i
  154. }
  155. }
  156. if index == -1 {
  157. continue
  158. }
  159. device.Tags = append(device.Tags[:index], device.Tags[index+1:]...)
  160. }
  161. err = config.DeviceRepository().Save(ctxOf(c), device, models.SMTags)
  162. if err != nil {
  163. return nil, err
  164. }
  165. }
  166. return devices, nil
  167. }))
  168. r.PUT("/:fetch/scene", handler(func(c *gin.Context) (interface{}, error) {
  169. var body models.DeviceSceneAssignment
  170. err := parseBody(c, &body)
  171. if err != nil {
  172. return nil, err
  173. }
  174. devices, err := fetchDevices(ctxOf(c), c.Param("fetch"))
  175. if err != nil {
  176. return nil, err
  177. }
  178. if len(devices) == 0 {
  179. return []models.Device{}, nil
  180. }
  181. _, err = config.SceneRepository().Find(ctxOf(c), body.SceneID)
  182. if err != nil {
  183. return nil, err
  184. }
  185. if body.DurationMS < 0 {
  186. body.DurationMS = 0
  187. }
  188. body.StartTime = time.Now()
  189. for i := range devices {
  190. devices[i].SceneAssignments = []models.DeviceSceneAssignment{body}
  191. }
  192. config.PublishChannel <- devices
  193. eg := errgroup.Group{}
  194. for i := range devices {
  195. device := devices[i]
  196. eg.Go(func() error {
  197. return config.DeviceRepository().Save(ctxOf(c), &device, 0)
  198. })
  199. }
  200. err = eg.Wait()
  201. if err != nil {
  202. return nil, err
  203. }
  204. return devices, nil
  205. }))
  206. }