diff --git a/app/controllers/Setup.scala b/app/controllers/Setup.scala index 0c3343fa9c..c06d574729 100644 --- a/app/controllers/Setup.scala +++ b/app/controllers/Setup.scala @@ -181,7 +181,9 @@ object Setup extends LilaController with TheftPrevention with play.api.http.Cont config => op(config)(ctx) flatMap { case (pov, call) => negotiate( html = fuccess(redirectPov(pov, call)), - api = fuccess(Created(lila.api.JsonView.pov(pov)) as JSON) + api = Env.round version pov.gameId map { v => + Created(Env.round.jsonView.playerJson(pov, v, ctx.pref)) as JSON + } ) } ) diff --git a/app/views/round/player.scala.html b/app/views/round/player.scala.html index 2cd1fb27f7..a9b5a77e54 100644 --- a/app/views/round/player.scala.html +++ b/app/views/round/player.scala.html @@ -16,10 +16,7 @@ goodies = views.html.game.infoBox(pov, tour), chat = chat.map(c => base.chat(c, trans.chatRoom.str())), underchat = underchat.some, signedJs = hijackEnabled(pov.game) option routes.Round.signedJs(pov.gameId) map (_.toString)) { -
+
@Html(lila.app.ui.Board.render(pov))
@trans.premoveEnabledClickAnywhereToCancel()
diff --git a/app/views/round/watcherGame.scala.html b/app/views/round/watcherGame.scala.html index 136ac8951f..816f217156 100644 --- a/app/views/round/watcherGame.scala.html +++ b/app/views/round/watcherGame.scala.html @@ -2,10 +2,7 @@ @import pov._ -
+
@Html(lila.app.ui.Board.render(pov))
@trans.youAreViewingThisGameAsASpectator()
diff --git a/doc/mobile-api.md b/doc/mobile-api.md index bb55de0160..5fb261b76f 100644 --- a/doc/mobile-api.md +++ b/doc/mobile-api.md @@ -35,11 +35,11 @@ All websocket messages, sent or received, are composed of a type `t` and data `d ## Connect to a game as a player ```javascript -var playerId; // obtained from game creation API +var baseUrl; // obtained from game creation API (`url.socket`) var clientId; // created by the client var socketVersion = 0; // last message version number seen on this socket. Starts at zero. -var socketUrl = 'http://socket.en.l.org:9021/' + playerId + '/socket?sri=' + clientId + '&version=' + socketVersion; +var socketUrl = 'http://socket.en.l.org:9021' + baseUrl + '?sri=' + clientId + '&version=' + socketVersion; var socket = new WebSocket(socketUrl); ``` diff --git a/modules/api/src/main/JsonView.scala b/modules/api/src/main/JsonView.scala deleted file mode 100644 index a39573cd5f..0000000000 --- a/modules/api/src/main/JsonView.scala +++ /dev/null @@ -1,23 +0,0 @@ -package lila.api - -import play.api.http.ContentTypes.JSON -import play.api.libs.json.{ JsObject, Json => J } -import play.api.mvc.Results.Ok - -import chess.format.Forsyth -import lila.game.{ Game, Pov } - -object JsonView { - - def pov(p: Pov) = J.obj( - "game" -> game(p.game), - "player" -> player(p)) - - private def game(g: Game) = J.obj( - "id" -> g.id, - "fen" -> (Forsyth >> g.toChess)) - - private def player(p: Pov) = J.obj( - "id" -> p.fullId, - "color" -> p.color.name) -} diff --git a/modules/round/src/main/Env.scala b/modules/round/src/main/Env.scala index 298bffeb11..8df5c77d00 100644 --- a/modules/round/src/main/Env.scala +++ b/modules/round/src/main/Env.scala @@ -139,9 +139,10 @@ final class Env( private lazy val reminder = new Reminder(db(CollectionReminder)) def nowPlaying = reminder.nowPlaying - private[round] def animationDelay = AnimationDelay private[round] def moretimeSeconds = Moretime.toSeconds + lazy val jsonView = new JsonView(AnimationDelay) + { import scala.concurrent.duration._ diff --git a/modules/round/src/main/JsonView.scala b/modules/round/src/main/JsonView.scala new file mode 100644 index 0000000000..5789c19707 --- /dev/null +++ b/modules/round/src/main/JsonView.scala @@ -0,0 +1,101 @@ +package lila.round + +import scala.concurrent.duration._ +import scala.math.{ min, max, round } + +import play.api.libs.json.Json + +import lila.common.PimpedJson._ +import lila.game.{ Pov, Game } +import lila.pref.Pref + +final class JsonView(baseAnimationDelay: Duration) { + + def playerJson(pov: Pov, version: Int, pref: Pref) = { + import pov._ + Json.obj( + "game" -> Json.obj( + "id" -> gameId, + "started" -> game.started, + "finished" -> game.finishedOrAborted, + "clock" -> game.hasClock, + "clockRunning" -> game.isClockRunning, + "player" -> game.turnColor.name, + "turns" -> game.turns, + "startedAtTurn" -> game.startedAtTurn, + "lastMove" -> game.castleLastMoveTime.lastMoveString), + "player" -> Json.obj( + "id" -> playerId, + "color" -> player.color.name, + "version" -> version, + "spectator" -> false + ), + "opponent" -> Json.obj( + "color" -> opponent.color.name, + "ai" -> opponent.isAi + ), + "url" -> Json.obj( + "socket" -> s"/$fullId/socket", + "end" -> s"/$fullId/end", + "table" -> s"/$fullId/table" + ), + "pref" -> Json.obj( + "animationDelay" -> animationDelay(pov), + "autoQueen" -> pref.autoQueen, + "autoThreefold" -> pref.autoThreefold, + "clockTenths" -> pref.clockTenths, + "clockBar" -> pref.clockBar, + "enablePremove" -> pref.premove + ), + "possibleMoves" -> possibleMoves(pov), + "tournamentId" -> game.tournamentId + ).noNull + } + + def watcherJson(pov: Pov, version: Int, tv: Boolean, pref: Pref) = { + import pov._ + Json.obj( + "game" -> Json.obj( + "id" -> gameId, + "started" -> game.started, + "finished" -> game.finishedOrAborted, + "clock" -> game.hasClock, + "clockRunning" -> game.isClockRunning, + "player" -> game.turnColor.name, + "turns" -> game.turns, + "startedAtTurn" -> game.startedAtTurn, + "lastMove" -> game.castleLastMoveTime.lastMoveString), + "player" -> Json.obj( + "color" -> color.name, + "version" -> version, + "spectator" -> true), + "opponent" -> Json.obj( + "color" -> opponent.color.name, + "ai" -> opponent.isAi), + "url" -> Json.obj( + "socket" -> s"/$gameId/${color.name}/socket", + "end" -> s"/$gameId/${color.name}/end", + "table" -> s"/$gameId/${color.name}/table" + ), + "pref" -> Json.obj( + "animationDelay" -> animationDelay(pov), + "clockTenths" -> pref.clockTenths, + "clockBar" -> pref.clockBar + ), + "possibleMoves" -> possibleMoves(pov), + "tv" -> tv + ).noNull + } + + private def possibleMoves(pov: Pov) = (pov.game playableBy pov.player) option { + pov.game.toChess.situation.destinations map { + case (from, dests) => from.key -> dests.mkString + } + } + + private def animationDelay(pov: Pov) = round { + baseAnimationDelay.toMillis * max(0, min(1.2, + ((pov.game.estimateTotalTime - 60) / 60) * 0.2 + )) + } +} diff --git a/modules/round/src/main/RoundHelper.scala b/modules/round/src/main/RoundHelper.scala index 1d2168092e..5cfcd3af13 100644 --- a/modules/round/src/main/RoundHelper.scala +++ b/modules/round/src/main/RoundHelper.scala @@ -1,14 +1,10 @@ package lila.round -import scala.math.{ min, max, round } - import play.api.libs.json.Json -import lila.game.Game -import lila.game.Pov +import lila.game.{ Pov, Game } import lila.pref.Pref import lila.round.Env.{ current => roundEnv } -import lila.user.UserContext trait RoundHelper { @@ -16,80 +12,9 @@ trait RoundHelper { def moretimeSeconds = roundEnv.moretimeSeconds - def gameAnimationDelay = roundEnv.animationDelay + def roundPlayerJsData(pov: Pov, version: Int, pref: Pref) = + roundEnv.jsonView.playerJson(pov, version, pref) - def roundPlayerJsData(pov: Pov, version: Int, pref: Pref)(implicit ctx: UserContext) = { - import pov._ - Json.obj( - "game" -> Json.obj( - "id" -> gameId, - "started" -> game.started, - "finished" -> game.finishedOrAborted, - "clock" -> game.hasClock, - "clockRunning" -> game.isClockRunning, - "player" -> game.turnColor.name, - "turns" -> game.turns, - "startedAtTurn" -> game.startedAtTurn, - "lastMove" -> game.castleLastMoveTime.lastMoveString), - "player" -> Json.obj( - "id" -> player.id, - "color" -> player.color.name, - "version" -> version, - "spectator" -> false - ), - "opponent" -> Json.obj( - "color" -> opponent.color.name, - "ai" -> opponent.isAi - ), - "possibleMoves" -> possibleMoves(pov), - "animationDelay" -> animationDelay(pov), - "autoQueen" -> pref.autoQueen, - "autoThreefold" -> pref.autoThreefold, - "clockTenths" -> pref.clockTenths, - "clockBar" -> pref.clockBar, - "enablePremove" -> pref.premove, - "tournamentId" -> game.tournamentId - ) - } - - def roundWatcherJsData(pov: Pov, version: Int, tv: Boolean, pref: Pref)(implicit ctx: UserContext) = { - import pov._ - Json.obj( - "game" -> Json.obj( - "id" -> gameId, - "started" -> game.started, - "finished" -> game.finishedOrAborted, - "clock" -> game.hasClock, - "clockRunning" -> game.isClockRunning, - "player" -> game.turnColor.name, - "turns" -> game.turns, - "startedAtTurn" -> game.startedAtTurn, - "lastMove" -> game.castleLastMoveTime.lastMoveString), - "player" -> Json.obj( - "color" -> player.color.name, - "version" -> version, - "spectator" -> true), - "opponent" -> Json.obj( - "color" -> opponent.color.name, - "ai" -> opponent.isAi), - "possibleMoves" -> possibleMoves(pov), - "animationDelay" -> animationDelay(pov), - "clockTenths" -> pref.clockTenths, - "clockBar" -> pref.clockBar, - "tv" -> tv - ) - } - - def possibleMoves(pov: Pov) = (pov.game playableBy pov.player) option { - pov.game.toChess.situation.destinations map { - case (from, dests) => from.key -> dests.mkString - } - } - - private def animationDelay(pov: Pov) = round { - roundEnv.animationDelay.toMillis * - max(0, min(1.2, - ((pov.game.estimateTotalTime - 60) / 60) * 0.2 - )) - } + def roundWatcherJsData(pov: Pov, version: Int, tv: Boolean, pref: Pref) = + roundEnv.jsonView.watcherJson(pov, version, tv, pref) } diff --git a/public/javascripts/big.js b/public/javascripts/big.js index 641175c72f..5f887f74e8 100644 --- a/public/javascripts/big.js +++ b/public/javascripts/big.js @@ -874,9 +874,6 @@ var storage = { self.premove = null; self.holdStart = null; self.holds = []; - self.options.tableUrl = self.element.data('table-url'); - self.options.endUrl = self.element.data('end-url'); - self.options.socketUrl = self.element.data('socket-url'); startTournamentClock(); @@ -941,7 +938,7 @@ var storage = { }); lichess.socket = new strongSocket( - self.options.socketUrl, + self.options.url.socket, self.options.player.version, $.extend(true, lichess.socketDefaults, { options: { @@ -1072,7 +1069,7 @@ var storage = { }); }, premove: function() { - if (self.options.enablePremove) { + if (self.options.pref.enablePremove) { self.element.queue(function() { self.applyPremove(); self.element.dequeue(); @@ -1193,8 +1190,8 @@ var storage = { return $(this).clock('getSeconds'); }).get(); times.sort(); - return this.options.animationDelay * Math.min(1, times[0] / 120); - } else return this.options.animationDelay; + return this.options.pref.animationDelay * Math.min(1, times[0] / 120); + } else return this.options.pref.animationDelay; }, highlightLastMove: function(notation) { var self = this; @@ -1243,7 +1240,7 @@ var storage = { }, applyPremove: function() { var self = this; - if (self.options.enablePremove && self.premove && self.isMyTurn()) { + if (self.options.pref.enablePremove && self.premove && self.isMyTurn()) { var move = self.premove; self.unsetPremove(); self.apiMove(move.from, move.to, true); @@ -1251,7 +1248,7 @@ var storage = { }, setPremove: function(move) { var self = this; - if (!self.options.enablePremove || self.isMyTurn()) return; + if (!self.options.pref.enablePremove || self.isMyTurn()) return; self.unsetPremove(); if (!self.validMove(move.from, move.to, move.piece)) return; self.premove = move; @@ -1311,7 +1308,7 @@ var storage = { var color = self.options.player.color; // promotion if ($piece.hasClass('pawn') && ((color == "white" && squareId[1] == 8) || (color == "black" && squareId[1] == 1))) { - var aq = self.options.autoQueen; + var aq = self.options.pref.autoQueen; if (aq == 3 || (isPremove && aq == 2)) { moveData.promotion = "queen"; sendMoveRequest(moveData); @@ -1466,7 +1463,7 @@ var storage = { }, reloadTable: function(callback) { var self = this; - self.get(self.options.tableUrl, { + self.get(self.options.url.table, { success: function(html) { self.$tableInner.html(html); self.initTable(); @@ -1474,8 +1471,8 @@ var storage = { $('body').trigger('lichess.content_loaded'); self.$tableInner.find('.lichess_claim_draw').each(function() { var $link = $(this); - if (self.options.autoThreefold == 3) $link.click(); - if (self.options.autoThreefold == 2) { + if (self.options.pref.autoThreefold == 3) $link.click(); + if (self.options.pref.autoThreefold == 2) { self.$table.find('.clock_bottom').each(function() { if ($(this).clock('getSeconds') < 30) $link.click(); }); @@ -1487,7 +1484,7 @@ var storage = { }, loadEnd: function(callback) { var self = this; - $.getJSON(self.options.endUrl, function(data) { + $.getJSON(self.options.url.end, function(data) { $(['white', 'black']).each(function() { if (data.players[this]) self.$table.find('div.username.' + this).html(data.players[this]); }); @@ -1534,8 +1531,8 @@ var storage = { self.$table.find('div.clock').each(function() { var $c = $(this); $c.clock({ - showTenths: self.options.clockTenths, - showBar: self.options.clockBar, + showTenths: self.options.pref.clockTenths, + showBar: self.options.pref.clockBar, time: $c.data('time'), barTime: $c.data('bar-time'), emerg: $c.data('emerg'),