package handler import ( "errors" "net/http" "os" "galaxy/model/order" "galaxy/model/rest" e "galaxy/error" "galaxy/game/internal/controller" "galaxy/game/internal/model/game" "github.com/gin-gonic/gin" "github.com/go-playground/validator/v10" ) type CommandExecutor interface { GenerateGame([]string) (rest.StateResponse, error) GenerateTurn() (rest.StateResponse, error) GameState() (rest.StateResponse, error) Execute(cmd ...Command) error ValidateOrder(actor string, cmd ...order.DecodableCommand) error } type Command func(controller.Ctrl) error type executor struct { cfg controller.Configurer } func initConfig() controller.Configurer { return func(p *controller.Param) { p.StoragePath = os.Getenv("STORAGE_PATH") } } func NewDefaultExecutor() CommandExecutor { return NewDefaultConfigExecutor(initConfig()) } func NewDefaultConfigExecutor(configurer controller.Configurer) CommandExecutor { return &executor{cfg: configurer} } func (e *executor) Execute(cmd ...Command) error { return controller.ExecuteCommand(e.cfg, func(c controller.Ctrl) error { for i := range cmd { if err := cmd[i](c); err != nil { return err } } return nil }) } func (e *executor) ValidateOrder(actor string, cmd ...order.DecodableCommand) error { return controller.ValidateOrder(e.cfg, actor, cmd...) } func (e *executor) GenerateGame(races []string) (rest.StateResponse, error) { s, err := controller.GenerateGame(e.cfg, races) if err != nil { return rest.StateResponse{}, err } return stateResponse(s), nil } func (e *executor) GenerateTurn() (rest.StateResponse, error) { err := controller.GenerateTurn(e.cfg) if err != nil { return rest.StateResponse{}, err } return e.GameState() } func (e *executor) GameState() (rest.StateResponse, error) { s, err := controller.GameState(e.cfg) if err != nil { return rest.StateResponse{}, err } return stateResponse(s), nil } func stateResponse(s game.State) rest.StateResponse { result := &rest.StateResponse{ ID: s.ID, Turn: s.Turn, Stage: s.Stage, Players: make([]rest.PlayerState, len(s.Players)), } for i := range s.Players { result.Players[i].ID = s.Players[i].ID result.Players[i].Name = s.Players[i].Name result.Players[i].Extinct = s.Players[i].Extinct } return *result } func errorResponse(c *gin.Context, err error) bool { if err == nil { return false } if v, ok := err.(validator.ValidationErrors); ok { c.JSON(http.StatusBadRequest, gin.H{"error": v.Error()}) return true } if ge, ok := errors.AsType[*e.GenericError](err); ok { switch ge.Code { case e.ErrGameNotInitialized: c.Status(http.StatusNotImplemented) default: c.JSON(http.StatusInternalServerError, gin.H{"generic_error": ge.Error(), "code": ge.Code}) } } else { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) } return true }