101 lines
2.2 KiB
Go
101 lines
2.2 KiB
Go
package external_api
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/tls"
|
|
"encoding/json"
|
|
"errors"
|
|
"github.com/tuusuario/go-sync-service/internal/domain/dto"
|
|
"io"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
// Estructura para guardar trazabilidad
|
|
|
|
// Client genérico con reintentos
|
|
type GenericClient struct {
|
|
Client *http.Client
|
|
MaxRetries int
|
|
RetryDelay time.Duration
|
|
EnableTrace bool // true = guarda trazabilidad
|
|
}
|
|
|
|
// Constructor
|
|
func NewGenericClient(maxRetries int, retryDelay time.Duration) *GenericClient {
|
|
return &GenericClient{
|
|
Client: &http.Client{Timeout: 30 * time.Second, Transport: &http.Transport{
|
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
|
}},
|
|
MaxRetries: maxRetries,
|
|
RetryDelay: retryDelay,
|
|
}
|
|
}
|
|
|
|
// Método genérico
|
|
func (gc *GenericClient) DoRequest(method, url string, headers map[string]string, body []byte) (map[string]interface{}, *dto.RequestTrace, error) {
|
|
trace := &dto.RequestTrace{
|
|
Method: method,
|
|
URL: url,
|
|
Headers: headers,
|
|
RequestBody: string(body),
|
|
StartedAt: time.Now(),
|
|
}
|
|
|
|
var lastErr error
|
|
var resp *http.Response
|
|
|
|
for attempt := 0; attempt <= gc.MaxRetries; attempt++ {
|
|
trace.Retries = attempt
|
|
|
|
req, err := http.NewRequest(method, url, bytes.NewReader(body))
|
|
if err != nil {
|
|
lastErr = err
|
|
break
|
|
}
|
|
|
|
// Headers
|
|
for k, v := range headers {
|
|
req.Header.Set(k, v)
|
|
}
|
|
|
|
start := time.Now()
|
|
resp, err = gc.Client.Do(req)
|
|
trace.Duration = time.Since(start)
|
|
|
|
if err == nil && resp.StatusCode < 500 {
|
|
break // éxito o error de cliente, no reintentar
|
|
}
|
|
|
|
lastErr = err
|
|
time.Sleep(gc.RetryDelay * (1 << attempt)) // backoff exponencial
|
|
}
|
|
|
|
if lastErr != nil {
|
|
trace.EndedAt = time.Now()
|
|
return nil, trace, lastErr
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
trace.StatusCode = resp.StatusCode
|
|
bodyResp, _ := io.ReadAll(resp.Body)
|
|
trace.Response = string(bodyResp)
|
|
trace.EndedAt = time.Now()
|
|
|
|
if resp.StatusCode >= 400 {
|
|
return nil, trace, errors.New("HTTP error: " + resp.Status)
|
|
}
|
|
|
|
// Si el código de estado es 204 (No Content), no hay cuerpo de respuesta
|
|
if resp.StatusCode == http.StatusNoContent {
|
|
return nil, trace, nil
|
|
}
|
|
|
|
var result map[string]interface{}
|
|
if err := json.Unmarshal(bodyResp, &result); err != nil {
|
|
return nil, trace, err
|
|
}
|
|
|
|
return result, trace, nil
|
|
}
|