now compiles in scala 2.10 RC3

This commit is contained in:
Thibault Duplessis 2012-11-30 15:36:36 +01:00
parent d30a675090
commit 433699382a
57 changed files with 236 additions and 264 deletions

View file

@ -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)
}

View file

@ -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 {

View file

@ -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) }
}
}

View file

@ -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))
}

View file

@ -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)
}
}

View file

@ -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)

View file

@ -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

View file

@ -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),

View file

@ -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

View file

@ -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"
))
)
}

View file

@ -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)
}
}

View file

@ -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,

View file

@ -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,

View file

@ -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 {

View file

@ -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
}

View file

@ -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"

View file

@ -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))
)

View file

@ -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)

View file

@ -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)
}
}
}

View file

@ -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

View file

@ -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,

View file

@ -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

View file

@ -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

View file

@ -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)
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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] =

View file

@ -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)

View file

@ -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)))
}

View file

@ -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))
}

View file

@ -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)

View file

@ -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 {

View file

@ -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)
}
}

View file

@ -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

View file

@ -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)
})
}
}

View file

@ -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)
)
}
}

View file

@ -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

View file

@ -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)

View file

@ -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)
}

View file

@ -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
}

View file

@ -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, "")
}

View file

@ -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 {

View file

@ -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()
)
)

View file

@ -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)
}
}

View file

@ -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

View file

@ -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)

View file

@ -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,

View file

@ -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] =

View file

@ -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(

View file

@ -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
}

View file

@ -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)

View file

@ -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,

View file

@ -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")">

View file

@ -16,4 +16,4 @@
</div>
}
@game.winner.fold(winner, noWinner)
@game.winner.fold(noWinner)(winner)

2
play

@ -1 +1 @@
Subproject commit e5217b2f79678d9b3328e913d4146a7a92aa712c
Subproject commit 3ffc15d66c45185b364ff5ff9c25d55c4d39d10c