broadcast stream download endpoint

pull/9768/head
Thibault Duplessis 2021-09-09 21:00:09 +02:00
parent 861c8c9763
commit a5a8ba23ba
5 changed files with 64 additions and 2 deletions

View File

@ -4,11 +4,13 @@ import play.api.data.Form
import play.api.mvc._
import scala.annotation.nowarn
import scala.concurrent.duration._
import scala.util.chaining._
import views._
import lila.api.Context
import lila.app._
import lila.common.config.MaxPerSecond
import lila.common.{ HTTPRequest, IpAddress }
import lila.relay.{ RelayRound => RoundModel, RelayTour => TourModel }
import lila.user.{ User => UserModel }
@ -124,6 +126,21 @@ final class RelayTour(env: Env, apiC: => Api) extends LilaController(env) {
}
}
def pgn(id: String) =
Action.async { req =>
env.relay.api tourById TourModel.Id(id) map {
_ ?? { tour =>
apiC.GlobalConcurrencyLimitPerIP(HTTPRequest ipAddress req)(
env.relay.pgnStream(tour)
) { source =>
asAttachmentStream(s"${env.relay.pgnStream filename tour}.pgn")(
Ok chunked source as pgnContentType
)
}
}
}
}
def apiIndex =
Action.async { implicit req =>
apiC.jsonStream {
@ -162,7 +179,7 @@ final class RelayTour(env: Env, apiC: => Api) extends LilaController(env) {
key = "broadcast.tournament.user"
)
private val CreateLimitPerIP = new lila.memo.RateLimit[lila.common.IpAddress](
private val CreateLimitPerIP = new lila.memo.RateLimit[IpAddress](
credits = 10 * 10,
duration = 24.hour,
key = "broadcast.tournament.ip"
@ -180,7 +197,7 @@ final class RelayTour(env: Env, apiC: => Api) extends LilaController(env) {
else if (me.hasTitle || me.isVerified) 5
else 10
CreateLimitPerUser(me.id, cost = cost) {
CreateLimitPerIP(lila.common.HTTPRequest ipAddress req, cost = cost) {
CreateLimitPerIP(HTTPRequest ipAddress req, cost = cost) {
create
}(fail.fuccess)
}(fail.fuccess)

View File

@ -200,6 +200,7 @@ GET /broadcast controllers.RelayTour.index(page:
GET /broadcast/new controllers.RelayTour.form
POST /broadcast/new controllers.RelayTour.create
GET /broadcast/:rs/$anyId<\w{8}> controllers.RelayTour.redirectOrApiTour(rs: String, anyId: String)
GET /broadcast/$tourId<\w{8}>.pgn controllers.RelayTour.pgn(tourId: String)
GET /broadcast/$tourId<\w{8}>/edit controllers.RelayTour.edit(tourId: String)
POST /broadcast/$tourId<\w{8}>/edit controllers.RelayTour.update(tourId: String)
GET /broadcast/$tourId<\w{8}>/new controllers.RelayRound.form(tourId: String)

View File

@ -14,6 +14,7 @@ final class Env(
multiboard: lila.study.StudyMultiBoard,
studyRepo: lila.study.StudyRepo,
chapterRepo: lila.study.ChapterRepo,
studyPgnDump: lila.study.PgnDump,
gameRepo: lila.game.GameRepo,
pgnDump: lila.game.PgnDump,
gameProxy: lila.round.GameProxyRepo,
@ -43,6 +44,8 @@ final class Env(
lazy val markup = wire[RelayMarkup]
lazy val pgnStream = wire[RelayPgnStream]
private lazy val sync = wire[RelaySync]
private lazy val formatApi = wire[RelayFormatApi]

View File

@ -0,0 +1,33 @@
package lila.relay
import akka.stream.scaladsl._
import org.joda.time.format.DateTimeFormat
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext
import lila.study.{ PgnDump, Study, StudyRepo }
final class RelayPgnStream(
roundRepo: RelayRoundRepo,
studyRepo: StudyRepo,
studyPgnDump: PgnDump
)(implicit ec: ExecutionContext) {
def apply(tour: RelayTour): Source[String, _] =
Source futureSource {
roundRepo.idsByTourOrdered(tour) flatMap { ids =>
studyRepo.byOrderedIds(ids.map(_.value).map(Study.Id)) map { studies =>
Source(studies).flatMapConcat { studyPgnDump(_, flags) }
}
}
}
private val flags = PgnDump.WithFlags(comments = false, variations = false, clocks = true)
private val fileR = """[\s,]""".r
private val dateFormat = DateTimeFormat forPattern "yyyy.MM.dd"
def filename(tour: RelayTour): String = {
val date = dateFormat.print(tour.syncedAt | tour.createdAt)
fileR.replaceAllIn(s"lichess_broadcast_${tour.slug}_${tour.id}_$date", "")
}
}

View File

@ -18,6 +18,14 @@ final private class RelayRoundRepo(val coll: Coll)(implicit ec: scala.concurrent
.cursor[RelayRound]()
.list(RelayTour.maxRelays)
def idsByTourOrdered(tour: RelayTour): Fu[List[RelayRound.Id]] =
coll
.find(selectors.tour(tour.id), $id(true).some)
.sort(sort.chrono)
.cursor[Bdoc]()
.list(RelayTour.maxRelays)
.map(_.flatMap(_.getAsOpt[RelayRound.Id]("_id")))
def lastByTour(tour: RelayTour): Fu[Option[RelayRound]] =
coll
.find(selectors tour tour.id)