<commit_before>package controllers

import play.api.libs.json._
import play.api.mvc._

import lila.api.Context
import lila.app._
import lila.common.{ HTTPRequest, ApiVersion }
import lila.common.PimpedJson._
import lila.game.{ Pov, GameRepo, Game => GameModel, PgnDump }
import lila.tournament.MiniStanding
import lila.user.{ User => UserModel }
import views._

object Round extends LilaController with TheftPrevention {

  private def env = Env.round
  private def analyser = Env.analyse.analyser

  def websocketWatcher(gameId: String, color: String) = SocketOption[JsValue] { implicit ctx =>
    getSocketUid("sri") ?? { uid =>
      env.socketHandler.watcher(
        gameId = gameId,
        colorName = color,
        uid = uid,
        user = ctx.me,
        ip = ctx.ip,
        userTv = get("userTv")
      )
    }
  }

  def websocketPlayer(fullId: String, apiVersion: Int) = SocketEither[JsValue] { implicit ctx =>
    GameRepo pov fullId flatMap {
      case Some(pov) =>
        if (isTheft(pov)) fuccess(Left(theftResponse))
        else getSocketUid("sri") match {
          case Some(uid) =>
            requestAiMove(pov) >>
              env.socketHandler.player(pov, uid, ctx.me, ctx.ip) map Right.apply
          case None => fuccess(Left(NotFound))
        }
      case None => fuccess(Left(NotFound))
    }
  }

  private def requestAiMove(pov: Pov) = pov.game.playableByAi ?? Env.fishnet.player(pov.game)

  private def renderPlayer(pov: Pov)(implicit ctx: Context): Fu[Result] =
    negotiate(
      html = pov.game.started.fold(
        Game.preloadUsers(pov.game) >> PreventTheft(pov) {
          myTour(pov.game.tournamentId, true) zip
            (pov.game.simulId ?? Env.simul.repo.find) zip
            getPlayerChat(pov.game) zip
            Env.game.crosstableApi.withMatchup(pov.game) zip
            (pov.game.isSwitchable ?? otherPovs(pov.game)) zip
            Env.bookmark.api.exists(pov.game, ctx.me) flatMap {
              case tour ~ simul ~ chatOption ~ crosstable ~ playing ~ bookmarked =>
                simul foreach Env.simul.api.onPlayerConnection(pov.game, ctx.me)
                Env.api.roundApi.player(pov, lila.api.Mobile.Api.currentVersion) map { data =>
                  Ok(html.round.player(pov, data,
                    tour = tour,
                    simul = simul,
                    cross = crosstable,
                    playing = playing,
                    chatOption = chatOption,
                    bookmarked = bookmarked))
                }
            }
        }.mon(_.http.response.player.website),
        notFound
      ),
      api = apiVersion => {
        if (isTheft(pov)) fuccess(theftResponse)
        else Env.api.roundApi.player(pov, apiVersion) zip
          getPlayerChat(pov.game) map {
            case (data, chat) => Ok {
              data.add("chat", chat.map(c => lila.chat.JsonView(c.chat)))
            }
          }
      }.mon(_.http.response.player.mobile)
    ) map NoCache

  def player(fullId: String) = Open { implicit ctx =>
    OptionFuResult(GameRepo pov fullId) { pov =>
      env.checkOutoftime(pov.game)
      renderPlayer(pov)
    }
  }

  private def otherPovs(game: GameModel)(implicit ctx: Context) = ctx.me ?? { user =>
    GameRepo urgentGames user map {
      _ filter { pov =>
        pov.game.id != game.id && pov.game.isSwitchable && pov.game.isSimul == game.isSimul
      }
    }
  }

