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.

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