package veli import ( "bytes" "context" "crypto/hmac" "crypto/sha512" "encoding/base64" "encoding/json" "fmt" "io" "net/http" "sort" "strings" "time" "github.com/SamuelTariku/FortuneBet-Backend/internal/config" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet" ) type Client struct { http *http.Client BaseURL string OperatorID string SecretKey string BrandID string walletSvc *wallet.Service } func NewClient(cfg *config.Config, walletSvc *wallet.Service) *Client { return &Client{ http: &http.Client{Timeout: 10 * time.Second}, BaseURL: cfg.VeliGames.BaseURL, OperatorID: cfg.VeliGames.OperatorID, SecretKey: cfg.VeliGames.SecretKey, BrandID: cfg.VeliGames.BrandID, walletSvc: walletSvc, } } // Signature generator func (c *Client) generateSignature(params map[string]string) (string, error) { keys := make([]string, 0, len(params)) for k := range params { keys = append(keys, k) } sort.Strings(keys) var b strings.Builder for i, k := range keys { if i > 0 { b.WriteString(";") } b.WriteString(fmt.Sprintf("%s:%s", k, params[k])) } h := hmac.New(sha512.New, []byte(c.SecretKey)) h.Write([]byte(b.String())) return fmt.Sprintf("%s:%s", c.OperatorID, base64.StdEncoding.EncodeToString(h.Sum(nil))), nil } // POST helper func (c *Client) post(ctx context.Context, path string, body any, sigParams map[string]string, result any) error { data, _ := json.Marshal(body) sig, err := c.generateSignature(sigParams) if err != nil { return err } req, _ := http.NewRequestWithContext(ctx, "POST", c.BaseURL+path, bytes.NewReader(data)) req.Header.Set("Content-Type", "application/json") req.Header.Set("signature", sig) res, err := c.http.Do(req) if err != nil { return err } defer res.Body.Close() b, _ := io.ReadAll(res.Body) if res.StatusCode >= 400 { return fmt.Errorf("error: %s", b) } if result != nil { return json.Unmarshal(b, result) } return nil }