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.

146 lines
3.4 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, assignment models.DeviceSceneAssignment) ([]models.Device, error) {
  53. devices := make([]models.Device, 0, 16)
  54. err := client.Fetch(ctx, "PUT", "/api/devices/"+fetchStr+"/scene", &devices, assignment)
  55. if err != nil {
  56. return nil, err
  57. }
  58. return devices, nil
  59. }
  60. func (client *Client) FireEvent(ctx context.Context, event models.Event) error {
  61. err := client.Fetch(ctx, "POST", "/api/events", nil, event)
  62. if err != nil {
  63. return err
  64. }
  65. return nil
  66. }
  67. func (client *Client) Fetch(ctx context.Context, method string, path string, dst interface{}, body interface{}) error {
  68. var reqBody io.ReadWriter
  69. if body != nil && method != "GET" {
  70. reqBody = bytes.NewBuffer(make([]byte, 0, 512))
  71. err := json.NewEncoder(reqBody).Encode(body)
  72. if err != nil {
  73. return err
  74. }
  75. }
  76. req, err := http.NewRequest(method, client.APIRoot+path, reqBody)
  77. if err != nil {
  78. return err
  79. }
  80. res, err := httpClient.Do(req.WithContext(ctx))
  81. if err != nil {
  82. return err
  83. }
  84. defer res.Body.Close()
  85. if !strings.HasPrefix(res.Header.Get("Content-Type"), "application/json") {
  86. return fmt.Errorf("%s: %s", path, res.Status)
  87. }
  88. var resJson struct {
  89. Code int `json:"code"`
  90. Message *string `json:"message"`
  91. Data json.RawMessage `json:"data"`
  92. }
  93. err = json.NewDecoder(res.Body).Decode(&resJson)
  94. if err != nil {
  95. return err
  96. }
  97. if resJson.Code != 200 {
  98. msg := ""
  99. if resJson.Message != nil {
  100. msg = *resJson.Message
  101. }
  102. return fmt.Errorf("%d: %s", resJson.Code, msg)
  103. }
  104. if dst == nil {
  105. return nil
  106. }
  107. return json.Unmarshal(resJson.Data, dst)
  108. }
  109. var httpClient = &http.Client{
  110. Transport: &http.Transport{
  111. Proxy: http.ProxyFromEnvironment,
  112. DialContext: (&net.Dialer{
  113. Timeout: 30 * time.Second,
  114. KeepAlive: 30 * time.Second,
  115. }).DialContext,
  116. MaxIdleConns: 16,
  117. MaxIdleConnsPerHost: 16,
  118. IdleConnTimeout: time.Minute,
  119. },
  120. Timeout: time.Minute,
  121. }