lila/app/controllers/Search.scala
2020-12-27 14:25:17 +01:00

97 lines
3.6 KiB
Scala

package controllers
import scala.concurrent.duration._
import views._
import lila.app._
import lila.common.{ HTTPRequest, IpAddress }
final class Search(env: Env) extends LilaController(env) {
def searchForm = env.gameSearch.forms.search
private val SearchRateLimitPerIP = new lila.memo.RateLimit[IpAddress](
credits = 50,
duration = 5.minutes,
key = "search.games.ip"
)
private val SearchConcurrencyLimitPerIP = new lila.memo.FutureConcurrencyLimit[IpAddress](
key = "search.games.concurrency.ip",
ttl = 10.minutes,
maxConcurrency = 1
)
def index(p: Int) =
OpenBody { implicit ctx =>
env.game.cached.nbTotal flatMap { nbGames =>
if (ctx.isAnon)
negotiate(
html = Unauthorized(html.search.login(nbGames)).fuccess,
api = _ => Unauthorized(jsonError("Login required")).fuccess
)
else
NotForBots {
val page = p atLeast 1
Reasonable(page, 100) {
val ip = HTTPRequest ipAddress ctx.req
val cost = scala.math.sqrt(page.toDouble).toInt
implicit def req = ctx.body
def limited =
fuccess {
val form = searchForm
.bindFromRequest()
.withError(
key = "",
message = "Please only send one request at a time per IP address"
)
TooManyRequests(html.search.index(form, none, nbGames))
}
SearchRateLimitPerIP(ip, cost = cost) {
SearchConcurrencyLimitPerIP(ip, limited = limited) {
negotiate(
html = searchForm
.bindFromRequest()
.fold(
failure => Ok(html.search.index(failure, none, nbGames)).fuccess,
data =>
data.nonEmptyQuery ?? { query =>
env.gameSearch.paginator(query, page) map some
} map { pager =>
Ok(html.search.index(searchForm fill data, pager, nbGames))
} recover { _ =>
InternalServerError("Sorry, we can't process that query at the moment")
}
),
api = _ =>
searchForm
.bindFromRequest()
.fold(
_ =>
Ok {
jsonError("Could not process search query")
}.fuccess,
data =>
data.nonEmptyQuery ?? { query =>
env.gameSearch.paginator(query, page) dmap some
} flatMap {
case Some(s) =>
env.api.userGameApi.jsPaginator(s) dmap {
Ok(_)
}
case None =>
BadRequest(jsonError("Could not process search query")).fuccess
} recover { _ =>
InternalServerError(
jsonError("Sorry, we can't process that query at the moment")
)
}
)
)
}
}(rateLimitedFu)
}
}
}
}
}