lila/modules/pool/src/main/GameStarter.scala

86 lines
2.5 KiB
Scala

package lila.pool
import scala.concurrent.duration._
import lila.game.{ Game, GameRepo, IdGenerator, Player }
import lila.rating.Perf
import lila.user.{ User, UserRepo }
final private class GameStarter(
userRepo: UserRepo,
gameRepo: GameRepo,
idGenerator: IdGenerator,
onStart: Game.Id => Unit
)(implicit
ec: scala.concurrent.ExecutionContext,
system: akka.actor.ActorSystem
) {
import PoolApi._
private val workQueue = new lila.hub.AsyncActorSequencer(maxSize = 32, timeout = 10 seconds, name = "gameStarter")
def apply(pool: PoolConfig, couples: Vector[MatchMaking.Couple]): Funit =
couples.nonEmpty ?? {
workQueue {
val userIds = couples.flatMap(_.userIds)
userRepo.perfOf(userIds, pool.perfType) flatMap { perfs =>
idGenerator.games(couples.size) flatMap { ids =>
couples.zip(ids).map((one(pool, perfs) _).tupled).sequenceFu.map { pairings =>
lila.common.Bus.publish(Pairings(pairings.flatten.toList), "poolPairings")
}
}
}
}
}
private def one(pool: PoolConfig, perfs: Map[User.ID, Perf])(
couple: MatchMaking.Couple,
id: Game.ID
): Fu[Option[Pairing]] = {
import couple._
import cats.implicits._
(perfs.get(p1.userId), perfs.get(p2.userId)).mapN((_, _)) ?? { case (perf1, perf2) =>
for {
p1White <- userRepo.firstGetsWhite(p1.userId, p2.userId)
(whitePerf, blackPerf) = if (p1White) perf1 -> perf2 else perf2 -> perf1
(whiteMember, blackMember) = if (p1White) p1 -> p2 else p2 -> p1
game = makeGame(
id,
pool,
whiteMember.userId -> whitePerf,
blackMember.userId -> blackPerf
).start
_ <- gameRepo insertDenormalized game
} yield {
onStart(Game.Id(game.id))
Pairing(
game,
whiteSri = whiteMember.sri,
blackSri = blackMember.sri
).some
}
}
}
private def makeGame(
id: Game.ID,
pool: PoolConfig,
whiteUser: (User.ID, Perf),
blackUser: (User.ID, Perf)
) =
Game(
id = id,
chess = chess.Game(
situation = chess.Situation(chess.variant.Standard),
clock = pool.clock.toClock.some
),
whitePlayer = Player.make(chess.White, whiteUser),
blackPlayer = Player.make(chess.Black, blackUser),
mode = chess.Mode.Rated,
status = chess.Status.Created,
daysPerTurn = none,
metadata = Game.metadata(lila.game.Source.Pool)
)
}