scala 2.10 wip

This commit is contained in:
Thibault Duplessis 2012-11-29 21:11:22 +01:00
parent f70900a485
commit 6ef1ba91a6
58 changed files with 206 additions and 232 deletions

View file

@ -5,7 +5,7 @@ import chess.{ Game, Move }
import game.DbGame
import analyse.Analysis
import akka.dispatch.Future
import scala.concurrent.Future
trait Ai {

View file

@ -2,7 +2,8 @@ package lila
package ai
import scalaz.effects._
import akka.dispatch.Future
import scala.concurrent.Future
import play.api.libs.concurrent.execution.Implicits._
trait Client extends Ai {
@ -36,7 +37,7 @@ trait Client extends Ai {
ping = p
}
private def isHealthy(p: Option[Int]) = p.fold(isFast, false)
private def isHealthy(p: Option[Int]) = p.fold(false)(isFast)
private def isFast(p: Int) = p < pingAlert
}

View file

@ -5,7 +5,7 @@ import chess.{ Game, Move }
import game.DbGame
import scalaz.effects._
import akka.dispatch.Future
import scala.concurrent.Future
final class StupidAi extends Ai with core.Futuristic {

View file

@ -7,9 +7,10 @@ import game.DbGame
import analyse.Analysis
import scalaz.effects._
import akka.dispatch.Future
import scala.concurrent.Future
import play.api.Play.current
import play.api.libs.concurrent._
import play.api.libs.concurrent.execution.Implicits._
final class Ai(server: Server) extends lila.ai.Ai with Stockfish {

View file

@ -8,10 +8,11 @@ import game.DbGame
import analyse.Analysis
import scalaz.effects._
import akka.dispatch.Future
import scala.concurrent.Future
import scala.concurrent.duration._
import play.api.Play.current
import play.api.libs.concurrent._
import play.api.libs.concurrent.execution.Implicits._
import play.api.libs.ws.WS
final class Client(
@ -38,26 +39,17 @@ final class Client(
}
private def fetchMove(pgn: String, initialFen: String, level: Int): Future[String] =
toAkkaFuture(WS.url(playUrl).withQueryString(
WS.url(playUrl).withQueryString(
"pgn" -> pgn,
"initialFen" -> initialFen,
"level" -> level.toString
).get() map (_.body))
).get() map (_.body)
private def fetchAnalyse(pgn: String, initialFen: String): Future[String] =
toAkkaFuture(WS.url(analyseUrl).withQueryString(
WS.url(analyseUrl).withQueryString(
"pgn" -> pgn,
"initialFen" -> initialFen
).get() map (_.body))
).get() map (_.body)
private implicit val executor = Akka.system.dispatcher
private def toAkkaFuture[A](promise: Promise[A]): Future[A] = {
val p = akka.dispatch.Promise[A]()
promise extend1 {
case Redeemed(value) p success value
case Thrown(exn) p failure exn
}
p.future
}
}

View file

@ -44,7 +44,7 @@ final class Config(settings: Settings) {
setoption("OwnBook", true),
"isready"))
def go(task: Task) = task.fold(
def go(task: Task): List[String] = task.fold(
play List(
position(play.fen, play.moves),
"go movetime %d%s".format(
@ -62,7 +62,7 @@ final class Config(settings: Settings) {
private def analyseMoveTime = settings.AiStockfishAnalyseMoveTime
private def position(fen: Option[String], moves: String) =
"position %s moves %s".format(fen.fold("fen " + _, "startpos"), moves)
"position %s moves %s".format(fen.fold("startpos")("fen " + _), moves)
private def setoption(name: String, value: Any) =
"setoption name %s value %s".format(name, value)

View file

@ -9,9 +9,8 @@ import analyse.Analysis
import model.{ GetQueueSize, QueueSize }
import akka.util.Timeout
import scala.concurrent.Duration
import scala.concurrent.duration._
import akka.dispatch.{ Future, Await }
import scala.concurrent.{ Future, Await }
import akka.actor.{ Props, Actor, ActorRef, Kill }
import akka.pattern.{ ask, AskTimeoutException }
import play.api.Play.current
@ -30,7 +29,7 @@ final class Server(
} yield play).fold(
err Future(failure(err)),
play actor ? play mapTo bestMoveManifest map { m
success(m.move | "")
success(~m.move)
} onFailure reboot
)
}
@ -52,15 +51,15 @@ final class Server(
}
}
private def chess960Fen(fen: String) = (Forsyth << fen).fold(
situation fen.replace("KQkq", situation.board.pieces.toList filter {
private def chess960Fen(fen: String) = (Forsyth << fen).fold(fen) { situation =>
fen.replace("KQkq", situation.board.pieces.toList filter {
case (_, piece) piece is Rook
} sortBy {
case (pos, _) (pos.y, pos.x)
} map {
case (pos, piece) piece.color.fold(pos.file.toUpperCase, pos.file)
} mkString ""),
fen)
} mkString "")
}
private val reboot: PartialFunction[Throwable, Unit] = {
case e: AskTimeoutException actor ! model.RebootException

View file

@ -26,9 +26,9 @@ object model {
override def toString = getClass.getName + " = " + queue.size
}
case class Todo(queue: Vector[Task] = Vector.empty) extends Data {
def doing[A](withTask: Doing A, without: Todo A) = dequeue.fold({
def doing[A](withTask: Doing A, without: Todo A) = dequeue.fold(without(this)) {
case (task, rest) withTask(Doing(task, rest))
}, without(this))
}
def fold[A](todo: Todo A, doing: Doing A): A = todo(this)
def enqueue(task: Task) = copy(queue :+ task)
}

View file

@ -1,17 +1,18 @@
package lila
package analyse
import com.codahale.jerkson.Json
import play.api.libs.json.Json
final class AdvantageChart(advices: Analysis.InfoAdvices) {
val max = 15
def columns = Json generate List(
"string" :: "Move" :: Nil,
"number" :: "Advantage" :: Nil)
def columns = Json.arr(
Json.arr("string", "Move"),
Json.arr("number", "Advantage")
)
def rows = Json generate {
def rows = Json.toJson {
val scale = floatBox(-max to max) _

View file

@ -7,7 +7,7 @@ import core.Settings
import com.mongodb.casbah.MongoCollection
import scalaz.effects._
import akka.dispatch.Future
import scala.concurrent.Future
final class AnalyseEnv(
settings: Settings,

View file

@ -6,7 +6,7 @@ import game.{ DbGame, GameRepo, PgnRepo }
import scalaz.effects._
import play.api.libs.concurrent.Akka
import play.api.Play.current
import akka.dispatch.Future
import scala.concurrent.Future
import scala.concurrent.duration._
import akka.util.Timeout
@ -28,32 +28,29 @@ final class Analyser(
private def getOrGenerateIO(id: String, userId: String, admin: Boolean): Future[Valid[Analysis]] = for {
a ioToFuture(analysisRepo doneById id)
b a.fold(
x Future(success(x)),
for {
userInProgress ioToFuture(admin.fold(
io(false),
analysisRepo userInProgress userId
))
gameOption ioToFuture(gameRepo game id)
pgnString ioToFuture(pgnRepo get id)
result gameOption.filterNot(_ userInProgress).fold(
game for {
_ ioToFuture(analysisRepo.progress(id, userId))
initialFen ioToFuture(gameRepo initialFen id)
analysis generator()(pgnString, initialFen)
_ ioToFuture(analysis.prefixFailuresWith("Analysis").fold(
fail for {
_ putFailures(fail)
_ analysisRepo.fail(id, fail)
} yield (),
analysisRepo.done(id, _)
))
} yield analysis,
Future(!!("No such game " + id): Valid[Analysis])
)
} yield result
)
b a.fold(for {
userInProgress ioToFuture(admin.fold(
io(false),
analysisRepo userInProgress userId
))
gameOption ioToFuture(gameRepo game id)
pgnString ioToFuture(pgnRepo get id)
result gameOption.filterNot(_ userInProgress).fold(
game for {
_ ioToFuture(analysisRepo.progress(id, userId))
initialFen ioToFuture(gameRepo initialFen id)
analysis generator()(pgnString, initialFen)
_ ioToFuture(analysis.prefixFailuresWith("Analysis").fold(
fail for {
_ putFailures(fail)
_ analysisRepo.fail(id, fail)
} yield (),
analysisRepo.done(id, _)
))
} yield analysis,
Future(!!("No such game " + id): Valid[Analysis])
)
} yield result) { x Future(success(x)) }
} yield b
private def ioToFuture[A](ioa: IO[A]) = Future {

View file

@ -158,7 +158,7 @@ case class Info(
encode(mate)
) mkString Info.separator
private def encode(oa: Option[Any]): String = oa.fold(_.toString, "_")
private def encode(oa: Option[Any]): String = oa.fold("_")(_.toString)
}
object Info {

View file

@ -12,14 +12,14 @@ final class AnalysisRepo(val collection: MongoCollection) {
def done(id: String, a: Analysis) = io {
collection.update(
DBObject("_id" -> id),
$set("done" -> true, "encoded" -> a.encode) ++ $unset("fail")
$set(Seq("done" -> true, "encoded" -> a.encode)) ++ $unset(Seq("fail"))
)
}
def fail(id: String, err: Failures) = io {
collection.update(
DBObject("_id" -> id),
$set("fail" -> err.shows)
$set(Seq("fail" -> err.shows))
)
}

View file

@ -25,7 +25,7 @@ object Annotator {
private def makeComment(advice: Advice): String = (advice match {
case CpAdvice(sev, _, _) sev.nag.toString
case MateAdvice(sev, _, _) sev.desc
}) ++ makeBestComment(advice).fold(". " + _, ".")
}) ++ makeBestComment(advice).fold(".")(". " + _)
private def makeBestComment(advice: Advice): Option[String] =
(advice.info.move != advice.info.best) option {

View file

@ -2,7 +2,7 @@ package lila
package analyse
import chess.format.Forsyth
import chess.format.{ pgn => chessPgn }
import chess.format.{ pgn chessPgn }
import chess.format.pgn.{ Pgn, Tag }
import game.{ DbGame, DbPlayer, GameRepo }
import user.{ User, UserRepo }
@ -21,7 +21,7 @@ final class PgnDump(
ts tags(game)
pgnObj = Pgn(ts, turns(pgn))
analysis analyser get game.id
} yield analysis.fold(Annotator(pgnObj, _), pgnObj)
} yield analysis.fold(pgnObj)(Annotator(pgnObj, _))
def filename(game: DbGame): IO[String] = for {
whiteUser user(game.whitePlayer)
@ -35,15 +35,11 @@ final class PgnDump(
private val baseUrl = "http://lichess.org/"
private val dateFormat = DateTimeFormat forPattern "yyyy-MM-dd";
private def elo(p: DbPlayer) = p.elo.fold(_.toString, "?")
private def elo(p: DbPlayer) = p.elo.fold("?")(_.toString)
private def user(p: DbPlayer): IO[Option[User]] = p.userId.fold(
userRepo.byId,
io(none))
private def user(p: DbPlayer): IO[Option[User]] = p.userId.fold(io(none[User]))(userRepo.byId)
private def player(p: DbPlayer, u: Option[User]) = p.aiLevel.fold(
"AI level " + _,
u.fold(_.username, "Anonymous"))
private def player(p: DbPlayer, u: Option[User]) = p.aiLevel.fold(u.fold(_.username, "Anonymous"))("AI level " + _)
private def tags(game: DbGame): IO[List[Tag]] = for {
whiteUser user(game.whitePlayer)
@ -77,8 +73,6 @@ final class PgnDump(
object PgnDump {
def result(game: DbGame) = game.finished.fold(
game.winnerColor.fold(
color color.white.fold("1-0", "0-1"),
"1/2-1/2"),
game.winnerColor.fold("1/2-1/2")(color color.white.fold("1-0", "0-1")),
"*")
}

View file

@ -5,18 +5,22 @@ import game.{ DbPlayer, DbGame, Namer }
import chess.Color.{ White, Black }
import scala.math.round
import com.codahale.jerkson.Json
import play.api.libs.json.Json
final class TimeChart(game: DbGame) {
def columns = Json generate {
List("string", "Move") :: game.players.map(p
List("number", "%s - %s".format(p.color, Namer.player(p)(identity))))
def columns = Json stringify {
Json toJson {
List("string", "Move") :: game.players.map(p
List("number", "%s - %s".format(p.color, Namer.player(p)(identity))))
}
}
def rows = Json generate {
(game.player(White).moveTimeList zip game.player(Black).moveTimeList).zipWithIndex map {
case ((white, black), move) List(move.toString, white, black)
def rows = Json stringify {
Json toJson {
(game.player(White).moveTimeList zip game.player(Black).moveTimeList).zipWithIndex map {
case ((white, black), move) List(move.toString, white, black)
}
}
}
}

View file

@ -3,15 +3,17 @@ package analyse
import game.{ DbPlayer, Pov }
import com.codahale.jerkson.Json
import play.api.libs.json.Json
final class TimePie(val pov: Pov) {
def columns = Json generate List(
"string" :: "Time in seconds" :: Nil,
"number" :: "Number of moves" :: Nil)
def columns = Json stringify {
Json toJson List(
"string" :: "Time in seconds" :: Nil,
"number" :: "Number of moves" :: Nil)
}
def rows = Json generate {
def rows = Json stringify {
import pov._
@ -29,8 +31,10 @@ final class TimePie(val pov: Pov) {
else "%d to %d seconds".format(min, max)
}
ranges zip (ranges map nbMoves) collect {
case (range, nb) if nb > 0 List(nameRange(range), nb)
Json toJson {
ranges zip (ranges map nbMoves) collect {
case (range, nb) if nb > 0 List(nameRange(range), nb)
}
}
}
}

View file

@ -15,13 +15,13 @@ final class BookmarkApi(
def toggle(gameId: String, user: User): IO[Unit] = for {
gameOption gameRepo game gameId
_ gameOption.fold(
game for {
_ gameOption.fold(io()) { game =>
for {
bookmarked bookmarkRepo.toggle(game.id, user.id)
_ gameRepo.incBookmarks(game.id, bookmarked.fold(1, -1))
_ io(cached invalidateUserId user.id)
} yield (),
io())
} yield ()
}
} yield ()
def bookmarked(game: DbGame, user: User): Boolean =

View file

@ -8,7 +8,7 @@ import mvc._
import play.api.libs.concurrent._
import play.api.Play.current
import akka.dispatch.Future
import scala.concurrent.Future
object Ai extends LilaController {
@ -24,7 +24,7 @@ object Ai extends LilaController {
pgn = getOr("pgn", ""),
initialFen = get("initialFen"),
level = getIntOr("level", 1)
).asPromise map (_.fold(
) map (_.fold(
err BadRequest(err.shows),
Ok(_)
))
@ -39,7 +39,7 @@ object Ai extends LilaController {
stockfishServer.analyse(
pgn = getOr("pgn", ""),
initialFen = get("initialFen")
).asPromise map (_.fold(
) map (_.fold(
err InternalServerError(err.shows),
analyse Ok(analyse.encode)
))
@ -50,10 +50,7 @@ object Ai extends LilaController {
def reportStockfish = Action { implicit req
IfServer {
Async {
env.ai.stockfishServerReport.fold(
_ map { Ok(_) },
Future(NotFound)
).asPromise
env.ai.stockfishServerReport.fold(Future(NotFound)) { _ map { Ok(_) } }
}
}
}

View file

@ -11,6 +11,7 @@ import play.api.http.ContentTypes
import play.api.templates.Html
import play.api.libs.concurrent._
import scalaz.effects._
import scala.util.{Try, Success, Failure}
object Analyse extends LilaController {
@ -28,8 +29,8 @@ object Analyse extends LilaController {
def computer(id: String, color: String) = Auth { implicit ctx
me
analyser.getOrGenerate(id, me.id, isGranted(_.MarkEngine)) onComplete {
case Left(e) println(e.getMessage)
case Right(a) a.fold(
case Failure(e) println(e.getMessage)
case Success(a) a.fold(
err println("Computer analysis failure: " + err.shows),
analysis roundHubMaster ! AnalysisAvailable(id)
)
@ -70,8 +71,8 @@ object Analyse extends LilaController {
def pgn(id: String) = Open { implicit ctx
IOResult(for {
gameOption gameRepo game id
res gameOption.fold(
game for {
res gameOption.fold(io(NotFound("No such game")), { game =>
for {
pgnString pgnRepo get id
pgnObj pgnDump(game, pgnString)
content = pgnObj.toString
@ -80,9 +81,8 @@ object Analyse extends LilaController {
CONTENT_LENGTH -> content.size.toString,
CONTENT_TYPE -> ContentTypes.TEXT,
CONTENT_DISPOSITION -> ("attachment; filename=" + filename)
),
io(NotFound("No such game"))
)
)
}
} yield res)
}
}

View file

@ -9,7 +9,7 @@ import core.Global
import play.api.mvc._
import play.api.data.Form
import play.api.http._
import com.codahale.jerkson.Json
import play.api.libs.json.Json
import scalaz.effects._
trait LilaController
@ -25,7 +25,7 @@ trait LilaController
override implicit def lang(implicit req: RequestHeader) =
env.i18n.pool.lang(req)
protected def toJson(map: Map[String, Any]) = Json generate map
protected def toJson(map: Map[String, Any]) = Json toJson map
protected def Open(f: Context Result): Action[AnyContent] =
Open(BodyParsers.parse.anyContent)(f)
@ -77,9 +77,9 @@ trait LilaController
protected def NoEngine[A <: Result](a: A)(implicit ctx: Context): Result =
ctx.me.fold(false)(_.engine).fold(Forbidden(views.html.site.noEngine()), a)
protected def JsonOk(map: Map[String, Any]) = Ok(toJson(map)) as JSON
protected def JsonOk(map: Map[String, Any]) = Ok(Json toJson map) as JSON
protected def JsonOk(list: List[Any]) = Ok(Json generate list) as JSON
protected def JsonOk(list: List[Any]) = Ok(Json toJson list) as JSON
protected def JsonIOk(map: IO[Map[String, Any]]) = JsonOk(map.unsafePerformIO)
@ -134,16 +134,16 @@ trait LilaController
implicit writer: Writeable[B],
ctype: ContentTypeOf[B],
ctx: Context) =
ioa.unsafePerformIO.fold(a Ok(op(a)), notFound(ctx))
ioa.unsafePerformIO.fold(notFound(ctx))(a Ok(op(a)))
protected def IOptionIOk[A, B](ioa: IO[Option[A]])(op: A IO[B])(
implicit writer: Writeable[B],
ctype: ContentTypeOf[B],
ctx: Context) =
ioa flatMap { aOption
aOption.fold(
a op(a) map { Ok(_) },
io(notFound(ctx))): IO[Result]
aOption.fold(io(notFound(ctx))) { a =>
a op(a) map { Ok(_) }
}//: IO[Result]
} unsafePerformIO
protected def IOptionIOResult[A](ioa: IO[Option[A]])(op: A IO[Result])(implicit ctx: Context) =

View file

@ -8,7 +8,8 @@ import views._
import play.api.mvc._
import play.api.libs.json.JsValue
import play.api.libs.concurrent._
import akka.dispatch.Future
import play.api.libs.concurrent.execution.Implicits._
import scala.concurrent.{ Future, Promise }
import scalaz.effects._
object Lobby extends LilaController with Results {
@ -44,7 +45,7 @@ object Lobby extends LilaController with Results {
posts,
tours,
featured))
})).asPromise
}))
def socket = WebSocket.async[JsValue] { implicit req
implicit val ctx = reqToCtx(req)
@ -59,11 +60,8 @@ object Lobby extends LilaController with Results {
def hook(ownerId: String) = Open { implicit ctx
Async {
hookRepo.ownedHook(ownerId).unsafePerformIO.fold(
hook renderHome(hook.some, Ok),
Promise.pure {
Redirect(routes.Lobby.home)
}
)
Promise pure { Redirect(routes.Lobby.home) }
) { hook renderHome(hook.some, Ok) }
}
}
@ -72,7 +70,7 @@ object Lobby extends LilaController with Results {
val myHookId = get("cancel")
joiner(hookId, myHookId)(ctx.me) map { result
result.fold(
_ myHookId.fold(routes.Lobby.hook(_), routes.Lobby.home),
_ myHookId.fold(routes.Lobby.home)(routes.Lobby.hook(_)),
pov routes.Round.player(pov.fullId))
}
}
@ -82,7 +80,7 @@ object Lobby extends LilaController with Results {
IORedirect {
for {
hook hookRepo ownedHook ownerId
_ hook.fold(fisherman.delete, io())
_ hook.fold(io())(fisherman.delete)
} yield routes.Lobby.home
}
}

View file

@ -28,13 +28,13 @@ object Monitor extends LilaController {
def status = Action {
Async {
(reporting ? GetStatus).mapTo[String].asPromise map { Ok(_) }
(reporting ? GetStatus).mapTo[String] map { Ok(_) }
}
}
def nbPlayers = Action {
Async {
(reporting ? GetNbMembers).mapTo[Int].asPromise map { players
(reporting ? GetNbMembers).mapTo[Int] map { players
Ok("%d %d".format(players, usernameMemo.preciseCount))
}
}
@ -42,7 +42,7 @@ object Monitor extends LilaController {
def nbMoves = Action {
Async {
(reporting ? GetNbMoves).mapTo[Int].asPromise map { Ok(_) }
(reporting ? GetNbMoves).mapTo[Int] map { Ok(_) }
}
}
}

View file

@ -140,11 +140,11 @@ object Round extends LilaController with TheftPrevention with RoundEventPerforme
def players(gameId: String) = Open { implicit ctx
import templating.Environment.playerLink
JsonIOk(gameRepo game gameId map { gameOption
gameOption.fold(Map()) { game
~(gameOption map { game
(game.players collect {
case player if player.isHuman player.color.name -> playerLink(player).text
} toMap) ++ ctx.me.fold(me Map("me" -> me.usernameWithElo), Map())
}
} toMap) ++ ~ctx.me.map(me Map("me" -> me.usernameWithElo))
})
})
}

View file

@ -40,9 +40,9 @@ object User extends LilaController {
val userSpy = isGranted(_.UserSpy) option securityStore.userSpy _
env.user.userInfo(u, bookmarkApi, userSpy, ctx) map { info
val filters = user.GameFilterMenu(info, ctx.me, filterName)
val paginator = filters.query.fold(
query gamePaginator.recentlyCreated(query, filters.cachedNb)(page),
bookmarkApi.gamePaginatorByUser(u, page))
val paginator = filters.query.fold(bookmarkApi.gamePaginatorByUser(u, page)) { query
gamePaginator.recentlyCreated(query, filters.cachedNb)(page)
}
html.user.show(u, info, paginator, filters)
}
}, io(html.user.disabled(u)))

View file

@ -103,7 +103,7 @@ object Cron {
Akka.system.scheduler.schedule(freq, randomize(freq), to._1, to._2)
}
def effect(freq: Duration, name: String)(op: IO[_]) {
def effect(freq: FiniteDuration, name: String)(op: IO[_]) {
val f = randomize(freq)
println("schedule effect %s every %s -> %s".format(name, freq, f))
Akka.system.scheduler.schedule(f, f) {
@ -111,7 +111,7 @@ object Cron {
}
}
def unsafe(freq: Duration, name: String)(op: Unit) {
def unsafe(freq: FiniteDuration, name: String)(op: Unit) {
Akka.system.scheduler.schedule(freq, randomize(freq)) {
tryNamed(name, op)
}
@ -127,7 +127,7 @@ object Cron {
}
}
private def randomize(d: Duration, ratio: Float = 0.1f): FiniteDuration = {
private def randomize(d: FiniteDuration, ratio: Float = 0.1f): FiniteDuration = {
import scala.util.Random
import scala.math.round
import ornicar.scalalib.Random.approximatly

View file

@ -77,9 +77,9 @@ final class PostApi(
def delete(postId: String, mod: User): IO[Unit] = for {
postOption env.postRepo byId postId
viewOption postOption.fold(io(none))(view)
_ viewOption.fold(
view for {
viewOption postOption.fold(io(none[PostView]))(view)
_ viewOption.fold(io()) { view
for {
_ (view.topic.nbPosts == 1).fold(
env.topicApi.delete(view.categ, view.topic),
for {
@ -90,10 +90,9 @@ final class PostApi(
} yield ()
)
post = view.post
_ modLog.deletePost(mod, post.userId, post.author, post.ip,
_ modLog.deletePost(mod, post.userId, post.author, post.ip,
text = "%s / %s / %s".format(view.categ.name, view.topic.name, post.text))
} yield (),
io()
)
} yield ()
}
} yield ()
}

View file

@ -12,9 +12,7 @@ final class TopicApi(env: ForumEnv, maxPerPage: Int) {
def show(categSlug: String, slug: String, page: Int): IO[Option[(Categ, Topic, Paginator[Post])]] =
for {
data get(categSlug, slug)
_ data.fold({
case (_, topic) env.topicRepo incViews topic
}, io())
_ data.fold(io())({ case (_, topic) env.topicRepo incViews topic })
} yield data map {
case (categ, topic) (categ, topic, env.postApi.paginator(topic, page))
}

View file

@ -130,15 +130,12 @@ case class DbGame(
ps = player encodePieces game.allPieces,
blurs = player.blurs + (blur && move.color == player.color).fold(1, 0),
moveTimes = (move.color == player.color).fold(
lastMoveTime.fold(
lmt (nowSeconds - lmt) |> { mt
lastMoveTime.fold("") { lmt
(nowSeconds - lmt) |> { mt
val encoded = MoveTime encode mt
player.moveTimes.isEmpty.fold(encoded.toString, player.moveTimes + encoded)
},
""
),
player.moveTimes)
)
}
}, player.moveTimes))
val updated = copy(
whitePlayer = copyPlayer(whitePlayer),
@ -158,7 +155,7 @@ case class DbGame(
)
val finalEvents = events :::
updated.clock.fold(c List(Event.Clock(c)), Nil) ::: {
~updated.clock.map(c List(Event.Clock(c))) ::: {
(updated.playable && (
abortable != updated.abortable || (Color.all exists { color
playerCanOfferDraw(color) != updated.playerCanOfferDraw(color)
@ -185,10 +182,9 @@ case class DbGame(
updatedAt = DateTime.now.some
))
def startClock(compensation: Float) = clock filterNot (_.isRunning) fold (
c copy(clock = c.run.giveTime(creatorColor, compensation).some),
this
)
def startClock(compensation: Float) = clock.filterNot(_.isRunning).fold(this) { c
copy(clock = c.run.giveTime(creatorColor, compensation).some)
}
def hasMoveTimes = players forall (_.hasMoveTimes)
@ -222,7 +218,7 @@ case class DbGame(
!(playerHasOfferedDraw(color))
def playerHasOfferedDraw(color: Color) =
player(color).lastDrawOffer.fold(_ >= turns - 1, false)
player(color).lastDrawOffer.fold(false)(_ >= turns - 1)
def playerCanRematch(color: Color) =
finishedOrAborted && opponent(color).isHuman && nonTournament
@ -273,14 +269,11 @@ case class DbGame(
def hasClock = clock.isDefined
def isClockRunning = clock.fold(_.isRunning, false)
def isClockRunning = clock.fold(false)(_.isRunning)
def withClock(c: Clock) = Progress(this, copy(clock = Some(c)))
def estimateTotalTime = clock.fold(
c c.limit + 30 * c.increment,
1200 // default to 20 minutes
)
def estimateTotalTime = clock.fold(1200) { c c.limit + 30 * c.increment }
def creator = player(creatorColor)
@ -310,12 +303,11 @@ case class DbGame(
}
def isBeingPlayed =
!finishedOrAborted && updatedAt.fold(_ > DateTime.now - 20.seconds, false)
!finishedOrAborted && updatedAt.fold(false)(_ > DateTime.now - 20.seconds)
def abandoned = updatedAt.fold(
u (status <= Status.Started) && (u <= DbGame.abandonedDate),
false
)
def abandoned = updatedAt.fold(false) { u =>
(status <= Status.Started) && (u <= DbGame.abandonedDate)
}
def hasBookmarks = bookmarks > 0
@ -437,7 +429,7 @@ case class RawDbGame(
clock = c map (_.decode),
lastMove = lm,
check = ck flatMap Pos.posAt,
creatorColor = cc.fold(Color.apply, Color.White),
creatorColor = cc.fold(Color.white)(Color.apply),
positionHashes = ph | "",
castles = cs | "-",
mode = (ra map Mode.apply) | Mode.Casual,

View file

@ -42,7 +42,7 @@ case class DbPlayer(
def hasUser = userId.isDefined
def isUser(u: User) = userId.fold(_ == u.id, false)
def isUser(u: User) = userId.fold(false)(_ == u.id)
def wins = isWinner getOrElse false

View file

@ -34,22 +34,22 @@ final class Export(user: User, gameRepo: GameRepo) {
List(
id,
dateFormatter.print(game.createdAt),
player.fold(_.color.name, "?"),
player.fold("?")(_.color.name),
(player map game.opponent flatMap (_.userId)) | "anonymous",
PgnDump result game,
game.status,
game.turns - 1,
game.variant,
game.mode,
game.clock.fold(c "%d %d".format(
c.limitInMinutes, c.increment),
"unlimited"),
(player flatMap (_.elo)).fold(_.toString, "?"),
(player flatMap (_.eloDiff)).fold(showEloDiff, "?"),
(player map game.opponent flatMap (_.elo)).fold(_.toString, "?"),
(player map game.opponent flatMap (_.eloDiff)).fold(showEloDiff, "?"),
baseUrl + routes.Round.watcher(game.id, player.fold(_.color.name, "white")),
baseUrl + routes.Analyse.replay(game.id, player.fold(_.color.name, "white")),
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),
(player map game.opponent flatMap (_.eloDiff)).fold("?")(showEloDiff),
baseUrl + routes.Round.watcher(game.id, player.fold("white")(_.color.name)),
baseUrl + routes.Analyse.replay(game.id, player.fold("white")(_.color.name)),
baseUrl + routes.Analyse.pgn(game.id)
)
}

View file

@ -2,9 +2,8 @@ package lila
package game
import akka.actor._
import akka.dispatch.{ Future, Await }
import scala.concurrent.{ Future, Await }
import akka.pattern.ask
import scala.concurrent.Duration
import scala.concurrent.duration._
import akka.util.Timeout
import play.api.Play.current

View file

@ -47,19 +47,19 @@ trait GameHelper { self: I18nHelper with UserHelper with StringHelper with AiHel
player.userId.fold(
"""<span class="user_link %s">%s</span>""".format(
cssClass | "",
player.aiLevel.fold(aiName, User.anonymous)
player.aiLevel.fold(User.anonymous)(aiName)
)
) { userId
userIdToUsername(userId) |> { username
"""<a class="user_link%s%s" href="%s">%s%s</a>""".format(
cssClass.fold(" " + _, ""),
~cssClass.map(" " + _),
withOnline.fold(
isUsernameOnline(username).fold(" online", " offline"),
""),
routes.User.show(username),
usernameWithElo(player) + player.eloDiff.filter(_ withDiff).fold(
diff " (%s)".format(showNumber(diff)),
""),
usernameWithElo(player) + ~(player.eloDiff filter (_ withDiff) map { diff
" (%s)".format(showNumber(diff))
}),
engine.fold(
"""<span class="engine_mark" title="%s"></span>""" format trans.thisPlayerUsesChessComputerAssistance(),
"")

View file

@ -37,7 +37,7 @@ final class GameRepo(collection: MongoCollection)
}
def pov(gameId: String, color: String): IO[Option[Pov]] =
Color(color).fold(pov(gameId, _), io(None))
Color(color).fold(io(none[Pov]))(pov(gameId, _))
def pov(fullId: String): IO[Option[Pov]] =
game(fullId take gameIdSize) map { gameOption
@ -62,8 +62,8 @@ final class GameRepo(collection: MongoCollection)
case (sets, unsets) {
val fullSets = ("ua" -> new Date) :: sets
val ops = unsets.isEmpty.fold(
$set(fullSets: _*),
$set(fullSets: _*) ++ $unset(unsets: _*)
$set(fullSets),
$set(fullSets) ++ $unset(unsets)
)
val wc = WriteConcern.None
io { collection.update(idSelector(progress.origin), ops, concern = wc) }

View file

@ -2,7 +2,7 @@ package lila
package game
import scalaz.effects._
import akka.dispatch.Future
import scala.concurrent.Future
abstract class Handler(gameRepo: GameRepo) extends core.Futuristic {

View file

@ -8,13 +8,10 @@ object Namer {
def player(player: DbPlayer, withElo: Boolean = true)(getUsername: String String) =
player.aiLevel.fold(
level "A.I. level " + level,
(player.userId map getUsername).fold(
username withElo.fold(
"%s (%s)".format(username, player.elo getOrElse "?"),
username),
User.anonymous)
)
(player.userId map getUsername).fold(User.anonymous) { username
withElo.fold("%s (%s)".format(username, player.elo getOrElse "?"), username)
}
) { level "A.I. level " + level }
def clock(clock: Clock): String = "%d minutes/side + %d seconds/move".format(
clock.limitInMinutes, clock.increment)

View file

@ -12,7 +12,7 @@ sealed abstract class Context(val req: RequestHeader, val me: Option[User]) {
def isAnon = !isAuth
def canSeeChat = me.fold(!_.isChatBan, false)
def canSeeChat = ~me.map(!_.isChatBan)
def isGranted(permission: Permission): Boolean = me.fold(Granter(permission), false)

View file

@ -27,11 +27,11 @@ final class Setting(ctx: Context) {
} getOrElse default
private def set(name: String, value: String)(userRepo: UserRepo): IO[Cookie] =
ctx.me.fold(
m userRepo.saveSetting(m, name, value.toString),
io()) map { _
LilaCookie.session(name, value.toString)(ctx.req)
}
ctx.me.fold(io()) { m
userRepo.saveSetting(m, name, value.toString)
} map { _
LilaCookie.session(name, value.toString)(ctx.req)
}
}
object Setting {

View file

@ -37,7 +37,7 @@ final class Translator(api: MessagesApi, pool: I18nPool) {
Some(if (args.isEmpty) pattern else pattern.format(args: _*))
}
catch {
case e {
case e: Exception {
println("Failed to translate %s -> %s (%s) - %s".format(
key, pattern, args, e.getMessage))
None

View file

@ -11,7 +11,7 @@ import tournament.Created
import play.api.mvc.Call
import play.api.libs.concurrent.Akka
import play.api.Play.current
import akka.dispatch.Future
import scala.concurrent.Future
import scala.concurrent.duration._
import akka.util.Timeout
import scalaz.effects._

View file

@ -42,7 +42,7 @@ final class Socket(hub: ActorRef, flood: Flood) {
val promise = for {
version versionOption
uid uidOption
} yield (hub ? Join(uid, username, version, hook)).asPromise map {
} yield (hub ? Join(uid, username, version, hook)) map {
case Connected(enumerator, channel)
val iteratee = Iteratee.foreach[JsValue] { e
e str "t" match {

View file

@ -2,9 +2,8 @@ package lila
package memo
import akka.actor._
import akka.dispatch.{ Future, Await }
import scala.concurrent.{ Future, Await }
import akka.pattern.ask
import scala.concurrent.Duration
import scala.concurrent.duration._
import akka.util.Timeout

View file

@ -54,7 +54,7 @@ final class Api(
for {
_ threadRepo saveIO newThread
receiver userRepo byId (thread receiverOf post)
_ receiver.fold(updateUser, io())
_ receiver.fold(io())(updateUser)
} yield thread
}

View file

@ -25,7 +25,7 @@ final class ModlogApi(repo: ModlogRepo) {
def deletePost(mod: User, userId: Option[String], author: Option[String], ip: Option[String], text: String) = add {
Modlog(mod.id, userId, Modlog.deletePost, details = Some(
author.fold(_ + " ", "") + ip.fold(_ + " ", "") + text.take(140)
author.fold("")(_ + " ") + ip.fold("")(_ + " ") + text.take(140)
))
}

View file

@ -8,7 +8,7 @@ import akka.actor._
import akka.pattern.{ ask, pipe }
import scala.concurrent.duration._
import akka.util.{ Duration, Timeout }
import akka.dispatch.{ Future, Promise }
import scala.concurrent.{ Future, Promise }
import play.api.libs.concurrent._
import play.api.Play.current
import scala.io.Source

View file

@ -21,7 +21,7 @@ final class Socket(hub: ActorRef) {
uidOption: Option[String]): SocketPromise = {
val promise: Option[SocketPromise] = for {
uid uidOption
} yield (hub ? Join(uid)).asPromise map {
} yield (hub ? Join(uid)) map {
case Connected(enumerator, channel)
val iteratee = Iteratee.foreach[JsValue] { e
e str "t" match {

View file

@ -5,6 +5,7 @@ import play.api.libs.concurrent.Promise
import play.api.libs.iteratee.{ Iteratee, Enumerator }
import play.api.libs.iteratee.Concurrent.Channel
import play.api.Play.current
import scala.concurrent.{ Future, Promise }
import com.novus.salat.{ Context, TypeHintFrequency, StringTypeHintStrategy }
import com.mongodb.casbah.commons.conversions.scala.RegisterJodaTimeConversionHelpers
@ -20,6 +21,7 @@ package object lila
with scalaz.NonEmptyLists
with scalaz.Strings
with scalaz.Lists
with scalaz.Zeros
with scalaz.Booleans {
type JsChannel = Channel[JsValue]

View file

@ -10,7 +10,7 @@ import chess.format.Forsyth
import scalaz.effects._
import akka.actor._
import akka.dispatch.{ Future, Await }
import scala.concurrent.{ Future, Await }
import akka.pattern.ask
import scala.concurrent.duration._
import akka.util.Timeout

View file

@ -8,7 +8,7 @@ import akka.actor.ReceiveTimeout
import scala.concurrent.duration._
import akka.util.Timeout
import akka.pattern.{ ask, pipe }
import akka.dispatch.Future
import scala.concurrent.Future
import play.api.libs.json._
import play.api.libs.concurrent._
import play.api.Play.current

View file

@ -5,7 +5,7 @@ import akka.actor._
import akka.pattern.ask
import scala.concurrent.duration._
import akka.util.Timeout
import akka.dispatch.Await
import scala.concurrent.Await
import play.api.libs.json._
import play.api.libs.iteratee._
import play.api.libs.concurrent._
@ -160,7 +160,7 @@ final class Socket(
enumerator)
}
}
} yield socket).asPromise: SocketPromise
} yield socket): SocketPromise
}) | connectionFail
// full game ids that have been hijacked

View file

@ -27,7 +27,7 @@ final class Socket(hub: ActorRef) {
flag: Option[String]): SocketPromise = {
val promise: Option[SocketPromise] = for {
uid uidOption
} yield (hub ? Join(uid, username, flag)).asPromise map {
} yield (hub ? Join(uid, username, flag)) map {
case Connected(enumerator, channel)
val iteratee = Iteratee.foreach[JsValue] { e
e str "t" match {

View file

@ -5,7 +5,7 @@ import akka.actor.ActorRef
import akka.pattern.{ ask, pipe }
import scala.concurrent._
import scala.concurrent.duration._
import akka.util.{ Duration, Timeout }
import akka.util.{ Timeout }
import play.api.libs.concurrent._
import play.api.Play.current
import play.api.libs.json._

View file

@ -8,7 +8,7 @@ import akka.actor.ReceiveTimeout
import scala.concurrent.duration._
import akka.util.Timeout
import akka.pattern.{ ask, pipe }
import akka.dispatch.{ Future, Promise }
import scala.concurrent.{ Future, Promise }
import play.api.libs.json._
import play.api.libs.concurrent._
import play.api.Play.current

View file

@ -8,7 +8,7 @@ import akka.actor._
import scala.concurrent.duration._
import akka.util.Timeout
import akka.pattern.{ ask, pipe }
import akka.dispatch.{ Future, Promise }
import scala.concurrent.{ Future, Promise }
import play.api.libs.concurrent._
import play.api.Play.current

View file

@ -6,7 +6,7 @@ import akka.actor.ReceiveTimeout
import scala.concurrent.duration._
import akka.util.Timeout
import akka.pattern.{ ask, pipe }
import akka.dispatch.{ Future, Promise }
import scala.concurrent.{ Future, Promise }
import play.api.libs.concurrent._
import play.api.Play.current
import play.api.libs.json._

View file

@ -5,7 +5,7 @@ import akka.actor._
import akka.pattern.ask
import scala.concurrent.duration._
import akka.util.Timeout
import akka.dispatch.Await
import scala.concurrent.Await
import play.api.libs.json._
import play.api.libs.iteratee._
import play.api.libs.concurrent._
@ -73,7 +73,7 @@ final class Socket(
},
enumerator)
}
} yield socket).asPromise: SocketPromise
} yield socket): SocketPromise
}) | connectionFail
}

View file

@ -83,11 +83,11 @@ class UserRepo(collection: MongoCollection)
}
def toggleChatBan(user: User): IO[Unit] = io {
collection.update(byIdQuery(user), $set("isChatBan" -> !user.isChatBan))
collection.update(byIdQuery(user), $set(Seq("isChatBan" -> !user.isChatBan)))
}
def saveSetting(user: User, key: String, value: String) = io {
collection.update(byIdQuery(user), $set(("settings." + key) -> value))
collection.update(byIdQuery(user), $set(Seq(("settings." + key) -> value)))
}
def exists(username: String): IO[Boolean] = io {

@ -1 +1 @@
Subproject commit d7f00b7275bb43179e4eebadc4c63e65a1b05085
Subproject commit 1d944956b54d6c17352149c2dbe8d3d8d4f7033e