more tournament model and tubes

pull/83/head
Thibault Duplessis 2013-05-10 14:21:03 -03:00
parent 31565c9d0f
commit f062bf5b26
9 changed files with 234 additions and 121 deletions

View File

@ -503,7 +503,8 @@ private[game] object RawGame {
"lmt" -> none[Int],
"bm" -> none[Int],
"r960" -> none[Boolean],
"me" -> none[RawMetadata])
"me" -> none[RawMetadata],
"ua" -> none[DateTime])
private[game] lazy val tube = Tube(
(__.json update (

View File

@ -0,0 +1,39 @@
package lila.tournament
import com.typesafe.config.Config
import lila.common.PimpedConfig._
import akka.actor._
import akka.pattern.pipe
final class Env(
config: Config,
db: lila.db.Env,
system: ActorSystem,
hub: lila.hub.Env,
scheduler: lila.common.Scheduler) {
private val settings = new {
val OrganizerName = config getString "organizer.name"
val CollectionTournament = config getString "collection.tournament"
val CollectionRoom = config getString "collection.room"
val MessageTtl = config duration "message.ttl"
val MemoTtl = config duration "memo.ttl"
val UidTimeout = config duration "uid.timeout"
val HubTimeout = config duration "hub.timeout"
}
import settings._
private[tournament] lazy val tournamentColl = db(CollectionTournament)
}
object Env {
private def app = play.api.Play.current
lazy val current = "[boot] tournamen" describes new Env(
config = lila.common.PlayApp loadConfig "tournamen",
db = lila.db.Env.current,
system = lila.common.PlayApp.system,
hub = lila.hub.Env.current,
scheduler = lila.common.PlayApp.scheduler)
}

View File

@ -49,15 +49,6 @@ private[tournament] case class Pairing(
)
}
private[tournament] case class RawPairing(g: String, s: Int, u: List[String], w: Option[String], t: Option[Int]) {
def decode: Option[Pairing] = for {
status chess.Status(s)
user1 u.lift(0)
user2 u.lift(1)
} yield Pairing(g, status, user1, user2, w, t)
}
private[tournament] object Pairing {
type P = (String, String)
@ -135,3 +126,28 @@ private[tournament] object Pairing {
case _ Nil
}
}
private[tournament] case class RawPairing(g: String, s: Int, u: List[String], w: Option[String], t: Option[Int]) {
def decode: Option[Pairing] = for {
status chess.Status(s)
user1 u.lift(0)
user2 u.lift(1)
} yield Pairing(g, status, user1, user2, w, t)
}
private[tournament] object RawPairing {
import lila.db.Tube
import Tube.Helpers._
import play.api.libs.json._
private def defaults = Json.obj(
"w" -> none[String],
"t" -> none[Int])
private[tournament] lazy val tube = Tube(
(__.json update merge(defaults)) andThen Json.reads[RawPairing],
Json.writes[RawPairing]
)
}

View File

@ -22,7 +22,7 @@ private[tournament] case class Player(
private[tournament] object Player {
def apply(user: User): Player = new Player(
def make(user: User): Player = new Player(
id = user.id,
username = user.username,
elo = user.elo)
@ -66,4 +66,20 @@ private[tournament] object Player {
winStreak = bestWinSeq,
score = score)
}
import lila.db.Tube
import Tube.Helpers._
import play.api.libs.json._
private def defaults = Json.obj(
"withdraw" -> false,
"nbWin" -> 0,
"nbLoss" -> 0,
"winStreak" -> 0,
"score" -> 0)
private[tournament] lazy val tube = Tube(
(__.json update merge(defaults)) andThen Json.reads[Player],
Json.writes[Player]
)
}

View File

@ -8,7 +8,7 @@ import chess.{ Variant, Mode }
import lila.user.User
import lila.game.PovRef
case class Data(
private[tournament] case class Data(
name: String,
clock: TournamentClock,
minutes: Int,
@ -127,7 +127,7 @@ case class Created(
def join(user: User): Valid[Created] = contains(user).fold(
!!("User %s is already part of the tournament" format user.id),
withPlayers(players :+ Player(user)).success
withPlayers(players :+ Player.make(user)).success
)
def withdraw(userId: String): Valid[Created] = contains(userId).fold(
@ -217,6 +217,45 @@ case class Finished(
def encode = encode(Status.Finished)
}
object Tournament {
import lila.db.Tube
import play.api.libs.json._
private[tournament] lazy val tube = Tube(
reader = Reads[Tournament](js
~(for {
obj js.asOpt[JsObject]
rawTour RawTournament.tube.read(obj).asOpt
tour rawTour.decode
} yield JsSuccess(tour): JsResult[Tournament])
),
writer = Writes[Tournament](tour
RawTournament.tube.write(tour.encode) getOrElse JsUndefined("[db] Can't write tournament " + tour.id)
)
)
def apply(
createdBy: User,
clock: TournamentClock,
minutes: Int,
minPlayers: Int,
variant: Variant,
mode: Mode): Created = Created(
id = Random nextString 8,
data = Data(
name = RandomName(),
clock = clock,
createdBy = createdBy.id,
createdAt = DateTime.now,
variant = variant,
mode = mode,
minutes = minutes,
minPlayers = minPlayers),
players = List(Player make createdBy)
)
}
private[tournament] case class RawTournament(
id: String,
name: String,
@ -232,6 +271,8 @@ private[tournament] case class RawTournament(
variant: Int = Variant.Standard.id,
mode: Int = Mode.Casual.id) {
def decode: Option[Tournament] = created orElse started orElse finished
def created: Option[Created] = (status == Status.Created.id) option Created(
id = id,
data = Data(name, clock, minutes, minPlayers, Variant orDefault variant, Mode orDefault mode, createdAt, createdBy),
@ -266,27 +307,25 @@ private[tournament] case class RawTournament(
}
}
object Tournament {
private[tournament] object RawTournament {
import lila.common.Form._
import lila.db.Tube
import Tube.Helpers._
import play.api.libs.json._
def apply(
createdBy: User,
clock: TournamentClock,
minutes: Int,
minPlayers: Int,
variant: Variant,
mode: Mode): Created = Created(
id = Random nextString 8,
data = Data(
name = RandomName(),
clock = clock,
createdBy = createdBy.id,
createdAt = DateTime.now,
variant = variant,
mode = mode,
minutes = minutes,
minPlayers = minPlayers),
players = List(Player(createdBy))
private implicit def pairingTube = RawPairing.tube
private implicit def clockTube = TournamentClock.tube
private implicit def PlayerTube = Player.tube
private def defaults = Json.obj(
"startedAt" -> none[DateTime])
private[tournament] lazy val tube = Tube(
(__.json update (
merge(defaults) andThen readDateOpt('startedAt)
)) andThen Json.reads[RawTournament],
Json.writes[RawTournament] andThen (__.json update (
writeDateOpt('startedAt)
))
)
}

View File

@ -9,3 +9,15 @@ case class TournamentClock(limit: Int, increment: Int) {
def chessClock = chess.Clock(limit, increment)
}
object TournamentClock {
import lila.db.Tube
import Tube.Helpers._
import play.api.libs.json._
private[tournament] lazy val tube = Tube(
Json.reads[TournamentClock],
Json.writes[TournamentClock]
)
}

View File

@ -0,0 +1,77 @@
package lila.tournament
import lila.db.api._
import lila.db.Implicits._
import tube.tournamentTube
import play.api.libs.json._
import org.joda.time.DateTime
import org.scala_tools.time.Imports._
// object TournamentRepo {
// def createdById(id: String): Fu[Option[Created]] = byIdAs(id, _.created)
// def startedById(id: String): Fu[Option[Started]] = byIdAs(id, _.started)
// def createdByIdAndCreator(id: String, userId: String): Fu[Option[Created]] =
// createdById(id) map (_ filter (_ isCreator userId))
// private def byIdAs[A](id: String, as: Tournament Option[A]): Fu[Option[A]] = io {
// $find byId id map (_ flatMap as)
// }
// def created: Fu[List[Created]] =
// $find($query(
// Json.obj("status" -> Status.Created.id)) sort $sort.createdDesc
// )).toList map2 { (tour: Tournament) => tour.created }
// def started: Fu[List[Started]] = io {
// find(DBObject("status" -> Status.Started.id))
// .sort(DBObject("createdAt" -> -1))
// .toList.map(_.started).flatten
// }
// def finished(limit: Int): Fu[List[Finished]] = io {
// find(DBObject("status" -> Status.Finished.id))
// .sort(DBObject("createdAt" -> -1))
// .limit(limit)
// .toList.map(_.finished).flatten
// }
// def setUsers(tourId: String, userIds: List[String]): Fu[Unit] = io {
// update(idSelector(tourId), $set(Seq("data.users" -> userIds.distinct)))
// }
// def userHasRunningTournament(username: String): Fu[Boolean] = io {
// collection.findOne(
// ("status" $ne Status.Finished.id) ++ ("data.users" -> username)
// ).isDefined
// }
// val inProgressIds: Fu[List[String]] = io {
// primitiveProjections(DBObject("status" -> Status.Started.id), "_id")
// }
// def saveFu(tournament: Tournament): Fu[Unit] = io {
// save(tournament.encode)
// }
// def removeFu(tournament: Tournament): Fu[Unit] = io {
// remove(idSelector(tournament))
// }
// def withdraw(userId: String): Fu[List[String]] = for {
// createds created
// createdIds (createds map (_ withdraw userId) collect {
// case Success(tour) saveFu(tour) map (_ tour.id)
// }).sequence
// starteds started
// startedIds (starteds map (_ withdraw userId) collect {
// case Success(tour) saveFu(tour) map (_ tour.id)
// }).sequence
// } yield createdIds ::: startedIds
// private def idSelector(id: String): DBObject = DBObject("_id" -> id)
// private def idSelector(tournament: Tournament): DBObject = idSelector(tournament.id)
// }

View File

@ -6,7 +6,7 @@ package object tournament extends PackageObject with WithPlay {
object tube {
// private[tournament] implicit lazy val pgnTube = Tube.json inColl Env.current.pgnColl
private[tournament] implicit lazy val tournamentTube = Tournament.tube inColl Env.current.tournamentColl
}
private[tournament]type Pairings = List[tournament.Pairing]

View File

@ -1,87 +0,0 @@
package lila.app
package tournament
import com.novus.salat._
import com.novus.salat.dao._
import com.mongodb.casbah.MongoCollection
import com.mongodb.casbah.query.Imports._
import scalaz.effects._
import scalaz.Success
import org.joda.time.DateTime
import org.scala_tools.time.Imports._
import user.User
class TournamentRepo(collection: MongoCollection)
extends SalatDAO[RawTournament, String](collection) {
def byId(id: String): IO[Option[Tournament]] = byIdAs(id, _.any)
def byId(id: Option[String]): IO[Option[Tournament]] =
id.fold(io(none[Tournament])) { i byIdAs(i, _.any) }
def createdById(id: String): IO[Option[Created]] = byIdAs(id, _.created)
def startedById(id: String): IO[Option[Started]] = byIdAs(id, _.started)
def createdByIdAndCreator(id: String, userId: String): IO[Option[Created]] =
createdById(id) map { tour tour filter (_ isCreator userId) }
private def byIdAs[A](id: String, as: RawTournament Option[A]): IO[Option[A]] = io {
findOneById(id) flatMap as
}
val created: IO[List[Created]] = io {
find(DBObject("status" -> Status.Created.id))
.sort(DBObject("createdAt" -> -1))
.toList.map(_.created).flatten
}
val started: IO[List[Started]] = io {
find(DBObject("status" -> Status.Started.id))
.sort(DBObject("createdAt" -> -1))
.toList.map(_.started).flatten
}
def finished(limit: Int): IO[List[Finished]] = io {
find(DBObject("status" -> Status.Finished.id))
.sort(DBObject("createdAt" -> -1))
.limit(limit)
.toList.map(_.finished).flatten
}
def setUsers(tourId: String, userIds: List[String]): IO[Unit] = io {
update(idSelector(tourId), $set(Seq("data.users" -> userIds.distinct)))
}
def userHasRunningTournament(username: String): IO[Boolean] = io {
collection.findOne(
("status" $ne Status.Finished.id) ++ ("data.users" -> username)
).isDefined
}
val inProgressIds: IO[List[String]] = io {
primitiveProjections(DBObject("status" -> Status.Started.id), "_id")
}
def saveIO(tournament: Tournament): IO[Unit] = io {
save(tournament.encode)
}
def removeIO(tournament: Tournament): IO[Unit] = io {
remove(idSelector(tournament))
}
def withdraw(userId: String): IO[List[String]] = for {
createds created
createdIds (createds map (_ withdraw userId) collect {
case Success(tour) saveIO(tour) map (_ tour.id)
}).sequence
starteds started
startedIds (starteds map (_ withdraw userId) collect {
case Success(tour) saveIO(tour) map (_ tour.id)
}).sequence
} yield createdIds ::: startedIds
private def idSelector(id: String): DBObject = DBObject("_id" -> id)
private def idSelector(tournament: Tournament): DBObject = idSelector(tournament.id)
}