The main server, and probably only repository in this org.
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.

225 lines
4.9 KiB

  1. package light
  2. import (
  3. "context"
  4. "log"
  5. "net/http"
  6. "sync"
  7. "time"
  8. "git.aiterp.net/lucifer/lucifer/internal/httperr"
  9. "git.aiterp.net/lucifer/lucifer/models"
  10. )
  11. // ErrUnknownDriver is returned by any function asking for a driver name if the driver specified doesn't exist.
  12. var ErrUnknownDriver = httperr.Error{Status: http.StatusNotImplemented, Kind: "unknown_driver", Message: "Unknown light driver"}
  13. // A Service wraps the repos for lights and bridges and takes care of the business logic.
  14. type Service struct {
  15. mutex sync.Mutex
  16. bridges models.BridgeRepository
  17. lights models.LightRepository
  18. }
  19. // DirectConnect connects to a bridge directly, without going through the discovery process to find them..
  20. func (s *Service) DirectConnect(ctx context.Context, driver string, addr string, name string) (models.Bridge, error) {
  21. d, ok := drivers[driver]
  22. if !ok {
  23. return models.Bridge{}, ErrUnknownDriver
  24. }
  25. bridge := models.Bridge{
  26. ID: -1,
  27. Name: name,
  28. Addr: addr,
  29. Driver: driver,
  30. }
  31. bridge, err := d.Connect(ctx, bridge)
  32. if err != nil {
  33. return models.Bridge{}, httperr.Error{Status: http.StatusPreconditionFailed, Kind: "connect_failed", Message: err.Error()}
  34. }
  35. bridge, err = s.bridges.Insert(ctx, bridge)
  36. if err != nil {
  37. return models.Bridge{}, err
  38. }
  39. return bridge, nil
  40. }
  41. // SyncLights syncs all lights in a bridge with the state in the database.
  42. func (s *Service) SyncLights(ctx context.Context, bridge models.Bridge) error {
  43. s.mutex.Lock()
  44. defer s.mutex.Unlock()
  45. d, ok := drivers[bridge.Driver]
  46. if !ok {
  47. return ErrUnknownDriver
  48. }
  49. bridgeLights, err := d.Lights(ctx, bridge)
  50. if err != nil {
  51. return err
  52. }
  53. dbLights, err := s.lights.ListByBridge(ctx, bridge)
  54. if err != nil {
  55. return err
  56. }
  57. // Add unknown lights
  58. for _, bridgeLight := range bridgeLights {
  59. found := false
  60. for _, dbLight := range dbLights {
  61. if dbLight.InternalID == bridgeLight.InternalID {
  62. found = true
  63. break
  64. }
  65. }
  66. // Add unknown lights if it doesn't exist in the databse.
  67. if !found {
  68. log.Println("Adding unknown light", bridgeLight.InternalID)
  69. bridgeLight.SetColor("FFFFFF")
  70. bridgeLight.Brightness = 254
  71. _, err := s.lights.Insert(ctx, bridgeLight)
  72. if err != nil {
  73. return err
  74. }
  75. }
  76. }
  77. changedLights, err := d.ChangedLights(ctx, bridge, dbLights...)
  78. if err != nil {
  79. return err
  80. }
  81. if len(changedLights) > 0 {
  82. err := d.Apply(ctx, bridge, changedLights...)
  83. if err != nil {
  84. log.Printf("Failed to apply one or more of the changes on bridge %d (%s): %s", bridge.ID, bridge.Name, err)
  85. }
  86. }
  87. return nil
  88. }
  89. // UpdateLight updates the light immediately.
  90. func (s *Service) UpdateLight(ctx context.Context, light models.Light) error {
  91. s.mutex.Lock()
  92. defer s.mutex.Unlock()
  93. err := s.lights.Update(ctx, light)
  94. if err != nil {
  95. return err
  96. }
  97. bridge, err := s.bridges.FindByID(ctx, light.BridgeID)
  98. if err != nil {
  99. return httperr.NotFound("Bridge")
  100. }
  101. d, ok := drivers[bridge.Driver]
  102. if !ok {
  103. return ErrUnknownDriver
  104. }
  105. return d.Apply(ctx, bridge, light)
  106. }
  107. // SyncLoop runs synclight on all bridges twice every second until the context is
  108. // done.
  109. func (s *Service) SyncLoop(ctx context.Context) {
  110. interval := time.NewTicker(time.Millisecond * 2500)
  111. for {
  112. select {
  113. case <-interval.C:
  114. {
  115. bridges, err := s.Bridges(context.Background())
  116. if err != nil {
  117. log.Println("Could not get bridges:", err)
  118. }
  119. for _, bridge := range bridges {
  120. err = s.SyncLights(ctx, bridge)
  121. if err != nil {
  122. log.Println("Sync failed:", err)
  123. }
  124. }
  125. }
  126. case <-ctx.Done():
  127. {
  128. log.Println("Sync loop stopped.")
  129. return
  130. }
  131. }
  132. }
  133. }
  134. // Bridge gets a bridge by ID.
  135. func (s *Service) Bridge(ctx context.Context, id int) (models.Bridge, error) {
  136. return s.bridges.FindByID(ctx, id)
  137. }
  138. // Bridges gets all known bridges.
  139. func (s *Service) Bridges(ctx context.Context) ([]models.Bridge, error) {
  140. return s.bridges.List(ctx)
  141. }
  142. // DeleteBridge deletes the bridge.
  143. func (s *Service) DeleteBridge(ctx context.Context, bridge models.Bridge) error {
  144. s.mutex.Lock()
  145. defer s.mutex.Unlock()
  146. err := s.bridges.Remove(ctx, bridge)
  147. if err != nil {
  148. return err
  149. }
  150. lights, err := s.lights.ListByBridge(ctx, bridge)
  151. if err != nil {
  152. return err
  153. }
  154. for _, light := range lights {
  155. err := s.lights.Remove(ctx, light)
  156. if err != nil {
  157. return err
  158. }
  159. }
  160. return nil
  161. }
  162. // UpdateBridge updates a bridge.
  163. func (s *Service) UpdateBridge(ctx context.Context, bridge models.Bridge) error {
  164. s.mutex.Lock()
  165. defer s.mutex.Unlock()
  166. err := s.bridges.Update(ctx, bridge)
  167. if err != nil {
  168. return err
  169. }
  170. return nil
  171. }
  172. // DiscoverLights discovers new lights.
  173. func (s *Service) DiscoverLights(ctx context.Context, bridge models.Bridge) error {
  174. d, ok := drivers[bridge.Driver]
  175. if !ok {
  176. return ErrUnknownDriver
  177. }
  178. return d.DiscoverLights(ctx, bridge)
  179. }
  180. // NewService creates a new light.Service.
  181. func NewService(bridges models.BridgeRepository, lights models.LightRepository) *Service {
  182. return &Service{
  183. bridges: bridges,
  184. lights: lights,
  185. }
  186. }