now compiles in scala 2.10 RC3
This commit is contained in:
parent
d30a675090
commit
433699382a
|
@ -58,7 +58,7 @@ object I18n extends LilaController {
|
|||
|
||||
def fetch(from: Int) = Open { implicit ctx ⇒
|
||||
JsonOk((repo findFrom from map {
|
||||
_ map (_.toMap)
|
||||
_ map (_.toJson)
|
||||
}).unsafePerformIO)
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ trait LilaController
|
|||
protected def Auth(f: Context ⇒ UserModel ⇒ Result): Action[AnyContent] =
|
||||
Auth(BodyParsers.parse.anyContent)(f)
|
||||
|
||||
protected def Auth[A](p: BodyParser[A])(f: Context ⇒ UserModel ⇒ PlainResult): Action[A] =
|
||||
protected def Auth[A](p: BodyParser[A])(f: Context ⇒ UserModel ⇒ Result): Action[A] =
|
||||
Action(p)(req ⇒ {
|
||||
val ctx = reqToCtx(req)
|
||||
ctx.me.fold(authenticationFailed(ctx.req))(me ⇒ f(ctx)(me))
|
||||
|
@ -143,7 +143,7 @@ trait LilaController
|
|||
} unsafePerformIO
|
||||
|
||||
protected def IOptionIOResult[A](ioa: IO[Option[A]])(op: A ⇒ IO[Result])(implicit ctx: Context) =
|
||||
ioa flatMap { _.fold(op)(io(notFound(ctx))) } unsafePerformIO
|
||||
ioa flatMap { _.fold(io(notFound(ctx)))(op) } unsafePerformIO
|
||||
|
||||
protected def IOptionRedirect[A](ioa: IO[Option[A]])(op: A ⇒ Call)(implicit ctx: Context) =
|
||||
ioa map {
|
||||
|
|
|
@ -9,6 +9,7 @@ import play.api.mvc._
|
|||
import play.api.libs.json.JsValue
|
||||
import play.api.libs.concurrent._
|
||||
import play.api.libs.concurrent.Execution.Implicits._
|
||||
import play.api.libs.json.Json
|
||||
import scala.concurrent.{ Future, Promise }
|
||||
import scalaz.effects._
|
||||
|
||||
|
@ -30,7 +31,7 @@ object Lobby extends LilaController with Results {
|
|||
|
||||
def handleNotFound(implicit ctx: Context): Result = Async { renderHome(none, NotFound) }
|
||||
|
||||
private def renderHome[A](myHook: Option[Hook], status: Status)(implicit ctx: Context): Promise[Result] =
|
||||
private def renderHome[A](myHook: Option[Hook], status: Status)(implicit ctx: Context): Future[Result] =
|
||||
preloader(
|
||||
auth = ctx.isAuth,
|
||||
chat = ctx.canSeeChat,
|
||||
|
@ -40,7 +41,7 @@ object Lobby extends LilaController with Results {
|
|||
tours = openTours
|
||||
).map(_.fold(Redirect(_), {
|
||||
case (preload, posts, tours, featured) ⇒ status(html.lobby.home(
|
||||
toJson(preload),
|
||||
Json stringify preload,
|
||||
myHook,
|
||||
posts,
|
||||
tours,
|
||||
|
@ -60,7 +61,7 @@ object Lobby extends LilaController with Results {
|
|||
def hook(ownerId: String) = Open { implicit ctx ⇒
|
||||
Async {
|
||||
hookRepo.ownedHook(ownerId).unsafePerformIO.fold(
|
||||
Promise pure { Redirect(routes.Lobby.home) }
|
||||
Future successful { Redirect(routes.Lobby.home): Result }
|
||||
) { hook ⇒ renderHome(hook.some, Ok) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,33 +3,33 @@ package controllers
|
|||
import lila._
|
||||
|
||||
import play.api.http._
|
||||
import scala.io.Codec
|
||||
import play.api.mvc.Codec
|
||||
|
||||
trait ResponseWriter {
|
||||
|
||||
// I like Unit requests.
|
||||
implicit def wUnit: Writeable[Unit] =
|
||||
Writeable[Unit](_ ⇒ Codec toUTF8 "ok")
|
||||
implicit def wUnit(implicit codec: Codec): Writeable[Unit] =
|
||||
Writeable[Unit]((_: Unit) ⇒ codec encode "ok")
|
||||
implicit def ctoUnit: ContentTypeOf[Unit] =
|
||||
ContentTypeOf[Unit](Some(ContentTypes.TEXT))
|
||||
|
||||
implicit def wFloat: Writeable[Float] =
|
||||
Writeable[Float](f ⇒ Codec toUTF8 f.toString)
|
||||
implicit def wFloat(implicit codec: Codec): Writeable[Float] =
|
||||
Writeable[Float]((f: Float) ⇒ codec encode f.toString)
|
||||
implicit def ctoFloat: ContentTypeOf[Float] =
|
||||
ContentTypeOf[Float](Some(ContentTypes.TEXT))
|
||||
|
||||
implicit def wLong: Writeable[Long] =
|
||||
Writeable[Long](a ⇒ Codec toUTF8 a.toString)
|
||||
implicit def wLong(implicit codec: Codec): Writeable[Long] =
|
||||
Writeable[Long]((a: Long) ⇒ codec encode a.toString)
|
||||
implicit def ctoLong: ContentTypeOf[Long] =
|
||||
ContentTypeOf[Long](Some(ContentTypes.TEXT))
|
||||
|
||||
implicit def wInt: Writeable[Int] =
|
||||
Writeable[Int](i ⇒ Codec toUTF8 i.toString)
|
||||
implicit def wInt(implicit codec: Codec): Writeable[Int] =
|
||||
Writeable[Int]((i: Int) ⇒ codec encode i.toString)
|
||||
implicit def ctoInt: ContentTypeOf[Int] =
|
||||
ContentTypeOf[Int](Some(ContentTypes.TEXT))
|
||||
|
||||
implicit def wOptionString: Writeable[Option[String]] =
|
||||
Writeable[Option[String]](i ⇒ Codec toUTF8 i.getOrElse(""))
|
||||
implicit def wOptionString(implicit codec: Codec): Writeable[Option[String]] =
|
||||
Writeable[Option[String]]((i: Option[String]) ⇒ codec encode ~i)
|
||||
implicit def ctoOptionString: ContentTypeOf[Option[String]] =
|
||||
ContentTypeOf[Option[String]](Some(ContentTypes.TEXT))
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ object User extends LilaController {
|
|||
}
|
||||
|
||||
val autocomplete = Action { implicit req ⇒
|
||||
get("term", req).filter(""!=).fold(BadRequest("No search term provided")) { term ⇒
|
||||
get("term", req).filter(""!=).fold(BadRequest("No search term provided"): PlainResult) { term ⇒
|
||||
JsonOk((userRepo usernamesLike term).unsafePerformIO)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -305,7 +305,7 @@ case class DbGame(
|
|||
def isBeingPlayed =
|
||||
!finishedOrAborted && updatedAt.fold(false)(_ > DateTime.now - 20.seconds)
|
||||
|
||||
def abandoned = updatedAt.fold(false) { u =>
|
||||
def abandoned = updatedAt.fold(false) { u ⇒
|
||||
(status <= Status.Started) && (u <= DbGame.abandonedDate)
|
||||
}
|
||||
|
||||
|
@ -343,7 +343,7 @@ case class DbGame(
|
|||
def averageUsersElo = userElos match {
|
||||
case a :: b :: Nil ⇒ Some((a + b) / 2)
|
||||
case a :: Nil ⇒ Some((a + 1200) / 2)
|
||||
case Nil ⇒ None
|
||||
case _ ⇒ None
|
||||
}
|
||||
|
||||
def with960Rematch(v: Boolean) = this.copy(is960Rematch = v)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package lila
|
||||
package game
|
||||
|
||||
import chess._
|
||||
import chess.{ Pos, Piece, Color }
|
||||
import user.User
|
||||
|
||||
case class DbPlayer(
|
||||
|
@ -123,10 +123,10 @@ case class RawDbPlayer(
|
|||
isWinner = w,
|
||||
elo = elo,
|
||||
eloDiff = ed,
|
||||
isOfferingDraw = isOfferingDraw | false,
|
||||
isOfferingRematch = isOfferingRematch | false,
|
||||
isOfferingDraw = ~isOfferingDraw,
|
||||
isOfferingRematch = ~isOfferingRematch,
|
||||
lastDrawOffer = lastDrawOffer,
|
||||
isProposingTakeback = isProposingTakeback | false,
|
||||
isProposingTakeback = ~isProposingTakeback,
|
||||
userId = uid,
|
||||
moveTimes = mts | "",
|
||||
blurs = bs | 0
|
||||
|
|
|
@ -43,7 +43,7 @@ final class Export(user: User, gameRepo: GameRepo) {
|
|||
game.mode,
|
||||
game.clock.fold("unlimited") { c ⇒
|
||||
"%d %d".format(c.limitInMinutes, c.increment)
|
||||
}
|
||||
},
|
||||
(player flatMap (_.elo)).fold("?")(_.toString),
|
||||
(player flatMap (_.eloDiff)).fold("?")(showEloDiff),
|
||||
(player map game.opponent flatMap (_.elo)).fold("?")(_.toString),
|
||||
|
|
|
@ -22,12 +22,12 @@ trait GameHelper { self: I18nHelper with UserHelper with StringHelper with AiHel
|
|||
}
|
||||
|
||||
def clockName(clock: Option[Clock])(implicit ctx: Context): String =
|
||||
clock.fold(Namer.clock, trans.unlimited.str())
|
||||
clock.fold(trans.unlimited.str())(Namer.clock)
|
||||
|
||||
def clockName(clock: Clock): String = Namer clock clock
|
||||
|
||||
def shortClockName(clock: Option[Clock])(implicit ctx: Context): String =
|
||||
clock.fold(Namer.shortClock, trans.unlimited.str())
|
||||
clock.fold(trans.unlimited.str())(Namer.shortClock)
|
||||
|
||||
def shortClockName(clock: Clock): String = Namer shortClock clock
|
||||
|
||||
|
|
|
@ -56,13 +56,13 @@ final class GameRepo(collection: MongoCollection)
|
|||
update(idSelector(game), _grater asDBObject game.encode)
|
||||
}
|
||||
|
||||
def save(progress: Progress): IO[Unit] =
|
||||
def save(progress: Progress): IO[Unit] =
|
||||
GameDiff(progress.origin.encode, progress.game.encode) |> {
|
||||
case (Nil, Nil) ⇒ io()
|
||||
case (sets, unsets) ⇒ {
|
||||
val fullSets = ("ua" -> new Date) :: sets
|
||||
val ops = unsets.isEmpty.fold(
|
||||
$set(fullSets),
|
||||
$set(fullSets),
|
||||
$set(fullSets) ++ $unset(unsets)
|
||||
)
|
||||
val wc = WriteConcern.None
|
||||
|
@ -92,22 +92,19 @@ final class GameRepo(collection: MongoCollection)
|
|||
def finish(id: String, winnerId: Option[String]) = io {
|
||||
update(
|
||||
idSelector(id),
|
||||
winnerId.fold(userId ⇒
|
||||
$set(Seq("wid" -> userId)),
|
||||
$set(Seq.empty))
|
||||
++ $unset(Seq(
|
||||
"c.t",
|
||||
"ph",
|
||||
"lmt",
|
||||
"p.0.previousMoveTs",
|
||||
"p.1.previousMoveTs",
|
||||
"p.0.lastDrawOffer",
|
||||
"p.1.lastDrawOffer",
|
||||
"p.0.isOfferingDraw",
|
||||
"p.1.isOfferingDraw",
|
||||
"p.0.isProposingTakeback",
|
||||
"p.1.isProposingTakeback"
|
||||
))
|
||||
(winnerId.fold($set(Seq.empty)) { userId ⇒ $set(Seq("wid" -> userId)) }) ++ $unset(Seq(
|
||||
"c.t",
|
||||
"ph",
|
||||
"lmt",
|
||||
"p.0.previousMoveTs",
|
||||
"p.1.previousMoveTs",
|
||||
"p.0.lastDrawOffer",
|
||||
"p.1.lastDrawOffer",
|
||||
"p.0.isOfferingDraw",
|
||||
"p.1.isOfferingDraw",
|
||||
"p.0.isProposingTakeback",
|
||||
"p.1.isProposingTakeback"
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ abstract class Handler(gameRepo: GameRepo) extends core.Futuristic {
|
|||
|
||||
protected def fromPov[A](povIO: IO[Option[Pov]])(op: Pov ⇒ IO[Valid[A]]): IO[Valid[A]] =
|
||||
povIO flatMap { povOption ⇒
|
||||
povOption.fold(io { "No such game".failNel })(op)
|
||||
povOption.fold(io { !![A]("No such game") })(op)
|
||||
}
|
||||
|
||||
protected def fromPovFuture[A](ref: PovRef)(op: Pov ⇒ Future[Valid[A]]): Future[Valid[A]] =
|
||||
|
@ -32,6 +32,6 @@ abstract class Handler(gameRepo: GameRepo) extends core.Futuristic {
|
|||
|
||||
protected def fromPovFuture[A](povIO: IO[Option[Pov]])(op: Pov ⇒ Future[Valid[A]]): Future[Valid[A]] =
|
||||
povIO.toFuture flatMap { povOption ⇒
|
||||
povOption.fold(Future("No such game".failNel))(op)
|
||||
povOption.fold(Future(!![A]("No such game")))(op)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ case class RawDbClock(
|
|||
increment = i,
|
||||
limit = l,
|
||||
whiteTime = w,
|
||||
blackTime = b)) { timer ⇒
|
||||
blackTime = b): Clock) { timer ⇒
|
||||
RunningClock(
|
||||
color = Color(c),
|
||||
increment = i,
|
||||
|
|
|
@ -17,7 +17,7 @@ object LilaCookie {
|
|||
def cookie(name: String, value: String, maxAge: Option[Int] = None)(implicit req: RequestHeader): Cookie = Cookie(
|
||||
name,
|
||||
value,
|
||||
maxAge | Session.maxAge,
|
||||
maxAge orElse Session.maxAge orElse 86400.some,
|
||||
"/",
|
||||
domain(req).some,
|
||||
Session.secure,
|
||||
|
|
|
@ -27,11 +27,9 @@ final class Setting(ctx: Context) {
|
|||
} getOrElse default
|
||||
|
||||
private def set(name: String, value: String)(userRepo: UserRepo): IO[Cookie] =
|
||||
ctx.me.fold(io()) { m ⇒
|
||||
userRepo.saveSetting(m, name, value.toString)
|
||||
} map { _ ⇒
|
||||
LilaCookie.session(name, value.toString)(ctx.req)
|
||||
}
|
||||
~(ctx.me map { m ⇒
|
||||
userRepo.saveSetting(m, name, value.toString).void
|
||||
}) inject LilaCookie.session(name, value.toString)(ctx.req)
|
||||
}
|
||||
|
||||
object Setting {
|
||||
|
|
|
@ -3,22 +3,23 @@ package i18n
|
|||
|
||||
import com.novus.salat.annotations.Key
|
||||
import org.joda.time.DateTime
|
||||
import play.api.libs.json.{ Json, JsObject }
|
||||
|
||||
case class Translation(
|
||||
@Key("_id") id: Int,
|
||||
code: String, // 2-chars code
|
||||
text: String,
|
||||
author: Option[String],
|
||||
comment: Option[String],
|
||||
createdAt: DateTime = DateTime.now) {
|
||||
@Key("_id") id: Int,
|
||||
code: String, // 2-chars code
|
||||
text: String,
|
||||
author: Option[String],
|
||||
comment: Option[String],
|
||||
createdAt: DateTime = DateTime.now) {
|
||||
|
||||
def toMap = Map(
|
||||
"id" -> id,
|
||||
"code" -> code,
|
||||
"text" -> text,
|
||||
"author" -> author,
|
||||
"comment" -> comment,
|
||||
"createdAt" -> createdAt.getMillis)
|
||||
def toJson: JsObject = Json.obj(
|
||||
"id" -> id,
|
||||
"code" -> code,
|
||||
"text" -> text,
|
||||
"author" -> author,
|
||||
"comment" -> comment,
|
||||
"createdAt" -> createdAt.getMillis)
|
||||
|
||||
def lines = text.split("\n").toList
|
||||
def lines = text.split("\n").toList
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import user.User
|
|||
|
||||
import com.novus.salat.annotations.Key
|
||||
import ornicar.scalalib.Random
|
||||
import play.api.libs.json.{ Json, JsObject }
|
||||
|
||||
case class Hook(
|
||||
@Key("_id") id: String,
|
||||
|
@ -34,7 +35,7 @@ case class Hook(
|
|||
|
||||
lazy val realEloRange: Option[EloRange] = EloRange noneIfDefault eloRange
|
||||
|
||||
def render = Map(
|
||||
def render: JsObject = Json.obj(
|
||||
"id" -> id,
|
||||
"username" -> username,
|
||||
"elo" -> elo,
|
||||
|
@ -43,8 +44,9 @@ case class Hook(
|
|||
"color" -> color,
|
||||
"clock" -> clockOrUnlimited,
|
||||
"emin" -> realEloRange.map(_.min),
|
||||
"emax" -> realEloRange.map(_.max)
|
||||
) +? (engine, "engine" -> true)
|
||||
"emax" -> realEloRange.map(_.max),
|
||||
"engine" -> engine
|
||||
)
|
||||
|
||||
def clockOrUnlimited =
|
||||
((time filter (_ ⇒ hasClock)) |@| increment apply renderClock _) | "Unlimited"
|
||||
|
|
|
@ -51,13 +51,13 @@ final class Hub(
|
|||
case AddHook(hook) ⇒ notifyVersion("hook_add", Seq(
|
||||
"id" -> JsString(hook.id),
|
||||
"username" -> JsString(hook.username),
|
||||
"elo" -> hook.elo.fold(JsNull)(JsNumber(_)),
|
||||
"elo" -> Json.toJson(hook.elo),
|
||||
"mode" -> JsString(hook.realMode.toString),
|
||||
"variant" -> JsString(hook.realVariant.toString),
|
||||
"color" -> JsString(hook.color),
|
||||
"clock" -> JsString(hook.clockOrUnlimited),
|
||||
"emin" -> hook.realEloRange.fold(range ⇒ JsNumber(range.min), JsNull),
|
||||
"emax" -> hook.realEloRange.fold(range ⇒ JsNumber(range.max), JsNull),
|
||||
"emin" -> Json.toJson(hook.realEloRange.map(_.min)),
|
||||
"emax" -> Json.toJson(hook.realEloRange.map(_.max)),
|
||||
"engine" -> JsBoolean(hook.engine))
|
||||
)
|
||||
|
||||
|
|
|
@ -4,13 +4,14 @@ package lobby
|
|||
import com.novus.salat.annotations.Key
|
||||
import org.bson.types.ObjectId
|
||||
import org.joda.time.DateTime
|
||||
import play.api.libs.json.{ Json, JsObject }
|
||||
|
||||
case class Message(
|
||||
@Key("_id") id: ObjectId = new ObjectId,
|
||||
username: String,
|
||||
text: String) {
|
||||
|
||||
def render = Map("txt" -> text, "u" -> username)
|
||||
def render: JsObject = Json.obj("txt" -> text, "u" -> username)
|
||||
|
||||
def createdAt = new DateTime(id.getTime)
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import tournament.Created
|
|||
import play.api.mvc.Call
|
||||
import play.api.libs.concurrent.Akka
|
||||
import play.api.Play.current
|
||||
import play.api.libs.json.{ Json, JsObject, JsArray }
|
||||
import scala.concurrent.Future
|
||||
import scala.concurrent.duration._
|
||||
import akka.util.Timeout
|
||||
|
@ -26,7 +27,7 @@ final class Preload(
|
|||
|
||||
private implicit val executor = Akka.system.dispatcher
|
||||
private implicit val timeout = Timeout(1 second)
|
||||
private type RightResponse = (Map[String, Any], List[PostView], List[Created], Option[DbGame])
|
||||
private type RightResponse = (JsObject, List[PostView], List[Created], Option[DbGame])
|
||||
private type Response = Either[Call, RightResponse]
|
||||
|
||||
def apply(
|
||||
|
@ -43,7 +44,7 @@ final class Preload(
|
|||
ioToFuture(posts) zip
|
||||
ioToFuture(tours) zip
|
||||
featured.one map {
|
||||
case (((((hooks, messages), entries), posts), tours), feat) ⇒ (Right((Map(
|
||||
case (((((hooks, messages), entries), posts), tours), feat) ⇒ (Right((Json.obj(
|
||||
"version" -> history.version,
|
||||
"pool" -> renderHooks(hooks, myHook),
|
||||
"chat" -> (messages.reverse map (_.render)),
|
||||
|
@ -51,10 +52,9 @@ final class Preload(
|
|||
), posts, tours, feat))): Response
|
||||
}) { gameId ⇒
|
||||
futureGame(gameId) map { gameOption ⇒
|
||||
Left(gameOption.fold(
|
||||
game ⇒ routes.Round.player(game fullIdOf game.creatorColor),
|
||||
routes.Lobby.home()
|
||||
)): Response
|
||||
Left(gameOption.fold(routes.Lobby.home()) { game ⇒
|
||||
routes.Round.player(game fullIdOf game.creatorColor)
|
||||
}): Response
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,9 +76,11 @@ final class Preload(
|
|||
|
||||
private def renderHooks(
|
||||
hooks: List[Hook],
|
||||
myHook: Option[Hook]) = hooks map { h ⇒
|
||||
myHook.exists(_.id == h.id).fold(
|
||||
h.render ++ Map("ownerId" -> h.ownerId),
|
||||
h.render)
|
||||
myHook: Option[Hook]): JsArray = JsArray {
|
||||
hooks map { h ⇒
|
||||
myHook.exists(_.id == h.id).fold(
|
||||
h.render ++ Json.obj("ownerId" -> h.ownerId),
|
||||
h.render)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ final class Socket(hub: ActorRef, flood: Flood) {
|
|||
uidOption: Option[String],
|
||||
username: Option[String],
|
||||
versionOption: Option[Int],
|
||||
hook: Option[String]): SocketPromise = {
|
||||
hook: Option[String]): SocketFuture = {
|
||||
val promise = for {
|
||||
version ← versionOption
|
||||
uid ← uidOption
|
||||
|
|
|
@ -8,13 +8,14 @@ import scala.concurrent.duration._
|
|||
import akka.util.Timeout
|
||||
|
||||
import play.api.Play.current
|
||||
import play.api.libs.concurrent.Execution.Implicits._
|
||||
import play.api.libs.concurrent._
|
||||
|
||||
import com.google.common.cache.LoadingCache
|
||||
|
||||
final class ActorMemo[K, V] private (
|
||||
cache: LoadingCache[K, V],
|
||||
atMost: Duration,
|
||||
atMost: FiniteDuration,
|
||||
valMan: Manifest[V]) {
|
||||
|
||||
def apply(key: K): V = Await.result(async(key), atMost)
|
||||
|
@ -33,7 +34,7 @@ final class ActorMemo[K, V] private (
|
|||
|
||||
object ActorMemo {
|
||||
|
||||
def apply[K, V](load: K ⇒ V, ttl: Int, atMost: Duration)(
|
||||
def apply[K, V](load: K ⇒ V, ttl: Int, atMost: FiniteDuration)(
|
||||
implicit valMan: Manifest[V]) = new ActorMemo(
|
||||
cache = Builder.cache[K, V](ttl, load),
|
||||
atMost = atMost,
|
||||
|
|
|
@ -12,6 +12,7 @@ import scala.concurrent.{ Future, Promise }
|
|||
import play.api.libs.concurrent._
|
||||
import play.api.Play.current
|
||||
import scala.io.Source
|
||||
import scala.util.{ Success, Failure }
|
||||
import java.lang.management.ManagementFactory
|
||||
import com.mongodb.casbah.MongoDB
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ package object lila
|
|||
|
||||
type JsChannel = Channel[JsValue]
|
||||
type JsEnumerator = Enumerator[JsValue]
|
||||
type SocketPromise = Promise[(Iteratee[JsValue, _], JsEnumerator)]
|
||||
type SocketFuture = Future[(Iteratee[JsValue, _], JsEnumerator)]
|
||||
|
||||
// custom salat context
|
||||
|
|
|
@ -23,7 +23,8 @@ final class Finisher(
|
|||
indexGame: DbGame ⇒ IO[Unit],
|
||||
tournamentOrganizerActorName: String) {
|
||||
|
||||
type ValidIOEvents = Valid[IO[List[Event]]]
|
||||
type IOEvents = IO[List[Event]]
|
||||
type ValidIOEvents = Valid[IOEvents]
|
||||
|
||||
private lazy val tournamentOrganizerActor =
|
||||
Akka.system.actorFor("/user/" + tournamentOrganizerActorName)
|
||||
|
@ -56,7 +57,7 @@ final class Finisher(
|
|||
else !!("opponent is not proposing a draw")
|
||||
|
||||
def outoftime(game: DbGame): ValidIOEvents = game.outoftimePlayer.fold(
|
||||
!!("no outoftime applicable " + game.clock.fold("-")(_.remainingTimes.toString))
|
||||
!![IOEvents]("no outoftime applicable " + game.clock.fold("-")(_.remainingTimes.toString))
|
||||
) { player ⇒
|
||||
finish(game, Outoftime, Some(!player.color) filter game.toChess.board.hasEnoughMaterialToMate)
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ final class Socket(
|
|||
colorName: String,
|
||||
version: Option[Int],
|
||||
uid: Option[String],
|
||||
ctx: Context): IO[SocketPromise] =
|
||||
ctx: Context): IO[SocketFuture] =
|
||||
getWatcherPov(gameId, colorName) map { join(_, false, version, uid, none, ctx) }
|
||||
|
||||
def joinPlayer(
|
||||
|
@ -121,7 +121,7 @@ final class Socket(
|
|||
version: Option[Int],
|
||||
uid: Option[String],
|
||||
token: Option[String],
|
||||
ctx: Context): IO[SocketPromise] = {
|
||||
ctx: Context): IO[SocketFuture] = {
|
||||
getPlayerPov(fullId) map { join(_, true, version, uid, token, ctx) }
|
||||
}
|
||||
|
||||
|
@ -161,7 +161,7 @@ final class Socket(
|
|||
enumerator)
|
||||
}
|
||||
}
|
||||
} yield socket): SocketPromise
|
||||
} yield socket): SocketFuture
|
||||
}) | connectionFail
|
||||
|
||||
// full game ids that have been hijacked
|
||||
|
|
|
@ -4,6 +4,7 @@ package search
|
|||
import game.DbGame
|
||||
import chess.{ OpeningExplorer, Status }
|
||||
|
||||
import play.api.libs.json.{ Json, JsObject, JsString, JsNumber }
|
||||
import org.joda.time.format.{ DateTimeFormat, DateTimeFormatter }
|
||||
|
||||
object Game {
|
||||
|
@ -23,16 +24,23 @@ object Game {
|
|||
}
|
||||
import fields._
|
||||
|
||||
def mapping = {
|
||||
def field(name: String, typ: String, analyzed: Boolean = false, attrs: Map[String, Any] = Map.empty) =
|
||||
name -> (Map(
|
||||
def jsonMapping: JsObject = {
|
||||
|
||||
def field(
|
||||
name: String,
|
||||
typ: String,
|
||||
analyzed: Boolean = false,
|
||||
attrs: JsObject = JsObject(Nil)): (String, JsObject) =
|
||||
name -> (Json.obj(
|
||||
"type" -> typ,
|
||||
"index" -> analyzed.fold("analyzed", "not_analyzed")
|
||||
) ++ attrs)
|
||||
def obj(name: String, properties: Map[String, Any]) =
|
||||
name -> Map("type" -> "object", "properties" -> properties)
|
||||
Map(
|
||||
"properties" -> List(
|
||||
|
||||
def obj(name: String, properties: JsObject) =
|
||||
name -> Json.obj("type" -> "object", "properties" -> properties)
|
||||
|
||||
Json.obj(
|
||||
"properties" -> JsObject(List(
|
||||
field(status, "short"),
|
||||
field(turns, "short"),
|
||||
field(rated, "boolean"),
|
||||
|
@ -42,27 +50,25 @@ object Game {
|
|||
field(averageElo, "short"),
|
||||
field(ai, "short"),
|
||||
field(opening, "string"),
|
||||
field(date, "date", attrs = Map("format" -> dateFormat)),
|
||||
field(date, "date", attrs = Json.obj("format" -> dateFormat)),
|
||||
field(duration, "short")
|
||||
).toMap
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
def from(pgn: String)(game: DbGame) = game.id -> (List(
|
||||
status -> game.status.is(_.Timeout).fold(Status.Resign, game.status).id.some,
|
||||
turns -> Some(math.ceil(game.turns.toFloat / 2)),
|
||||
rated -> game.rated.some,
|
||||
variant -> game.variant.id.some,
|
||||
uids -> (game.userIds.toNel map (_.list)),
|
||||
winner -> (game.winner flatMap (_.userId)),
|
||||
averageElo -> game.averageUsersElo,
|
||||
ai -> game.aiLevel,
|
||||
date -> (dateFormatter print game.createdAt).some,
|
||||
duration -> game.estimateTotalTime.some,
|
||||
opening -> (OpeningExplorer openingOf pgn map (_.code.toLowerCase))
|
||||
) collect {
|
||||
case (x, Some(y)) ⇒ x -> y
|
||||
}).toMap
|
||||
def from(pgn: String)(game: DbGame) = game.id -> Json.obj(
|
||||
status -> game.status.is(_.Timeout).fold(Status.Resign, game.status).id,
|
||||
turns -> math.ceil(game.turns.toFloat / 2),
|
||||
rated -> game.rated,
|
||||
variant -> game.variant.id,
|
||||
uids -> game.userIds,
|
||||
winner -> Json.toJson(game.winner flatMap (_.userId)),
|
||||
averageElo -> Json.toJson(game.averageUsersElo),
|
||||
ai -> Json.toJson(game.aiLevel),
|
||||
date -> (dateFormatter print game.createdAt),
|
||||
duration -> game.estimateTotalTime,
|
||||
opening -> Json.toJson(OpeningExplorer openingOf pgn map (_.code.toLowerCase))
|
||||
)
|
||||
|
||||
private val dateFormat = "YYYY-MM-dd HH:mm:ss"
|
||||
val dateFormatter: DateTimeFormatter = DateTimeFormat forPattern dateFormat
|
||||
|
|
|
@ -45,7 +45,7 @@ final class Indexer(
|
|||
} map (_ ⇒ ()) except { e ⇒ putStrLn("Index does not exist yet") } map { _ ⇒
|
||||
es.createIndex(indexName, settings = Map())
|
||||
es.waitTillActive()
|
||||
es.putMapping(indexName, typeName, Json toJson Map(typeName -> Game.mapping))
|
||||
es.putMapping(indexName, typeName, Json stringify Json.obj(typeName -> Game.jsonMapping))
|
||||
es.refresh()
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ final class Indexer(
|
|||
case (game, pgn) ⇒ game.decode map Game.from(pgn)
|
||||
} collect {
|
||||
case Some((id, doc)) ⇒
|
||||
es.index_prepare(indexName, typeName, id, Json toJson doc).request
|
||||
es.index_prepare(indexName, typeName, id, Json stringify doc).request
|
||||
}
|
||||
if (actions.nonEmpty) {
|
||||
es bulk actions
|
||||
|
|
|
@ -6,13 +6,11 @@ import org.joda.time.DateTime
|
|||
|
||||
final class Range[A] private (val a: Option[A], val b: Option[A]) {
|
||||
|
||||
def filters(name: String) = a.fold(
|
||||
aa ⇒ b.fold(
|
||||
bb ⇒ List(rangeFilter(name) gte aa lte bb),
|
||||
List(rangeFilter(name) gte aa)
|
||||
),
|
||||
b.toList map { bb ⇒ rangeFilter(name) lte bb }
|
||||
)
|
||||
def filters(name: String) = a.fold(b.toList map { bb ⇒ rangeFilter(name) lte bb }) { aa ⇒
|
||||
b.fold(List(rangeFilter(name) gte aa)) { bb ⇒
|
||||
List(rangeFilter(name) gte aa lte bb)
|
||||
}
|
||||
}
|
||||
|
||||
def map[B](f: A ⇒ B) = new Range(a map f, b map f)
|
||||
|
||||
|
@ -26,7 +24,7 @@ object Range {
|
|||
case (Some(aa), Some(bb)) ⇒ o.lt(aa, bb).fold(
|
||||
new Range(a, b), new Range(b, a)
|
||||
)
|
||||
case (x, y) ⇒ new Range(x, y)
|
||||
case (x, y) ⇒ new Range(x, y)
|
||||
}
|
||||
|
||||
def none[A]: Range[A] = new Range(None, None)
|
||||
|
|
|
@ -31,7 +31,7 @@ trait AuthImpl {
|
|||
protected def logoutSucceeded(req: RequestHeader): PlainResult =
|
||||
Redirect(routes.Lobby.home)
|
||||
|
||||
protected def authenticationFailed(implicit req: RequestHeader): PlainResult =
|
||||
protected def authenticationFailed(implicit req: RequestHeader): Result =
|
||||
Redirect(routes.Auth.signup) withCookies LilaCookie.session("access_uri", req.uri)
|
||||
|
||||
protected def saveAuthentication(username: String)(implicit req: RequestHeader): String =
|
||||
|
@ -60,7 +60,7 @@ trait AuthImpl {
|
|||
Redirect(uri)
|
||||
}
|
||||
|
||||
protected def authorizationFailed(req: RequestHeader): PlainResult =
|
||||
protected def authorizationFailed(req: RequestHeader): Result =
|
||||
Forbidden("no permission")
|
||||
|
||||
protected def authenticateUser(username: String, password: String): Option[User] =
|
||||
|
|
|
@ -17,22 +17,21 @@ final class Firewall(
|
|||
enabled: Boolean) {
|
||||
|
||||
val requestHandler: (RequestHeader ⇒ Option[Handler]) = enabled.fold(
|
||||
cookieName.fold(
|
||||
cn ⇒ req ⇒ {
|
||||
cookieName.fold((_: RequestHeader) ⇒ none[Handler]) { cn ⇒
|
||||
req ⇒ {
|
||||
val bIp = blocksIp(req.remoteAddress)
|
||||
val bCs = blocksCookies(req.cookies, cn)
|
||||
if (bIp && !bCs) infectCookie(cn)(req).some
|
||||
else if (bCs && !bIp) { blockIp(req.remoteAddress); none }
|
||||
else none
|
||||
},
|
||||
_ ⇒ None),
|
||||
}
|
||||
},
|
||||
_ ⇒ None)
|
||||
|
||||
val blocks: (RequestHeader) ⇒ Boolean = enabled.fold(
|
||||
cookieName.fold(
|
||||
cn ⇒ req ⇒ (blocksIp(req.remoteAddress) || blocksCookies(req.cookies, cn)),
|
||||
req ⇒ blocksIp(req.remoteAddress)
|
||||
),
|
||||
cookieName.fold((req: RequestHeader) ⇒ blocksIp(req.remoteAddress)) { cn ⇒
|
||||
req ⇒ (blocksIp(req.remoteAddress) || blocksCookies(req.cookies, cn))
|
||||
},
|
||||
_ ⇒ false)
|
||||
|
||||
def accepts(req: RequestHeader): Boolean = !blocks(req)
|
||||
|
|
|
@ -34,16 +34,10 @@ final class Flood {
|
|||
}
|
||||
|
||||
private def duplicateMessage(msg: Message, msgs: Messages): Boolean =
|
||||
msgs.headOption.fold(
|
||||
m ⇒ (m same msg) || msgs.tail.headOption.fold(
|
||||
_ same msg,
|
||||
false
|
||||
),
|
||||
false)
|
||||
~(msgs.headOption map { m ⇒
|
||||
(m same msg) || ~(msgs.tail.headOption map (_ same msg))
|
||||
})
|
||||
|
||||
private def quickPost(msg: Message, msgs: Messages): Boolean =
|
||||
(msgs lift floodNumber).fold(
|
||||
old ⇒ old.date > (msg.date - floodDelay.millis),
|
||||
false
|
||||
)
|
||||
~(msgs lift floodNumber map (old ⇒ old.date > (msg.date - floodDelay.millis)))
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@ import user.User
|
|||
|
||||
object Granter {
|
||||
|
||||
def apply(permission: Permission)(user: User): Boolean =
|
||||
def apply(permission: Permission)(user: User): Boolean =
|
||||
Permission(user.roles) exists (_ is permission)
|
||||
|
||||
def option(permission: Permission)(user: Option[User]): Boolean =
|
||||
user.fold(apply(permission), false)
|
||||
def option(permission: Permission)(user: Option[User]): Boolean =
|
||||
~user.map(apply(permission))
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import http.Context
|
|||
trait SecurityHelper {
|
||||
|
||||
def isGranted(permission: Permission)(implicit ctx: Context): Boolean =
|
||||
ctx.me.fold(Granter(permission), false)
|
||||
~ctx.me.map(Granter(permission))
|
||||
|
||||
def isGranted(permission: Permission, user: User): Boolean =
|
||||
Granter(permission)(user)
|
||||
|
|
|
@ -35,7 +35,7 @@ final class Store(collection: MongoCollection) {
|
|||
def delete(sessionId: String) {
|
||||
collection.update(
|
||||
DBObject("_id" -> sessionId),
|
||||
$set("up" -> false))
|
||||
$set(Seq("up" -> false)))
|
||||
}
|
||||
|
||||
// useful when closing an account,
|
||||
|
@ -43,7 +43,7 @@ final class Store(collection: MongoCollection) {
|
|||
def deleteUsername(username: String) {
|
||||
collection.update(
|
||||
DBObject("user" -> normalize(username)),
|
||||
$set("up" -> false))
|
||||
$set(Seq("up" -> false)))
|
||||
}
|
||||
|
||||
def userSpy(username: String): IO[UserSpy] = io {
|
||||
|
|
|
@ -27,10 +27,10 @@ final class FormFactory(
|
|||
)(AiConfig.<<)(_.>>)
|
||||
)
|
||||
|
||||
def aiConfig(implicit ctx: Context): IO[AiConfig] = ctx.me.fold(
|
||||
user ⇒ configRepo.config(user) map (_.ai),
|
||||
io(AiConfig.default)
|
||||
)
|
||||
def aiConfig(implicit ctx: Context): IO[AiConfig] =
|
||||
ctx.me.fold(io(AiConfig.default)) { user ⇒
|
||||
configRepo.config(user) map (_.ai)
|
||||
}
|
||||
|
||||
def friendFilled(implicit ctx: Context): IO[Form[FriendConfig]] =
|
||||
friendConfig map friend(ctx).fill
|
||||
|
@ -46,10 +46,10 @@ final class FormFactory(
|
|||
)(FriendConfig.<<)(_.>>) verifying ("Invalid clock", _.validClock)
|
||||
)
|
||||
|
||||
def friendConfig(implicit ctx: Context): IO[FriendConfig] = ctx.me.fold(
|
||||
user ⇒ configRepo.config(user) map (_.friend),
|
||||
io(FriendConfig.default)
|
||||
)
|
||||
def friendConfig(implicit ctx: Context): IO[FriendConfig] =
|
||||
ctx.me.fold(io(FriendConfig.default)) { user ⇒
|
||||
configRepo.config(user) map (_.friend)
|
||||
}
|
||||
|
||||
def hookFilled(implicit ctx: Context): IO[Form[HookConfig]] =
|
||||
hookConfig map hook(ctx).fill
|
||||
|
@ -68,8 +68,8 @@ final class FormFactory(
|
|||
.verifying("Can't create rated unlimited in lobby", _.noRatedUnlimited)
|
||||
)
|
||||
|
||||
def hookConfig(implicit ctx: Context): IO[HookConfig] = ctx.me.fold(
|
||||
user ⇒ configRepo.config(user) map (_.hook),
|
||||
io(HookConfig.default)
|
||||
)
|
||||
def hookConfig(implicit ctx: Context): IO[HookConfig] =
|
||||
ctx.me.fold(io(HookConfig.default)) { user ⇒
|
||||
configRepo.config(user) map (_.hook)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,11 +18,11 @@ final class FriendJoiner(
|
|||
game.notStarted option {
|
||||
val color = game.invitedColor
|
||||
for {
|
||||
p1 ← user.fold(
|
||||
u ⇒ gameRepo.setUser(game.id, color, u) map { _ ⇒
|
||||
p1 ← user.fold(io(Progress(game))) { u ⇒
|
||||
gameRepo.setUser(game.id, color, u) map { _ ⇒
|
||||
Progress(game, game.updatePlayer(color, _ withUser u))
|
||||
},
|
||||
io(Progress(game)))
|
||||
}
|
||||
}
|
||||
p2 = p1 map (_.start)
|
||||
p3 ← messenger init p2.game map { evts ⇒
|
||||
p2 + Event.RedirectOwner(!color, playerUrl(p2.game, !color)) ++ evts
|
||||
|
|
|
@ -20,20 +20,16 @@ final class HookJoiner(
|
|||
def apply(hookId: String, myHookId: Option[String])(me: Option[User]): IO[Valid[Pov]] =
|
||||
for {
|
||||
hookOption ← hookRepo hook hookId
|
||||
myHookOption ← myHookId.fold(hookRepo.ownedHook, io(none))
|
||||
result ← hookOption.fold(
|
||||
hook ⇒ canJoin(hook, me).fold(
|
||||
join(hook, myHookOption)(me) map success,
|
||||
io(!!("Can not join hook"))
|
||||
),
|
||||
io(!!("No such hook"))
|
||||
)
|
||||
|
||||
myHookOption ← ~(myHookId map hookRepo.ownedHook)
|
||||
result ← hookOption.fold(io(!![Pov]("No such hook"))) { hook ⇒
|
||||
if (canJoin(hook, me)) join(hook, myHookOption)(me) map success
|
||||
else io(!![Pov]("Can not join hook"))
|
||||
}
|
||||
} yield result
|
||||
|
||||
private def join(hook: Hook, myHook: Option[Hook])(me: Option[User]): IO[Pov] = for {
|
||||
_ ← myHook.fold(fisherman.delete, io())
|
||||
ownerOption ← hook.userId.fold(userRepo.byId, io(none))
|
||||
_ ← ~(myHook map fisherman.delete)
|
||||
ownerOption ← hook.userId.fold(io(none[User]))(userRepo.byId)
|
||||
game = blame(
|
||||
_.invitedColor, me,
|
||||
blame(_.creatorColor, ownerOption, makeGame(hook))
|
||||
|
@ -48,9 +44,7 @@ final class HookJoiner(
|
|||
} yield Pov(game, game.invitedColor)
|
||||
|
||||
def blame(color: DbGame ⇒ ChessColor, userOption: Option[User], game: DbGame) =
|
||||
userOption.fold(
|
||||
user ⇒ game.updatePlayer(color(game), _ withUser user),
|
||||
game)
|
||||
userOption.fold(game)(user ⇒ game.updatePlayer(color(game), _ withUser user))
|
||||
|
||||
def makeGame(hook: Hook) = DbGame(
|
||||
game = Game(
|
||||
|
@ -71,7 +65,7 @@ final class HookJoiner(
|
|||
private def canJoin(hook: Hook, me: Option[User]) =
|
||||
!hook.`match` && {
|
||||
hook.realMode.casual || (me exists { u ⇒
|
||||
hook.realEloRange.fold(_ contains u.elo, true)
|
||||
hook.realEloRange.fold(true)(_ contains u.elo)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import lobby.{ Hook, Fisherman }
|
|||
import i18n.I18nDomain
|
||||
import controllers.routes
|
||||
|
||||
import play.api.libs.json.{ Json, JsObject }
|
||||
import scalaz.effects._
|
||||
|
||||
final class Processor(
|
||||
|
@ -22,14 +23,9 @@ final class Processor(
|
|||
ai: () ⇒ Ai) extends core.Futuristic {
|
||||
|
||||
def ai(config: AiConfig)(implicit ctx: Context): IO[Pov] = for {
|
||||
_ ← ctx.me.fold(
|
||||
user ⇒ configRepo.update(user)(_ withAi config),
|
||||
io()
|
||||
)
|
||||
_ ← ~(ctx.me map (user ⇒ configRepo.update(user)(_ withAi config)))
|
||||
pov = config.pov
|
||||
game = ctx.me.fold(
|
||||
user ⇒ pov.game.updatePlayer(pov.color, _ withUser user),
|
||||
pov.game)
|
||||
game = ctx.me.fold(pov.game)(user ⇒ pov.game.updatePlayer(pov.color, _ withUser user))
|
||||
_ ← gameRepo insert game
|
||||
_ ← gameRepo denormalizeStarted game
|
||||
_ ← timelinePush(game)
|
||||
|
@ -50,40 +46,32 @@ final class Processor(
|
|||
} yield pov2
|
||||
|
||||
def friend(config: FriendConfig)(implicit ctx: Context): IO[Pov] = for {
|
||||
_ ← ctx.me.fold(
|
||||
user ⇒ configRepo.update(user)(_ withFriend config),
|
||||
io()
|
||||
)
|
||||
_ ← ~(ctx.me map (user ⇒ configRepo.update(user)(_ withFriend config)))
|
||||
pov = config.pov
|
||||
game = ctx.me.fold(
|
||||
user ⇒ pov.game.updatePlayer(pov.color, _ withUser user),
|
||||
pov.game)
|
||||
game = ctx.me.fold(pov.game)(user ⇒ pov.game.updatePlayer(pov.color, _ withUser user))
|
||||
_ ← gameRepo insert game
|
||||
_ ← timelinePush(game)
|
||||
_ ← friendConfigMemo.set(pov.game.id, config)
|
||||
} yield pov
|
||||
|
||||
def hook(config: HookConfig)(implicit ctx: Context): IO[Hook] = for {
|
||||
_ ← ctx.me.fold(
|
||||
user ⇒ configRepo.update(user)(_ withHook config),
|
||||
io()
|
||||
)
|
||||
_ ← ~(ctx.me map { user ⇒ configRepo.update(user)(_ withHook config) })
|
||||
hook = config hook ctx.me
|
||||
_ ← fisherman add hook
|
||||
} yield hook
|
||||
|
||||
def api(implicit ctx: Context): IO[Map[String, Any]] = {
|
||||
def api(implicit ctx: Context): IO[JsObject] = {
|
||||
val domain = "http://" + I18nDomain(ctx.req.domain).commonDomain
|
||||
val config = ApiConfig
|
||||
val pov = config.pov
|
||||
val game = ctx.me.fold(
|
||||
user ⇒ pov.game.updatePlayer(pov.color, _ withUser user),
|
||||
pov.game).start
|
||||
val game = ctx.me.fold(pov.game)(user ⇒ pov.game.updatePlayer(pov.color, _ withUser user)).start
|
||||
import chess.Color._
|
||||
for {
|
||||
_ ← gameRepo insert game
|
||||
_ ← timelinePush(game)
|
||||
} yield ChessColor.all map { color ⇒
|
||||
color.name -> (domain + routes.Round.player(game fullIdOf color).url)
|
||||
} toMap
|
||||
} yield Json.obj(
|
||||
White.name -> (domain + routes.Round.player(game fullIdOf White).url),
|
||||
Black.name -> (domain + routes.Round.player(game fullIdOf Black).url)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,10 +23,7 @@ final class Rematcher(
|
|||
attempt(fullId, {
|
||||
case pov @ Pov(game, color) if game playerCanRematch color ⇒
|
||||
success(game.opponent(color).isOfferingRematch.fold(
|
||||
game.next.fold(
|
||||
rematchExists(pov),
|
||||
rematchJoin(pov)
|
||||
),
|
||||
game.next.fold(rematchJoin(pov))(rematchExists(pov)),
|
||||
rematchCreate(pov)
|
||||
))
|
||||
case _ ⇒ !!("invalid rematch offer " + fullId)
|
||||
|
@ -34,9 +31,7 @@ final class Rematcher(
|
|||
|
||||
private def rematchExists(pov: Pov)(nextId: String): IO[Result] =
|
||||
gameRepo.pov(nextId, !pov.color) map { nextPovOption ⇒
|
||||
nextPovOption.fold(
|
||||
_.fullId -> Nil,
|
||||
pov.fullId -> Nil)
|
||||
nextPovOption.fold(pov.fullId -> Nil)(_.fullId -> Nil)
|
||||
}
|
||||
|
||||
private def rematchJoin(pov: Pov): IO[Result] = for {
|
||||
|
@ -92,17 +87,13 @@ final class Rematcher(
|
|||
|
||||
private def returnPlayer(game: DbGame, color: ChessColor): IO[DbPlayer] =
|
||||
DbPlayer(color = color, aiLevel = None) |> { player ⇒
|
||||
game.player(!color).userId.fold(
|
||||
userId ⇒ userRepo byId userId map { userOption ⇒
|
||||
userOption.fold(
|
||||
user ⇒ player withUser user,
|
||||
player)
|
||||
},
|
||||
io(player))
|
||||
game.player(!color).userId.fold(io(player)) { userId ⇒
|
||||
userRepo byId userId map { _.fold(player)(player.withUser) }
|
||||
}
|
||||
}
|
||||
|
||||
private def clockName(clock: Option[Clock]): String =
|
||||
clock.fold(Namer.clock, "Unlimited")
|
||||
clock.fold("Unlimited")(Namer.clock)
|
||||
|
||||
private def playerUrl(game: DbGame, color: ChessColor): String =
|
||||
routes.Round.player(game fullIdOf color).url
|
||||
|
|
|
@ -8,6 +8,7 @@ import akka.util.Timeout
|
|||
import play.api.libs.json._
|
||||
import play.api.libs.iteratee._
|
||||
import play.api.libs.concurrent._
|
||||
import play.api.libs.concurrent.Execution.Implicits._
|
||||
import scalaz.effects._
|
||||
|
||||
import implicits.RichJs._
|
||||
|
@ -24,8 +25,8 @@ final class Socket(hub: ActorRef) {
|
|||
def join(
|
||||
uidOption: Option[String],
|
||||
username: Option[String],
|
||||
flag: Option[String]): SocketPromise = {
|
||||
val promise: Option[SocketPromise] = for {
|
||||
flag: Option[String]): SocketFuture = {
|
||||
val promise: Option[SocketFuture] = for {
|
||||
uid ← uidOption
|
||||
} yield (hub ? Join(uid, username, flag)) map {
|
||||
case Connected(enumerator, channel) ⇒
|
||||
|
|
|
@ -111,9 +111,8 @@ abstract class HubActor[M <: SocketMember](uidTimeout: Int) extends Actor {
|
|||
members.values find (_.userId == someId)
|
||||
}
|
||||
|
||||
def membersByUserIds(userIds: Set[String]): Iterable[M] = {
|
||||
members.values filter (_.userId.fold(userIds.contains, false))
|
||||
}
|
||||
def membersByUserIds(userIds: Set[String]): Iterable[M] =
|
||||
members.values filter (member ⇒ ~member.userId.map(userIds.contains))
|
||||
|
||||
def usernames: Iterable[String] = members.values.map(_.username).flatten
|
||||
|
||||
|
@ -121,7 +120,7 @@ abstract class HubActor[M <: SocketMember](uidTimeout: Int) extends Actor {
|
|||
val msg = makeMessage("fen", JsObject(Seq(
|
||||
"id" -> JsString(gameId),
|
||||
"fen" -> JsString(fen),
|
||||
"lm" -> lastMove.fold(JsString(_), JsNull)
|
||||
"lm" -> Json.toJson(lastMove)
|
||||
)))
|
||||
members.values filter (_ liveGames gameId) foreach (_.channel push msg)
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package lila
|
||||
package templating
|
||||
|
||||
import com.codahale.jerkson.Json
|
||||
import play.api.libs.json.Json
|
||||
|
||||
trait JsonHelper {
|
||||
|
||||
def mapToJson(map: Map[String, Any]) = Json generate map
|
||||
// def toJson(data: Write) = Json generate map
|
||||
|
||||
def listToJson(list: List[Any]) = Json generate list
|
||||
// def listToJson(list: List[Any]) = Json generate list
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ trait StringHelper {
|
|||
|
||||
def showNumber(n: Int): String = (n > 0).fold("+" + n, n.toString)
|
||||
|
||||
implicit def richString(str: String) = new {
|
||||
implicit def lilaRichString(str: String) = new {
|
||||
def active(other: String, one: String = "active") =
|
||||
(str == other).fold(one, "")
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ case class Entry(
|
|||
whiteName -> whiteId,
|
||||
blackName -> blackId)
|
||||
|
||||
def render =
|
||||
def render: String =
|
||||
"<td>%s</td><td>%s</td><td class='trans_me'>%s</td><td class='trans_me'>%s</td><td class='trans_me'>%s</td>".format(
|
||||
"<a class='watch' href='/%s'></a>" format gameId,
|
||||
players map {
|
||||
|
|
|
@ -9,6 +9,7 @@ import round.Meddler
|
|||
import scalaz.effects._
|
||||
import play.api.libs.concurrent._
|
||||
import play.api.Play.current
|
||||
import play.api.libs.concurrent.Execution.Implicits._
|
||||
import scala.concurrent.duration._
|
||||
|
||||
final class GameJoiner(
|
||||
|
@ -51,19 +52,18 @@ final class GameJoiner(
|
|||
private def idleCheck(povRef: PovRef) {
|
||||
(for {
|
||||
povOption ← gameRepo pov povRef
|
||||
_ ← povOption.filter(_.game.playable).fold(idleResult, io())
|
||||
_ ← ~(povOption filter (_.game.playable) map idleResult)
|
||||
} yield ()).unsafePerformIO
|
||||
}
|
||||
|
||||
private def idleResult(pov: Pov) = {
|
||||
private def idleResult(pov: Pov): IO[Unit] = {
|
||||
val idle = !pov.game.playerHasMoved(pov.color)
|
||||
idle.fold(
|
||||
roundMeddler resign pov,
|
||||
(pov.color.white && !pov.game.playerHasMoved(Color.Black)).fold(
|
||||
scheduleIdleCheck(!pov.ref, pov.game.lastMoveTime.fold(
|
||||
lastMoveTime ⇒ lastMoveTime - nowSeconds + secondsToMove,
|
||||
secondsToMove
|
||||
)),
|
||||
scheduleIdleCheck(!pov.ref, pov.game.lastMoveTime.fold(secondsToMove) { lmt ⇒
|
||||
lmt - nowSeconds + secondsToMove
|
||||
}),
|
||||
io()
|
||||
)
|
||||
)
|
||||
|
|
|
@ -45,7 +45,7 @@ final class Hub(
|
|||
ping(uid)
|
||||
lastPingTime = nowMillis
|
||||
withMember(uid) { m ⇒
|
||||
history.since(v).fold(_ foreach m.channel.push, resync(m))
|
||||
history.since(v).fold(resync(m))(_ foreach m.channel.push)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,10 +40,9 @@ final class HubMaster(
|
|||
}
|
||||
}
|
||||
|
||||
case msg @ GetTournamentVersion(id) ⇒ (hubs get id).fold(
|
||||
_ ? msg pipeTo sender,
|
||||
sender ! 0
|
||||
)
|
||||
case msg @ GetTournamentVersion(id) ⇒ (hubs get id).fold(sender ! 0) {
|
||||
_ ? msg pipeTo sender
|
||||
}
|
||||
|
||||
case CloseTournament(id) ⇒ hubs get id foreach { hub ⇒
|
||||
hub ! Close
|
||||
|
@ -56,10 +55,9 @@ final class HubMaster(
|
|||
(hub ? GetNbMembers).mapTo[Int]
|
||||
} map (_.sum) pipeTo sender
|
||||
|
||||
case GetTournamentUsernames(id) ⇒ hubs get id fold (
|
||||
hub ⇒ (hub ? GetUsernames).mapTo[Iterable[String]] pipeTo sender,
|
||||
sender ! Nil
|
||||
)
|
||||
case GetTournamentUsernames(id) ⇒ (hubs get id).fold(sender ! Nil) { hub ⇒
|
||||
(hub ? GetUsernames).mapTo[Iterable[String]] pipeTo sender
|
||||
}
|
||||
|
||||
case GetTournamentIds ⇒ hubs.keys
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ final class Messenger(
|
|||
|
||||
def init(tour: Created): IO[List[Message]] = for {
|
||||
userOption ← getUser(tour.data.createdBy)
|
||||
username = userOption.fold(_.username, tour.data.createdBy)
|
||||
username = userOption.fold(tour.data.createdBy)(_.username)
|
||||
message ← systemMessage(tour, "%s creates the tournament" format username)
|
||||
} yield List(message)
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import akka.util.Timeout
|
|||
import akka.pattern.{ ask, pipe }
|
||||
import scala.concurrent.{ Future, Promise }
|
||||
import play.api.libs.concurrent._
|
||||
import play.api.Play.current
|
||||
import play.api.libs.concurrent.Execution.Implicits._
|
||||
|
||||
private[tournament] final class Organizer(
|
||||
api: TournamentApi,
|
||||
|
|
|
@ -26,7 +26,7 @@ case class Pairing(
|
|||
def opponentOf(user: String): Option[String] =
|
||||
if (user == user1) user2.some else if (user == user2) user1.some else none
|
||||
|
||||
def wonBy(user: String): Boolean = winner.fold(user ==, false)
|
||||
def wonBy(user: String): Boolean = ~winner.map(user ==)
|
||||
def draw: Boolean = finished && winner.isEmpty
|
||||
|
||||
def colorOf(userId: String): Option[Color] =
|
||||
|
|
|
@ -49,9 +49,9 @@ object Player {
|
|||
prevWin: Boolean = false) {
|
||||
|
||||
def +(winner: Option[String]) = {
|
||||
val (win, loss): Pair[Boolean, Boolean] = winner.fold(
|
||||
w ⇒ if (w == player.id) true -> false else false -> true,
|
||||
false -> false)
|
||||
val (win, loss): Pair[Boolean, Boolean] = winner.fold(false -> false) { w =>
|
||||
if (w == player.id) true -> false else false -> true
|
||||
}
|
||||
val newWinSeq = if (win) prevWin.fold(winSeq + 1, 1) else 0
|
||||
val points = win.fold(1 + newWinSeq, loss.fold(0, 1))
|
||||
copy(
|
||||
|
|
|
@ -54,7 +54,7 @@ final class Socket(
|
|||
tournamentId: String,
|
||||
version: Option[Int],
|
||||
uid: Option[String],
|
||||
user: Option[User]): IO[SocketPromise] =
|
||||
user: Option[User]): IO[SocketFuture] =
|
||||
getTournament(tournamentId) map { tourOption ⇒
|
||||
((tourOption |@| uid |@| version) apply {
|
||||
(tour: Tournament, uid: String, version: Int) ⇒
|
||||
|
@ -73,7 +73,7 @@ final class Socket(
|
|||
},
|
||||
enumerator)
|
||||
}
|
||||
} yield socket): SocketPromise
|
||||
} yield socket): SocketFuture
|
||||
}) | connectionFail
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ final class Cached(
|
|||
username(userId) | User.anonymous
|
||||
|
||||
def usernameOrAnonymous(userId: Option[String]): String =
|
||||
userId.fold(usernameOrAnonymous, User.anonymous)
|
||||
(userId flatMap username) | User.anonymous
|
||||
|
||||
def countEnabled: Int = memo(CountEnabled)
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ object GameFilterMenu extends NonEmptyLists {
|
|||
val user = info.user
|
||||
|
||||
val all = nel(All, List(
|
||||
info.nbWithMe.fold(_ > 0, false) option Me,
|
||||
~info.nbWithMe.map(_ > 0) option Me,
|
||||
(info.nbRated > 0) option Rated,
|
||||
(info.user.nbWins > 0) option Win,
|
||||
(info.user.nbLosses > 0) option Loss,
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
<div id="nb_connected_players" class="nb_connected_players none">
|
||||
@trans.nbConnectedPlayers("<strong>0</strong>")
|
||||
</div>
|
||||
@ctx.me.fold(auth.miniLogin)(auth.loggedIn(_))
|
||||
@ctx.me.fold(auth.miniLogin())(auth.loggedIn(_))
|
||||
<div class="themepicker">
|
||||
<a class="theme_toggle toggle"><span class="theme_demo">@trans.color()</span></a>
|
||||
<div class="themes dropdown" data-href="@routes.Setting.set("theme")">
|
||||
|
|
|
@ -16,4 +16,4 @@
|
|||
</div>
|
||||
}
|
||||
|
||||
@game.winner.fold(winner, noWinner)
|
||||
@game.winner.fold(noWinner)(winner)
|
||||
|
|
2
play
2
play
|
@ -1 +1 @@
|
|||
Subproject commit e5217b2f79678d9b3328e913d4146a7a92aa712c
|
||||
Subproject commit 3ffc15d66c45185b364ff5ff9c25d55c4d39d10c
|
Loading…
Reference in a new issue