server/internal/handlers/webhook_delivery.go
Rama main · réplica de lectura del repositorio original.
package handlers
import (
"encoding/json"
"log"
"net/http"
"sync/atomic"
"time"
"blackbox/server/internal/models"
"github.com/oklog/ulid/v2"
"gorm.io/gorm"
)
const webhookDeliveryRetention = 1_000
var webhookPruneInFlight atomic.Bool
func pruneWebhookDeliveries(db *gorm.DB) {
if !webhookPruneInFlight.CompareAndSwap(false, true) {
return
}
go func() {
defer webhookPruneInFlight.Store(false)
if err := db.Exec(
"DELETE FROM webhook_deliveries WHERE id NOT IN (SELECT id FROM webhook_deliveries ORDER BY received_at DESC LIMIT ?)",
webhookDeliveryRetention,
).Error; err != nil {
log.Printf("RecordWebhookDelivery prune failed: %v", err)
}
}()
}
func RecordWebhookDelivery(
db *gorm.DB,
source, payloadSnippet, matchedIncidentID, status, errorMessage string,
) {
row := models.WebhookDelivery{
ID: ulid.Make().String(),
Source: source,
ReceivedAt: time.Now().UTC(),
PayloadSnippet: payloadSnippet,
Status: status,
ErrorMessage: errorMessage,
}
if matchedIncidentID != "" {
row.MatchedIncidentID = &matchedIncidentID
}
if err := db.Create(&row).Error; err != nil {
log.Printf("RecordWebhookDelivery insert failed: %v", err)
return
}
pruneWebhookDeliveries(db)
}
func ListWebhookDeliveries(db *gorm.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if !requireAdminRequest(w, r) {
return
}
page, perPage, ok := parsePaginationParams(w, r)
if !ok {
return
}
q := db.Model(&models.WebhookDelivery{})
if source := r.URL.Query().Get("source"); source != "" {
q = q.Where("source = ?", source)
}
if status := r.URL.Query().Get("status"); status != "" {
q = q.Where("status = ?", status)
}
var total int64
if err := q.Count(&total).Error; err != nil {
writeError(w, http.StatusInternalServerError, "failed to count webhook deliveries")
return
}
var rows []models.WebhookDelivery
offset := (page - 1) * perPage
if err := q.Order("received_at DESC").Offset(offset).Limit(perPage).Find(&rows).Error; err != nil {
writeError(w, http.StatusInternalServerError, "failed to list webhook deliveries")
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(map[string]interface{}{
"total": total,
"page": page,
"per_page": perPage,
"items": rows,
}); err != nil {
log.Printf("ListWebhookDeliveries encode: %v", err)
}
}
}
func payloadSnippet(body []byte) string {
const max = 2000
runes := []rune(string(body))
if len(runes) <= max {
return string(runes)
}
return string(runes[:max])
}