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.

270 lines
6.2 KiB

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