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:
@@ -306,7 +306,11 @@ func main() {
|
|||||||
registrationTokenHandler := handlers.NewRegistrationTokenHandler(registrationTokenQueries, agentQueries, cfg)
|
registrationTokenHandler := handlers.NewRegistrationTokenHandler(registrationTokenQueries, agentQueries, cfg)
|
||||||
rateLimitHandler := handlers.NewRateLimitHandler(rateLimiter)
|
rateLimitHandler := handlers.NewRateLimitHandler(rateLimiter)
|
||||||
downloadHandler := handlers.NewDownloadHandler(filepath.Join("/app"), cfg, packageQueries)
|
downloadHandler := handlers.NewDownloadHandler(filepath.Join("/app"), cfg, packageQueries)
|
||||||
subsystemHandler := handlers.NewSubsystemHandler(subsystemQueries, commandQueries, signingService, securityLogger)
|
|
||||||
|
// Create command factory for consistent command creation
|
||||||
|
commandFactory := command.NewFactory(commandQueries)
|
||||||
|
subsystemHandler := handlers.NewSubsystemHandler(subsystemQueries, commandQueries, commandFactory, signingService, securityLogger)
|
||||||
|
|
||||||
metricsHandler := handlers.NewMetricsHandler(metricsQueries, agentQueries, commandQueries)
|
metricsHandler := handlers.NewMetricsHandler(metricsQueries, agentQueries, commandQueries)
|
||||||
dockerReportsHandler := handlers.NewDockerReportsHandler(dockerQueries, agentQueries, commandQueries)
|
dockerReportsHandler := handlers.NewDockerReportsHandler(dockerQueries, agentQueries, commandQueries)
|
||||||
storageMetricsHandler := handlers.NewStorageMetricsHandler(storageMetricsQueries)
|
storageMetricsHandler := handlers.NewStorageMetricsHandler(storageMetricsQueries)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"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/database/queries"
|
||||||
"github.com/Fimeg/RedFlag/aggregator-server/internal/models"
|
"github.com/Fimeg/RedFlag/aggregator-server/internal/models"
|
||||||
"github.com/Fimeg/RedFlag/aggregator-server/internal/services"
|
"github.com/Fimeg/RedFlag/aggregator-server/internal/services"
|
||||||
@@ -17,14 +18,16 @@ import (
|
|||||||
type SubsystemHandler struct {
|
type SubsystemHandler struct {
|
||||||
subsystemQueries *queries.SubsystemQueries
|
subsystemQueries *queries.SubsystemQueries
|
||||||
commandQueries *queries.CommandQueries
|
commandQueries *queries.CommandQueries
|
||||||
|
commandFactory *command.Factory
|
||||||
signingService *services.SigningService
|
signingService *services.SigningService
|
||||||
securityLogger *logging.SecurityLogger
|
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{
|
return &SubsystemHandler{
|
||||||
subsystemQueries: sq,
|
subsystemQueries: sq,
|
||||||
commandQueries: cq,
|
commandQueries: cq,
|
||||||
|
commandFactory: cf,
|
||||||
signingService: signingService,
|
signingService: signingService,
|
||||||
securityLogger: securityLogger,
|
securityLogger: securityLogger,
|
||||||
}
|
}
|
||||||
@@ -249,14 +252,9 @@ func (h *SubsystemHandler) TriggerSubsystem(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create command for the subsystem
|
// Create command for the subsystem using factory with idempotency
|
||||||
commandType := "scan_" + subsystem
|
commandType := "scan_" + subsystem
|
||||||
command := &models.AgentCommand{
|
idempotencyKey := fmt.Sprintf("%s_%s_%d", agentID.String(), subsystem, time.Now().Unix())
|
||||||
AgentID: agentID,
|
|
||||||
CommandType: commandType,
|
|
||||||
Status: "pending",
|
|
||||||
Source: "manual", // Manual trigger from UI (must be 'manual' or 'system' per DB constraint)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log command creation attempt
|
// Log command creation attempt
|
||||||
log.Printf("[INFO] [server] [command] creating_scan_command agent_id=%s subsystem=%s command_type=%s timestamp=%s",
|
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",
|
log.Printf("[HISTORY] [server] [scan_%s] command_creation_started agent_id=%s timestamp=%s",
|
||||||
subsystem, agentID, time.Now().Format(time.RFC3339))
|
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)
|
err = h.signAndCreateCommand(command)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[ERROR] [server] [scan_%s] command_creation_failed agent_id=%s error=%v", subsystem, agentID, err)
|
log.Printf("[ERROR] [server] [scan_%s] command_creation_failed agent_id=%s error=%v", subsystem, agentID, err)
|
||||||
|
|||||||
Reference in New Issue
Block a user