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.

133 lines
3.2 KiB

2 years ago
2 years ago
  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/script"
  8. "git.aiterp.net/lucifer3/server/services/uistate"
  9. "github.com/labstack/echo/v4"
  10. "github.com/labstack/echo/v4/middleware"
  11. "log"
  12. "net"
  13. "sync"
  14. )
  15. func New(addr string) (lucifer3.Service, error) {
  16. svc := &service{}
  17. e := echo.New()
  18. e.HideBanner = true
  19. e.HidePort = true
  20. e.Use(middleware.CORS())
  21. e.GET("/state", func(c echo.Context) error {
  22. svc.mu.Lock()
  23. data := svc.data
  24. svc.mu.Unlock()
  25. return c.JSON(200, data)
  26. })
  27. e.POST("/command", func(c echo.Context) error {
  28. var input commandInput
  29. err := c.Bind(&input)
  30. if err != nil {
  31. return err
  32. }
  33. svc.mu.Lock()
  34. bus := svc.bus
  35. svc.mu.Unlock()
  36. if bus == nil {
  37. return c.String(413, "Waiting for bus")
  38. }
  39. switch {
  40. case input.Assign != nil:
  41. bus.RunCommand(commands.Assign{
  42. ID: nil,
  43. Match: input.Assign.Match,
  44. Effect: input.Assign.Effect.Effect,
  45. })
  46. case input.PairDevice != nil:
  47. bus.RunCommand(*input.PairDevice)
  48. case input.ConnectDevice != nil:
  49. bus.RunCommand(*input.ConnectDevice)
  50. case input.ForgetDevice != nil:
  51. bus.RunCommand(*input.ForgetDevice)
  52. case input.SearchDevices != nil:
  53. bus.RunCommand(*input.SearchDevices)
  54. case input.AddAlias != nil:
  55. bus.RunCommand(*input.AddAlias)
  56. case input.RemoveAlias != nil:
  57. bus.RunCommand(*input.RemoveAlias)
  58. case input.UpdateScript != nil:
  59. bus.RunCommand(*input.UpdateScript)
  60. case input.ExecuteScript != nil:
  61. bus.RunCommand(*input.ExecuteScript)
  62. default:
  63. return c.String(400, "No supported command found in input")
  64. }
  65. return c.JSON(200, input)
  66. })
  67. listener, err := net.Listen("tcp", addr)
  68. if err != nil {
  69. return nil, err
  70. }
  71. e.Listener = listener
  72. go func() {
  73. err := e.Start(addr)
  74. if err != nil {
  75. log.Fatalln("Failed to listen to webserver")
  76. }
  77. }()
  78. return svc, nil
  79. }
  80. type service struct {
  81. mu sync.Mutex
  82. data uistate.Data
  83. bus *lucifer3.EventBus
  84. }
  85. func (s *service) Active() bool {
  86. return true
  87. }
  88. func (s *service) HandleEvent(bus *lucifer3.EventBus, event lucifer3.Event) {
  89. switch event := event.(type) {
  90. case events.Started:
  91. s.mu.Lock()
  92. s.bus = bus
  93. s.mu.Unlock()
  94. case uistate.Patch:
  95. s.mu.Lock()
  96. s.data = s.data.WithPatch(event)
  97. s.mu.Unlock()
  98. // TODO: Broadcast websockets
  99. }
  100. }
  101. type commandInput struct {
  102. Assign *assignInput `json:"assign,omitempty"`
  103. AddAlias *commands.AddAlias `json:"addAlias,omitempty"`
  104. RemoveAlias *commands.RemoveAlias `json:"removeAlias,omitempty"`
  105. PairDevice *commands.PairDevice `json:"pairDevice,omitempty"`
  106. ConnectDevice *commands.ConnectDevice `json:"connectDevice,omitempty"`
  107. SearchDevices *commands.SearchDevices `json:"searchDevices,omitempty"`
  108. ForgetDevice *commands.ForgetDevice `json:"forgetDevice,omitempty"`
  109. UpdateScript *script.UpdateScript `json:"updateScript,omitempty"`
  110. ExecuteScript *script.ExecuteScript `json:"executeScript,omitempty"`
  111. }
  112. type assignInput struct {
  113. Match string `json:"match"`
  114. Effect effects.Serializable `json:"effect"`
  115. }