package handler import ( "encoding/json" "fmt" "net/http" "github.com/go-playground/validator/v10" "github.com/iliadenisov/galaxy/internal/controller" "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" "github.com/iliadenisov/galaxy/internal/model/rest" ) func CommandHandler(c *gin.Context, executor CommandExecutor) { var cmd rest.Command if errorResponded(c, c.ShouldBindJSON(&cmd)) { return } commands := make([]Command, 0) for i := range cmd.Commands { command, err := parseCommand(cmd.Actor, cmd.Commands[i]) if errorResponded(c, err) { return } commands = append(commands, command) } if len(commands) == 0 { c.JSON(http.StatusBadRequest, gin.H{"error": "no commands given"}) return } if errorResponded(c, executor.Execute(commands...)) { return } c.Status(http.StatusNoContent) } func parseCommand(actor string, c json.RawMessage) (Command, error) { meta := new(rest.CommandMeta) if err := json.Unmarshal(c, meta); err != nil { return nil, err } switch t := meta.Type; t { case rest.CommandTypeRaceQuit: return commandRaceQuit(actor) case rest.CommandTypeRaceVote: return commandRaceVote(actor, c) case rest.CommandTypeRaceRelation: return commandRaceRelation(actor, c) case rest.CommandTypeShipClassCreate: return commandShipClassCreate(actor, c) default: return nil, fmt.Errorf("unknown comman type: %s", t) } } func commandRaceQuit(actor string) (Command, error) { return func(c controller.Ctrl) error { return c.RaceQuit(actor) }, nil } func commandRaceVote(actor string, c json.RawMessage) (Command, error) { var v rest.CommandRaceVote if err := json.Unmarshal(c, &v); err != nil { return nil, err } if err := validateCommand(v); err != nil { return nil, err } return func(c controller.Ctrl) error { return c.RaceVote(actor, v.Recipient) }, nil } func commandRaceRelation(actor string, c json.RawMessage) (Command, error) { var v rest.CommandRaceRelation if err := json.Unmarshal(c, &v); err != nil { return nil, err } if err := validateCommand(v); err != nil { return nil, err } return func(c controller.Ctrl) error { return c.RaceRelation(actor, v.Opponent, v.Relation) }, nil } func commandShipClassCreate(actor string, c json.RawMessage) (Command, error) { v := new(rest.CommandShipClassCreate) if err := json.Unmarshal(c, v); err != nil { return nil, err } if err := validateCommand(v); err != nil { return nil, err } return func(c controller.Ctrl) error { return c.ShipClassCreate(actor, v.Name, v.Drive, int(v.Armament), v.Weapons, v.Shields, v.Cargo) }, nil } func validateCommand(v any) error { if ve, ok := binding.Validator.Engine().(*validator.Validate); ok { if err := ve.Struct(v); err != nil { return err } } return nil }