Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
L
LibreHomework
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Releases
Package Registry
Model registry
Operate
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
HGEpro
LibreHomework
Commits
300d818b
Unverified
Commit
300d818b
authored
3 years ago
by
YeahNotSewerSide
Committed by
GitHub
3 years ago
Browse files
Options
Downloads
Patches
Plain Diff
Wrote better rate limiter
parent
e42d1500
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
server/ratelimiter.py
+59
-40
59 additions, 40 deletions
server/ratelimiter.py
with
59 additions
and
40 deletions
server/ratelimiter.py
+
59
−
40
View file @
300d818b
from
functools
import
wraps
import
time
from
sanic.response
import
json
class
RateLimiter
:
class
TokenBucket
:
'''
Implementation of TokenBucket
'''
def
__init__
(
self
,
tokens
:
int
,
time_for_token
:
int
):
'''
tokens:int - maximum amount of tokens
time_for_token: - time in which 1 token is added
'''
self
.
token_koef
=
tokens
/
time_for_token
self
.
tokens
=
tokens
self
.
last_check
=
time
.
time
()
def
handle
(
self
)
->
bool
:
current_time
=
time
.
time
()
time_delta
=
current_time
-
self
.
last_check
self
.
last_check
=
current_time
self
.
tokens
+=
time_delta
*
self
.
token_koef
if
self
.
tokens
>
self
.
max_tokens
:
self
.
tokens
=
self
.
max_tokens
if
self
.
tokens
<
1
:
return
False
self
.
tokens
-=
1
return
True
class
RateLimited
(
Exception
):
def
__init__
(
self
):
s
elf
.
sto
ra
g
e
=
{}
s
uper
().
__init__
(
"
Call was
ra
t
e
limited
"
)
async
def
limit
(
self
,
calls
,
per_second
,
func
,
request
,
*
args
,
**
kwargs
):
GLOBAL_BUCKETS
=
{}
current_time
=
time
.
time
()
cell
=
self
.
storage
.
get
(
request
.
ip
)
def
rate_limit
(
tokens
:
int
,
time_for_token
:
int
):
def
wrapper
(
function
):
def
wrapped
(
*
args
,
**
kwargs
):
fn_name
=
function
.
__name__
try
:
bucket
=
GLOBAL_BUCKETS
[
fn_name
]
except
:
bucket
=
TokenBucket
(
tokens
,
time_for_token
)
GLOBAL_BUCKETS
[
fn_name
]
=
bucket
if
not
cell
:
cell
=
[
calls
-
1
,
current_time
]
self
.
storage
[
request
.
ip
]
=
cell
return
await
func
(
request
,
*
args
,
**
kwargs
)
if
not
bucket
.
handle
():
raise
RateLimited
()
time_delta
=
current_time
-
cell
[
-
1
]
to_add
=
int
(
time_delta
*
(
calls
/
per_second
))
cell
[
0
]
+=
to_add
return
function
(
*
args
,
**
kwargs
)
return
wrapped
return
wrapper
if
cell
[
0
]
>
calls
:
cell
[
0
]
=
calls
if
cell
[
0
]
<=
0
:
return
json
({
"
success
"
:
False
,
"
ratelimit
"
:
True
})
self
.
storage
[
request
.
ip
][
0
]
-=
1
self
.
storage
[
request
.
ip
][
1
]
=
current_time
return
await
func
(
request
,
*
args
,
**
kwargs
)
if
__name__
==
"
__main__
"
:
@rate_limit
(
3
,
50
)
def
func1
(
a
):
print
(
"
Function1
"
,
a
)
for
i
in
range
(
10
):
try
:
a
=
func1
(
555
)
except
RateLimited
:
print
(
"
RT
"
)
time
.
sleep
(
2
)
class
EndpointLimiter
:
def
__init__
(
self
):
self
.
funcs
=
{}
def
limit
(
self
,
calls
,
per_second
):
def
decorator
(
func
):
@wraps
(
func
)
async
def
wrapper
(
request
,
*
args
,
**
kwargs
):
try
:
return
await
self
.
funcs
[
func
.
__name__
].
limit
(
calls
,
per_second
,
func
,
request
,
*
args
,
**
kwargs
)
except
KeyError
:
rate_limiter
=
RateLimiter
()
self
.
funcs
[
func
.
__name__
]
=
rate_limiter
return
await
self
.
funcs
[
func
.
__name__
].
limit
(
calls
,
per_second
,
func
,
request
,
*
args
,
**
kwargs
)
return
wrapper
return
decorator
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment