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.

161 lines
3.7 KiB

  1. package client
  2. import (
  3. "bytes"
  4. "context"
  5. "encoding/json"
  6. "fmt"
  7. "git.aiterp.net/lucifer/new-server/models"
  8. "io"
  9. "net"
  10. "net/http"
  11. "strings"
  12. "time"
  13. )
  14. type Client struct {
  15. APIRoot string
  16. }
  17. func (client *Client) GetDevices(ctx context.Context, fetchStr string) ([]models.Device, error) {
  18. devices := make([]models.Device, 0, 16)
  19. err := client.Fetch(ctx, "GET", "/api/devices/"+fetchStr, &devices, nil)
  20. if err != nil {
  21. return nil, err
  22. }
  23. return devices, nil
  24. }
  25. func (client *Client) PutDevice(ctx context.Context, fetchStr string, update models.DeviceUpdate) ([]models.Device, error) {
  26. devices := make([]models.Device, 0, 16)
  27. err := client.Fetch(ctx, "PUT", "/api/devices/"+fetchStr, &devices, update)
  28. if err != nil {
  29. return nil, err
  30. }
  31. return devices, nil
  32. }
  33. func (client *Client) PutDeviceState(ctx context.Context, fetchStr string, update models.NewDeviceState) ([]models.Device, error) {
  34. devices := make([]models.Device, 0, 16)
  35. err := client.Fetch(ctx, "PUT", "/api/devices/"+fetchStr+"/state", &devices, update)
  36. if err != nil {
  37. return nil, err
  38. }
  39. return devices, nil
  40. }
  41. func (client *Client) PutDeviceTags(ctx context.Context, fetchStr string, addTags []string, removeTags []string) ([]models.Device, error) {
  42. devices := make([]models.Device, 0, 16)
  43. err := client.Fetch(ctx, "PUT", "/api/devices/"+fetchStr+"/tags", &devices, map[string][]string{
  44. "add": addTags,
  45. "remove": removeTags,
  46. })
  47. if err != nil {
  48. return nil, err
  49. }
  50. return devices, nil
  51. }
  52. func (client *Client) AssignDevice(ctx context.Context, fetchStr string, push bool, assignment models.DeviceSceneAssignment) ([]models.Device, error) {
  53. query := ""
  54. if push {
  55. query = "?push=true"
  56. }
  57. devices := make([]models.Device, 0, 16)
  58. err := client.Fetch(ctx, "PUT", "/api/devices/"+fetchStr+"/scene"+query, &devices, assignment)
  59. if err != nil {
  60. return nil, err
  61. }
  62. return devices, nil
  63. }
  64. func (client *Client) ClearDevice(ctx context.Context, fetchStr string) ([]models.Device, error) {
  65. devices := make([]models.Device, 0, 16)
  66. err := client.Fetch(ctx, "DELETE", "/api/devices/"+fetchStr+"/scene", &devices, nil)
  67. if err != nil {
  68. return nil, err
  69. }
  70. return devices, nil
  71. }
  72. func (client *Client) FireEvent(ctx context.Context, event models.Event) error {
  73. err := client.Fetch(ctx, "POST", "/api/events", nil, event)
  74. if err != nil {
  75. return err
  76. }
  77. return nil
  78. }
  79. func (client *Client) Fetch(ctx context.Context, method string, path string, dst interface{}, body interface{}) error {
  80. var reqBody io.ReadWriter
  81. if body != nil && method != "GET" {
  82. reqBody = bytes.NewBuffer(make([]byte, 0, 512))
  83. err := json.NewEncoder(reqBody).Encode(body)
  84. if err != nil {
  85. return err
  86. }
  87. }
  88. req, err := http.NewRequest(method, client.APIRoot+path, reqBody)
  89. if err != nil {
  90. return err
  91. }
  92. res, err := httpClient.Do(req.WithContext(ctx))
  93. if err != nil {
  94. return err
  95. }
  96. defer res.Body.Close()
  97. if !strings.HasPrefix(res.Header.Get("Content-Type"), "application/json") {
  98. return fmt.Errorf("%s: %s", path, res.Status)
  99. }
  100. var resJson struct {
  101. Code int `json:"code"`
  102. Message *string `json:"message"`
  103. Data json.RawMessage `json:"data"`
  104. }
  105. err = json.NewDecoder(res.Body).Decode(&resJson)
  106. if err != nil {
  107. return err
  108. }
  109. if resJson.Code != 200 {
  110. msg := ""
  111. if resJson.Message != nil {
  112. msg = *resJson.Message
  113. }
  114. return fmt.Errorf("%d: %s", resJson.Code, msg)
  115. }
  116. if dst == nil {
  117. return nil
  118. }
  119. return json.Unmarshal(resJson.Data, dst)
  120. }
  121. var httpClient = &http.Client{
  122. Transport: &http.Transport{
  123. Proxy: http.ProxyFromEnvironment,
  124. DialContext: (&net.Dialer{
  125. Timeout: 30 * time.Second,
  126. KeepAlive: 30 * time.Second,
  127. }).DialContext,
  128. MaxIdleConns: 16,
  129. MaxIdleConnsPerHost: 16,
  130. IdleConnTimeout: time.Minute,
  131. },
  132. Timeout: time.Minute,
  133. }