package service import ( "context" "errors" "time" "github.com/jackc/pgx/v5/pgconn" "gitrepo.ru/neonxp/nquest/pkg/models" "gorm.io/gorm" ) var ( ErrGameNotStarted = errors.New("game not started") ) type Game struct { DB *gorm.DB } // NewGame returns new Game. func NewGame(db *gorm.DB) *Game { return &Game{ DB: db, } } func (gs *Game) GetByID(ctx context.Context, id uint) (*models.Game, error) { g := &models.Game{} return g, gs.DB. WithContext(ctx). Preload("FirstTask"). First(g, id). Error } func (gs *Game) List(ctx context.Context) ([]*models.Game, error) { games := make([]*models.Game, 0) return games, gs.DB. WithContext(ctx). Preload("Teams"). Preload("Teams.Team"). Order("start_at DESC"). Find(&games, "visible = true"). Limit(20). Error } func (gs *Game) GetTaskID(ctx context.Context, id uint) (*models.Task, error) { t := &models.Task{} return t, gs.DB.WithContext(ctx).Preload("Next").First(t, id).Error } func (gs *Game) GetHistory(ctx context.Context, game *models.Game, team *models.Team) ([]*models.GamePassing, error) { db := gs.DB.WithContext(ctx) history := []*models.GamePassing{} return history, db.Where(`team_id = ? and game_id = ?`, team.ID, game.ID).Find(&history).Error } func (gs *Game) GetState(ctx context.Context, game *models.Game, team *models.Team) (*models.GamePassing, error) { db := gs.DB.WithContext(ctx) if !game.StartAt.Before(time.Now()) { return nil, ErrGameNotStarted } // Пытаемся получить GamePassing gamepass := &models.GamePassing{ Team: team, Game: game, Task: game.FirstTask, Status: models.PassStarted, Codes: []*models.Code{}, CreatedAt: game.StartAt, Deadline: game.StartAt.Add(time.Minute * time.Duration(game.FirstTask.MaxTime)), } err := db. Where(`team_id = ? and game_id = ? and status = ?`, team.ID, game.ID, models.PassStarted). Preload("Task"). FirstOrCreate(gamepass). Error if err != nil { if err, ok := err.(*pgconn.PgError); ok { if err.Code == "23505" { return nil, nil } } return nil, err } for { if !gamepass.Timeouted() { break } gamepass.Status = models.PassFailed gamepass.FinishedAt = &gamepass.Deadline if err := db.Save(gamepass).Error; err != nil { return nil, err } taskID := gamepass.TaskID task, err := gs.GetTaskID(ctx, taskID) if err != nil { return nil, err } if task.Next == nil { return nil, nil } gamepass = &models.GamePassing{ Team: team, Game: game, Task: task.Next, CreatedAt: gamepass.Deadline, Deadline: gamepass.Deadline.Add(time.Minute * time.Duration(task.Next.MaxTime)), Status: models.PassStarted, Codes: []*models.Code{}, } if err := db.Create(gamepass).Error; err != nil { return nil, err } } return gamepass, nil } func (gs *Game) ListByAuthor(ctx context.Context, author *models.User) ([]*models.Game, error) { games := make([]*models.Game, 0) return games, gs.DB. WithContext(ctx). Model(&models.Game{}). Preload("Teams"). Preload("Teams.Team"). Preload("Authors", gs.DB.Where("id = ?", author.ID)). Order("created_at DESC"). Find(&games). Limit(20). Error }