swiss WIP

swiss
Thibault Duplessis 2020-05-04 01:38:24 -06:00
parent 1408c888d6
commit 64761dafc9
6 changed files with 81 additions and 16 deletions

View File

@ -368,6 +368,9 @@ tournament {
api_actor.name = tournament-api
pairing.delay = 3.1 seconds
}
swiss {
bbpairing = "/path/to/bbpPairings.exe"
}
simul {
collection.simul = simul
feature.views = 10000 # max frontpage views of simul per host per day

View File

@ -382,6 +382,7 @@ object mon {
}
object swiss {
def standingOverload = counter("swiss.standing.overload").withoutTags
val tick = future("swiss.tick")
}
object plan {
val paypal = histogram("plan.amount").withTag("service", "paypal")

View File

@ -1,14 +1,18 @@
package lila.swiss
import com.softwaremill.macwire._
import play.api.Configuration
import scala.concurrent.duration._
import lila.socket.Socket.{ GetVersion, SocketVersion }
import lila.common.config._
import lila.common.{ AtMost, Every, ResilientScheduler }
import lila.socket.Socket.{ GetVersion, SocketVersion }
@Module
final class Env(
remoteSocketApi: lila.socket.RemoteSocket,
appConfig: Configuration,
db: lila.db.Db,
remoteSocketApi: lila.socket.RemoteSocket,
chatApi: lila.chat.ChatApi,
cacheApi: lila.memo.CacheApi,
lightUserApi: lila.user.LightUserApi
@ -23,6 +27,10 @@ final class Env(
private val colls = wire[SwissColls]
private val pairingSystem = new PairingSystem(appConfig.get[String]("swiss.bbpairing"))
private val director = wire[SwissDirector]
val api = wire[SwissApi]
private lazy val socket = wire[SwissSocket]
@ -41,6 +49,13 @@ final class Env(
private lazy val cache: SwissCache = wire[SwissCache]
lazy val getName = new GetSwissName(cache.name.sync)
ResilientScheduler(
every = Every(2 seconds),
atMost = AtMost(15 seconds),
// initialDelay = 20 seconds
initialDelay = 5 seconds
) { api.tick }
}
private class SwissColls(db: lila.db.Db) {

View File

@ -2,6 +2,7 @@ package lila.swiss
import java.io.{ File, PrintWriter }
import scala.util.chaining._
import scala.sys.process._
final private class PairingSystem(executable: String) {
@ -10,11 +11,11 @@ final private class PairingSystem(executable: String) {
players: List[SwissPlayer],
pairings: List[SwissPairing]
): List[SwissPairing.Pending] =
writer(swiss, players, pairings) pipe invoke pipe reader
writer(swiss, players, pairings).pp pipe invoke pipe reader
private def invoke(input: String): String =
withTempFile(input) { file =>
s"$executable --dutch $file -p"
s"$executable --dutch $file -p".pp.!!
}
private def reader(output: String): List[SwissPairing.Pending] =
@ -35,6 +36,7 @@ final private class PairingSystem(executable: String) {
def apply(swiss: Swiss, players: List[SwissPlayer], pairings: List[SwissPairing]): String = {
s"XXR ${swiss.nbRounds}" ::
s"XXC ${chess.Color(scala.util.Random.nextBoolean).name}1" ::
players.map(player(swiss, SwissPairing.toMap(pairings))).map(format)
} mkString "\n"
@ -72,11 +74,12 @@ final private class PairingSystem(executable: String) {
val p = new PrintWriter(file, "UTF-8")
try {
p.write(contents)
p.flush()
val res = f(file)
file.delete()
res
} finally {
p.close()
file.delete()
}
}
}

View File

@ -1,7 +1,9 @@
package lila.swiss
import akka.stream.scaladsl._
import org.joda.time.DateTime
import ornicar.scalalib.Zero
import reactivemongo.akkastream.cursorProducer
import reactivemongo.api._
import scala.concurrent.duration._
@ -12,7 +14,8 @@ import lila.user.User
final class SwissApi(
colls: SwissColls,
socket: SwissSocket
socket: SwissSocket,
director: SwissDirector
)(
implicit ec: scala.concurrent.ExecutionContext,
mat: akka.stream.Materializer,
@ -25,8 +28,9 @@ final class SwissApi(
import BsonHandlers._
def byId(id: Swiss.Id) = colls.swiss.byId[Swiss](id.value)
def enterableById(id: Swiss.Id) = colls.swiss.byId[Swiss](id.value).dmap(_.filter(_.isEnterable))
def startedById(id: Swiss.Id) = colls.swiss.byId[Swiss](id.value).dmap(_.filter(_.isStarted))
def enterableById(id: Swiss.Id) = byId(id).dmap(_.filter(_.isEnterable))
def createdById(id: Swiss.Id) = byId(id).dmap(_.filter(_.isCreated))
def startedById(id: Swiss.Id) = byId(id).dmap(_.filter(_.isStarted))
def create(data: SwissForm.SwissData, me: User, teamId: TeamID): Fu[Swiss] = {
val swiss = Swiss(
@ -67,10 +71,10 @@ final class SwissApi(
def join(id: Swiss.Id, me: User, isInTeam: TeamID => Boolean): Fu[Boolean] = Sequencing(id)(enterableById) {
swiss =>
isInTeam(swiss.teamId) ?? {
val number = SwissPlayer.Number(swiss.nbPlayers + 1)
colls.player.insert.one(SwissPlayer.make(swiss.id, number, me, swiss.perfLens)) >>
updateNbPlayers(swiss.id) >>-
socket.reload(swiss.id) inject true
val number = SwissPlayer.Number(swiss.nbPlayers + 1).pp
colls.player.insert.one(SwissPlayer.make(swiss.id, number, me, swiss.perfLens)) zip
colls.swiss.updateField($id(swiss.id), "nbPlayers", number) >>-
socket.reload(swiss.id) inject true
}
}
@ -115,10 +119,18 @@ final class SwissApi(
else funit
}
private def updateNbPlayers(swissId: Swiss.Id): Funit =
colls.player.countSel($doc(SwissPlayer.Fields.swissId -> swissId)) flatMap {
colls.swiss.updateField($id(swissId), "nbPlayers", _).void
}
private[swiss] def tick: Funit =
colls.swiss.ext
.find($doc("startsAt" $lt DateTime.now, "finishedAt" $exists false))
.batchSize(1)
.cursor[Swiss]()
.documentSource()
.mapAsync(2)(director.apply)
.log(getClass.getName)
.toMat(Sink.ignore)(Keep.right)
.run
.monSuccess(_.swiss.tick)
.void
private def insertPairing(pairing: SwissPairing) =
colls.pairing.insert.one {

View File

@ -0,0 +1,31 @@
package lila.swiss
import lila.db.dsl._
final private class SwissDirector(
colls: SwissColls,
pairingSystem: PairingSystem
)(
implicit ec: scala.concurrent.ExecutionContext
) {
import BsonHandlers._
def apply(swiss: Swiss): Funit =
for {
players <- SwissPlayer.fields { f =>
colls.player.ext
.find($doc(f.swissId -> swiss.id))
.sort($sort asc f.number)
.list[SwissPlayer]()
}
prevPairings <- SwissPairing.fields { f =>
colls.pairing.ext
.find($doc(f.swissId -> swiss.id))
.sort($sort asc f.round)
.list[SwissPairing]()
}
} yield {
val pairings = pairingSystem(swiss, players, prevPairings)
println(pairings)
}
}