package hook import ( "bytes" "crypto/hmac" "crypto/sha256" "encoding/hex" "encoding/json" "fmt" "net/http" "time" ) type HookClient struct { BaseURL string Domain string SecretKey string HTTPClient *http.Client } type HookPayload struct { Email string `json:"email"` Domain string `json:"domain"` Action string `json:"action"` Timestamp time.Time `json:"timestamp"` } func NewHookClient(baseURL, domain, secretKey string) *HookClient { return &HookClient{ BaseURL: baseURL, Domain: domain, SecretKey: secretKey, HTTPClient: &http.Client{ Timeout: 10 * time.Second, }, } } func (c *HookClient) SendWebhook(email, action string) error { payload := HookPayload{ Email: email, Domain: c.Domain, Action: action, Timestamp: time.Now(), } payloadBytes, err := json.Marshal(payload) if err != nil { return fmt.Errorf("erreur de marshalling: %w", err) } // Calcul de la signature signature := c.calculateHMAC(payloadBytes) // Création de la requête req, err := http.NewRequest( "POST", fmt.Sprintf("%s/webhook/user-sync", c.BaseURL), bytes.NewBuffer(payloadBytes), ) if err != nil { return fmt.Errorf("erreur de création de requête: %w", err) } // Ajout des headers req.Header.Set("Content-Type", "application/json") req.Header.Set("X-Webhook-Signature", signature) req.Header.Set("X-Webhook-Domain", c.Domain) // Envoi de la requête avec retry var lastErr error for retry := 0; retry < 3; retry++ { resp, err := c.HTTPClient.Do(req) if err != nil { lastErr = err time.Sleep(time.Duration(retry+1) * time.Second) continue } defer resp.Body.Close() if resp.StatusCode == http.StatusOK { return nil } if resp.StatusCode == http.StatusTooManyRequests { // Attendre avant de réessayer time.Sleep(time.Duration(retry+1) * time.Second) continue } // Erreur définitive if resp.StatusCode >= 400 && resp.StatusCode != http.StatusTooManyRequests { return fmt.Errorf("erreur HTTP %d", resp.StatusCode) } } return fmt.Errorf("échec après 3 tentatives: %w", lastErr) } func (c *HookClient) calculateHMAC(message []byte) string { mac := hmac.New(sha256.New, []byte(c.SecretKey)) mac.Write(message) return hex.EncodeToString(mac.Sum(nil)) } func (c *HookClient) Close() error { if c.HTTPClient != nil { // Close idle connections if transport, ok := c.HTTPClient.Transport.(*http.Transport); ok { transport.CloseIdleConnections() } // Clear the client c.HTTPClient = nil } return nil }