improve rate limiter

This commit is contained in:
Thibault Duplessis 2016-03-02 12:30:22 +07:00
parent 2815bf3c56
commit 253504bfec
7 changed files with 58 additions and 54 deletions

View file

@ -18,8 +18,6 @@ object Challenge extends LilaController {
private def env = Env.challenge
private val PostRateLimit = new lila.memo.RateLimit(5, 1 minute)
def all = Auth { implicit ctx =>
me =>
env.api allFor me.id map { all =>

View file

@ -7,7 +7,7 @@ import views._
object ForumPost extends LilaController with ForumController {
private val CreateRateLimit = new lila.memo.RateLimit(4, 5 minutes)
private val CreateRateLimit = new lila.memo.RateLimit(4, 5 minutes, "forum create post")
def search(text: String, page: Int) = OpenBody { implicit ctx =>
NotForKids {

View file

@ -8,7 +8,7 @@ import views._
object ForumTopic extends LilaController with ForumController {
private val CreateRateLimit = new lila.memo.RateLimit(2, 5 minutes)
private val CreateRateLimit = new lila.memo.RateLimit(2, 5 minutes, "forum create topic")
def form(categSlug: String) = Open { implicit ctx =>
NotForKids {

View file

@ -19,7 +19,7 @@ object Setup extends LilaController with TheftPrevention {
private def env = Env.setup
private val PostRateLimit = new lila.memo.RateLimit(5, 1 minute)
private val PostRateLimit = new lila.memo.RateLimit(5, 1 minute, "setup post")
def aiForm = Open { implicit ctx =>
if (HTTPRequest isXhr ctx.req) {
@ -60,37 +60,39 @@ object Setup extends LilaController with TheftPrevention {
def friend(userId: Option[String]) =
OpenBody { implicit ctx =>
implicit val req = ctx.body
env.forms.friend(ctx).bindFromRequest.fold(
f => negotiate(
html = Lobby.renderHome(Results.BadRequest),
api = _ => fuccess(BadRequest(errorsAsJson(f)))
), {
case config => userId ?? UserRepo.byId flatMap { destUser =>
import lila.challenge.Challenge._
val challenge = lila.challenge.Challenge.make(
variant = config.variant,
initialFen = config.fen,
timeControl = config.makeClock map { c =>
TimeControl.Clock(c.limit, c.increment)
} orElse config.makeDaysPerTurn.map {
TimeControl.Correspondence.apply
} getOrElse TimeControl.Unlimited,
mode = config.mode,
color = config.color.name,
challenger = (ctx.me, HTTPRequest sid req) match {
case (Some(user), _) => Right(user)
case (_, Some(sid)) => Left(sid)
case _ => Left("no_sid")
},
destUser = destUser,
rematchOf = none)
env.processor.saveFriendConfig(config) >>
(Env.challenge.api create challenge) >> negotiate(
html = fuccess(Redirect(routes.Round.watcher(challenge.id, "white"))),
api = _ => Challenge showChallenge challenge)
PostRateLimit(req.remoteAddress) {
env.forms.friend(ctx).bindFromRequest.fold(
f => negotiate(
html = Lobby.renderHome(Results.BadRequest),
api = _ => fuccess(BadRequest(errorsAsJson(f)))
), {
case config => userId ?? UserRepo.byId flatMap { destUser =>
import lila.challenge.Challenge._
val challenge = lila.challenge.Challenge.make(
variant = config.variant,
initialFen = config.fen,
timeControl = config.makeClock map { c =>
TimeControl.Clock(c.limit, c.increment)
} orElse config.makeDaysPerTurn.map {
TimeControl.Correspondence.apply
} getOrElse TimeControl.Unlimited,
mode = config.mode,
color = config.color.name,
challenger = (ctx.me, HTTPRequest sid req) match {
case (Some(user), _) => Right(user)
case (_, Some(sid)) => Left(sid)
case _ => Left("no_sid")
},
destUser = destUser,
rematchOf = none)
env.processor.saveFriendConfig(config) >>
(Env.challenge.api create challenge) >> negotiate(
html = fuccess(Redirect(routes.Round.watcher(challenge.id, "white"))),
api = _ => Challenge showChallenge challenge)
}
}
}
)
)
}
}
def hookForm = Open { implicit ctx =>
@ -167,21 +169,23 @@ object Setup extends LilaController with TheftPrevention {
private def process[A](form: Context => Form[A])(op: A => BodyContext[_] => Fu[Pov]) =
OpenBody { implicit ctx =>
implicit val req = ctx.body
form(ctx).bindFromRequest.fold(
f => negotiate(
html = Lobby.renderHome(Results.BadRequest),
api = _ => fuccess(BadRequest(errorsAsJson(f)))
),
config => op(config)(ctx) flatMap { pov =>
negotiate(
html = fuccess(redirectPov(pov)),
api = apiVersion => Env.api.roundApi.player(pov, apiVersion) map { data =>
Created(data) as JSON
}
)
}
)
PostRateLimit(ctx.req.remoteAddress) {
implicit val req = ctx.body
form(ctx).bindFromRequest.fold(
f => negotiate(
html = Lobby.renderHome(Results.BadRequest),
api = _ => fuccess(BadRequest(errorsAsJson(f)))
),
config => op(config)(ctx) flatMap { pov =>
negotiate(
html = fuccess(redirectPov(pov)),
api = apiVersion => Env.api.roundApi.player(pov, apiVersion) map { data =>
Created(data) as JSON
}
)
}
)
}
}
private[controllers] def redirectPov(pov: Pov)(implicit ctx: Context) = {

View file

@ -20,7 +20,7 @@ private[lobby] final class SocketHandler(
socket: ActorRef,
blocking: String => Fu[Set[String]]) {
lazy val JoinRateLimit = new lila.memo.RateLimit(4, 1 minute)
lazy val JoinRateLimit = new lila.memo.RateLimit(4, 1 minute, "lobby join")
private def controller(
socket: ActorRef,

View file

@ -6,7 +6,7 @@ import scala.concurrent.duration.Duration
/**
* side effect throttler that allows X ops per Y unit of time
*/
final class RateLimit(nb: Int, duration: Duration) {
final class RateLimit(nb: Int, duration: Duration, name: String) {
private type NbOps = Int
private type ClearAt = Long
@ -26,6 +26,8 @@ final class RateLimit(nb: Int, duration: Duration) {
case Some((_, clearAt)) if nowMillis > clearAt =>
storage.put(key, 1 -> makeClearAt)
op
case _ => default.zero
case _ =>
play.api.Logger("ratelimit").info(s"$name ($nb/$duration) $key")
default.zero
}
}

View file

@ -19,7 +19,7 @@ object Handler {
val emptyController: Controller = PartialFunction.empty
lazy val AnaRateLimit = new lila.memo.RateLimit(90, 60 seconds)
lazy val AnaRateLimit = new lila.memo.RateLimit(90, 60 seconds, "socket analysis move")
def apply(
hub: lila.hub.Env,