swiss models and handlers

swiss
Thibault Duplessis 2020-04-28 19:22:38 -06:00
parent 4b0199964e
commit c209918070
8 changed files with 263 additions and 2 deletions

View File

@ -54,7 +54,7 @@ lazy val modules = Seq(
playban, insight, perfStat, slack, quote, challenge,
study, studySearch, fishnet, explorer, learn, plan,
event, coach, practice, evalCache, irwin,
activity, relay, streamer, bot, clas
activity, relay, streamer, bot, clas, swiss
)
lazy val moduleRefs = modules map projectToRef
@ -253,6 +253,11 @@ lazy val tournament = module("tournament",
Seq(scalatags, lettuce) ++ reactivemongo.bundle
)
lazy val swiss = module("swiss",
Seq(common, hub, socket, game, round, security, chat, memo, i18n, room),
Seq(scalatags, lettuce) ++ reactivemongo.bundle
)
lazy val simul = module("simul",
Seq(common, hub, socket, game, round, chat, memo, quote, room),
Seq(lettuce) ++ reactivemongo.bundle

View File

@ -37,6 +37,7 @@ trait Lilaisms
with scalaz.syntax.ToValidationOps {
type StringValue = lila.base.LilaTypes.StringValue
type IntValue = lila.base.LilaTypes.IntValue
@inline implicit def toPimpedFuture[A](f: Fu[A]) = new PimpedFuture(f)
@inline implicit def toPimpedFutureBoolean(f: Fu[Boolean]) = new PimpedFutureBoolean(f)

View File

@ -0,0 +1,132 @@
package lila.swiss
import chess.Clock.{ Config => ClockConfig }
import chess.variant.Variant
import chess.StartingPosition
import lila.db.BSON
import lila.db.dsl._
import reactivemongo.api.bson._
private object BsonHandlers {
implicit private[swiss] val statusHandler = tryHandler[Status](
{ case BSONInteger(v) => Status(v) toTry s"No such status: $v" },
x => BSONInteger(x.id)
)
implicit val clockHandler = tryHandler[ClockConfig](
{
case doc: BSONDocument =>
for {
limit <- doc.getAsTry[Int]("limit")
inc <- doc.getAsTry[Int]("increment")
} yield ClockConfig(limit, inc)
},
c =>
BSONDocument(
"limit" -> c.limitSeconds,
"increment" -> c.incrementSeconds
)
)
implicit val variantHandler = lila.db.dsl.quickHandler[Variant](
{
case BSONString(v) => Variant orDefault v
case _ => Variant.default
},
v => BSONString(v.key)
)
private lazy val fenIndex: Map[String, StartingPosition] = StartingPosition.all.view.map { p =>
p.fen -> p
}.toMap
implicit val startingPositionHandler = lila.db.dsl.quickHandler[StartingPosition](
{
case BSONString(v) => fenIndex.getOrElse(v, StartingPosition.initial)
case _ => StartingPosition.initial
},
v => BSONString(v.fen)
)
implicit val playerNumberHandler = intAnyValHandler[SwissPlayer.Number](_.value, SwissPlayer.Number.apply)
implicit val playerIdHandler = tryHandler[SwissPlayer.Id](
{
case BSONString(v) =>
(v split ':' match {
case Array(swissId, number) =>
number.toIntOption map { n =>
SwissPlayer.Id(Swiss.Id(swissId), SwissPlayer.Number(n))
}
case _ => None
}) toTry s"Invalid player ID $v"
},
id => BSONString(s"${id.swissId}:${id.number}")
)
implicit val playerHandler = new BSON[SwissPlayer] {
def reads(r: BSON.Reader) = SwissPlayer(
id = r.get[SwissPlayer.Id]("_id"),
userId = r str "uid",
rating = r int "r",
provisional = r boolD "pr"
)
def writes(w: BSON.Writer, o: SwissPlayer) = $doc(
"_id" -> o.id,
"uid" -> o.userId,
"r" -> o.rating,
"pr" -> w.boolO(o.provisional)
)
}
implicit val pairingHandler = new BSON[SwissPairing] {
def reads(r: BSON.Reader) = {
val white = r.get[SwissPlayer.Number]("w")
val black = r.get[SwissPlayer.Number]("b")
SwissPairing(
gameId = r str "g",
white = white,
black = black,
winner = r boolO "w" map {
case true => white
case _ => black
}
)
}
def writes(w: BSON.Writer, o: SwissPairing) = $doc(
"g" -> o.gameId,
"w" -> o.white,
"b" -> o.black,
"w" -> o.winner.map(o.white ==)
)
}
implicit val roundNumberHandler = intAnyValHandler[SwissRound.Number](_.value, SwissRound.Number.apply)
implicit val roundIdHandler = tryHandler[SwissRound.Id](
{
case BSONString(v) =>
(v split ':' match {
case Array(swissId, number) =>
number.toIntOption map { n =>
SwissRound.Id(Swiss.Id(swissId), SwissRound.Number(n))
}
case _ => None
}) toTry s"Invalid round ID $v"
},
id => BSONString(id.toString)
)
implicit val roundHandler = new BSON[SwissRound] {
def reads(r: BSON.Reader) =
SwissRound(
id = r.get[SwissRound.Id]("_id"),
pairings = r.get[List[SwissPairing]]("p"),
byes = r.get[List[SwissPlayer.Number]]("b")
)
def writes(w: BSON.Writer, o: SwissRound) = $doc(
"id" -> o.id,
"p" -> o.pairings,
"b" -> o.byes
)
}
implicit val swissIdHandler = stringAnyValHandler[Swiss.Id](_.value, Swiss.Id.apply)
implicit val swissHandler = Macros.handler[Swiss]
}

View File

@ -0,0 +1,19 @@
package lila.clas
import com.softwaremill.macwire._
import lila.common.config._
@Module
final class Env(
db: lila.db.Db,
userRepo: lila.user.UserRepo
)(implicit ec: scala.concurrent.ExecutionContext) {
private val colls = wire[SwissColls]
}
private class SwissColls(db: lila.db.Db) {
val swiss = db(CollName("swiss"))
}

View File

@ -0,0 +1,22 @@
package lila.swiss
sealed abstract private[swiss] class Status(val id: Int) extends Ordered[Status] {
def compare(other: Status) = Integer.compare(id, other.id)
def name = toString
def is(s: Status): Boolean = this == s
}
private[swiss] object Status {
case object Created extends Status(10)
case object Started extends Status(20)
case object Finished extends Status(30)
val all = List(Created, Started, Finished)
val byId = all map { v =>
(v.id, v)
} toMap
def apply(id: Int): Option[Status] = byId get id
}

View File

@ -0,0 +1,76 @@
package lila.swiss
import org.joda.time.{ DateTime, Duration, Interval }
import ornicar.scalalib.Random
import chess.Clock.{ Config => ClockConfig }
import chess.StartingPosition
import lila.user.User
import lila.game.Game
case class Swiss(
_id: Swiss.Id,
name: String,
status: Status,
clock: ClockConfig,
variant: chess.variant.Variant,
position: StartingPosition,
rated: Boolean,
nbRounds: Int,
nbPlayers: Int,
createdAt: DateTime,
createdBy: User.ID,
startsAt: DateTime,
winnerId: Option[User.ID] = None,
description: Option[String] = None,
hasChat: Boolean = true
) {}
object Swiss {
case class Id(value: String) extends AnyVal with StringValue
case class Round(value: Int) extends AnyVal with IntValue
def makeId = Id(scala.util.Random.alphanumeric take 8 mkString)
}
case class SwissPlayer(
id: SwissPlayer.Id,
userId: User.ID,
rating: Int,
provisional: Boolean
)
object SwissPlayer {
case class Id(swissId: Swiss.Id, number: Number)
case class Number(value: Int) extends AnyVal with IntValue
}
case class SwissRound(
id: SwissRound.Id,
pairings: List[SwissPairing],
byes: List[SwissPlayer.Number]
) {}
object SwissRound {
case class Id(swissId: Swiss.Id, number: Number) {
override def toString = s"$swissId:$number"
}
case class Number(value: Int) extends AnyVal with IntValue
}
case class SwissPairing(
gameId: Game.ID,
white: SwissPlayer.Number,
black: SwissPlayer.Number,
winner: Option[SwissPlayer.Number]
)
object SwissPairing {
case class Id(value: String) extends AnyVal with StringValue
}

View File

@ -0,0 +1,6 @@
package lila
package object swiss extends PackageObject {
private[swiss] val logger = lila.log("swiss")
}

View File

@ -5,7 +5,7 @@ import lila.game.{ Game, IdGenerator }
import lila.user.User
case class Pairing(
id: Game.ID, // game Id
id: Game.ID,
tourId: Tournament.ID,
status: chess.Status,
user1: User.ID,