diff --git a/backend/internal/server/handlers_user_games.go b/backend/internal/server/handlers_user_games.go index d9ec2ca..56df37e 100644 --- a/backend/internal/server/handlers_user_games.go +++ b/backend/internal/server/handlers_user_games.go @@ -14,7 +14,6 @@ import ( "galaxy/backend/internal/server/httperr" "galaxy/backend/internal/server/middleware/userid" "galaxy/backend/internal/telemetry" - "galaxy/model/order" gamerest "galaxy/model/rest" "github.com/gin-gonic/gin" @@ -26,8 +25,8 @@ import ( // `engineclient` against running engine containers. type UserGamesHandlers struct { runtime *runtime.Service - engine *engineclient.Client - logger *zap.Logger + engine *engineclient.Client + logger *zap.Logger } // NewUserGamesHandlers constructs the handler set. When runtime or @@ -123,7 +122,6 @@ func (h *UserGamesHandlers) Orders() gin.HandlerFunc { // handler. Per ARCHITECTURE.md ยง9 backend is the only caller // of the engine, so the body never carries a client-supplied // actor. - _ = order.Order{} payload, err := rebindActor(body, mapping.RaceName) if err != nil { httperr.Abort(c, http.StatusBadRequest, httperr.CodeInvalidRequest, "request body must be a JSON object") diff --git a/game/internal/controller/controller.go b/game/internal/controller/controller.go index 1b14546..3bd57d9 100644 --- a/game/internal/controller/controller.go +++ b/game/internal/controller/controller.go @@ -2,6 +2,7 @@ package controller import ( "errors" + "time" "galaxy/game/internal/model/game" @@ -47,10 +48,10 @@ type Repo interface { LoadReport(uint, uuid.UUID) (*report.Report, error) // SaveOrder stores order for given turn - SaveOrder(uint, uuid.UUID, *order.Order) error + SaveOrder(uint, uuid.UUID, *order.UserGamesOrder) error // LoadOrder loads order for specific turn and player id - LoadOrder(uint, uuid.UUID) (*order.Order, bool, error) + LoadOrder(uint, uuid.UUID) (*order.UserGamesOrder, bool, error) } type Ctrl interface { @@ -126,14 +127,22 @@ func ExecuteCommand(configure func(*Param), consumer func(c Ctrl) error) (err er return ec.executeCommand(func(c *Controller) error { return consumer(c) }) } -func ValidateOrder(configure func(*Param), actor string, cmd ...order.DecodableCommand) (err error) { +func ValidateOrder(configure func(*Param), actor string, cmd ...order.DecodableCommand) (*order.UserGamesOrder, error) { ec, err := NewRepoController(configure) if err != nil { - return err + return nil, err } return ec.validateOrder(actor, cmd...) } +func FetchOrder(configure func(*Param), actor string, turn uint) (order *order.UserGamesOrder, ok bool, err error) { + ec, err := NewRepoController(configure) + if err != nil { + return nil, false, err + } + return ec.fetchOrder(actor, turn) +} + func BanishRace(configure func(*Param), actor string) error { ec, err := NewRepoController(configure) if err != nil { @@ -213,8 +222,8 @@ func (ec *RepoController) NewGameController(g *game.Game) *Controller { } } -func (ec *RepoController) validateOrder(actor string, cmd ...order.DecodableCommand) (err error) { - return ec.executeSafe(func(t uint, c *Controller) error { +func (ec *RepoController) validateOrder(actor string, cmd ...order.DecodableCommand) (o *order.UserGamesOrder, err error) { + err = ec.executeSafe(func(t uint, c *Controller) error { id, err := c.RaceID(actor) if err != nil { return err @@ -223,10 +232,33 @@ func (ec *RepoController) validateOrder(actor string, cmd ...order.DecodableComm if err != nil { return err } - o := &order.Order{Commands: make([]order.DecodableCommand, len(cmd))} + o = &order.UserGamesOrder{ + GameID: c.Cache.g.ID, + UpdatedAt: time.Now().UTC().UnixMilli(), + Commands: make([]order.DecodableCommand, len(cmd)), + } copy(o.Commands, cmd) return ec.Repo.SaveOrder(t, id, o) }) + if err != nil { + return nil, err + } + return +} + +func (ec *RepoController) fetchOrder(actor string, turn uint) (order *order.UserGamesOrder, ok bool, err error) { + err = ec.executeSafe(func(t uint, c *Controller) error { + id, err := c.RaceID(actor) + if err != nil { + return err + } + order, ok, err = ec.Repo.LoadOrder(turn, id) + return err + }) + if err != nil { + return + } + return } func (ec *RepoController) loadReport(actor string, turn uint) (r *report.Report, err error) { diff --git a/game/internal/controller/order.go b/game/internal/controller/order.go index 9759337..fe39c22 100644 --- a/game/internal/controller/order.go +++ b/game/internal/controller/order.go @@ -114,6 +114,7 @@ func (c *Controller) applyCommand(actor string, cmd order.DecodableCommand) (err func (c *Controller) applyOrders(t uint) error { raceOrder := make(map[int][]order.DecodableCommand) + raceOrderUpdated := make(map[int]int64) commandRace := make(map[string]string) challenge := make(map[string]*order.CommandShipGroupUnload) cmdApplied := make(map[string]bool) @@ -127,6 +128,7 @@ func (c *Controller) applyOrders(t uint) error { continue } raceOrder[ri] = o.Commands + raceOrderUpdated[ri] = o.UpdatedAt for i := range o.Commands { commandRace[o.Commands[i].CommandID()] = c.Cache.g.Race[ri].Name if v, ok := order.AsCommand[*order.CommandShipGroupUnload](o.Commands[i]); ok { @@ -156,10 +158,12 @@ func (c *Controller) applyOrders(t uint) error { // any command might fail due to challenged planets colonization _ = c.applyCommand(commandRace[cmd.CommandID()], cmd) } - } - - for ri := range c.Cache.listRaceActingIdx() { - if err := c.Repo.SaveOrder(t, c.Cache.g.Race[ri].ID, &order.Order{Commands: raceOrder[ri]}); err != nil { + // re-save order to persist possible changed commands result outcome + if err := c.Repo.SaveOrder(t, c.Cache.g.Race[ri].ID, &order.UserGamesOrder{ + GameID: c.Cache.g.ID, + UpdatedAt: raceOrderUpdated[ri], + Commands: raceOrder[ri], + }); err != nil { return err } } diff --git a/game/internal/repo/game.go b/game/internal/repo/game.go index 26ab0db..aa595ee 100644 --- a/game/internal/repo/game.go +++ b/game/internal/repo/game.go @@ -29,7 +29,9 @@ const ( ) type storedOrder struct { - Commands []json.RawMessage `json:"cmd"` + GameID uuid.UUID `json:"game_id"` + UpdatedAt int64 `json:"updatedAt"` + Commands []json.RawMessage `json:"cmd"` } func (o storedOrder) MarshalBinary() (data []byte, err error) { @@ -201,11 +203,11 @@ func loadReport(s Storage, t uint, id uuid.UUID) (*report.Report, error) { return result, nil } -func (r *repo) SaveOrder(t uint, id uuid.UUID, o *order.Order) error { +func (r *repo) SaveOrder(t uint, id uuid.UUID, o *order.UserGamesOrder) error { return saveOrder(r.s, t, id, o) } -func saveOrder(s Storage, t uint, id uuid.UUID, o *order.Order) error { +func saveOrder(s Storage, t uint, id uuid.UUID, o *order.UserGamesOrder) error { path := OrderDir(t, id) if err := s.WriteSafe(path, o); err != nil { return NewStorageError(err) @@ -213,11 +215,11 @@ func saveOrder(s Storage, t uint, id uuid.UUID, o *order.Order) error { return nil } -func (r *repo) LoadOrder(t uint, id uuid.UUID) (*order.Order, bool, error) { +func (r *repo) LoadOrder(t uint, id uuid.UUID) (*order.UserGamesOrder, bool, error) { return loadOrder(r.s, t, id) } -func loadOrder(s Storage, t uint, id uuid.UUID) (*order.Order, bool, error) { +func loadOrder(s Storage, t uint, id uuid.UUID) (*order.UserGamesOrder, bool, error) { path := OrderDir(t, id) exist, err := s.Exists(path) @@ -228,17 +230,21 @@ func loadOrder(s Storage, t uint, id uuid.UUID) (*order.Order, bool, error) { return nil, false, nil } - cmd := new(storedOrder) - if err := s.ReadSafe(path, cmd); err != nil { + stored := new(storedOrder) + if err := s.ReadSafe(path, stored); err != nil { return nil, false, NewStorageError(err) } - result := &order.Order{Commands: make([]order.DecodableCommand, len(cmd.Commands))} - if len(cmd.Commands) == 0 { + result := &order.UserGamesOrder{ + GameID: stored.GameID, + UpdatedAt: stored.UpdatedAt, + Commands: make([]order.DecodableCommand, len(stored.Commands)), + } + if len(stored.Commands) == 0 { return nil, false, errors.New("no commands were stored") } - for i := range cmd.Commands { - command, err := ParseOrder(cmd.Commands[i], nil) + for i := range stored.Commands { + command, err := ParseOrder(stored.Commands[i], nil) if err != nil { return nil, false, err } diff --git a/game/internal/repo/repo_export_test.go b/game/internal/repo/repo_export_test.go index 83fdcdb..e544141 100644 --- a/game/internal/repo/repo_export_test.go +++ b/game/internal/repo/repo_export_test.go @@ -6,10 +6,10 @@ import ( "github.com/google/uuid" ) -func LoadOrder_T(s Storage, t uint, id uuid.UUID) (*order.Order, bool, error) { +func LoadOrder_T(s Storage, t uint, id uuid.UUID) (*order.UserGamesOrder, bool, error) { return loadOrder(s, t, id) } -func SaveOrder_T(s Storage, t uint, id uuid.UUID, o *order.Order) error { +func SaveOrder_T(s Storage, t uint, id uuid.UUID, o *order.UserGamesOrder) error { return saveOrder(s, t, id, o) } diff --git a/game/internal/repo/repo_test.go b/game/internal/repo/repo_test.go index 5be1c3c..738b239 100644 --- a/game/internal/repo/repo_test.go +++ b/game/internal/repo/repo_test.go @@ -3,6 +3,7 @@ package repo_test import ( "path/filepath" "testing" + "time" "galaxy/model/order" @@ -18,7 +19,11 @@ func TestSaveOrder(t *testing.T) { s, err := fs.NewFileStorage(root) assert.NoError(t, err) id := uuid.New() - o := &order.Order{ + gameID := uuid.New() + now := time.Now().UTC().UnixMilli() + o := &order.UserGamesOrder{ + GameID: gameID, + UpdatedAt: now, Commands: []order.DecodableCommand{ &order.CommandRaceVote{ CommandMeta: order.CommandMeta{ @@ -87,17 +92,19 @@ func TestSaveOrder(t *testing.T) { LoadOrderTest(t, s, root, turn, id, o) } -func LoadOrderTest(t *testing.T, s repo.Storage, root string, turn uint, id uuid.UUID, expected *order.Order) { +func LoadOrderTest(t *testing.T, s repo.Storage, root string, turn uint, id uuid.UUID, expected *order.UserGamesOrder) { o, ok, err := repo.LoadOrder_T(s, turn, id) assert.NoError(t, err) assert.True(t, ok) assert.Len(t, o.Commands, 5) + assert.Equal(t, expected.GameID, o.GameID) + assert.Equal(t, expected.UpdatedAt, o.UpdatedAt) assert.ElementsMatch(t, expected.Commands, o.Commands) CommandResultTest(t, o) } -func CommandResultTest(t *testing.T, o *order.Order) { +func CommandResultTest(t *testing.T, o *order.UserGamesOrder) { assert.NotEmpty(t, o.Commands) for i := range o.Commands { if v, ok := order.AsCommand[*order.CommandRaceVote](o.Commands[i]); ok { diff --git a/game/internal/router/handler/command.go b/game/internal/router/handler/command.go index a102e5b..745e599 100644 --- a/game/internal/router/handler/command.go +++ b/game/internal/router/handler/command.go @@ -41,7 +41,7 @@ func CommandHandler(c *gin.Context, executor CommandExecutor) { return } - c.Status(http.StatusNoContent) + c.Status(http.StatusAccepted) } func parseCommand(actor string, c json.RawMessage) (Command, error) { diff --git a/game/internal/router/handler/handler.go b/game/internal/router/handler/handler.go index 8d3b314..ca4ad6d 100644 --- a/game/internal/router/handler/handler.go +++ b/game/internal/router/handler/handler.go @@ -25,8 +25,10 @@ type CommandExecutor interface { GameState() (rest.StateResponse, error) BanishRace(string) error LoadReport(actor string, turn uint) (*report.Report, error) + // Execute is reserved for future use; any API request for orders should use ValidateOrder Execute(cmd ...Command) error - ValidateOrder(actor string, cmd ...order.DecodableCommand) error + ValidateOrder(actor string, cmd ...order.DecodableCommand) (*order.UserGamesOrder, error) + FetchOrder(actor string, turn uint) (*order.UserGamesOrder, bool, error) } type Command func(controller.Ctrl) error @@ -76,10 +78,14 @@ func (e *executor) Execute(cmd ...Command) error { }) } -func (e *executor) ValidateOrder(actor string, cmd ...order.DecodableCommand) error { +func (e *executor) ValidateOrder(actor string, cmd ...order.DecodableCommand) (*order.UserGamesOrder, error) { return controller.ValidateOrder(e.cfg, actor, cmd...) } +func (e *executor) FetchOrder(actor string, turn uint) (*order.UserGamesOrder, bool, error) { + return controller.FetchOrder(e.cfg, actor, turn) +} + func (e *executor) GenerateGame(races []string) (rest.StateResponse, error) { s, err := controller.GenerateGame(e.cfg, races) if err != nil { diff --git a/game/internal/router/handler/order.go b/game/internal/router/handler/order.go index 39764fa..b70c8e2 100644 --- a/game/internal/router/handler/order.go +++ b/game/internal/router/handler/order.go @@ -12,7 +12,7 @@ import ( "github.com/gin-gonic/gin" ) -func OrderHandler(c *gin.Context, executor CommandExecutor) { +func PutOrderHandler(c *gin.Context, executor CommandExecutor) { var cmd rest.Command if errorResponse(c, c.ShouldBindJSON(&cmd)) { return @@ -31,9 +31,38 @@ func OrderHandler(c *gin.Context, executor CommandExecutor) { return } - if errorResponse(c, executor.ValidateOrder(cmd.Actor, commands...)) { + result, err := executor.ValidateOrder(cmd.Actor, commands...) + if errorResponse(c, err) { return } - c.Status(http.StatusNoContent) + c.JSON(http.StatusAccepted, result) +} + +type orderParam struct { + Player string `form:"player" binding:"required,notblank"` + Turn int `form:"turn" binding:"gte=0"` +} + +func GetOrderHandler(c *gin.Context, executor CommandExecutor) { + p := &orderParam{} + err := c.ShouldBindQuery(p) + if errorResponse(c, err) { + return + } + + order, ok, err := executor.FetchOrder(p.Player, uint(p.Turn)) + if errorResponse(c, err) { + return + } + if !ok { + // there was no order previously sent by player + c.Status(http.StatusNoContent) + } + var cmd rest.Command + if errorResponse(c, c.ShouldBindJSON(&cmd)) { + return + } + + c.JSON(http.StatusOK, order) } diff --git a/game/internal/router/router.go b/game/internal/router/router.go index 592cf0d..0ff10a2 100644 --- a/game/internal/router/router.go +++ b/game/internal/router/router.go @@ -74,8 +74,11 @@ func setupRouter(executor handler.CommandExecutor) *gin.Engine { groupAdmin.POST("/race/banish", func(ctx *gin.Context) { handler.BanishHandler(ctx, executor) }) groupV1.GET("/report", func(ctx *gin.Context) { handler.ReportHandler(ctx, executor) }) + groupV1.PUT("/order", func(ctx *gin.Context) { handler.PutOrderHandler(ctx, executor) }) + groupV1.GET("/order", func(ctx *gin.Context) { handler.GetOrderHandler(ctx, executor) }) + + // /command is reserved for future use; any API request for orders should use /order groupV1.PUT("/command", LimitMiddleware(1), func(ctx *gin.Context) { handler.CommandHandler(ctx, executor) }) - groupV1.PUT("/order", func(ctx *gin.Context) { handler.OrderHandler(ctx, executor) }) return r } diff --git a/game/internal/router/router_helper_test.go b/game/internal/router/router_helper_test.go index 4be3963..98520e9 100644 --- a/game/internal/router/router_helper_test.go +++ b/game/internal/router/router_helper_test.go @@ -16,7 +16,7 @@ import ( ) var ( - commandNoErrorsStatus = http.StatusNoContent + commandNoErrorsStatus = http.StatusAccepted commandDefaultActor = "Gorlum" apiCommandMethod = "PUT" apiCommandPath = "/api/v1/command" @@ -34,9 +34,13 @@ type dummyExecutor struct { CommandsExecuted int } -func (e *dummyExecutor) ValidateOrder(actor string, cmd ...order.DecodableCommand) error { +func (e *dummyExecutor) ValidateOrder(actor string, cmd ...order.DecodableCommand) (*order.UserGamesOrder, error) { e.CommandsExecuted = len(cmd) - return nil + return nil, nil +} + +func (e *dummyExecutor) FetchOrder(actor string, turn uint) (*order.UserGamesOrder, bool, error) { + return nil, true, nil } func (e *dummyExecutor) Execute(command ...handler.Command) error { diff --git a/pkg/model/client/client.go b/pkg/model/client/client.go index 6df4e3e..fd3468e 100644 --- a/pkg/model/client/client.go +++ b/pkg/model/client/client.go @@ -57,7 +57,7 @@ type GameState struct { } type GameData struct { - Turn uint `json:"turn"` - Report report.Report `json:"report"` - Order *order.Order `json:"order,omitempty"` + Turn uint `json:"turn"` + Report report.Report `json:"report"` + Order *order.UserGamesOrder `json:"order,omitempty"` } diff --git a/pkg/model/order/order.go b/pkg/model/order/order.go index 6a7ddce..33df363 100644 --- a/pkg/model/order/order.go +++ b/pkg/model/order/order.go @@ -40,23 +40,17 @@ type UserGamesOrder struct { // UpdatedAt is the client-side timestamp used for stale-order // detection on the engine side. - UpdatedAt int `json:"updatedAt"` + UpdatedAt int64 `json:"updatedAt"` // Commands is the player order batch. Commands []DecodableCommand `json:"cmd"` } -type Order struct { - // TODO: check with already stored order, if any, and generate an error, if newer order exists - UpdatedAt int `json:"updatedAt"` - Commands []DecodableCommand `json:"cmd"` -} - -func (o Order) MarshalBinary() (data []byte, err error) { +func (o UserGamesOrder) MarshalBinary() (data []byte, err error) { return json.Marshal(&o) } -func (o *Order) UnmarshalBinary(data []byte) error { +func (o *UserGamesOrder) UnmarshalBinary(data []byte) error { return json.Unmarshal(data, o) } diff --git a/pkg/storage/fs/fs.go b/pkg/storage/fs/fs.go index 8ce367f..a35b167 100644 --- a/pkg/storage/fs/fs.go +++ b/pkg/storage/fs/fs.go @@ -17,6 +17,8 @@ import ( "galaxy/model/order" "galaxy/model/report" "galaxy/util" + + "github.com/google/uuid" ) const ( @@ -62,7 +64,8 @@ type fsStorage struct { } type storedOrder struct { - UpdatedAt int `json:"updatedAt"` + GameID uuid.UUID `json:"game_id"` + UpdatedAt int64 `json:"updatedAt"` Commands []json.RawMessage `json:"cmd"` } @@ -155,7 +158,7 @@ func (s *fsStorage) SaveReportAsync(id client.GameID, turn uint, rep report.Repo }() } -func (s *fsStorage) LoadOrderAsync(id client.GameID, turn uint, callback func(order.Order, error)) { +func (s *fsStorage) LoadOrderAsync(id client.GameID, turn uint, callback func(order.UserGamesOrder, error)) { go func() { o, err := s.loadOrderSync(id, turn) if callback != nil { @@ -164,7 +167,7 @@ func (s *fsStorage) LoadOrderAsync(id client.GameID, turn uint, callback func(or }() } -func (s *fsStorage) SaveOrderAsync(id client.GameID, turn uint, o order.Order, callback func(error)) { +func (s *fsStorage) SaveOrderAsync(id client.GameID, turn uint, o order.UserGamesOrder, callback func(error)) { go func() { err := s.saveOrderSync(id, turn, o) if callback != nil { @@ -320,18 +323,18 @@ func (s *fsStorage) saveReportSync(id client.GameID, turn uint, rep report.Repor })) } -func (s *fsStorage) loadOrderSync(id client.GameID, turn uint) (order.Order, error) { +func (s *fsStorage) loadOrderSync(id client.GameID, turn uint) (order.UserGamesOrder, error) { gameData, err := s.loadGameDataSync(id, turn) if err != nil { - return order.Order{}, classifyStorageError(err) + return order.UserGamesOrder{}, classifyStorageError(err) } if gameData.Order == nil { - return order.Order{}, classifyStorageError(fmt.Errorf("load order for game %q turn %d: %w", id, turn, os.ErrNotExist)) + return order.UserGamesOrder{}, classifyStorageError(fmt.Errorf("load order for game %q turn %d: %w", id, turn, os.ErrNotExist)) } return *gameData.Order, nil } -func (s *fsStorage) saveOrderSync(id client.GameID, turn uint, o order.Order) error { +func (s *fsStorage) saveOrderSync(id client.GameID, turn uint, o order.UserGamesOrder) error { absPath, err := s.resolvePath(gameTurnFilePath(id, turn)) if err != nil { return classifyStorageError(err) @@ -474,8 +477,9 @@ func (d storedGameData) toGameData() (client.GameData, error) { return gameData, nil } -func makeStoredOrder(o order.Order) (storedOrder, error) { +func makeStoredOrder(o order.UserGamesOrder) (storedOrder, error) { result := storedOrder{ + GameID: o.GameID, UpdatedAt: o.UpdatedAt, Commands: make([]json.RawMessage, len(o.Commands)), } @@ -489,12 +493,13 @@ func makeStoredOrder(o order.Order) (storedOrder, error) { return result, nil } -func (o *storedOrder) toOrder() (*order.Order, error) { +func (o *storedOrder) toOrder() (*order.UserGamesOrder, error) { if o == nil { return nil, nil } - result := &order.Order{ + result := &order.UserGamesOrder{ + GameID: o.GameID, UpdatedAt: o.UpdatedAt, Commands: make([]order.DecodableCommand, len(o.Commands)), } diff --git a/pkg/storage/fs/fs_test.go b/pkg/storage/fs/fs_test.go index efcd848..8592b35 100644 --- a/pkg/storage/fs/fs_test.go +++ b/pkg/storage/fs/fs_test.go @@ -14,6 +14,8 @@ import ( "galaxy/model/client" "galaxy/model/order" "galaxy/model/report" + + "github.com/google/uuid" ) const testTimeout = time.Second @@ -137,9 +139,9 @@ func TestReportAndOrderRoundTripAsync(t *testing.T) { t.Fatalf("loaded report mismatch\nwant: %#v\ngot: %#v", updatedReport, gotReport.value) } - loadOrderDone := make(chan callbackResult[order.Order], 1) - s.LoadOrderAsync(id, turn, func(got order.Order, err error) { - loadOrderDone <- callbackResult[order.Order]{value: got, err: err} + loadOrderDone := make(chan callbackResult[order.UserGamesOrder], 1) + s.LoadOrderAsync(id, turn, func(got order.UserGamesOrder, err error) { + loadOrderDone <- callbackResult[order.UserGamesOrder]{value: got, err: err} }) gotOrder := waitResult(t, loadOrderDone) if gotOrder.err != nil { @@ -529,8 +531,9 @@ func sampleReport(turn uint, race string) report.Report { } } -func sampleOrder() order.Order { - return order.Order{ +func sampleOrder() order.UserGamesOrder { + return order.UserGamesOrder{ + GameID: uuid.New(), UpdatedAt: 1700, Commands: []order.DecodableCommand{ &order.CommandPlanetRename{ diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index f6aabdd..d180d7e 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -53,9 +53,9 @@ type UIStorage interface { // LoadOrderAsync loads a [order.Order] for a given [model.GameID] and turn number from filesystem asynchronously. // Passed callback func will will accept non-nil error in case of I/O or decoding errors occuried, // otherwise callback func accepts loaded [order.Order]. - LoadOrderAsync(client.GameID, uint, func(order.Order, error)) + LoadOrderAsync(client.GameID, uint, func(order.UserGamesOrder, error)) // SaveOrderAsync stores given [order.Order] for a given [model.GameID] and turn number at the filesystem asynchronously. // I/O or encoding error may occur, it that case callback func will be called with non-nil error. - SaveOrderAsync(client.GameID, uint, order.Order, func(error)) + SaveOrderAsync(client.GameID, uint, order.UserGamesOrder, func(error)) } diff --git a/pkg/transcoder/order.go b/pkg/transcoder/order.go index b164772..290c9da 100644 --- a/pkg/transcoder/order.go +++ b/pkg/transcoder/order.go @@ -916,13 +916,13 @@ func PayloadToUserGamesOrder(data []byte) (result *model.UserGamesOrder, err err if gameID == nil { return nil, errors.New("decode user games order payload: game_id is missing") } - updatedAt, convErr := int64ToInt(flat.UpdatedAt(), "updated_at") - if convErr != nil { - return nil, fmt.Errorf("decode user games order payload: %w", convErr) - } + // updatedAt, convErr := int64ToInt(flat.UpdatedAt(), "updated_at") + // if convErr != nil { + // return nil, fmt.Errorf("decode user games order payload: %w", convErr) + // } out := &model.UserGamesOrder{ GameID: uuidFromHiLo(gameID.Hi(), gameID.Lo()), - UpdatedAt: updatedAt, + UpdatedAt: flat.UpdatedAt(), } count := flat.CommandsLength() if count > 0 {