  private def getNext(currentGame: GameModel)(povs: List[Pov])(implicit ctx: Context) =
    povs find { pov =><commit_msg>improve game page load parallelism<commit_after>package controllers

import play.api.libs.json._
import play.api.mvc._

import lila.api.Context
import lila.app._
import lila.common.PimpedJson._
import lila.common.{ HTTPRequest, ApiVersion }
import lila.game.{ Pov, GameRepo, Game => GameModel, PgnDump }
import lila.tournament.MiniStanding
import lila.user.{ User => UserModel }
import views._

object Round extends LilaController with TheftPrevention {

  private def env = Env.round
  private def analyser = Env.analyse.analyser

  def websocketWatcher(gameId: String, color: String) = SocketOption[JsValue] { implicit ctx =>
    getSocketUid("sri") ?? { uid =>
      env.socketHandler.watcher(
        gameId = gameId,
        colorName = color,
        uid = uid,
        user = ctx.me,
        ip = ctx.ip,
        userTv = get("userTv")
      )
    }
  }

  def websocketPlayer(fullId: String, apiVersion: Int) = SocketEither[JsValue] { implicit ctx =>
    GameRepo pov fullId flatMap {
      case Some(pov) =>
        if (isTheft(pov)) fuccess(Left(theftResponse))
        else getSocketUid("sri") match {
          case Some(uid) =>
            requestAiMove(pov) >>
              env.socketHandler.player(pov, uid, ctx.me, ctx.ip) map Right.apply
          case None => fuccess(Left(NotFound))
        }
      case None => fuccess(Left(NotFound))
    }
  }

  private def requestAiMove(pov: Pov) = pov.game.playableByAi ?? Env.fishnet.player(pov.game)

  private def renderPlayer(pov: Pov)(implicit ctx: Context): Fu[Result] = negotiate(
    html = pov.game.started.fold(
      PreventTheft(pov) {
        Game.preloadUsers(pov.game) zip
          myTour(pov.game.tournamentId, true) zip
          (pov.game.simulId ?? Env.simul.repo.find) zip
          getPlayerChat(pov.game) zip
          Env.game.crosstableApi.withMatchup(pov.game) zip // probably what raises page mean time?
          (pov.game.isSwitchable ?? otherPovs(pov.game)) zip
          Env.bookmark.api.exists(pov.game, ctx.me) zip
          Env.api.roundApi.player(pov, lila.api.Mobile.Api.currentVersion) map {
            case _ ~ tour ~ simul ~ chatOption ~ crosstable ~ playing ~ bookmarked ~ data =>
              simul foreach Env.simul.api.onPlayerConnection(pov.game, ctx.me)
              Ok(html.round.player(pov, data,
                tour = tour,
                simul = simul,
                cross = crosstable,
                playing = playing,
                chatOption = chatOption,
                bookmarked = bookmarked))
          }
      }.mon(_.http.response.player.website),
      notFound
    ),
    api = apiVersion => {
      if (isTheft(pov)) fuccess(theftResponse)
      else Game.preloadUsers(pov.game) zip
        Env.api.roundApi.player(pov, apiVersion) zip
        getPlayerChat(pov.game) map {
          case _ ~ data ~ chat => Ok {
            data.add("chat", chat.map(c => lila.chat.JsonView(c.chat)))
          }
        }
    }.mon(_.http.response.player.mobile)
  ) map NoCache

  def player(fullId: String) = Open { implicit ctx =>
    OptionFuResult(GameRepo pov fullId) { pov =>
      env.checkOutoftime(pov.game)
      renderPlayer(pov)
    }
  }

  private def otherPovs(game: GameModel)(implicit ctx: Context) = ctx.me ?? { user =>
    GameRepo urgentGames user map {
      _ filter { pov =>
        pov.game.id != game.id && pov.game.isSwitchable && pov.game.isSimul == game.isSimul
      }
    }
  }

  private def getNext(currentGame: GameModel)(povs: List[Pov])(implicit ctx: Context) =
    povs find { pov =>
{'fraction_non_alphanumeric': 0.11746391168978206, 'fraction_numerical': 0.0, 'mean_word_length': 2.3256470588235296, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 46, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2982824', 'n_tokens_mistral': 2323, 'n_tokens_neox': 2288, 'n_words': 473}