/** Ċ Ġ* ĠCopyright Ġ 2 0 1 8 ĠB rend en ĠMat the ws Ġ< bre nd en @ d idd y inc . com > Ċ Ġ* Ċ Ġ* ĠLicensed Ġunder Ġthe ĠApache ĠLicense , ĠVersion Ġ 2 . 0 Ġ( the Ġ" License "); Ċ Ġ* Ġyou Ġmay Ġnot Ġuse Ġthis Ġfile Ġexcept Ġin Ġcompliance Ġwith Ġthe ĠLicense . Ċ Ġ* ĠYou Ġmay Ġobtain Ġa Ġcopy Ġof Ġthe ĠLicense Ġat Ċ Ġ* Ċ Ġ* ĠĠ Ġhttp :// www . apache . org / licenses / LICENSE - 2 . 0 Ċ Ġ* Ċ Ġ* ĠUnless Ġrequired Ġby Ġapplicable Ġlaw Ġor Ġagreed Ġto Ġin Ġwriting , Ġsoftware Ċ Ġ* Ġdistributed Ġunder Ġthe ĠLicense Ġis Ġdistributed Ġon Ġan Ġ" AS ĠIS " ĠBASIS , Ċ Ġ* ĠWITHOUT ĠWARRANTIES ĠOR ĠCONDITIONS ĠOF ĠANY ĠKIND , Ġeither Ġexpress Ġor Ġimplied . Ċ Ġ* ĠSee Ġthe ĠLicense Ġfor Ġthe Ġspecific Ġlanguage Ġgoverning Ġpermissions Ġand Ċ Ġ* Ġlimitations Ġunder Ġthe ĠLicense . Ċ Ġ*/ Ċ package Ġorg . omp ldr . server . apis Ċ Ċ import Ġio . ktor . application . Application Call Pipeline Ċ import Ġio . ktor . application . Application Feature Ċ import Ġio . ktor . application . call Ċ import Ġio . ktor . http . HttpStatusCode Ċ import Ġio . ktor . request . header Ċ import Ġio . ktor . request . path Ċ import Ġio . ktor . response . header Ċ import Ġio . ktor . response . respond Ċ import Ġio . ktor . util . Attribute Key Ċ import Ġmu . Kotlin Logging Ċ import Ġredis . clients . j edis . J edis Pool Config Ċ import Ġredis . clients . j edis . J edis Pool Ċ import Ġredis . clients . j edis . exceptions . J edis Exception Ċ Ċ private Ġval Ġlogger Ġ= ĠKotlin Logging . logger Ġ{} Ċ Ċ class ĠRate Limiter ( config : ĠConfiguration ) Ġ{ ĊĠ Ġval Ġredis Host Ġ= Ġconfig . redis Host ĊĠ Ġval Ġredis Port Ġ= Ġconfig . redis Port ĊĠ Ġval Ġcount Limit Ġ= Ġconfig . count Limit ĊĠ Ġval Ġperiod Ġ= Ġconfig . period ĊĠ Ġval Ġburst Ġ= Ġconfig . burst ĊĊĠ Ġclass ĠConfiguration Ġ{ ĊĠĠĠ Ġvar Ġredis Host Ġ= Ġ" localhost " ĊĠĠĠ Ġvar Ġredis Port Ġ= Ġ 6 3 7 9 ĊĠĠĠ Ġvar Ġcount Limit Ġ= Ġ 3 0 ĊĠĠĠ Ġvar Ġperiod Ġ= Ġ 6 0 ĊĠĠĠ Ġvar Ġburst Ġ= Ġ 1 5 ĊĠ Ġ} ĊĊĠ Ġprivate Ġval Ġignored Paths Ġ= Ġset Of ("/ ping ") ĊĊĠ Ġvar Ġpool Ġ= ĠJ edis Pool ( J edis Pool Config (), Ġredis Host , Ġredis Port ) ĊĊĠ Ġcompanion Ġobject ĠFeature Ġ: ĠApplication Feature < Application Call Pipeline , ĠConfiguration , ĠRate Limiter > Ġ{ ĊĠĠĠ Ġoverride Ġval Ġkey Ġ= ĠAttribute Key < Rate Limiter >(" Rate Limiter ") ĊĠĠĠ Ġoverride Ġfun Ġinstall ( pipeline : ĠApplication Call Pipeline , Ġconfigure : ĠConfiguration . () Ġ-> ĠUnit ): ĠRate Limiter Ġ{ ĊĠĠĠĠĠ Ġval Ġfeature Ġ= ĠRate Limiter ( Configuration (). apply ( configure )) ĊĠĠĠĠĠ Ġpipeline . intercept ( Application Call Pipeline . Infrastructure ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( call . request . path () Ġ! in Ġfeature . ignored Paths Ġ&& Ġcall . request . headers . contains (" X - Forwarded - For ")) Ġ{ ĊĠĠĠĠĠĠĠĠĠ Ġfeature . pool . resource . use Ġ{ Ġjed is Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġforwarded For Ġ= ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcall . request . header (" X - Forwarded - For ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ? . split (",") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ? . first OrNull () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ? . trim () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ?: Ġ" local " ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġkeys Ġ= ĠlistOf ( for warded For ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġargs Ġ= ĠlistOf ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfeature . burst . toString (), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfeature . count Limit . toString (), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfeature . period . toString () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ@ Suppress (" UN CHECK ED _ CAST ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġresponse Ġ= Ġjed is . eval ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" return Ġ{ redis . call (' CL . TH RO TT LE ', KEYS [ 1 ], ARGV [ 1 ], ARGV [ 2 ], ARGV [ 3 ]) }", ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġkeys , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġargs ĊĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) Ġas ĠArrayList < ArrayList < Long >> ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġwas Limit ed Ġ= Ġresponse [ 0 ][ 0 ] ĊĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġlimit Ġ= Ġresponse [ 0 ][ 1 ] ĊĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġlimit Remaining Ġ= Ġresponse [ 0 ][ 2 ] ĊĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġretry After Ġ= Ġresponse [ 0 ][ 3 ] ĊĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġlimit Reset Ġ= Ġresponse [ 0 ][ 4 ] ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcall . response . header (" X - RateLimit - Limit ", Ġlimit ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcall . response . header (" X - RateLimit - Remaining ", Ġlimit Remaining ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcall . response . header (" X - RateLimit - Reset ", Ġlimit Reset ) ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( was Limit ed Ġ== Ġ 1 L ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcall . response . header (" Retry - After ", Ġretry After ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcall . respond ( HttpStatusCode . Too Many Requests ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfinish () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠJ edis Exception ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . error (" Got Ġan Ġexception Ġfrom ĠRedis ", Ġe ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠ Ġ} ĊĠĠĠĠĠ Ġreturn Ġfeature ĊĠĠĠ Ġ} ĊĠ Ġ} Ċ } Ċ