store_client.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. // package store_client -- HTTP-клиент для выполнения запросов на сервер
  2. package store_client
  3. /*
  4. import (
  5. "context"
  6. "encoding/json"
  7. "fmt"
  8. "io"
  9. "log"
  10. "net"
  11. "net/http"
  12. "os"
  13. "time"
  14. "git.p78su.freemyip.com/svi/gostore/internal/store_user"
  15. )
  16. // IClient -- HTTP-клиент для выполнения запросов на сервер
  17. type IClient interface {
  18. // Get -- получить значени ключа
  19. Get(key string) ([]byte, error)
  20. // Put -- разместить ключ на сервере
  21. Put(key string, val []byte) error
  22. // Del -- удаляет запись по ключу
  23. Del(key string)
  24. // Find -- найти ключи по префиксу
  25. Find(prefixKey string) ([]string, error)
  26. // Time -- возвращает время сервера
  27. Time() (string, error)
  28. }
  29. // StoreClient -- HTTP-клиент для выполнения запросов на сервер
  30. type StoreClient struct {
  31. login string
  32. pass string
  33. url string
  34. urlParam string // Сумма логина и пароль
  35. client *http.Client
  36. }
  37. // NewStoreClient -- возвращает новый HTTP-клиент для выполнения запросов на сервер
  38. func NewStoreClient() (IClient, error) {
  39. user, err := store_user.NewStoreUser()
  40. if err != nil {
  41. return nil, fmt.Errorf("NewStoreClient(): in create IStoreUser, err=\n\t%w", err)
  42. }
  43. url := os.Getenv("STORE_URL")
  44. if url == "" {
  45. return nil, fmt.Errorf("NewStoreClient(): env STORE_URL not set")
  46. }
  47. sf := &StoreClient{
  48. login: user.Login(),
  49. pass: user.Pass(),
  50. url: url,
  51. client: &http.Client{
  52. Transport: &http.Transport{
  53. Dial: (&net.Dialer{
  54. Timeout: 3 * time.Second,
  55. KeepAlive: 6 * time.Second,
  56. }).Dial,
  57. IdleConnTimeout: 10 * time.Second,
  58. },
  59. },
  60. }
  61. sf.urlParam = "/" + sf.login + "/" + sf.pass + "/"
  62. if _, err := sf.Time(); err != nil {
  63. return nil, fmt.Errorf("NewStoreClient(): in check connect, err=\n\t%w", err)
  64. }
  65. go sf.ping()
  66. return sf, nil
  67. }
  68. type ListValRequest struct {
  69. Val_ []string `json:"val" form:"val"`
  70. }
  71. // Find -- поиск ключей по префиксу
  72. func (sf *StoreClient) Find(prefixKey string) ([]string, error) {
  73. ctx, fnCancel := context.WithTimeout(context.Background(), time.Second*6)
  74. defer fnCancel()
  75. req, err := http.NewRequestWithContext(ctx, http.MethodPost, sf.url+sf.urlParam+prefixKey, nil)
  76. if err != nil {
  77. return nil, fmt.Errorf("StoreClient.Find(): in create HTTP-request, err=\n\t%w", err)
  78. }
  79. req.Header.Set("Content-Type", "application/json")
  80. resp, err := sf.client.Do(req)
  81. if err != nil {
  82. return nil, fmt.Errorf("StoreClient.Find(): in exec HTTP-request, err=\n\t%w", err)
  83. }
  84. defer resp.Body.Close()
  85. if resp.StatusCode != http.StatusOK {
  86. return nil, fmt.Errorf("StoreClient.Find(): bad status HTTP-request, code=%v", resp.Status)
  87. }
  88. binBody, err := io.ReadAll(resp.Body)
  89. if err != nil {
  90. return nil, fmt.Errorf("StoreClient.Find(): in read body HTTP-request, err\n\t%w", err)
  91. }
  92. _resp := &ListValRequest{
  93. Val_: []string{},
  94. }
  95. err = json.Unmarshal(binBody, _resp)
  96. if err != nil {
  97. return nil, fmt.Errorf("StoreClient.Find(): in unmarshal body HTTP-response, err\n\t%w", err)
  98. }
  99. return _resp.Val_, nil
  100. }
  101. // Del -- удаляет ключ с сервера
  102. func (sf *StoreClient) Del(key string) {
  103. ctx, fnCancel := context.WithTimeout(context.Background(), time.Second*6)
  104. defer fnCancel()
  105. req, err := http.NewRequestWithContext(ctx, http.MethodPost, sf.url+sf.urlParam+key, nil)
  106. if err != nil {
  107. log.Printf("StoreClient.Del(): in create HTTP-request, err=\n\t%w", err)
  108. return
  109. }
  110. req.Header.Set("Content-Type", "application/json")
  111. resp, err := sf.client.Do(req)
  112. if err != nil {
  113. log.Printf("StoreClient.Del(): in exec HTTP-request, err=\n\t%w", err)
  114. return
  115. }
  116. defer resp.Body.Close()
  117. if resp.StatusCode != http.StatusOK {
  118. log.Printf("StoreClient.Del(): bad status HTTP-request, code=%v", resp.Status)
  119. return
  120. }
  121. }
  122. // Time -- проверяет время сервера
  123. func (sf *StoreClient) Time() (string, error) {
  124. ctx, fnCancel := context.WithTimeout(context.Background(), time.Second*6)
  125. defer fnCancel()
  126. req, err := http.NewRequestWithContext(ctx, http.MethodGet, sf.url+"/time", nil)
  127. if err != nil {
  128. fmt.Println(err)
  129. return "", fmt.Errorf("StoreClient.Time(): in create HTTP-request, err=\n\t%w", err)
  130. }
  131. resp, err := sf.client.Do(req)
  132. if err != nil {
  133. return "", fmt.Errorf("StoreClient.Time(): in exec HTTP-request, err=\n\t%w", err)
  134. }
  135. defer resp.Body.Close()
  136. if resp.StatusCode != http.StatusOK {
  137. return "", fmt.Errorf("StoreClient.Time(): bad status HTTP-request, code=%v", resp.Status)
  138. }
  139. binBody, err := io.ReadAll(resp.Body)
  140. if err != nil {
  141. return "", fmt.Errorf("StoreClient.Time(): in read body HTTP-request, err\n\t%w", err)
  142. }
  143. return string(binBody), nil
  144. }
  145. // Пингует в фоне сервер, чтобы не оборвался коннект
  146. func (sf *StoreClient) ping() {
  147. for {
  148. _, _ = sf.Time()
  149. time.Sleep(time.Second * 7)
  150. }
  151. }
  152. */