feat: Integrate factory with SubsystemHandler for idempotency support\n\n- Add commandFactory field to SubsystemHandler\n- Update NewSubsystemHandler to accept factory\n- Modify TriggerSubsystem to use CreateWithIdempotency\n- Update main.go to pass factory to handler\n\nNow all subsystem commands use idempotency keys, preventing duplicates from rapid clicks.

This commit is contained in:
Fimeg
2025-12-20 16:15:53 -05:00
parent 6e6ad053d4
commit d226536c76
2 changed files with 28 additions and 9 deletions

View File

@@ -6,6 +6,7 @@ import (
"net/http"
"time"
"github.com/Fimeg/RedFlag/aggregator-server/internal/command"
"github.com/Fimeg/RedFlag/aggregator-server/internal/database/queries"
"github.com/Fimeg/RedFlag/aggregator-server/internal/models"
"github.com/Fimeg/RedFlag/aggregator-server/internal/services"
@@ -17,14 +18,16 @@ import (
type SubsystemHandler struct {
subsystemQueries *queries.SubsystemQueries
commandQueries *queries.CommandQueries
commandFactory *command.Factory
signingService *services.SigningService
securityLogger *logging.SecurityLogger
}
func NewSubsystemHandler(sq *queries.SubsystemQueries, cq *queries.CommandQueries, signingService *services.SigningService, securityLogger *logging.SecurityLogger) *SubsystemHandler {
func NewSubsystemHandler(sq *queries.SubsystemQueries, cq *queries.CommandQueries, cf *command.Factory, signingService *services.SigningService, securityLogger *logging.SecurityLogger) *SubsystemHandler {
return &SubsystemHandler{
subsystemQueries: sq,
commandQueries: cq,
commandFactory: cf,
signingService: signingService,
securityLogger: securityLogger,
}
@@ -249,14 +252,9 @@ func (h *SubsystemHandler) TriggerSubsystem(c *gin.Context) {
return
}
// Create command for the subsystem
// Create command for the subsystem using factory with idempotency
commandType := "scan_" + subsystem
command := &models.AgentCommand{
AgentID: agentID,
CommandType: commandType,
Status: "pending",
Source: "manual", // Manual trigger from UI (must be 'manual' or 'system' per DB constraint)
}
idempotencyKey := fmt.Sprintf("%s_%s_%d", agentID.String(), subsystem, time.Now().Unix())
// Log command creation attempt
log.Printf("[INFO] [server] [command] creating_scan_command agent_id=%s subsystem=%s command_type=%s timestamp=%s",
@@ -264,6 +262,23 @@ func (h *SubsystemHandler) TriggerSubsystem(c *gin.Context) {
log.Printf("[HISTORY] [server] [scan_%s] command_creation_started agent_id=%s timestamp=%s",
subsystem, agentID, time.Now().Format(time.RFC3339))
command, err := h.commandFactory.CreateWithIdempotency(
agentID,
commandType,
map[string]interface{}{"subsystem": subsystem},
idempotencyKey,
)
if err != nil {
log.Printf("[ERROR] [server] [scan_%s] command_creation_failed agent_id=%s error=%v", subsystem, agentID, err)
log.Printf("[HISTORY] [server] [scan_%s] command_creation_failed error=\"%v\" timestamp=%s",
subsystem, err, time.Now().Format(time.RFC3339))
c.JSON(http.StatusInternalServerError, gin.H{
"error": fmt.Sprintf("Failed to create %s scan command: %v", subsystem, err),
})
return
}
err = h.signAndCreateCommand(command)
if err != nil {
log.Printf("[ERROR] [server] [scan_%s] command_creation_failed agent_id=%s error=%v", subsystem, agentID, err)