server/internal/handlers/docker_restart.go
Rama main · réplica de lectura del repositorio original.
package handlers
import (
"errors"
"blackbox/server/internal/hub"
"blackbox/shared/types"
"gorm.io/gorm"
)
// replaceDockerRestartResult is returned by replaceDockerRestartEntry.
type replaceDockerRestartResult struct {
Updated types.Entry
Found bool
Err error
}
// replaceDockerRestartEntry looks up the stop entry that a docker restart
// supersedes, applies the restart entry's fields to it, re-fetches the updated
// row, and broadcasts the replacement over the WebSocket hub.
//
// The lookup is scoped to nodeName and source="docker" so a client-supplied
// ReplaceID cannot reference entries belonging to other nodes or sources.
//
// Return semantics:
// - Found=false, Err=nil → no matching stop found; caller should insert as new
// - Found=true, Err=nil → update applied; Updated holds the refreshed row
// - Found=false, Err!=nil → a DB error occurred; caller should surface it
func replaceDockerRestartEntry(
database *gorm.DB,
entry types.Entry,
nodeName string,
h *hub.Hub,
incidentCh chan<- types.Entry,
shutdown <-chan struct{},
) replaceDockerRestartResult {
lookupID := entry.ID
if entry.ReplaceID != "" {
lookupID = entry.ReplaceID
}
var existing types.Entry
lookupErr := database.First(&existing, "id = ? AND node_name = ? AND source = ? AND event IN ?", lookupID, nodeName, "docker", []string{"stop", "restart"}).Error
if lookupErr != nil {
if errors.Is(lookupErr, gorm.ErrRecordNotFound) {
return replaceDockerRestartResult{Found: false}
}
return replaceDockerRestartResult{Err: lookupErr}
}
updates := map[string]interface{}{
"event": entry.Event,
"content": entry.Content,
"metadata": entry.Metadata,
"timestamp": entry.Timestamp,
"compose_service": entry.ComposeService,
}
if err := database.Model(&existing).Updates(updates).Error; err != nil {
return replaceDockerRestartResult{Err: err}
}
// Refresh to pick up server-side defaults written during the update.
if err := database.Take(&existing, "id = ? AND node_name = ? AND source = ?", lookupID, nodeName, "docker").Error; err != nil {
return replaceDockerRestartResult{Err: err}
}
if h != nil {
type replacedPayload struct {
OldID string `json:"old_id"`
Entry types.Entry `json:"entry"`
}
if msg := MarshalWSMessage("entry_replaced", replacedPayload{OldID: existing.ID, Entry: existing}); msg != nil {
h.Broadcast(msg)
}
}
dispatchToIncidentChannelWithShutdown(incidentCh, shutdown, existing)
return replaceDockerRestartResult{Updated: existing, Found: true}
}