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.

280 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. go func() {
  117. err = config.DeviceRepository().SaveMany(ctxOf(c), models.SMState, devices)
  118. if err != nil {
  119. log.Println("Failed to save devices states")
  120. }
  121. }()
  122. return withSceneState(devices), nil
  123. }))
  124. r.PUT("/:fetch/tags", handler(func(c *gin.Context) (interface{}, error) {
  125. var body struct {
  126. Add []string `json:"add"`
  127. Remove []string `json:"remove"`
  128. }
  129. err := parseBody(c, &body)
  130. if err != nil {
  131. return nil, err
  132. }
  133. devices, err := fetchDevices(ctxOf(c), c.Param("fetch"))
  134. if err != nil {
  135. return nil, err
  136. }
  137. if len(devices) == 0 {
  138. return []models.Device{}, nil
  139. }
  140. for i := range devices {
  141. device := &devices[i]
  142. for _, tag := range body.Add {
  143. found := false
  144. for _, tag2 := range device.Tags {
  145. if tag == tag2 {
  146. found = true
  147. break
  148. }
  149. }
  150. if !found {
  151. device.Tags = append(device.Tags, tag)
  152. }
  153. }
  154. for _, tag := range body.Remove {
  155. index := -1
  156. for i, tag2 := range device.Tags {
  157. if tag == tag2 {
  158. index = i
  159. }
  160. }
  161. if index == -1 {
  162. continue
  163. }
  164. device.Tags = append(device.Tags[:index], device.Tags[index+1:]...)
  165. }
  166. err = config.DeviceRepository().Save(ctxOf(c), device, models.SMTags)
  167. if err != nil {
  168. return nil, err
  169. }
  170. }
  171. return withSceneState(devices), nil
  172. }))
  173. r.PUT("/:fetch/scene", handler(func(c *gin.Context) (interface{}, error) {
  174. var body models.DeviceSceneAssignment
  175. err := parseBody(c, &body)
  176. if err != nil {
  177. return nil, err
  178. }
  179. devices, err := fetchDevices(ctxOf(c), c.Param("fetch"))
  180. if err != nil {
  181. return nil, err
  182. }
  183. if len(devices) == 0 {
  184. return []models.Device{}, nil
  185. }
  186. _, err = config.SceneRepository().Find(ctxOf(c), body.SceneID)
  187. if err != nil {
  188. return nil, err
  189. }
  190. if body.DurationMS < 0 {
  191. body.DurationMS = 0
  192. }
  193. body.StartTime = time.Now()
  194. pushMode := c.Query("push") == "true"
  195. for i := range devices {
  196. if pushMode {
  197. devices[i].SceneAssignments = append(devices[i].SceneAssignments, body)
  198. } else {
  199. devices[i].SceneAssignments = []models.DeviceSceneAssignment{body}
  200. }
  201. }
  202. config.PublishChannel <- devices
  203. err = config.DeviceRepository().SaveMany(ctxOf(c), 0, devices)
  204. if err != nil {
  205. return nil, err
  206. }
  207. return withSceneState(devices), nil
  208. }))
  209. r.DELETE("/:fetch/scene", handler(func(c *gin.Context) (interface{}, error) {
  210. devices, err := fetchDevices(ctxOf(c), c.Param("fetch"))
  211. if err != nil {
  212. return nil, err
  213. }
  214. if len(devices) == 0 {
  215. return []models.Device{}, nil
  216. }
  217. for i := range devices {
  218. devices[i].SceneAssignments = []models.DeviceSceneAssignment{}
  219. }
  220. config.PublishChannel <- devices
  221. err = config.DeviceRepository().SaveMany(ctxOf(c), 0, devices)
  222. if err != nil {
  223. return nil, err
  224. }
  225. return withSceneState(devices), nil
  226. }))
  227. }
  228. func withSceneState(devices []models.Device) []models.Device {
  229. res := make([]models.Device, 0, len(devices))
  230. for _, device := range devices {
  231. device.SceneState = publisher.Global().SceneState(device.ID)
  232. res = append(res, device)
  233. }
  234. return res
  235. }