/api/tournament/{id}/games endpoint - closes #4656
parent
143e98d5b6
commit
a54853e5a8
|
@ -7,10 +7,10 @@ import play.api.libs.json._
|
|||
import play.api.mvc._
|
||||
import scala.concurrent.duration._
|
||||
|
||||
import lila.api.Context
|
||||
import lila.api.{ Context, GameApiV2 }
|
||||
import lila.app._
|
||||
import lila.common.PimpedJson._
|
||||
import lila.common.{ HTTPRequest, IpAddress, MaxPerPage }
|
||||
import lila.common.{ HTTPRequest, IpAddress, MaxPerPage, MaxPerSecond }
|
||||
|
||||
object Api extends LilaController {
|
||||
|
||||
|
@ -229,14 +229,33 @@ object Api extends LilaController {
|
|||
}
|
||||
|
||||
def tournament(id: String) = ApiRequest { req =>
|
||||
val page = (getInt("page", req) | 1) atLeast 1 atMost 200
|
||||
lila.tournament.TournamentRepo byId id flatMap {
|
||||
_ ?? { tour =>
|
||||
val page = (getInt("page", req) | 1) atLeast 1 atMost 200
|
||||
Env.tournament.jsonView(tour, page.some, none, { _ => fuccess(Nil) }, none, none, lila.i18n.defaultLang) map some
|
||||
}
|
||||
} map toApiResult
|
||||
}
|
||||
|
||||
def tournamentGames(id: String) = Action.async { req =>
|
||||
lila.tournament.TournamentRepo byId id flatMap {
|
||||
_ ?? { tour =>
|
||||
GlobalLinearLimitPerIP(HTTPRequest lastRemoteAddress req) {
|
||||
val format = GameApiV2.Format byRequest req
|
||||
val config = GameApiV2.ByTournamentConfig(
|
||||
tournamentId = tour.id,
|
||||
format = GameApiV2.Format byRequest req,
|
||||
flags = Game.requestPgnFlags(req, extended = false),
|
||||
perSecond = MaxPerSecond(20)
|
||||
)
|
||||
Ok.chunked(Env.api.gameApiV2.exportByTournament(config)).withHeaders(
|
||||
CONTENT_TYPE -> Game.gameContentType(config)
|
||||
).fuccess
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def gamesByUsersStream = Action.async(parse.tolerantText) { req =>
|
||||
val userIds = req.body.split(',').take(300).toSet map lila.user.User.normalize
|
||||
jsonStream(Env.game.gamesByUsersStream(userIds)).fuccess
|
||||
|
|
|
@ -122,7 +122,7 @@ object Game extends LilaController {
|
|||
}
|
||||
}
|
||||
|
||||
private def requestPgnFlags(req: RequestHeader, extended: Boolean) =
|
||||
private[controllers] def requestPgnFlags(req: RequestHeader, extended: Boolean) =
|
||||
lila.game.PgnDump.WithFlags(
|
||||
moves = getBoolOpt("moves", req) | true,
|
||||
tags = getBoolOpt("tags", req) | true,
|
||||
|
@ -132,7 +132,7 @@ object Game extends LilaController {
|
|||
literate = getBoolOpt("literate", req) | false
|
||||
)
|
||||
|
||||
private def gameContentType(config: GameApiV2.Config) = config.format match {
|
||||
private[controllers] def gameContentType(config: GameApiV2.Config) = config.format match {
|
||||
case GameApiV2.Format.PGN => pgnContentType
|
||||
case GameApiV2.Format.JSON => config match {
|
||||
case _: GameApiV2.OneConfig => JSON
|
||||
|
|
|
@ -502,6 +502,7 @@ GET /api/game/:id controllers.Api.game(id: String)
|
|||
GET /api/games/team/:teamId controllers.Api.gamesVsTeam(teamId: String)
|
||||
GET /api/tournament controllers.Api.currentTournaments
|
||||
GET /api/tournament/:id controllers.Api.tournament(id: String)
|
||||
GET /api/tournament/:id/games controllers.Api.tournamentGames(id: String)
|
||||
POST /api/tournament controllers.Tournament.apiCreate
|
||||
GET /api/status controllers.Api.status
|
||||
GET /api/socket controllers.Main.apiWebsocket
|
||||
|
|
|
@ -14,6 +14,7 @@ import lila.db.dsl._
|
|||
import lila.game.JsonView._
|
||||
import lila.game.PgnDump.WithFlags
|
||||
import lila.game.{ Game, GameRepo, Query, PerfPicker }
|
||||
import lila.tournament.Tournament
|
||||
import lila.user.User
|
||||
|
||||
final class GameApiV2(
|
||||
|
@ -86,6 +87,19 @@ final class GameApiV2(
|
|||
Enumeratee.mapM(enrich(config.flags)) &>
|
||||
formatterFor(config)
|
||||
|
||||
def exportByTournament(config: ByTournamentConfig): Enumerator[String] =
|
||||
lila.tournament.PairingRepo.sortedGameIdsCursor(
|
||||
tournamentId = config.tournamentId,
|
||||
batchSize = config.perSecond.value
|
||||
).bulkEnumerator() &>
|
||||
Enumeratee.mapM { pairingDocs =>
|
||||
GameRepo.gamesFromSecondary(pairingDocs.flatMap { _.getAs[Game.ID]("_id") }.toSeq)
|
||||
} &>
|
||||
lila.common.Iteratee.delay(1 second) &>
|
||||
Enumeratee.mapConcat(_.toSeq) &>
|
||||
Enumeratee.mapM(enrich(config.flags)) &>
|
||||
formatterFor(config)
|
||||
|
||||
private def enrich(flags: WithFlags)(game: Game) =
|
||||
GameRepo initialFen game flatMap { initialFen =>
|
||||
(flags.evals ?? AnalysisRepo.byGame(game)) map { analysis =>
|
||||
|
@ -200,4 +214,11 @@ object GameApiV2 {
|
|||
flags: WithFlags,
|
||||
perSecond: MaxPerSecond
|
||||
) extends Config
|
||||
|
||||
case class ByTournamentConfig(
|
||||
tournamentId: Tournament.ID,
|
||||
format: Format,
|
||||
flags: WithFlags,
|
||||
perSecond: MaxPerSecond
|
||||
) extends Config
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package lila.tournament
|
|||
|
||||
import org.joda.time.DateTime
|
||||
import reactivemongo.bson._
|
||||
import reactivemongo.api.{ CursorProducer, ReadPreference }
|
||||
import scala.collection.breakOut
|
||||
|
||||
import BSONHandlers._
|
||||
|
@ -138,6 +139,17 @@ object PairingRepo {
|
|||
).void
|
||||
}
|
||||
|
||||
def sortedGameIdsCursor(
|
||||
tournamentId: Tournament.ID,
|
||||
batchSize: Int = 0,
|
||||
readPreference: ReadPreference = ReadPreference.secondaryPreferred
|
||||
)(implicit cp: CursorProducer[Bdoc]) = {
|
||||
val query = coll
|
||||
.find(selectTour(tournamentId), $id(true))
|
||||
.sort(recentSort)
|
||||
query.copy(options = query.options.batchSize(batchSize)).cursor[Bdoc](readPreference)
|
||||
}
|
||||
|
||||
private[tournament] def playingUserIds(tour: Tournament): Fu[Set[User.ID]] =
|
||||
coll.distinct[User.ID, Set]("u", Some(selectTour(tour.id) ++ selectPlaying))
|
||||
|
||||
|
|
Loading…
Reference in New Issue