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.

112 lines
2.3 KiB

  1. package httpapiv1
  2. import (
  3. lucifer3 "git.aiterp.net/lucifer3/server"
  4. "git.aiterp.net/lucifer3/server/commands"
  5. "git.aiterp.net/lucifer3/server/effects"
  6. "git.aiterp.net/lucifer3/server/events"
  7. "git.aiterp.net/lucifer3/server/services/uistate"
  8. "github.com/labstack/echo/v4"
  9. "log"
  10. "net"
  11. "sync"
  12. )
  13. func New(addr string) (lucifer3.Service, error) {
  14. svc := &service{}
  15. e := echo.New()
  16. e.GET("/state", func(c echo.Context) error {
  17. svc.mu.Lock()
  18. data := svc.data
  19. svc.mu.Unlock()
  20. return c.JSON(200, data)
  21. })
  22. e.POST("/command", func(c echo.Context) error {
  23. var input commandInput
  24. err := c.Bind(&input)
  25. if err != nil {
  26. return err
  27. }
  28. svc.mu.Lock()
  29. bus := svc.bus
  30. svc.mu.Unlock()
  31. if bus == nil {
  32. return c.String(413, "Waiting for bus")
  33. }
  34. switch {
  35. case input.Assign != nil:
  36. bus.RunCommand(commands.Assign{
  37. ID: nil,
  38. Match: input.Assign.Match,
  39. Effect: input.Assign.Effect.Effect,
  40. })
  41. case input.PairDevice != nil:
  42. bus.RunCommand(*input.PairDevice)
  43. case input.ForgetDevice != nil:
  44. bus.RunCommand(*input.ForgetDevice)
  45. case input.SearchDevices != nil:
  46. bus.RunCommand(*input.SearchDevices)
  47. default:
  48. return c.String(400, "No supported command found in input")
  49. }
  50. return c.JSON(200, input)
  51. })
  52. listener, err := net.Listen("tcp", addr)
  53. if err != nil {
  54. return nil, err
  55. }
  56. e.Listener = listener
  57. go func() {
  58. err := e.Start(addr)
  59. if err != nil {
  60. log.Fatalln("Failed to listen to webserver")
  61. }
  62. }()
  63. return svc, nil
  64. }
  65. type service struct {
  66. mu sync.Mutex
  67. data uistate.Data
  68. bus *lucifer3.EventBus
  69. }
  70. func (s *service) Active() bool {
  71. return true
  72. }
  73. func (s *service) HandleEvent(bus *lucifer3.EventBus, event lucifer3.Event) {
  74. switch event := event.(type) {
  75. case events.Started:
  76. s.mu.Lock()
  77. s.bus = bus
  78. s.mu.Unlock()
  79. case uistate.Patch:
  80. s.mu.Lock()
  81. s.data = s.data.WithPatch(event)
  82. s.mu.Unlock()
  83. // TODO: Broadcast websockets
  84. }
  85. }
  86. type commandInput struct {
  87. Assign *assignInput `json:"assign,omitempty"`
  88. PairDevice *commands.PairDevice `json:"pairDevice,omitempty"`
  89. SearchDevices *commands.SearchDevices `json:"searchDevices,omitempty"`
  90. ForgetDevice *commands.ForgetDevice `json:"forgetDevice,omitempty"`
  91. }
  92. type assignInput struct {
  93. Match string `json:"match"`
  94. Effect effects.Serializable `json:"effect"`
  95. }