From 502235f08af00d30667572d7a76eab44f5ce8c10 Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Fri, 18 May 2012 00:35:31 +0200 Subject: [PATCH] Ai start --- app/AppApi.scala | 153 ++++++++++++++++----------------- app/{lobby => }/Preload.scala | 2 +- app/controllers/AppApi.scala | 108 +++++++++++------------ app/controllers/Lobby.scala | 24 +++--- app/core/CoreEnv.scala | 35 +++++--- app/game/GameHelper.scala | 9 +- app/game/PlayerNamer.scala | 15 ++++ app/game/Pov.scala | 2 + app/lobby/Api.scala | 55 ++++++------ app/lobby/LobbyEnv.scala | 34 ++------ app/lobby/Starter.scala | 27 ------ app/setup/Processor.scala | 23 ++++- app/setup/SetupEnv.scala | 12 ++- app/setup/UserConfigRepo.scala | 4 +- app/timeline/Entry.scala | 21 ----- app/timeline/Push.scala | 36 ++++++++ app/timeline/TimelineEnv.scala | 10 ++- conf/routes | 26 +++--- 18 files changed, 306 insertions(+), 290 deletions(-) rename app/{lobby => }/Preload.scala (96%) create mode 100644 app/game/PlayerNamer.scala delete mode 100644 app/lobby/Starter.scala create mode 100644 app/timeline/Push.scala diff --git a/app/AppApi.scala b/app/AppApi.scala index 36c17c2df0..b68726a135 100644 --- a/app/AppApi.scala +++ b/app/AppApi.scala @@ -20,7 +20,6 @@ final class AppApi( gameRepo: GameRepo, roundSocket: round.Socket, messenger: round.Messenger, - starter: lobby.Starter, eloUpdater: EloUpdater, gameInfo: DbGame ⇒ IO[GameInfo]) { @@ -50,85 +49,85 @@ final class AppApi( } yield gameInfo } - def join( - fullId: String, - url: String, - messages: String, - entryData: String): IO[Valid[Unit]] = for { - povOption ← gameRepo pov fullId - op ← povOption.fold( - pov ⇒ for { - p1 ← starter.start(pov.game, entryData) - p2 ← messenger.systemMessages(p1.game, messages) map { evts ⇒ - p1 + Event.RedirectOwner(!pov.color, url) ++ evts - } - _ ← gameRepo save p2 - _ ← roundSocket send p2 - } yield success(), - io(GameNotFound) - ) - } yield op + //def join( + //fullId: String, + //url: String, + //messages: String, + //entryData: String): IO[Valid[Unit]] = for { + //povOption ← gameRepo pov fullId + //op ← povOption.fold( + //pov ⇒ for { + //p1 ← starter.start(pov.game, entryData) + //p2 ← messenger.systemMessages(p1.game, messages) map { evts ⇒ + //p1 + Event.RedirectOwner(!pov.color, url) ++ evts + //} + //_ ← gameRepo save p2 + //_ ← roundSocket send p2 + //} yield success(), + //io(GameNotFound) + //) + //} yield op - def start(gameId: String, entryData: String): IO[Valid[Unit]] = - gameRepo game gameId flatMap { gameOption ⇒ - gameOption.fold( - g1 ⇒ for { - progress ← starter.start(g1, entryData) - _ ← gameRepo save progress - _ ← roundSocket send progress - } yield success(Unit), - io { !!("No such game") } - ) - } + //def start(gameId: String, entryData: String): IO[Valid[Unit]] = + //gameRepo game gameId flatMap { gameOption ⇒ + //gameOption.fold( + //g1 ⇒ for { + //progress ← starter.start(g1, entryData) + //_ ← gameRepo save progress + //_ ← roundSocket send progress + //} yield success(Unit), + //io { !!("No such game") } + //) + //} - def rematchAccept( - gameId: String, - newGameId: String, - colorName: String, - whiteRedirect: String, - blackRedirect: String, - entryData: String, - messageString: String): IO[Valid[Unit]] = Color(colorName).fold( - color ⇒ for { - newGameOption ← gameRepo game newGameId - g1Option ← gameRepo game gameId - result ← (newGameOption |@| g1Option).apply( - (newGame, g1) ⇒ { - val progress = Progress(g1, List( - Event.RedirectOwner(White, whiteRedirect), - Event.RedirectOwner(Black, blackRedirect), - // tell spectators to reload the table - Event.ReloadTable(White), - Event.ReloadTable(Black))) - for { - _ ← gameRepo save progress - _ ← roundSocket send progress - newProgress ← starter.start(newGame, entryData) - newProgress2 ← messenger.systemMessages( - newProgress.game, messageString - ) map newProgress.++ - _ ← gameRepo save newProgress2 - _ ← roundSocket send newProgress2 - } yield success() - } - ).fold(identity, io(GameNotFound)) - } yield result, - io { !!("Wrong color name") } - ) + //def rematchAccept( + //gameId: String, + //newGameId: String, + //colorName: String, + //whiteRedirect: String, + //blackRedirect: String, + //entryData: String, + //messageString: String): IO[Valid[Unit]] = Color(colorName).fold( + //color ⇒ for { + //newGameOption ← gameRepo game newGameId + //g1Option ← gameRepo game gameId + //result ← (newGameOption |@| g1Option).apply( + //(newGame, g1) ⇒ { + //val progress = Progress(g1, List( + //Event.RedirectOwner(White, whiteRedirect), + //Event.RedirectOwner(Black, blackRedirect), + //// tell spectators to reload the table + //Event.ReloadTable(White), + //Event.ReloadTable(Black))) + //for { + //_ ← gameRepo save progress + //_ ← roundSocket send progress + //newProgress ← starter.start(newGame, entryData) + //newProgress2 ← messenger.systemMessages( + //newProgress.game, messageString + //) map newProgress.++ + //_ ← gameRepo save newProgress2 + //_ ← roundSocket send newProgress2 + //} yield success() + //} + //).fold(identity, io(GameNotFound)) + //} yield result, + //io { !!("Wrong color name") } + //) - def reloadTable(gameId: String): IO[Valid[Unit]] = for { - g1Option ← gameRepo game gameId - result ← g1Option.fold( - g1 ⇒ { - val progress = Progress(g1, Color.all map Event.ReloadTable) - for { - _ ← gameRepo save progress - _ ← roundSocket send progress - } yield success() - }, - io(GameNotFound) - ) - } yield result + //def reloadTable(gameId: String): IO[Valid[Unit]] = for { + //g1Option ← gameRepo game gameId + //result ← g1Option.fold( + //g1 ⇒ { + //val progress = Progress(g1, Color.all map Event.ReloadTable) + //for { + //_ ← gameRepo save progress + //_ ← roundSocket send progress + //} yield success() + //}, + //io(GameNotFound) + //) + //} yield result def gameVersion(gameId: String): Future[Int] = futureVersion(gameId) diff --git a/app/lobby/Preload.scala b/app/Preload.scala similarity index 96% rename from app/lobby/Preload.scala rename to app/Preload.scala index 8fdafade42..dd2e8cebd0 100644 --- a/app/lobby/Preload.scala +++ b/app/Preload.scala @@ -1,6 +1,6 @@ package lila -package lobby +import lobby.{ Fisherman, History, HookRepo, Hook, MessageRepo } import timeline.EntryRepo import game.GameRepo diff --git a/app/controllers/AppApi.scala b/app/controllers/AppApi.scala index 61690288ef..0beb00d55e 100644 --- a/app/controllers/AppApi.scala +++ b/app/controllers/AppApi.scala @@ -8,68 +8,68 @@ import play.api.libs.concurrent._ object AppApi extends LilaController { - private val api = env.appApi + //private val api = env.appApi - def show(fullId: String) = Action { - Async { - (api show fullId).asPromise map { op ⇒ - op.unsafePerformIO.fold(e ⇒ BadRequest(e.shows), JsonOk) - } - } - } + //def show(fullId: String) = Action { + //Async { + //(api show fullId).asPromise map { op ⇒ + //op.unsafePerformIO.fold(e ⇒ BadRequest(e.shows), JsonOk) + //} + //} + //} - def reloadTable(gameId: String) = Action { - ValidIOk(api reloadTable gameId) - } + //def reloadTable(gameId: String) = Action { + //ValidIOk(api reloadTable gameId) + //} - def start(gameId: String) = Action { implicit req ⇒ - FormValidIOk[EntryData](entryForm)(entryData ⇒ api.start(gameId, entryData)) - } + //def start(gameId: String) = Action { implicit req ⇒ + //FormValidIOk[EntryData](entryForm)(entryData ⇒ api.start(gameId, entryData)) + //} - def join(fullId: String) = Action { implicit req ⇒ - FormValidIOk[JoinData](joinForm) { join ⇒ - api.join(fullId, join._1, join._2, join._3) - } - } + //def join(fullId: String) = Action { implicit req ⇒ + //FormValidIOk[JoinData](joinForm) { join ⇒ + //api.join(fullId, join._1, join._2, join._3) + //} + //} - def activity(gameId: String, color: String) = Action { - Async { - api.isConnected(gameId, color).asPromise map { bool ⇒ - Ok(bool.fold(1, 0)) - } - } - } + //def activity(gameId: String, color: String) = Action { + //Async { + //api.isConnected(gameId, color).asPromise map { bool ⇒ + //Ok(bool.fold(1, 0)) + //} + //} + //} - def gameVersion(gameId: String) = Action { - Async { - (api gameVersion gameId).asPromise map { Ok(_) } - } - } + //def gameVersion(gameId: String) = Action { + //Async { + //(api gameVersion gameId).asPromise map { Ok(_) } + //} + //} - def gameInfo(gameId: String) = Action { - (api gameInfo gameId).unsafePerformIO.fold( - info ⇒ JsonOk(info.toMap), - BadRequest("No such game") - ) - } + //def gameInfo(gameId: String) = Action { + //(api gameInfo gameId).unsafePerformIO.fold( + //info ⇒ JsonOk(info.toMap), + //BadRequest("No such game") + //) + //} - def rematchAccept(gameId: String, color: String, newGameId: String) = Action { implicit req ⇒ - FormValidIOk[RematchData](rematchForm)(r ⇒ - api.rematchAccept(gameId, newGameId, color, r._1, r._2, r._3, r._4)) - } + //def rematchAccept(gameId: String, color: String, newGameId: String) = Action { implicit req ⇒ + //FormValidIOk[RematchData](rematchForm)(r ⇒ + //api.rematchAccept(gameId, newGameId, color, r._1, r._2, r._3, r._4)) + //} - def adjust(username: String) = Action { - IOk(api adjust username) - } + //def adjust(username: String) = Action { + //IOk(api adjust username) + //} - def captcha = Action { - env.site.captcha.create.unsafePerformIO.fold( - err ⇒ BadRequest(err.shows), - data ⇒ JsonOk(Map( - "id" -> data._1, - "fen" -> data._2, - "color" -> data._3.toString - )) - ) - } + //def captcha = Action { + //env.site.captcha.create.unsafePerformIO.fold( + //err ⇒ BadRequest(err.shows), + //data ⇒ JsonOk(Map( + //"id" -> data._1, + //"fen" -> data._2, + //"color" -> data._3.toString + //)) + //) + //} } diff --git a/app/controllers/Lobby.scala b/app/controllers/Lobby.scala index c8a72d2d7d..b351181298 100644 --- a/app/controllers/Lobby.scala +++ b/app/controllers/Lobby.scala @@ -14,8 +14,8 @@ import play.api.libs.iteratee._ object Lobby extends LilaController { - private val api = env.lobby.api - private val preloader = env.lobby.preloader + //private val api = env.lobby.api + private val preloader = env.preloader val home = Open { implicit ctx ⇒ renderHome(ctx).fold(identity, Ok(_)) @@ -46,10 +46,10 @@ object Lobby extends LilaController { ) } - def cancel(ownerId: String) = Action { - api.cancel(ownerId).unsafePerformIO - Redirect("/") - } + def cancel(ownerId: String) = TODO + //api.cancel(ownerId).unsafePerformIO + //Redirect("/") + //} def join(hookId: String) = TODO @@ -59,11 +59,11 @@ object Lobby extends LilaController { //) //} - def create(hookOwnerId: String) = Action { - IOk(api create hookOwnerId) - } + //def create(hookOwnerId: String) = Action { + //IOk(api create hookOwnerId) + //} - def chatBan(username: String) = Action { - IOk(env.lobby.messenger ban username) - } + //def chatBan(username: String) = Action { + //IOk(env.lobby.messenger ban username) + //} } diff --git a/app/core/CoreEnv.scala b/app/core/CoreEnv.scala index 40651404ba..54beb62b15 100644 --- a/app/core/CoreEnv.scala +++ b/app/core/CoreEnv.scala @@ -30,20 +30,21 @@ final class CoreEnv private (application: Application, val settings: Settings) { settings = settings, mongodb = mongodb.apply _, userRepo = user.userRepo, - gameRepo = game.gameRepo, roundSocket = round.socket, - roundMessenger = round.messenger, - entryRepo = timeline.entryRepo, - ai = ai.ai) + roundMessenger = round.messenger) lazy val setup = new lila.setup.SetupEnv( settings = settings, mongodb = mongodb.apply _, - gameRepo = game.gameRepo) + gameRepo = game.gameRepo, + timelinePush = timeline.push.apply, + ai = ai.ai) lazy val timeline = new lila.timeline.TimelineEnv( settings = settings, - mongodb = mongodb.apply _) + mongodb = mongodb.apply _, + lobbyNotify = lobby.socket.addEntry, + getUsername = user.cached.username) lazy val ai = new lila.ai.AiEnv( settings = settings) @@ -71,14 +72,22 @@ final class CoreEnv private (application: Application, val settings: Settings) { settings = settings, gameRepo = game.gameRepo) - lazy val appApi = new AppApi( - userRepo = user.userRepo, + lazy val preloader = new Preload( + fisherman = lobby.fisherman, + history = lobby.history, + hookRepo = lobby.hookRepo, gameRepo = game.gameRepo, - roundSocket = round.socket, - messenger = round.messenger, - starter = lobby.starter, - eloUpdater = user.eloUpdater, - gameInfo = analyse.gameInfo) + messageRepo = lobby.messageRepo, + entryRepo = timeline.entryRepo) + + //lazy val appApi = new AppApi( + //userRepo = user.userRepo, + //gameRepo = game.gameRepo, + //roundSocket = round.socket, + //messenger = round.messenger, + //starter = lobby.starter, + //eloUpdater = user.eloUpdater, + //gameInfo = analyse.gameInfo) lazy val mongodb = MongoConnection( new MongoServer(MongoHost, MongoPort), diff --git a/app/game/GameHelper.scala b/app/game/GameHelper.scala index fd3cc0c523..553c829d2f 100644 --- a/app/game/GameHelper.scala +++ b/app/game/GameHelper.scala @@ -14,7 +14,6 @@ import play.api.mvc.Call trait GameHelper { self: I18nHelper with UserHelper ⇒ - val anonPlayerName = "Anonymous" val aiName = "Crafty A.I." def variantName(variant: Variant)(implicit ctx: Context) = variant match { @@ -28,13 +27,7 @@ trait GameHelper { self: I18nHelper with UserHelper ⇒ def clockName(clock: Clock): String = "%d minutes/side + %d seconds/move".format( clock.limitInMinutes, clock.increment) - def usernameWithElo(player: DbPlayer) = - player.aiLevel.fold( - level ⇒ "A.I. level " + level, - (player.userId map userIdToUsername).fold( - username ⇒ "%s (%s)".format(username, player.elo getOrElse "?"), - anonPlayerName) - ) + def usernameWithElo(player: DbPlayer) = PlayerNamer(player)(userIdToUsername) def playerLink(player: DbPlayer, cssClass: Option[String] = None) = Html { player.userId.fold( diff --git a/app/game/PlayerNamer.scala b/app/game/PlayerNamer.scala new file mode 100644 index 0000000000..446cbeb439 --- /dev/null +++ b/app/game/PlayerNamer.scala @@ -0,0 +1,15 @@ +package lila +package game + +object PlayerNamer { + + val anonPlayerName = "Anonymous" + + def apply(player: DbPlayer)(getUsername: String ⇒ String) = + player.aiLevel.fold( + level ⇒ "A.I. level " + level, + (player.userId map getUsername).fold( + username ⇒ "%s (%s)".format(username, player.elo getOrElse "?"), + anonPlayerName) + ) +} diff --git a/app/game/Pov.scala b/app/game/Pov.scala index 7293ea8798..d25049e5be 100644 --- a/app/game/Pov.scala +++ b/app/game/Pov.scala @@ -21,6 +21,8 @@ case class Pov(game: DbGame, color: Color) { fullId some { game.isPlayerFullId(player, _) } none false def ref = PovRef(game.id, color) + + def withGame(g: DbGame) = Pov(g, color) } object Pov { diff --git a/app/lobby/Api.scala b/app/lobby/Api.scala index e91cbcd8db..58b9484c54 100644 --- a/app/lobby/Api.scala +++ b/app/lobby/Api.scala @@ -12,40 +12,39 @@ final class Api( fisherman: Fisherman, gameRepo: GameRepo, roundSocket: RoundSocket, - roundMessenger: RoundMessenger, - starter: Starter) { + roundMessenger: RoundMessenger) { def cancel(ownerId: String): IO[Unit] = for { hook ← hookRepo ownedHook ownerId _ ← hook.fold(fisherman.delete, io()) } yield () - def join( - gameId: String, - colorName: String, - entryData: String, - messageString: String, - hookOwnerId: String, - myHookOwnerId: Option[String]): IO[Valid[Unit]] = for { - hook ← hookRepo ownedHook hookOwnerId - gameOption ← gameRepo game gameId - result ← (Color(colorName) |@| gameOption).apply( - (color, game) ⇒ { - for { - p1 ← starter.start(game, entryData) - p2 ← roundMessenger.systemMessages(game, messageString) map p1.++ - _ ← gameRepo save p2 - _ ← roundSocket send p2 - _ ← hook.fold(h ⇒ fisherman.bite(h, p2.game), io()) - _ ← myHookOwnerId.fold( - ownerId ⇒ hookRepo ownedHook ownerId flatMap { myHook ⇒ - myHook.fold(fisherman.delete, io()) - }, - io()) - } yield success() - } - ).fold(identity, io(GameNotFound)) - } yield result + //def join( + //gameId: String, + //colorName: String, + //entryData: String, + //messageString: String, + //hookOwnerId: String, + //myHookOwnerId: Option[String]): IO[Valid[Unit]] = for { + //hook ← hookRepo ownedHook hookOwnerId + //gameOption ← gameRepo game gameId + //result ← (Color(colorName) |@| gameOption).apply( + //(color, game) ⇒ { + //for { + //p1 ← starter.start(game, entryData) + //p2 ← roundMessenger.systemMessages(game, messageString) map p1.++ + //_ ← gameRepo save p2 + //_ ← roundSocket send p2 + //_ ← hook.fold(h ⇒ fisherman.bite(h, p2.game), io()) + //_ ← myHookOwnerId.fold( + //ownerId ⇒ hookRepo ownedHook ownerId flatMap { myHook ⇒ + //myHook.fold(fisherman.delete, io()) + //}, + //io()) + //} yield success() + //} + //).fold(identity, io(GameNotFound)) + //} yield result def create(hookOwnerId: String): IO[Unit] = for { hook ← hookRepo ownedHook hookOwnerId diff --git a/app/lobby/LobbyEnv.scala b/app/lobby/LobbyEnv.scala index 4c4ec8965c..ce92d8e5c8 100644 --- a/app/lobby/LobbyEnv.scala +++ b/app/lobby/LobbyEnv.scala @@ -13,7 +13,6 @@ import play.api.i18n.MessagesPlugin import user.UserRepo import game.GameRepo import round.{ Socket ⇒ RoundSocket, Messenger ⇒ RoundMessenger } -import timeline.EntryRepo import ai.Ai import core.Settings @@ -22,21 +21,12 @@ final class LobbyEnv( settings: Settings, mongodb: String ⇒ MongoCollection, userRepo: UserRepo, - gameRepo: GameRepo, roundSocket: RoundSocket, - roundMessenger: RoundMessenger, - entryRepo: EntryRepo, - ai: () ⇒ Ai) { + roundMessenger: RoundMessenger) { implicit val ctx = app import settings._ - lazy val starter = new Starter( - gameRepo = gameRepo, - entryRepo = entryRepo, - ai = ai, - socket = socket) - lazy val history = new History(timeout = LobbyMessageLifetime) lazy val messenger = new Messenger( @@ -51,14 +41,6 @@ final class LobbyEnv( lazy val socket = new Socket(hub = hub) - lazy val preloader = new Preload( - fisherman = fisherman, - history = history, - hookRepo = hookRepo, - gameRepo = gameRepo, - messageRepo = messageRepo, - entryRepo = entryRepo) - lazy val fisherman = new Fisherman( hookRepo = hookRepo, hookMemo = hookMemo, @@ -68,13 +50,13 @@ final class LobbyEnv( collection = mongodb(MongoCollectionMessage), max = LobbyMessageMax) - lazy val api = new Api( - hookRepo = hookRepo, - fisherman = fisherman, - gameRepo = gameRepo, - roundSocket = roundSocket, - roundMessenger = roundMessenger, - starter = starter) + //lazy val api = new Api( + //hookRepo = hookRepo, + //fisherman = fisherman, + //gameRepo = gameRepo, + //roundSocket = roundSocket, + //roundMessenger = roundMessenger, + //starter = starter) lazy val hookRepo = new HookRepo(mongodb(MongoCollectionHook)) diff --git a/app/lobby/Starter.scala b/app/lobby/Starter.scala deleted file mode 100644 index 2a54927a52..0000000000 --- a/app/lobby/Starter.scala +++ /dev/null @@ -1,27 +0,0 @@ -package lila -package lobby - -import timeline.{ EntryRepo, Entry } -import game.{ GameRepo, DbGame } -import round.{ Progress } -import ai.Ai - -import scalaz.effects._ - -final class Starter( - gameRepo: GameRepo, - entryRepo: EntryRepo, - socket: Socket, - ai: () ⇒ Ai) { - - def start(game: DbGame, entryData: String): IO[Progress] = for { - _ ← if (game.variant.standard) io() else gameRepo saveInitialFen game - _ ← Entry(game, entryData).fold( - entry ⇒ entryRepo add entry flatMap { _ ⇒ socket addEntry entry }, - io()) - progress ← if (game.player.isHuman) io(Progress(game)) else for { - aiResult ← ai()(game) map (_.err) - (newChessGame, move) = aiResult - } yield game.update(newChessGame, move) - } yield progress -} diff --git a/app/setup/Processor.scala b/app/setup/Processor.scala index f33d63ce8f..00812f9dbd 100644 --- a/app/setup/Processor.scala +++ b/app/setup/Processor.scala @@ -2,14 +2,17 @@ package lila package setup import http.Context -import game.{ GameRepo, Pov } +import game.{ DbGame, GameRepo, Pov } import chess.{ Game, Board } +import ai.Ai import scalaz.effects._ final class Processor( configRepo: UserConfigRepo, - gameRepo: GameRepo) { + gameRepo: GameRepo, + timelinePush: DbGame ⇒ IO[Unit], + ai: () ⇒ Ai) { def ai(config: AiConfig)(implicit ctx: Context): IO[Pov] = for { _ ← ctx.me.fold( @@ -17,6 +20,18 @@ final class Processor( io() ) pov = config.pov - _ ← gameRepo insert pov.game - } yield pov + game = pov.game + _ ← gameRepo insert game + _ ← game.variant.standard.fold(io(), gameRepo saveInitialFen game) + _ ← timelinePush(game) + pov2 ← game.player.isHuman.fold( + io(pov), + for { + aiResult ← ai()(game) map (_.err) + (newChessGame, move) = aiResult + progress = game.update(newChessGame, move) + _ ← gameRepo save progress + } yield pov withGame progress.game + ) + } yield pov2 } diff --git a/app/setup/SetupEnv.scala b/app/setup/SetupEnv.scala index b5bd287b7d..07fd5e7d6f 100644 --- a/app/setup/SetupEnv.scala +++ b/app/setup/SetupEnv.scala @@ -2,14 +2,18 @@ package lila package setup import com.mongodb.casbah.MongoCollection +import scalaz.effects._ import core.Settings -import game.GameRepo +import game.{ DbGame, GameRepo } +import ai.Ai final class SetupEnv( settings: Settings, mongodb: String ⇒ MongoCollection, - gameRepo: GameRepo) { + gameRepo: GameRepo, + timelinePush: DbGame ⇒ IO[Unit], + ai: () ⇒ Ai) { import settings._ @@ -20,5 +24,7 @@ final class SetupEnv( lazy val processor = new Processor( configRepo = configRepo, - gameRepo = gameRepo) + gameRepo = gameRepo, + timelinePush = timelinePush, + ai = ai) } diff --git a/app/setup/UserConfigRepo.scala b/app/setup/UserConfigRepo.scala index 9aa6c26dc1..ae1242428e 100644 --- a/app/setup/UserConfigRepo.scala +++ b/app/setup/UserConfigRepo.scala @@ -24,8 +24,8 @@ class UserConfigRepo(collection: MongoCollection) def save(config: UserConfig): IO[Unit] = io { update( - DBObject("_id" -> config.id).pp, - _grater asDBObject config.encode.pp, + DBObject("_id" -> config.id), + _grater asDBObject config.encode, upsert = true, wc = WriteConcern.Safe) } diff --git a/app/timeline/Entry.scala b/app/timeline/Entry.scala index 40c77abfc5..2ffb8878a1 100644 --- a/app/timeline/Entry.scala +++ b/app/timeline/Entry.scala @@ -1,8 +1,6 @@ package lila package timeline -import game.DbGame - import com.novus.salat.annotations._ import com.mongodb.BasicDBList @@ -32,22 +30,3 @@ case class Entry( rated ? "Rated" | "Casual", clock | "Unlimited") } - -object Entry { - - def apply(game: DbGame, encodedData: String): Option[Entry] = - encodedData.split('$').toList match { - case wu :: wue :: bu :: bue :: Nil ⇒ Some( - new Entry( - gameId = game.id, - whiteName = wue, - blackName = bue, - whiteId = Some(wu) filter (_.nonEmpty), - blackId = Some(bu) filter (_.nonEmpty), - variant = game.variant.name, - rated = game.isRated, - clock = game.clock map (_.show)) - ) - case _ ⇒ None - } -} diff --git a/app/timeline/Push.scala b/app/timeline/Push.scala new file mode 100644 index 0000000000..a0900380a3 --- /dev/null +++ b/app/timeline/Push.scala @@ -0,0 +1,36 @@ +package lila +package timeline + +import chess.Color +import game.{ DbGame, PlayerNamer } + +import scalaz.effects._ + +final class Push( + entryRepo: EntryRepo, + lobbyNotify: Entry ⇒ IO[Unit], + getUsername: String ⇒ String) { + + def apply(game: DbGame): IO[Unit] = makeEntry(game) |> { entry ⇒ + for { + _ ← entryRepo add entry + _ ← lobbyNotify(entry) + } yield () + } + + private def makeEntry(game: DbGame) = Entry( + gameId = game.id, + whiteName = usernameElo(game, Color.White), + blackName = usernameElo(game, Color.Black), + whiteId = userId(game, Color.White), + blackId = userId(game, Color.Black), + variant = game.variant.name, + rated = game.isRated, + clock = game.clock map (_.show)) + + private def userId(game: DbGame, color: Color): Option[String] = + (game player color).userId + + private def usernameElo(game: DbGame, color: Color): String = + PlayerNamer(game player color)(getUsername) +} diff --git a/app/timeline/TimelineEnv.scala b/app/timeline/TimelineEnv.scala index 94d7803ac3..7ff2791b06 100644 --- a/app/timeline/TimelineEnv.scala +++ b/app/timeline/TimelineEnv.scala @@ -2,16 +2,24 @@ package lila package timeline import com.mongodb.casbah.MongoCollection +import scalaz.effects._ import core.Settings final class TimelineEnv( settings: Settings, - mongodb: String ⇒ MongoCollection) { + mongodb: String ⇒ MongoCollection, + lobbyNotify: Entry ⇒ IO[Unit], + getUsername: String => String) { import settings._ lazy val entryRepo = new EntryRepo( collection = mongodb(settings.MongoCollectionEntry), max = LobbyEntryMax) + + lazy val push = new Push( + entryRepo = entryRepo, + lobbyNotify = lobbyNotify, + getUsername = getUsername) } diff --git a/conf/routes b/conf/routes index 119578677a..13d642acf1 100644 --- a/conf/routes +++ b/conf/routes @@ -63,17 +63,17 @@ GET /socket/:gameId/:color controllers.App.gameSocket(gameId: String, GET /ai controllers.Ai.run # App Private API -POST /api/start/:gameId controllers.AppApi.start(gameId: String) -POST /api/join/$fullId<[\w\-]{12}> controllers.AppApi.join(fullId: String) -POST /api/reload-table/:gameId controllers.AppApi.reloadTable(gameId: String) -POST /api/adjust/:username controllers.AppApi.adjust(username: String) -GET /api/activity/:gameId/:color controllers.AppApi.activity(gameId: String, color: String) -GET /api/game-version/:gameId controllers.AppApi.gameVersion(gameId: String) -GET /api/game-info/:gameId controllers.AppApi.gameInfo(gameId: String) -POST /api/rematch-accept/:gameId/:color/:newGameId controllers.AppApi.rematchAccept(gameId: String, color: String, newGameId: String) - -GET /api/captcha/create controllers.Captcha.create -GET /api/captcha/solve/:gameId controllers.Captcha.solve(gameId: String) +#POST /api/start/:gameId controllers.AppApi.start(gameId: String) +#POST /api/join/$fullId<[\w\-]{12}> controllers.AppApi.join(fullId: String) +#POST /api/reload-table/:gameId controllers.AppApi.reloadTable(gameId: String) +#POST /api/adjust/:username controllers.AppApi.adjust(username: String) +#GET /api/activity/:gameId/:color controllers.AppApi.activity(gameId: String, color: String) +#GET /api/game-version/:gameId controllers.AppApi.gameVersion(gameId: String) +#GET /api/game-info/:gameId controllers.AppApi.gameInfo(gameId: String) +#POST /api/rematch-accept/:gameId/:color/:newGameId controllers.AppApi.rematchAccept(gameId: String, color: String, newGameId: String) +# +#GET /api/captcha/create controllers.Captcha.create +#GET /api/captcha/solve/:gameId controllers.Captcha.solve(gameId: String) # Lobby Public API GET / controllers.Lobby.home @@ -84,8 +84,8 @@ GET /lobby/socket controllers.Lobby.socket # Lobby Private API #POST /api/lobby/join/:gameId/:color controllers.Lobby.join(gameId: String, color: String) #GET /api/lobby/preload controllers.Lobby.preload -POST /api/lobby/create/:hookOwnerId controllers.Lobby.create(hookOwnerId: String) -POST /api/lobby/chat-ban/:username controllers.Lobby.chatBan(username: String) +#POST /api/lobby/create/:hookOwnerId controllers.Lobby.create(hookOwnerId: String) +#POST /api/lobby/chat-ban/:username controllers.Lobby.chatBan(username: String) # Reporting API GET /nb-players controllers.Report.nbPlayers