lila/modules/tournament/src/main/Cached.scala

121 lines
3.5 KiB
Scala

package lila.tournament
import play.api.i18n.Lang
import scala.concurrent.duration._
import lila.hub.LightTeam.TeamID
import lila.memo._
import lila.memo.CacheApi._
import lila.user.User
import play.api.libs.json.JsArray
final private[tournament] class Cached(
playerRepo: PlayerRepo,
pairingRepo: PairingRepo,
tournamentRepo: TournamentRepo,
cacheApi: CacheApi
)(implicit
ec: scala.concurrent.ExecutionContext
) {
val nameCache = cacheApi.sync[(Tournament.ID, Lang), Option[String]](
name = "tournament.name",
initialCapacity = 65536,
compute = { case (id, lang) =>
tournamentRepo byId id dmap2 { _.name()(lang) }
},
default = _ => none,
strategy = Syncache.WaitAfterUptime(20 millis),
expireAfter = Syncache.ExpireAfterAccess(20 minutes)
)
val onHomepage = cacheApi.unit[List[Tournament]] {
_.refreshAfterWrite(2 seconds)
.buildAsyncFuture(_ => tournamentRepo.onHomepage)
}
def ranking(tour: Tournament): Fu[Ranking] =
if (tour.isFinished) finishedRanking get tour.id
else ongoingRanking get tour.id
private[tournament] val teamInfo =
cacheApi[(Tournament.ID, TeamID), Option[TeamBattle.TeamInfo]](16, "tournament.teamInfo") {
_.expireAfterWrite(5 seconds)
.maximumSize(64)
.buildAsyncFuture { case (tourId, teamId) =>
playerRepo.teamInfo(tourId, teamId) dmap some
}
}
// only applies to ongoing tournaments
private val ongoingRanking = cacheApi[Tournament.ID, Ranking](64, "tournament.ongoingRanking") {
_.expireAfterWrite(3 seconds)
.buildAsyncFuture(playerRepo.computeRanking)
}
// only applies to finished tournaments
private val finishedRanking = cacheApi[Tournament.ID, Ranking](1024, "tournament.finishedRanking") {
_.expireAfterAccess(1 hour)
.maximumSize(2048)
.buildAsyncFuture(playerRepo.computeRanking)
}
object battle {
val teamStanding =
cacheApi[Tournament.ID, List[TeamBattle.RankedTeam]](8, "tournament.teamStanding") {
_.expireAfterWrite(1 second)
.buildAsyncFuture { id =>
tournamentRepo teamBattleOf id flatMap {
_ ?? { playerRepo.bestTeamIdsByTour(id, _) }
}
}
}
}
private[tournament] object sheet {
import arena.Sheet
private case class SheetKey(
tourId: Tournament.ID,
userId: User.ID,
version: Sheet.Version,
streakable: Sheet.Streakable
)
def apply(tour: Tournament, userId: User.ID): Fu[Sheet] =
cache.get(keyOf(tour, userId))
def update(tour: Tournament, userId: User.ID): Fu[Sheet] = {
val key = keyOf(tour, userId)
cache.invalidate(key)
cache.get(key)
}
private def keyOf(tour: Tournament, userId: User.ID) =
SheetKey(
tour.id,
userId,
Sheet versionOf tour.startsAt,
if (tour.streakable) Sheet.Streaks else Sheet.NoStreaks
)
private def compute(key: SheetKey): Fu[Sheet] =
pairingRepo.finishedByPlayerChronological(key.tourId, key.userId) map {
arena.Sheet(key.userId, _, key.version, key.streakable)
}
private val cache = cacheApi[SheetKey, Sheet](8192, "tournament.sheet") {
_.expireAfterAccess(3 minutes)
.maximumSize(32768)
.buildAsyncFuture(compute)
}
}
private[tournament] val notableFinishedCache = cacheApi.unit[List[Tournament]] {
_.refreshAfterWrite(15 seconds)
.buildAsyncFuture(_ => tournamentRepo.notableFinished(20))
}
}