token bucket implemented in memory, in app
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
__pycache__/
|
||||
env/
|
||||
*.pyc
|
||||
0
my_limiter/__init__.py
Normal file
0
my_limiter/__init__.py
Normal file
33
my_limiter/algos.py
Normal file
33
my_limiter/algos.py
Normal file
@@ -0,0 +1,33 @@
|
||||
import datetime as dt
|
||||
|
||||
|
||||
|
||||
TOKEN_BUCKET = {}
|
||||
TIME_INTERVAL_SECONDS = 15
|
||||
|
||||
class TooManyRequests(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def token_bucket(ip: str):
|
||||
"""
|
||||
Tokens are put in the bucket at preset rates periodically.
|
||||
Once the bucket is full, no more tokens are added.
|
||||
The refiller puts NUM_TOKENS_TO_REFILL tokens into the bucket every minute.
|
||||
"""
|
||||
REFILL_EVERY_SECONDS = TIME_INTERVAL_SECONDS
|
||||
NUM_TOKENS_TO_REFILL = 4
|
||||
MAX_CAPACITY = 4
|
||||
|
||||
entry = TOKEN_BUCKET.get(ip)
|
||||
|
||||
if entry is None:
|
||||
TOKEN_BUCKET[ip] = {'tokens': 4, 'last_refilled': dt.datetime.now().timestamp()}
|
||||
else:
|
||||
if dt.datetime.now().timestamp() >= entry['last_refilled'] + REFILL_EVERY_SECONDS:
|
||||
entry['last_refilled'] = dt.datetime.now().timestamp()
|
||||
entry['tokens'] = min(entry['tokens'] + NUM_TOKENS_TO_REFILL, MAX_CAPACITY)
|
||||
left = TOKEN_BUCKET[ip]['tokens']
|
||||
if left == 0:
|
||||
raise TooManyRequests
|
||||
TOKEN_BUCKET[ip]['tokens'] -= 1
|
||||
1
my_limiter/config.py
Normal file
1
my_limiter/config.py
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
22
my_limiter/wsgi.py
Normal file
22
my_limiter/wsgi.py
Normal file
@@ -0,0 +1,22 @@
|
||||
import flask as f
|
||||
|
||||
from . import algos
|
||||
|
||||
|
||||
application = f.Flask(__name__)
|
||||
|
||||
|
||||
increment_requests_func = algos.token_bucket
|
||||
|
||||
|
||||
@application.before_request
|
||||
def before_request():
|
||||
ip = f.request.remote_addr
|
||||
try:
|
||||
increment_requests_func(ip)
|
||||
except algos.TooManyRequests:
|
||||
return f.abort(429)
|
||||
|
||||
@application.route('/')
|
||||
def home():
|
||||
return '<!doctype html><title>Hello</title><h1>Hello</h1>'
|
||||
Reference in New Issue
Block a user