diff --git a/app/Env.scala b/app/Env.scala
index 983e89be8f..3469288d4d 100644
--- a/app/Env.scala
+++ b/app/Env.scala
@@ -29,6 +29,7 @@ final class Env(
bookmarkApi = Env.bookmark.api,
eloCalculator = Env.round.eloCalculator,
relationApi = Env.relation.api,
+ gameCached = Env.game.cached,
postApi = Env.forum.postApi,
getRank = Env.user.ranking.get) _
diff --git a/app/controllers/Tv.scala b/app/controllers/Tv.scala
index f120b22006..82fcaf1c5b 100644
--- a/app/controllers/Tv.scala
+++ b/app/controllers/Tv.scala
@@ -36,7 +36,7 @@ object Tv extends LilaController {
private def confrontation(game: GameModel): Fu[Option[Confrontation]] = ~{
(game.creator.userId |@| game.invited.userId) apply {
case (id1, id2) ⇒ (UserRepo byId id1) zip (UserRepo byId id2) flatMap {
- case (Some(user1), Some(user2)) ⇒ GameRepo.confrontation(user1, user2) map (_.some)
+ case (Some(user1), Some(user2)) ⇒ Env.game.cached.confrontation(user1, user2) map (_.some)
case _ ⇒ fuccess(none)
}
}
diff --git a/app/mashup/UserInfo.scala b/app/mashup/UserInfo.scala
index 6b8af6c953..26e072ab26 100644
--- a/app/mashup/UserInfo.scala
+++ b/app/mashup/UserInfo.scala
@@ -36,16 +36,17 @@ object UserInfo {
bookmarkApi: BookmarkApi,
eloCalculator: EloCalculator,
relationApi: RelationApi,
+ gameCached: lila.game.Cached,
postApi: PostApi,
getRank: String ⇒ Fu[Option[Int]])(user: User, ctx: Context): Fu[UserInfo] =
(getRank(user.id) flatMap {
_ ?? { rank ⇒ countUsers() map { nb ⇒ (rank -> nb).some } }
}) zip
((ctx is user) ?? {
- GameRepo count (_ notFinished user.id) map (_.some)
+ gameCached nbPlaying user.id map (_.some)
}) zip
(ctx.me.filter(user!=) ?? { me ⇒
- GameRepo.confrontation(me, user) map (_.some filterNot (_.empty))
+ gameCached.confrontation(me, user) map (_.some filterNot (_.empty))
}) zip
(bookmarkApi countByUser user) zip
EloChart(user) zip
diff --git a/app/views/user/confrontation.scala.html b/app/views/user/confrontation.scala.html
index 6b4aa2c93b..8de55e1dda 100644
--- a/app/views/user/confrontation.scala.html
+++ b/app/views/user/confrontation.scala.html
@@ -1,7 +1,7 @@
@(c: lila.user.Confrontation)(implicit ctx: Context)
-
@userLink(c.user1, withElo = false, withOnline = false) vs @userLink(c.user2, withElo = false, withOnline = false)
+
@userIdLink(c.user1.some, withOnline = false) vs @userIdLink(c.user2.some, withOnline = false)
@trans.nbWins("
"+c.wins+""),
@trans.nbDraws("
"+c.draws+""),
@trans.nbLosses("
"+c.losses+"")
diff --git a/modules/game/src/main/Cached.scala b/modules/game/src/main/Cached.scala
index 1bfb233d8e..f7a2bb09d1 100644
--- a/modules/game/src/main/Cached.scala
+++ b/modules/game/src/main/Cached.scala
@@ -9,15 +9,23 @@ import lila.memo.AsyncCache
import lila.user.{ User, Confrontation }
import tube.gameTube
-private[game] final class Cached(ttl: Duration) {
+final class Cached(ttl: Duration) {
def nbGames: Fu[Int] = count(Query.all)
def nbMates: Fu[Int] = count(Query.mate)
def nbPopular: Fu[Int] = count(Query.popular)
def nbImported: Fu[Int] = count(Query.imported)
- def confrontation(user1: User, user2: User): Fu[Confrontation] =
- confrontationCache(List(user1, user2).sortBy(_.count.game).map(_.id))
+ def nbPlaying(userId: String): Fu[Int] = count(Query notFinished userId)
+
+ def confrontation(user1: User, user2: User): Fu[Confrontation] = {
+ def idGame(user: User) = (user.id, user.count.game)
+ confrontationCache {
+ (user1 < user2).fold(
+ idGame(user1) -> idGame(user2),
+ idGame(user2) -> idGame(user1))
+ }
+ }
private val confrontationCache =
AsyncCache(GameRepo.confrontation, timeToLive = 1.minute)
diff --git a/modules/game/src/main/GameRepo.scala b/modules/game/src/main/GameRepo.scala
index 2550a369a6..49e3725530 100644
--- a/modules/game/src/main/GameRepo.scala
+++ b/modules/game/src/main/GameRepo.scala
@@ -226,32 +226,37 @@ object GameRepo {
_ sort Query.sortCreated skip (Random nextInt 1000)
)
- // user1 wins, draws, losses
+ // gets 2 users (id, nbGames)
+ // returns user1 wins, draws, losses
// the 2 userIds SHOULD be sorted by game count desc
// this method is cached in lila.game.Cached
- private[game] def confrontation(userIds: List[String]): Fu[Confrontation] = {
- import reactivemongo.bson._
- import reactivemongo.core.commands._
- val command = Aggregate(gameTube.coll.name, Seq(
- Match(BSONDocument(
- "uids" -> BSONDocument("$all" -> userIds),
- "s" -> BSONDocument("$gte" -> chess.Status.Mate.id)
- )),
- GroupField("wid")("nb" -> SumValue(1))
- ))
- gameTube.coll.db.command(command) map { stream ⇒
- val res = (stream.toList map { obj ⇒
- toJSON(obj).asOpt[JsObject] flatMap { o ⇒
- o int "nb" map { nb ⇒
- ~(o str "_id") -> nb
+ private[game] def confrontation(users: ((String, Int), (String, Int))): Fu[Confrontation] = users match {
+ case (user1, user2) ⇒ {
+ import reactivemongo.bson._
+ import reactivemongo.core.commands._
+ val userIds = List(user1, user2).sortBy(_._2).map(_._1)
+ val command = Aggregate(gameTube.coll.name, Seq(
+ Match(BSONDocument(
+ "uids" -> BSONDocument("$all" -> userIds),
+ "s" -> BSONDocument("$gte" -> chess.Status.Mate.id)
+ )),
+ GroupField("wid")("nb" -> SumValue(1))
+ ))
+ gameTube.coll.db.command(command) map { stream ⇒
+ val res = (stream.toList map { obj ⇒
+ toJSON(obj).asOpt[JsObject] flatMap { o ⇒
+ o int "nb" map { nb ⇒
+ ~(o str "_id") -> nb
+ }
}
- }
- }).flatten.toMap
- Confrontation(
- ~(res get ~userIds.lift(0)),
- ~(res get ""),
- ~(res get ~userIds.lift(1))
- )
+ }).flatten.toMap
+ Confrontation(
+ user1._1, user2._1,
+ ~(res get user1._1),
+ ~(res get ""),
+ ~(res get user2._1)
+ )
+ }
}
}
}
diff --git a/modules/user/src/main/Confrontation.scala b/modules/user/src/main/Confrontation.scala
index 9701d126ac..99baef2407 100644
--- a/modules/user/src/main/Confrontation.scala
+++ b/modules/user/src/main/Confrontation.scala
@@ -1,6 +1,11 @@
package lila.user
-case class Confrontation(wins: Int, draws: Int, losses: Int) {
+case class Confrontation(
+ user1: String,
+ user2: String,
+ wins: Int,
+ draws: Int,
+ losses: Int) {
def games = wins + draws + losses