2013-12-30 19:00:56 -07:00
|
|
|
package controllers
|
|
|
|
|
2019-12-04 16:39:16 -07:00
|
|
|
import akka.stream.scaladsl._
|
2017-08-18 23:38:50 -06:00
|
|
|
import ornicar.scalalib.Zero
|
2015-01-17 04:35:54 -07:00
|
|
|
import play.api.libs.json._
|
2017-01-15 05:26:08 -07:00
|
|
|
import play.api.mvc._
|
2016-07-10 02:08:02 -06:00
|
|
|
import scala.concurrent.duration._
|
2013-12-30 19:00:56 -07:00
|
|
|
|
2019-12-04 16:39:16 -07:00
|
|
|
import lila.api.{ Context, GameApiV2 }
|
2013-12-30 19:00:56 -07:00
|
|
|
import lila.app._
|
2019-12-04 16:39:16 -07:00
|
|
|
import lila.common.config.{ MaxPerPage, MaxPerSecond }
|
2019-12-07 17:43:22 -07:00
|
|
|
import lila.common.Json.jodaWrites
|
2019-12-04 16:39:16 -07:00
|
|
|
import lila.common.{ HTTPRequest, IpAddress }
|
2013-12-30 19:00:56 -07:00
|
|
|
|
2019-12-04 16:39:16 -07:00
|
|
|
final class Api(
|
|
|
|
env: Env,
|
2019-12-05 14:51:18 -07:00
|
|
|
gameC: => Game
|
2019-12-04 16:39:16 -07:00
|
|
|
) extends LilaController(env) {
|
2013-12-30 19:00:56 -07:00
|
|
|
|
2019-12-05 14:51:18 -07:00
|
|
|
import Api._
|
|
|
|
|
2019-12-04 16:39:16 -07:00
|
|
|
private val userApi = env.api.userApi
|
|
|
|
private val gameApi = env.api.gameApi
|
2014-01-07 18:43:20 -07:00
|
|
|
|
2019-12-13 07:30:20 -07:00
|
|
|
implicit private[controllers] val limitedDefault = Zero.instance[ApiResult](Limited)
|
2016-08-31 15:59:31 -06:00
|
|
|
|
2017-10-31 09:38:23 -06:00
|
|
|
private lazy val apiStatusJson = {
|
2015-01-24 03:36:05 -07:00
|
|
|
val api = lila.api.Mobile.Api
|
2017-10-31 09:38:23 -06:00
|
|
|
Json.obj(
|
2015-01-24 03:36:05 -07:00
|
|
|
"api" -> Json.obj(
|
2016-07-15 11:41:48 -06:00
|
|
|
"current" -> api.currentVersion.value,
|
2015-01-24 03:36:05 -07:00
|
|
|
"olds" -> api.oldVersions.map { old =>
|
|
|
|
Json.obj(
|
2019-12-13 07:30:20 -07:00
|
|
|
"version" -> old.version.value,
|
|
|
|
"deprecatedAt" -> old.deprecatedAt,
|
2017-02-14 08:34:07 -07:00
|
|
|
"unsupportedAt" -> old.unsupportedAt
|
|
|
|
)
|
|
|
|
}
|
|
|
|
)
|
2017-10-31 09:38:23 -06:00
|
|
|
)
|
2015-01-17 04:35:54 -07:00
|
|
|
}
|
|
|
|
|
2016-08-02 04:43:13 -06:00
|
|
|
val status = Action { req =>
|
2019-12-13 07:30:20 -07:00
|
|
|
val appVersion = get("v", req)
|
2017-11-03 23:49:52 -06:00
|
|
|
val mustUpgrade = appVersion exists lila.api.Mobile.AppVersion.mustUpgrade _
|
2017-10-31 09:38:23 -06:00
|
|
|
Ok(apiStatusJson.add("mustUpgrade", mustUpgrade)) as JSON
|
2016-08-02 04:43:13 -06:00
|
|
|
}
|
|
|
|
|
2018-04-01 22:04:41 -06:00
|
|
|
def index = Action {
|
2019-04-16 09:34:11 -06:00
|
|
|
Ok(views.html.site.bits.api)
|
2018-04-01 22:04:41 -06:00
|
|
|
}
|
|
|
|
|
2018-04-26 17:27:52 -06:00
|
|
|
def user(name: String) = CookieBasedApiRequest { ctx =>
|
2018-04-03 19:45:32 -06:00
|
|
|
userApi.extended(name, ctx.me) map toApiResult
|
2018-02-03 14:40:03 -07:00
|
|
|
}
|
|
|
|
|
2018-04-03 19:45:32 -06:00
|
|
|
private[controllers] val UsersRateLimitGlobal = new lila.memo.RateLimit[String](
|
2016-08-11 16:41:50 -06:00
|
|
|
credits = 1000,
|
|
|
|
duration = 1 minute,
|
2016-09-01 15:54:43 -06:00
|
|
|
name = "team users API global",
|
2017-02-14 08:34:07 -07:00
|
|
|
key = "team_users.api.global"
|
|
|
|
)
|
2016-08-11 16:41:50 -06:00
|
|
|
|
2018-04-03 19:45:32 -06:00
|
|
|
private[controllers] val UsersRateLimitPerIP = new lila.memo.RateLimit[IpAddress](
|
2016-08-11 16:41:50 -06:00
|
|
|
credits = 1000,
|
|
|
|
duration = 10 minutes,
|
2016-09-01 15:54:43 -06:00
|
|
|
name = "team users API per IP",
|
2017-02-14 08:34:07 -07:00
|
|
|
key = "team_users.api.ip"
|
|
|
|
)
|
2016-08-11 16:41:50 -06:00
|
|
|
|
2018-04-26 17:27:52 -06:00
|
|
|
def usersByIds = Action.async(parse.tolerantText) { req =>
|
|
|
|
val usernames = req.body.split(',').take(300).toList
|
2019-12-13 07:30:20 -07:00
|
|
|
val ip = HTTPRequest lastRemoteAddress req
|
|
|
|
val cost = usernames.size / 4
|
2017-01-22 14:21:57 -07:00
|
|
|
UsersRateLimitPerIP(ip, cost = cost) {
|
2017-02-15 17:53:15 -07:00
|
|
|
UsersRateLimitGlobal("-", cost = cost, msg = ip.value) {
|
2019-12-10 14:01:18 -07:00
|
|
|
lila.mon.api.users.increment(cost)
|
2019-12-04 18:47:46 -07:00
|
|
|
env.user.repo nameds usernames map {
|
2019-12-04 16:39:16 -07:00
|
|
|
_.map { env.user.jsonView(_, none) }
|
2018-04-26 17:54:58 -06:00
|
|
|
} map toApiResult map toHttp
|
2017-01-22 14:21:57 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-26 17:27:52 -06:00
|
|
|
def usersStatus = ApiRequest { req =>
|
|
|
|
val ids = get("ids", req).??(_.split(',').take(50).toList map lila.user.User.normalize)
|
2019-12-04 16:39:16 -07:00
|
|
|
env.user.lightUserApi asyncMany ids dmap (_.flatten) map { users =>
|
2019-12-13 07:30:20 -07:00
|
|
|
val actualIds = users.map(_.id)
|
|
|
|
val playingIds = env.relation.online.playing intersect actualIds
|
2019-12-04 16:39:16 -07:00
|
|
|
val streamingIds = env.streamer.liveStreamApi.userIds
|
2017-01-29 08:20:03 -07:00
|
|
|
toApiResult {
|
|
|
|
users.map { u =>
|
2019-12-13 07:30:20 -07:00
|
|
|
lila.common.LightUser.lightUserWrites
|
|
|
|
.writes(u)
|
2019-12-04 16:39:16 -07:00
|
|
|
.add("online" -> env.socket.isOnline(u.id))
|
2018-04-03 12:52:02 -06:00
|
|
|
.add("playing" -> playingIds(u.id))
|
|
|
|
.add("streaming" -> streamingIds(u.id))
|
2017-01-29 08:20:03 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-15 17:53:15 -07:00
|
|
|
private val UserGamesRateLimitPerIP = new lila.memo.RateLimit[IpAddress](
|
2016-07-29 09:57:48 -06:00
|
|
|
credits = 10 * 1000,
|
|
|
|
duration = 10 minutes,
|
2016-09-01 15:54:43 -06:00
|
|
|
name = "user games API per IP",
|
2017-02-14 08:34:07 -07:00
|
|
|
key = "user_games.api.ip"
|
|
|
|
)
|
2016-07-30 15:46:37 -06:00
|
|
|
|
2017-02-15 17:53:15 -07:00
|
|
|
private val UserGamesRateLimitPerUA = new lila.memo.RateLimit[String](
|
2016-08-01 06:38:07 -06:00
|
|
|
credits = 10 * 1000,
|
2016-08-01 07:11:18 -06:00
|
|
|
duration = 5 minutes,
|
2016-09-01 15:54:43 -06:00
|
|
|
name = "user games API per UA",
|
2017-02-14 08:34:07 -07:00
|
|
|
key = "user_games.api.ua"
|
|
|
|
)
|
2016-08-01 06:38:07 -06:00
|
|
|
|
2017-02-15 17:53:15 -07:00
|
|
|
private val UserGamesRateLimitGlobal = new lila.memo.RateLimit[String](
|
2018-04-17 18:05:02 -06:00
|
|
|
credits = 20 * 1000,
|
2017-04-06 06:14:39 -06:00
|
|
|
duration = 2 minute,
|
2016-09-01 15:54:43 -06:00
|
|
|
name = "user games API global",
|
2017-02-14 08:34:07 -07:00
|
|
|
key = "user_games.api.global"
|
|
|
|
)
|
2016-07-08 17:32:54 -06:00
|
|
|
|
2018-04-26 17:27:52 -06:00
|
|
|
private def UserGamesRateLimit(cost: Int, req: RequestHeader)(run: => Fu[ApiResult]) = {
|
|
|
|
val ip = HTTPRequest lastRemoteAddress req
|
2017-08-19 08:56:34 -06:00
|
|
|
UserGamesRateLimitPerIP(ip, cost = cost) {
|
2018-04-26 17:27:52 -06:00
|
|
|
UserGamesRateLimitPerUA(~HTTPRequest.userAgent(req), cost = cost, msg = ip.value) {
|
2017-08-19 08:56:34 -06:00
|
|
|
UserGamesRateLimitGlobal("-", cost = cost, msg = ip.value) {
|
|
|
|
run
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-26 17:27:52 -06:00
|
|
|
private def gameFlagsFromRequest(req: RequestHeader) =
|
2017-04-24 03:42:44 -06:00
|
|
|
lila.api.GameApi.WithFlags(
|
2018-04-26 17:27:52 -06:00
|
|
|
analysis = getBool("with_analysis", req),
|
|
|
|
moves = getBool("with_moves", req),
|
|
|
|
fens = getBool("with_fens", req),
|
|
|
|
opening = getBool("with_opening", req),
|
|
|
|
moveTimes = getBool("with_movetimes", req),
|
|
|
|
token = get("token", req)
|
2017-04-24 03:42:44 -06:00
|
|
|
)
|
|
|
|
|
2018-05-07 16:39:26 -06:00
|
|
|
// for mobile app
|
|
|
|
def userGames(name: String) = MobileApiRequest { req =>
|
2018-04-26 17:27:52 -06:00
|
|
|
val page = (getInt("page", req) | 1) atLeast 1 atMost 200
|
2019-12-13 07:30:20 -07:00
|
|
|
val nb = MaxPerPage((getInt("nb", req) | 10) atLeast 1 atMost 100)
|
2019-12-04 16:39:16 -07:00
|
|
|
val cost = page * nb.value + 10
|
2018-04-26 17:27:52 -06:00
|
|
|
UserGamesRateLimit(cost, req) {
|
2019-12-10 14:01:18 -07:00
|
|
|
lila.mon.api.userGames.increment(cost)
|
2019-12-04 18:47:46 -07:00
|
|
|
env.user.repo named name flatMap {
|
2017-08-19 08:56:34 -06:00
|
|
|
_ ?? { user =>
|
|
|
|
gameApi.byUser(
|
|
|
|
user = user,
|
2018-04-26 17:27:52 -06:00
|
|
|
rated = getBoolOpt("rated", req),
|
|
|
|
playing = getBoolOpt("playing", req),
|
|
|
|
analysed = getBoolOpt("analysed", req),
|
|
|
|
withFlags = gameFlagsFromRequest(req),
|
2019-12-04 16:39:16 -07:00
|
|
|
nb = nb,
|
2017-08-19 08:56:34 -06:00
|
|
|
page = page
|
|
|
|
) map some
|
2016-07-08 17:32:54 -06:00
|
|
|
}
|
2017-08-19 08:56:34 -06:00
|
|
|
} map toApiResult
|
2016-01-21 23:45:07 -07:00
|
|
|
}
|
2013-12-30 19:00:56 -07:00
|
|
|
}
|
|
|
|
|
2017-02-15 17:53:15 -07:00
|
|
|
private val GameRateLimitPerIP = new lila.memo.RateLimit[IpAddress](
|
2017-01-15 05:56:49 -07:00
|
|
|
credits = 100,
|
|
|
|
duration = 1 minute,
|
|
|
|
name = "game API per IP",
|
2017-02-14 08:34:07 -07:00
|
|
|
key = "game.api.one.ip"
|
|
|
|
)
|
2016-08-31 15:59:31 -06:00
|
|
|
|
2018-04-26 17:27:52 -06:00
|
|
|
def game(id: String) = ApiRequest { req =>
|
2018-10-22 00:42:37 -06:00
|
|
|
GameRateLimitPerIP(HTTPRequest lastRemoteAddress req, cost = 1) {
|
2019-12-10 14:01:18 -07:00
|
|
|
lila.mon.api.game.increment(1)
|
2018-04-26 17:27:52 -06:00
|
|
|
gameApi.one(id take lila.game.Game.gameIdSize, gameFlagsFromRequest(req)) map toApiResult
|
2016-08-31 15:59:31 -06:00
|
|
|
}
|
2014-06-06 03:08:43 -06:00
|
|
|
}
|
|
|
|
|
2018-04-18 12:52:53 -06:00
|
|
|
private val CrosstableRateLimitPerIP = new lila.memo.RateLimit[IpAddress](
|
|
|
|
credits = 30,
|
|
|
|
duration = 10 minutes,
|
|
|
|
name = "crosstable API per IP",
|
|
|
|
key = "crosstable.api.ip"
|
|
|
|
)
|
|
|
|
|
2018-04-26 17:27:52 -06:00
|
|
|
def crosstable(u1: String, u2: String) = ApiRequest { req =>
|
|
|
|
CrosstableRateLimitPerIP(HTTPRequest lastRemoteAddress req, cost = 1) {
|
2019-12-23 09:07:21 -07:00
|
|
|
env.game.crosstableApi.fetchOrEmpty(u1, u2) map { ct =>
|
2018-03-06 14:14:32 -07:00
|
|
|
toApiResult {
|
2019-08-23 14:01:12 -06:00
|
|
|
lila.game.JsonView.crosstableWrites.writes(ct).some
|
2018-03-06 14:14:32 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-04 16:39:16 -07:00
|
|
|
def currentTournaments = ApiRequest { _ =>
|
|
|
|
env.tournament.api.fetchVisibleTournaments flatMap
|
|
|
|
env.tournament.apiJsonView.apply map Data.apply
|
2016-08-15 05:10:53 -06:00
|
|
|
}
|
|
|
|
|
2018-04-26 17:27:52 -06:00
|
|
|
def tournament(id: String) = ApiRequest { req =>
|
2019-12-04 16:39:16 -07:00
|
|
|
env.tournament.tournamentRepo byId id flatMap {
|
2016-08-15 05:10:53 -06:00
|
|
|
_ ?? { tour =>
|
2018-10-20 01:48:18 -06:00
|
|
|
val page = (getInt("page", req) | 1) atLeast 1 atMost 200
|
2019-12-04 16:39:16 -07:00
|
|
|
env.tournament.jsonView(
|
2019-10-03 06:58:59 -06:00
|
|
|
tour = tour,
|
|
|
|
page = page.some,
|
|
|
|
me = none,
|
|
|
|
getUserTeamIds = _ => fuccess(Nil),
|
2019-12-04 16:39:16 -07:00
|
|
|
getTeamName = env.team.getTeamName.apply _,
|
2019-10-03 06:58:59 -06:00
|
|
|
playerInfoExt = none,
|
|
|
|
socketVersion = none,
|
|
|
|
partial = false,
|
|
|
|
lang = lila.i18n.defaultLang
|
|
|
|
) map some
|
2016-08-15 05:10:53 -06:00
|
|
|
}
|
|
|
|
} map toApiResult
|
|
|
|
}
|
|
|
|
|
2018-10-20 01:48:18 -06:00
|
|
|
def tournamentGames(id: String) = Action.async { req =>
|
2019-12-04 16:39:16 -07:00
|
|
|
env.tournament.tournamentRepo byId id flatMap {
|
2018-10-20 01:48:18 -06:00
|
|
|
_ ?? { tour =>
|
|
|
|
GlobalLinearLimitPerIP(HTTPRequest lastRemoteAddress req) {
|
|
|
|
val config = GameApiV2.ByTournamentConfig(
|
|
|
|
tournamentId = tour.id,
|
|
|
|
format = GameApiV2.Format byRequest req,
|
2019-12-04 16:39:16 -07:00
|
|
|
flags = gameC.requestPgnFlags(req, extended = false),
|
2018-10-20 01:48:18 -06:00
|
|
|
perSecond = MaxPerSecond(20)
|
|
|
|
)
|
2019-12-13 07:30:20 -07:00
|
|
|
Ok.chunked(env.api.gameApiV2.exportByTournament(config))
|
|
|
|
.withHeaders(
|
|
|
|
noProxyBufferHeader
|
|
|
|
)
|
|
|
|
.as(gameC.gameContentType(config))
|
|
|
|
.fuccess
|
2018-10-20 01:48:18 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-19 22:15:33 -07:00
|
|
|
def tournamentResults(id: String) = Action.async { req =>
|
2019-12-04 16:39:16 -07:00
|
|
|
env.tournament.tournamentRepo byId id flatMap {
|
2018-11-19 22:15:33 -07:00
|
|
|
_ ?? { tour =>
|
|
|
|
GlobalLinearLimitPerIP(HTTPRequest lastRemoteAddress req) {
|
|
|
|
import lila.tournament.JsonView.playerResultWrites
|
|
|
|
val nb = getInt("nb", req) | Int.MaxValue
|
2019-12-04 16:39:16 -07:00
|
|
|
jsonStream {
|
2019-12-13 07:30:20 -07:00
|
|
|
env.tournament.api
|
|
|
|
.resultStream(tour, MaxPerSecond(50), nb)
|
2019-12-04 16:39:16 -07:00
|
|
|
.map(playerResultWrites.writes)
|
|
|
|
}.fuccess
|
2018-11-19 22:15:33 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-04 02:21:45 -06:00
|
|
|
def tournamentsByOwner(name: String) = Action.async { req =>
|
2019-12-04 18:47:46 -07:00
|
|
|
(name != "lichess") ?? env.user.repo.named(name) flatMap {
|
2019-10-04 02:21:45 -06:00
|
|
|
_ ?? { user =>
|
|
|
|
GlobalLinearLimitPerIP(HTTPRequest lastRemoteAddress req) {
|
|
|
|
val nb = getInt("nb", req) | Int.MaxValue
|
2019-12-04 16:39:16 -07:00
|
|
|
jsonStream {
|
2019-12-13 07:30:20 -07:00
|
|
|
env.tournament.api
|
|
|
|
.byOwnerStream(user, MaxPerSecond(20), nb)
|
2019-12-04 16:39:16 -07:00
|
|
|
.mapAsync(1)(env.tournament.apiJsonView.fullJson)
|
|
|
|
}.fuccess
|
2019-10-04 02:21:45 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-16 18:02:31 -06:00
|
|
|
def gamesByUsersStream = Action.async(parse.tolerantText) { req =>
|
2019-12-04 16:39:16 -07:00
|
|
|
val userIds = req.body.split(',').view.take(300).map(lila.user.User.normalize).toSet
|
|
|
|
jsonStream {
|
|
|
|
env.game.gamesByUsersStream(userIds)
|
|
|
|
}.fuccess
|
2016-10-30 17:21:48 -06:00
|
|
|
}
|
|
|
|
|
2019-12-08 10:35:26 -07:00
|
|
|
def eventStream = Scoped(_.Bot.Play, _.Challenge.Read) { _ => me =>
|
2019-12-04 16:39:16 -07:00
|
|
|
env.round.proxyRepo.urgentGames(me) flatMap { povs =>
|
|
|
|
env.challenge.api.createdByDestId(me.id) map { challenges =>
|
|
|
|
jsonOptionStream {
|
|
|
|
env.api.eventStream(me, povs.map(_.game), challenges)
|
|
|
|
}
|
2018-04-16 17:58:20 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-17 18:05:02 -06:00
|
|
|
private val UserActivityRateLimitPerIP = new lila.memo.RateLimit[IpAddress](
|
|
|
|
credits = 15,
|
|
|
|
duration = 2 minutes,
|
|
|
|
name = "user activity API per IP",
|
|
|
|
key = "user_activity.api.ip"
|
|
|
|
)
|
|
|
|
|
2018-04-26 17:27:52 -06:00
|
|
|
def activity(name: String) = ApiRequest { req =>
|
|
|
|
UserActivityRateLimitPerIP(HTTPRequest lastRemoteAddress req, cost = 1) {
|
2019-12-10 14:01:18 -07:00
|
|
|
lila.mon.api.activity.increment(1)
|
2019-12-04 18:47:46 -07:00
|
|
|
env.user.repo named name flatMap {
|
2017-08-19 08:56:34 -06:00
|
|
|
_ ?? { user =>
|
2019-12-04 16:39:16 -07:00
|
|
|
env.activity.read.recent(user) flatMap {
|
|
|
|
_.map { env.activity.jsonView(_, user) }.sequenceFu
|
2017-08-19 08:56:34 -06:00
|
|
|
}
|
2017-08-18 23:38:50 -06:00
|
|
|
}
|
2017-08-19 08:56:34 -06:00
|
|
|
} map toApiResult
|
2017-08-18 23:38:50 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-26 17:27:52 -06:00
|
|
|
def CookieBasedApiRequest(js: Context => Fu[ApiResult]) = Open { ctx =>
|
2018-04-26 17:54:58 -06:00
|
|
|
js(ctx) map toHttp
|
2018-04-26 17:27:52 -06:00
|
|
|
}
|
|
|
|
def ApiRequest(js: RequestHeader => Fu[ApiResult]) = Action.async { req =>
|
2018-04-26 17:54:58 -06:00
|
|
|
js(req) map toHttp
|
2017-01-22 13:57:12 -07:00
|
|
|
}
|
2018-05-07 16:39:26 -06:00
|
|
|
def MobileApiRequest(js: RequestHeader => Fu[ApiResult]) = Action.async { req =>
|
|
|
|
if (lila.api.Mobile.Api requested req) js(req) map toHttp
|
|
|
|
else fuccess(NotFound)
|
|
|
|
}
|
2017-01-22 13:57:12 -07:00
|
|
|
|
2019-12-13 07:30:20 -07:00
|
|
|
lazy val tooManyRequests =
|
|
|
|
Results.TooManyRequests(jsonError("Error 429: Too many requests! Try again later."))
|
2019-12-05 14:51:18 -07:00
|
|
|
def toApiResult(json: Option[JsValue]): ApiResult = json.fold[ApiResult](NoData)(Data.apply)
|
2019-12-13 07:30:20 -07:00
|
|
|
def toApiResult(json: Seq[JsValue]): ApiResult = Data(JsArray(json))
|
2017-05-07 02:31:25 -06:00
|
|
|
|
2019-12-05 14:51:18 -07:00
|
|
|
def toHttp(result: ApiResult): Result = result match {
|
2019-12-13 07:30:20 -07:00
|
|
|
case Limited => tooManyRequests
|
|
|
|
case NoData => NotFound
|
2018-04-03 22:06:50 -06:00
|
|
|
case Custom(result) => result
|
2019-12-13 07:30:20 -07:00
|
|
|
case Data(json) => Ok(json) as JSON
|
2013-12-30 19:00:56 -07:00
|
|
|
}
|
2018-05-07 16:29:14 -06:00
|
|
|
|
2019-12-05 14:51:18 -07:00
|
|
|
def jsonStream(stream: Source[JsObject, _]): Result = jsonStringStream {
|
2019-12-13 07:30:20 -07:00
|
|
|
stream.map { o =>
|
|
|
|
Json.stringify(o) + "\n"
|
|
|
|
}
|
2018-05-08 08:31:38 -06:00
|
|
|
}
|
|
|
|
|
2019-12-05 14:51:18 -07:00
|
|
|
def jsonOptionStream(stream: Source[Option[JsObject], _]): Result = jsonStringStream {
|
2019-12-04 16:39:16 -07:00
|
|
|
stream.map { _ ?? Json.stringify + "\n" }
|
2018-05-08 08:31:38 -06:00
|
|
|
}
|
|
|
|
|
2019-12-05 14:51:18 -07:00
|
|
|
def jsonStringStream(stream: Source[String, _]): Result =
|
2019-12-08 19:54:14 -07:00
|
|
|
Ok.chunked(stream).as(ndJsonContentType) |> noProxyBuffer
|
2019-12-05 14:51:18 -07:00
|
|
|
|
|
|
|
private[controllers] val GlobalLinearLimitPerIP = new lila.memo.LinearLimit[IpAddress](
|
|
|
|
name = "linear API per IP",
|
|
|
|
key = "api.ip",
|
|
|
|
ttl = 6 hours
|
|
|
|
)
|
|
|
|
private[controllers] val GlobalLinearLimitPerUser = new lila.memo.LinearLimit[lila.user.User.ID](
|
|
|
|
name = "linear API per user",
|
|
|
|
key = "api.user",
|
|
|
|
ttl = 6 hours
|
|
|
|
)
|
2019-12-13 07:30:20 -07:00
|
|
|
private[controllers] def GlobalLinearLimitPerUserOption(
|
|
|
|
user: Option[lila.user.User]
|
|
|
|
)(f: Fu[Result]): Fu[Result] =
|
2019-12-05 14:51:18 -07:00
|
|
|
user.fold(f) { u =>
|
|
|
|
GlobalLinearLimitPerUser(u.id)(f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private[controllers] object Api {
|
|
|
|
|
|
|
|
sealed trait ApiResult
|
2019-12-13 07:30:20 -07:00
|
|
|
case class Data(json: JsValue) extends ApiResult
|
|
|
|
case object NoData extends ApiResult
|
|
|
|
case object Limited extends ApiResult
|
2019-12-05 14:51:18 -07:00
|
|
|
case class Custom(result: Result) extends ApiResult
|
2013-12-30 19:00:56 -07:00
|
|
|
}
|