// package store_client -- HTTP-клиент для выполнения запросов на сервер package store_client /* import ( "context" "encoding/json" "fmt" "io" "log" "net" "net/http" "os" "time" "git.p78su.freemyip.com/svi/gostore/internal/store_user" ) // IClient -- HTTP-клиент для выполнения запросов на сервер type IClient interface { // Get -- получить значени ключа Get(key string) ([]byte, error) // Put -- разместить ключ на сервере Put(key string, val []byte) error // Del -- удаляет запись по ключу Del(key string) // Find -- найти ключи по префиксу Find(prefixKey string) ([]string, error) // Time -- возвращает время сервера Time() (string, error) } // StoreClient -- HTTP-клиент для выполнения запросов на сервер type StoreClient struct { login string pass string url string urlParam string // Сумма логина и пароль client *http.Client } // NewStoreClient -- возвращает новый HTTP-клиент для выполнения запросов на сервер func NewStoreClient() (IClient, error) { user, err := store_user.NewStoreUser() if err != nil { return nil, fmt.Errorf("NewStoreClient(): in create IStoreUser, err=\n\t%w", err) } url := os.Getenv("STORE_URL") if url == "" { return nil, fmt.Errorf("NewStoreClient(): env STORE_URL not set") } sf := &StoreClient{ login: user.Login(), pass: user.Pass(), url: url, client: &http.Client{ Transport: &http.Transport{ Dial: (&net.Dialer{ Timeout: 3 * time.Second, KeepAlive: 6 * time.Second, }).Dial, IdleConnTimeout: 10 * time.Second, }, }, } sf.urlParam = "/" + sf.login + "/" + sf.pass + "/" if _, err := sf.Time(); err != nil { return nil, fmt.Errorf("NewStoreClient(): in check connect, err=\n\t%w", err) } go sf.ping() return sf, nil } type ListValRequest struct { Val_ []string `json:"val" form:"val"` } // Find -- поиск ключей по префиксу func (sf *StoreClient) Find(prefixKey string) ([]string, error) { ctx, fnCancel := context.WithTimeout(context.Background(), time.Second*6) defer fnCancel() req, err := http.NewRequestWithContext(ctx, http.MethodPost, sf.url+sf.urlParam+prefixKey, nil) if err != nil { return nil, fmt.Errorf("StoreClient.Find(): in create HTTP-request, err=\n\t%w", err) } req.Header.Set("Content-Type", "application/json") resp, err := sf.client.Do(req) if err != nil { return nil, fmt.Errorf("StoreClient.Find(): in exec HTTP-request, err=\n\t%w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("StoreClient.Find(): bad status HTTP-request, code=%v", resp.Status) } binBody, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("StoreClient.Find(): in read body HTTP-request, err\n\t%w", err) } _resp := &ListValRequest{ Val_: []string{}, } err = json.Unmarshal(binBody, _resp) if err != nil { return nil, fmt.Errorf("StoreClient.Find(): in unmarshal body HTTP-response, err\n\t%w", err) } return _resp.Val_, nil } // Del -- удаляет ключ с сервера func (sf *StoreClient) Del(key string) { ctx, fnCancel := context.WithTimeout(context.Background(), time.Second*6) defer fnCancel() req, err := http.NewRequestWithContext(ctx, http.MethodPost, sf.url+sf.urlParam+key, nil) if err != nil { log.Printf("StoreClient.Del(): in create HTTP-request, err=\n\t%w", err) return } req.Header.Set("Content-Type", "application/json") resp, err := sf.client.Do(req) if err != nil { log.Printf("StoreClient.Del(): in exec HTTP-request, err=\n\t%w", err) return } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { log.Printf("StoreClient.Del(): bad status HTTP-request, code=%v", resp.Status) return } } // Time -- проверяет время сервера func (sf *StoreClient) Time() (string, error) { ctx, fnCancel := context.WithTimeout(context.Background(), time.Second*6) defer fnCancel() req, err := http.NewRequestWithContext(ctx, http.MethodGet, sf.url+"/time", nil) if err != nil { fmt.Println(err) return "", fmt.Errorf("StoreClient.Time(): in create HTTP-request, err=\n\t%w", err) } resp, err := sf.client.Do(req) if err != nil { return "", fmt.Errorf("StoreClient.Time(): in exec HTTP-request, err=\n\t%w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return "", fmt.Errorf("StoreClient.Time(): bad status HTTP-request, code=%v", resp.Status) } binBody, err := io.ReadAll(resp.Body) if err != nil { return "", fmt.Errorf("StoreClient.Time(): in read body HTTP-request, err\n\t%w", err) } return string(binBody), nil } // Пингует в фоне сервер, чтобы не оборвался коннект func (sf *StoreClient) ping() { for { _, _ = sf.Time() time.Sleep(time.Second * 7) } } */