package binance import ( "context" "encoding/json" "fmt" "net/http" "net/url" "time" "cryptoHermes/pkg/httpclient" ) const sourceName = "binance" type Client struct { http *httpclient.Client source string } type ClientOptions struct { BaseURL string Timeout time.Duration RetryCount int RPS float64 Burst int } func NewClient(opts ClientOptions) *Client { return &Client{ http: httpclient.New(httpclient.Options{ BaseURL: opts.BaseURL, Timeout: opts.Timeout, RetryCount: opts.RetryCount, RPS: opts.RPS, Burst: opts.Burst, }), source: sourceName, } } type ExternalAPIError struct { Source string Path string StatusCode int Message string } func (e *ExternalAPIError) Error() string { return fmt.Sprintf("%s %s status=%d: %s", e.Source, e.Path, e.StatusCode, e.Message) } func (c *Client) get(ctx context.Context, path string, q url.Values, out any) error { status, body, _, err := c.http.Do(ctx, httpclient.Request{ Method: http.MethodGet, Path: path, Query: q, }) if err != nil { return &ExternalAPIError{Source: c.source, Path: path, StatusCode: 0, Message: err.Error()} } if status >= 400 { return &ExternalAPIError{Source: c.source, Path: path, StatusCode: status, Message: string(body)} } if out == nil { return nil } if err := json.Unmarshal(body, out); err != nil { return &ExternalAPIError{Source: c.source, Path: path, StatusCode: status, Message: "decode: " + err.Error()} } return nil }