Loading CHANGELOG.md +1 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ The format is based on [keep a changelog](http://keepachangelog.com) and this pr - Use correct parameter type for creator ID in group update queries. - Use correct parameter name for lang tag in group update queries. - Do not allow users to send friend requests to the root user. - Tournament listings now report correct active periods if the start time is in the future. ## [2.2.1] - 2018-11-20 ### Added Loading server/core_leaderboard.go +1 −1 Original line number Diff line number Diff line Loading @@ -61,7 +61,7 @@ func LeaderboardRecordsList(ctx context.Context, logger *zap.Logger, db *sql.DB, if expiryTime == 0 { now := time.Now().UTC() if leaderboard.IsTournament() { _, _, expiryTime = calculateTournamentDeadlines(leaderboard, now) _, _, expiryTime = calculateTournamentDeadlines(leaderboard.StartTime, leaderboard.EndTime, int64(leaderboard.Duration), leaderboard.ResetSchedule, now) } else if leaderboard.ResetSchedule != nil { expiryTime = leaderboard.ResetSchedule.Next(now).UTC().Unix() } Loading server/core_tournament.go +26 −39 Original line number Diff line number Diff line Loading @@ -133,7 +133,7 @@ func TournamentJoin(ctx context.Context, logger *zap.Logger, db *sql.DB, cache L now := time.Now().UTC() nowUnix := now.Unix() _, endActive, expiryTime := calculateTournamentDeadlines(leaderboard, now) _, endActive, expiryTime := calculateTournamentDeadlines(leaderboard.StartTime, leaderboard.EndTime, int64(leaderboard.Duration), leaderboard.ResetSchedule, now) if endActive <= nowUnix { logger.Info("Cannot join tournament outside of tournament duration.") return ErrTournamentOutsideDuration Loading Loading @@ -281,7 +281,7 @@ func TournamentRecordWrite(ctx context.Context, logger *zap.Logger, db *sql.DB, nowTime := time.Now().UTC() nowUnix := nowTime.Unix() startActiveUnix, endActiveUnix, expiryUnix := calculateTournamentDeadlines(leaderboard, nowTime) startActiveUnix, endActiveUnix, expiryUnix := calculateTournamentDeadlines(leaderboard.StartTime, leaderboard.EndTime, int64(leaderboard.Duration), leaderboard.ResetSchedule, nowTime) if startActiveUnix > nowUnix || endActiveUnix <= nowUnix { logger.Info("Cannot write tournament record as it is outside of tournament duration.", zap.String("id", leaderboard.Id)) return nil, ErrTournamentOutsideDuration Loading Loading @@ -456,38 +456,38 @@ func TournamentRecordsHaystack(ctx context.Context, logger *zap.Logger, db *sql. sortOrder := leaderboard.SortOrder _, _, expiry := calculateTournamentDeadlines(leaderboard, time.Now().UTC()) _, _, expiry := calculateTournamentDeadlines(leaderboard.StartTime, leaderboard.EndTime, int64(leaderboard.Duration), leaderboard.ResetSchedule, time.Now().UTC()) expiryTime := time.Unix(expiry, 0).UTC() return getLeaderboardRecordsHaystack(ctx, logger, db, rankCache, ownerId, limit, leaderboard.Id, sortOrder, expiryTime) } func calculateTournamentDeadlines(leaderboard *Leaderboard, t time.Time) (int64, int64, int64) { if leaderboard.ResetSchedule != nil { schedules := leaderboard.ResetSchedule.NextN(t, 2) func calculateTournamentDeadlines(startTime, endTime, duration int64, resetSchedule *cronexpr.Expression, t time.Time) (int64, int64, int64) { if resetSchedule != nil { schedules := resetSchedule.NextN(t, 2) schedule0Unix := schedules[0].UTC().Unix() schedule1Unix := schedules[1].UTC().Unix() startActiveUnix := schedule0Unix - (schedule1Unix - schedule0Unix) endActiveUnix := startActiveUnix + int64(leaderboard.Duration) endActiveUnix := startActiveUnix + duration expiryUnix := schedule0Unix if leaderboard.StartTime > endActiveUnix { if startTime > endActiveUnix { // The start time after the end of the current active period but before the next reset. // e.g. Reset schedule is daily at noon, duration is 1 hour, but time is currently 3pm. startActiveUnix = leaderboard.ResetSchedule.Next(time.Unix(leaderboard.StartTime, 0).UTC()).UTC().Unix() endActiveUnix = startActiveUnix + int64(leaderboard.Duration) startActiveUnix = resetSchedule.Next(time.Unix(startTime, 0).UTC()).UTC().Unix() endActiveUnix = startActiveUnix + duration expiryUnix = startActiveUnix + (schedule1Unix - schedule0Unix) } return startActiveUnix, endActiveUnix, expiryUnix } else { endActiveUnix := int64(0) if leaderboard.StartTime <= t.Unix() { endActiveUnix = leaderboard.StartTime + int64(leaderboard.Duration) if startTime <= t.Unix() { endActiveUnix = startTime + duration } expiryUnix := leaderboard.EndTime return leaderboard.StartTime, endActiveUnix, expiryUnix expiryUnix := endTime return startTime, endActiveUnix, expiryUnix } } Loading @@ -512,30 +512,17 @@ func parseTournament(scannable Scannable, now time.Time) (*api.Tournament, error return nil, err } canEnter := true endActive := int64(0) nextReset := int64(0) var resetSchedule *cronexpr.Expression if dbResetSchedule.Valid { cron := cronexpr.MustParse(dbResetSchedule.String) schedules := cron.NextN(now, 2) sessionStartTime := schedules[0].Unix() - (schedules[1].Unix() - schedules[0].Unix()) if dbStartTime.Time.UTC().After(now) { endActive = 0 } else { endActive = sessionStartTime + int64(dbDuration) } nextReset = schedules[0].Unix() } else { if dbStartTime.Time.UTC().After(now) { endActive = 0 } else { endActive = dbStartTime.Time.UTC().Unix() + int64(dbDuration) } resetSchedule = cronexpr.MustParse(dbResetSchedule.String) } if endActive < now.Unix() { canEnter := true endTime := dbEndTime.Time.UTC().Unix() _, endActiveUnix, expiryUnix := calculateTournamentDeadlines(dbStartTime.Time.UTC().Unix(), endTime, int64(dbDuration), resetSchedule, now) if endActiveUnix < now.Unix() { canEnter = false } Loading @@ -553,16 +540,16 @@ func parseTournament(scannable Scannable, now time.Time) (*api.Tournament, error MaxSize: uint32(dbMaxSize), MaxNumScore: uint32(dbMaxNumScore), CanEnter: canEnter, EndActive: uint32(endActive), NextReset: uint32(nextReset), EndActive: uint32(endActiveUnix), NextReset: uint32(expiryUnix), Metadata: dbMetadata, CreateTime: ×tamp.Timestamp{Seconds: dbCreateTime.Time.UTC().Unix()}, StartTime: ×tamp.Timestamp{Seconds: dbStartTime.Time.UTC().Unix()}, Duration: uint32(dbDuration), } if dbEndTime.Time.Unix() > 0 { tournament.EndTime = ×tamp.Timestamp{Seconds: dbEndTime.Time.UTC().Unix()} if endTime > 0 { tournament.EndTime = ×tamp.Timestamp{Seconds: endTime} } return tournament, nil Loading server/leaderboard_scheduler.go +1 −1 Original line number Diff line number Diff line Loading @@ -154,7 +154,7 @@ func (ls *LocalLeaderboardScheduler) Update() { for _, l := range leaderboards { if l.Duration > 0 { // Tournament. _, endActive, expiry := calculateTournamentDeadlines(l, now) _, endActive, expiry := calculateTournamentDeadlines(l.StartTime, l.EndTime, int64(l.Duration), l.ResetSchedule, now) if l.EndTime > 0 && l.EndTime < nowUnix { // Tournament has ended permanently. Loading Loading
CHANGELOG.md +1 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ The format is based on [keep a changelog](http://keepachangelog.com) and this pr - Use correct parameter type for creator ID in group update queries. - Use correct parameter name for lang tag in group update queries. - Do not allow users to send friend requests to the root user. - Tournament listings now report correct active periods if the start time is in the future. ## [2.2.1] - 2018-11-20 ### Added Loading
server/core_leaderboard.go +1 −1 Original line number Diff line number Diff line Loading @@ -61,7 +61,7 @@ func LeaderboardRecordsList(ctx context.Context, logger *zap.Logger, db *sql.DB, if expiryTime == 0 { now := time.Now().UTC() if leaderboard.IsTournament() { _, _, expiryTime = calculateTournamentDeadlines(leaderboard, now) _, _, expiryTime = calculateTournamentDeadlines(leaderboard.StartTime, leaderboard.EndTime, int64(leaderboard.Duration), leaderboard.ResetSchedule, now) } else if leaderboard.ResetSchedule != nil { expiryTime = leaderboard.ResetSchedule.Next(now).UTC().Unix() } Loading
server/core_tournament.go +26 −39 Original line number Diff line number Diff line Loading @@ -133,7 +133,7 @@ func TournamentJoin(ctx context.Context, logger *zap.Logger, db *sql.DB, cache L now := time.Now().UTC() nowUnix := now.Unix() _, endActive, expiryTime := calculateTournamentDeadlines(leaderboard, now) _, endActive, expiryTime := calculateTournamentDeadlines(leaderboard.StartTime, leaderboard.EndTime, int64(leaderboard.Duration), leaderboard.ResetSchedule, now) if endActive <= nowUnix { logger.Info("Cannot join tournament outside of tournament duration.") return ErrTournamentOutsideDuration Loading Loading @@ -281,7 +281,7 @@ func TournamentRecordWrite(ctx context.Context, logger *zap.Logger, db *sql.DB, nowTime := time.Now().UTC() nowUnix := nowTime.Unix() startActiveUnix, endActiveUnix, expiryUnix := calculateTournamentDeadlines(leaderboard, nowTime) startActiveUnix, endActiveUnix, expiryUnix := calculateTournamentDeadlines(leaderboard.StartTime, leaderboard.EndTime, int64(leaderboard.Duration), leaderboard.ResetSchedule, nowTime) if startActiveUnix > nowUnix || endActiveUnix <= nowUnix { logger.Info("Cannot write tournament record as it is outside of tournament duration.", zap.String("id", leaderboard.Id)) return nil, ErrTournamentOutsideDuration Loading Loading @@ -456,38 +456,38 @@ func TournamentRecordsHaystack(ctx context.Context, logger *zap.Logger, db *sql. sortOrder := leaderboard.SortOrder _, _, expiry := calculateTournamentDeadlines(leaderboard, time.Now().UTC()) _, _, expiry := calculateTournamentDeadlines(leaderboard.StartTime, leaderboard.EndTime, int64(leaderboard.Duration), leaderboard.ResetSchedule, time.Now().UTC()) expiryTime := time.Unix(expiry, 0).UTC() return getLeaderboardRecordsHaystack(ctx, logger, db, rankCache, ownerId, limit, leaderboard.Id, sortOrder, expiryTime) } func calculateTournamentDeadlines(leaderboard *Leaderboard, t time.Time) (int64, int64, int64) { if leaderboard.ResetSchedule != nil { schedules := leaderboard.ResetSchedule.NextN(t, 2) func calculateTournamentDeadlines(startTime, endTime, duration int64, resetSchedule *cronexpr.Expression, t time.Time) (int64, int64, int64) { if resetSchedule != nil { schedules := resetSchedule.NextN(t, 2) schedule0Unix := schedules[0].UTC().Unix() schedule1Unix := schedules[1].UTC().Unix() startActiveUnix := schedule0Unix - (schedule1Unix - schedule0Unix) endActiveUnix := startActiveUnix + int64(leaderboard.Duration) endActiveUnix := startActiveUnix + duration expiryUnix := schedule0Unix if leaderboard.StartTime > endActiveUnix { if startTime > endActiveUnix { // The start time after the end of the current active period but before the next reset. // e.g. Reset schedule is daily at noon, duration is 1 hour, but time is currently 3pm. startActiveUnix = leaderboard.ResetSchedule.Next(time.Unix(leaderboard.StartTime, 0).UTC()).UTC().Unix() endActiveUnix = startActiveUnix + int64(leaderboard.Duration) startActiveUnix = resetSchedule.Next(time.Unix(startTime, 0).UTC()).UTC().Unix() endActiveUnix = startActiveUnix + duration expiryUnix = startActiveUnix + (schedule1Unix - schedule0Unix) } return startActiveUnix, endActiveUnix, expiryUnix } else { endActiveUnix := int64(0) if leaderboard.StartTime <= t.Unix() { endActiveUnix = leaderboard.StartTime + int64(leaderboard.Duration) if startTime <= t.Unix() { endActiveUnix = startTime + duration } expiryUnix := leaderboard.EndTime return leaderboard.StartTime, endActiveUnix, expiryUnix expiryUnix := endTime return startTime, endActiveUnix, expiryUnix } } Loading @@ -512,30 +512,17 @@ func parseTournament(scannable Scannable, now time.Time) (*api.Tournament, error return nil, err } canEnter := true endActive := int64(0) nextReset := int64(0) var resetSchedule *cronexpr.Expression if dbResetSchedule.Valid { cron := cronexpr.MustParse(dbResetSchedule.String) schedules := cron.NextN(now, 2) sessionStartTime := schedules[0].Unix() - (schedules[1].Unix() - schedules[0].Unix()) if dbStartTime.Time.UTC().After(now) { endActive = 0 } else { endActive = sessionStartTime + int64(dbDuration) } nextReset = schedules[0].Unix() } else { if dbStartTime.Time.UTC().After(now) { endActive = 0 } else { endActive = dbStartTime.Time.UTC().Unix() + int64(dbDuration) } resetSchedule = cronexpr.MustParse(dbResetSchedule.String) } if endActive < now.Unix() { canEnter := true endTime := dbEndTime.Time.UTC().Unix() _, endActiveUnix, expiryUnix := calculateTournamentDeadlines(dbStartTime.Time.UTC().Unix(), endTime, int64(dbDuration), resetSchedule, now) if endActiveUnix < now.Unix() { canEnter = false } Loading @@ -553,16 +540,16 @@ func parseTournament(scannable Scannable, now time.Time) (*api.Tournament, error MaxSize: uint32(dbMaxSize), MaxNumScore: uint32(dbMaxNumScore), CanEnter: canEnter, EndActive: uint32(endActive), NextReset: uint32(nextReset), EndActive: uint32(endActiveUnix), NextReset: uint32(expiryUnix), Metadata: dbMetadata, CreateTime: ×tamp.Timestamp{Seconds: dbCreateTime.Time.UTC().Unix()}, StartTime: ×tamp.Timestamp{Seconds: dbStartTime.Time.UTC().Unix()}, Duration: uint32(dbDuration), } if dbEndTime.Time.Unix() > 0 { tournament.EndTime = ×tamp.Timestamp{Seconds: dbEndTime.Time.UTC().Unix()} if endTime > 0 { tournament.EndTime = ×tamp.Timestamp{Seconds: endTime} } return tournament, nil Loading
server/leaderboard_scheduler.go +1 −1 Original line number Diff line number Diff line Loading @@ -154,7 +154,7 @@ func (ls *LocalLeaderboardScheduler) Update() { for _, l := range leaderboards { if l.Duration > 0 { // Tournament. _, endActive, expiry := calculateTournamentDeadlines(l, now) _, endActive, expiry := calculateTournamentDeadlines(l.StartTime, l.EndTime, int64(l.Duration), l.ResetSchedule, now) if l.EndTime > 0 && l.EndTime < nowUnix { // Tournament has ended permanently. Loading