api to export games of a swiss tournament
parent
8309a9d6b5
commit
de1d0005eb
|
@ -276,6 +276,31 @@ final class Api(
|
|||
}
|
||||
}
|
||||
|
||||
def swissGames(id: String) =
|
||||
Action.async { req =>
|
||||
env.swiss.api byId lila.swiss.Swiss.Id(id) flatMap {
|
||||
_ ?? { swiss =>
|
||||
val config = GameApiV2.BySwissConfig(
|
||||
swissId = swiss.id,
|
||||
format = GameApiV2.Format byRequest req,
|
||||
flags = gameC.requestPgnFlags(req, extended = false),
|
||||
perSecond = MaxPerSecond(20)
|
||||
)
|
||||
GlobalConcurrencyLimitPerIP(HTTPRequest lastRemoteAddress req)(
|
||||
env.api.gameApiV2.exportBySwiss(config)
|
||||
) { source =>
|
||||
val filename = env.api.gameApiV2.filename(swiss, config.format)
|
||||
Ok.chunked(source)
|
||||
.withHeaders(
|
||||
noProxyBufferHeader,
|
||||
CONTENT_DISPOSITION -> s"attachment; filename=$filename"
|
||||
)
|
||||
.as(gameC gameContentType config)
|
||||
}.fuccess
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def gamesByUsersStream =
|
||||
AnonOrScopedBody(parse.tolerantText)()(
|
||||
anon = gamesByUsers(300),
|
||||
|
|
|
@ -555,6 +555,7 @@ GET /api/tournament/:id/games controllers.Api.tournamentGames(id: Strin
|
|||
GET /api/tournament/:id/results controllers.Api.tournamentResults(id: String)
|
||||
POST /api/tournament controllers.Tournament.apiCreate
|
||||
POST /api/swiss/new/:teamId controllers.Swiss.apiCreate(teamId: String)
|
||||
GET /api/swiss/:id/games controllers.Api.swissGames(id: String)
|
||||
GET /api/simul controllers.Simul.apiList
|
||||
GET /api/status controllers.Api.status
|
||||
GET /api/users/status controllers.Api.usersStatus
|
||||
|
|
|
@ -22,6 +22,7 @@ final class GameApiV2(
|
|||
pgnDump: PgnDump,
|
||||
gameRepo: lila.game.GameRepo,
|
||||
pairingRepo: lila.tournament.PairingRepo,
|
||||
swissApi: lila.swiss.SwissApi,
|
||||
analysisRepo: lila.analyse.AnalysisRepo,
|
||||
getLightUser: LightUser.Getter
|
||||
)(implicit ec: scala.concurrent.ExecutionContext, system: akka.actor.ActorSystem) {
|
||||
|
@ -73,6 +74,16 @@ final class GameApiV2(
|
|||
),
|
||||
"_"
|
||||
)
|
||||
def filename(swiss: lila.swiss.Swiss, format: Format): String =
|
||||
fileR.replaceAllIn(
|
||||
"lichess_swiss_%s_%s_%s.%s".format(
|
||||
Tag.UTCDate.format.print(swiss.startsAt),
|
||||
swiss.id,
|
||||
lila.common.String.slugify(swiss.name),
|
||||
format.toString.toLowerCase
|
||||
),
|
||||
"_"
|
||||
)
|
||||
|
||||
def exportByUser(config: ByUserConfig): Source[String, _] =
|
||||
gameRepo
|
||||
|
@ -138,6 +149,37 @@ final class GameApiV2(
|
|||
}
|
||||
}
|
||||
|
||||
def exportBySwiss(config: BySwissConfig): Source[String, _] =
|
||||
swissApi
|
||||
.pairingCursor(
|
||||
swissId = config.swissId,
|
||||
batchSize = config.perSecond.value
|
||||
)
|
||||
.documentSource()
|
||||
.grouped(config.perSecond.value)
|
||||
.throttle(1, 1 second)
|
||||
.mapAsync(1) { pairings =>
|
||||
gameRepo.gameOptionsFromSecondary(pairings.map(_.gameId)) map {
|
||||
_.zip(pairings) collect {
|
||||
case (Some(game), pairing) => game -> pairing
|
||||
}
|
||||
}
|
||||
}
|
||||
.mapConcat(identity)
|
||||
.mapAsync(4) {
|
||||
case (game, pairing) => enrich(config.flags)(game) dmap { _ -> pairing }
|
||||
}
|
||||
.mapAsync(4) {
|
||||
case ((game, fen, analysis), pairing) =>
|
||||
config.format match {
|
||||
case Format.PGN => pgnDump.formatter(config.flags)(game, fen, analysis)
|
||||
case Format.JSON =>
|
||||
toJson(game, fen, analysis, config.flags) dmap { json =>
|
||||
s"${Json.stringify(json)}\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def preparationFlow(config: Config) =
|
||||
Flow[Game]
|
||||
.mapAsync(4)(enrich(config.flags))
|
||||
|
@ -277,4 +319,11 @@ object GameApiV2 {
|
|||
flags: WithFlags,
|
||||
perSecond: MaxPerSecond
|
||||
) extends Config
|
||||
|
||||
case class BySwissConfig(
|
||||
swissId: lila.swiss.Swiss.Id,
|
||||
format: Format,
|
||||
flags: WithFlags,
|
||||
perSecond: MaxPerSecond
|
||||
) extends Config
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package lila.swiss
|
|||
|
||||
import org.joda.time.DateTime
|
||||
import ornicar.scalalib.Zero
|
||||
import reactivemongo.akkastream.{ cursorProducer, AkkaStreamCursor }
|
||||
import reactivemongo.api._
|
||||
import reactivemongo.api.bson._
|
||||
import scala.concurrent.duration._
|
||||
|
@ -139,6 +140,19 @@ final class SwissApi(
|
|||
.list[SwissPairing]()
|
||||
}
|
||||
|
||||
def pairingCursor(
|
||||
swissId: Swiss.Id,
|
||||
batchSize: Int = 0,
|
||||
readPreference: ReadPreference = ReadPreference.secondaryPreferred
|
||||
): AkkaStreamCursor[SwissPairing] =
|
||||
SwissPairing.fields { f =>
|
||||
colls.pairing.ext
|
||||
.find($doc(f.swissId -> swissId))
|
||||
.sort($sort asc f.round)
|
||||
.batchSize(batchSize)
|
||||
.cursor[SwissPairing](readPreference)
|
||||
}
|
||||
|
||||
def featuredInTeam(teamId: TeamID): Fu[List[Swiss]] =
|
||||
cache.featuredInTeam.get(teamId) flatMap { ids =>
|
||||
colls.swiss.byOrderedIds[Swiss, Swiss.Id](ids)(_.id)
|
||||
|
|
Loading…
Reference in New Issue