summaryrefslogtreecommitdiff
path: root/day7/router.py
diff options
context:
space:
mode:
Diffstat (limited to 'day7/router.py')
-rw-r--r--day7/router.py87
1 files changed, 87 insertions, 0 deletions
diff --git a/day7/router.py b/day7/router.py
new file mode 100644
index 0000000..b0705c3
--- /dev/null
+++ b/day7/router.py
@@ -0,0 +1,87 @@
+import re
+from utils import NOT_FOUND, add_text_headers, HTTP_METHODS
+import db
+
+from backend import *
+
+
+class Route:
+ def __init__(self, callback, url_format, methods=None):
+ self.methods = ['GET'] if methods is None else methods
+ self.url_pattern = re.compile(url_format)
+ self.callback = callback
+
+ def check_route(self, url, method):
+ match = self.url_pattern.fullmatch(url)
+ return bool(match) and len(match.groups()) == self.url_pattern.groups and method in self.methods
+
+ def invoke_callback(self, url, method, query):
+ match = self.url_pattern.fullmatch(url)
+ groups = match.groups()
+
+ matched = match and len(groups) == self.url_pattern.groups and method in self.methods
+ if not matched:
+ return NOT_FOUND, NOT_FOUND
+
+ return self.callback(query, *match.groups())
+
+
+# url_format - регулярное выражение
+def route(url_format, methods=None):
+ if methods is None:
+ methods = ['GET']
+
+ def wrapper(func):
+ def inner(url, query, *args, **kwargs):
+ pattern = re.compile(url_format)
+ match = re.fullmatch(pattern, url)
+
+ if match is None or len(match.groups()) != pattern.groups:
+ return NOT_FOUND, '404 NOT FOUND'
+
+ return func(query, *match.groups(), *args, **kwargs)
+
+ # Добавляем вызываемую функцию в дерево роутера.
+ # Благодаря этому указывать паттерн url и метод нужно указывать
+ # только в инициализаторе декоратора, а функция run сама разберется
+ # при каких условиях нужно вызвать конкретную функцию
+ _router_tree.append(Route(func, url_format, methods))
+ return inner
+
+ return wrapper
+
+
+def run(request):
+ res = NOT_FOUND, NOT_FOUND
+
+ for key, value in request['cookies'].items():
+ db.set_cookie(key, value)
+
+ method, url = request['method'], request['url']
+
+ for route in _router_tree:
+ if route.check_route(url, method):
+ res = route.invoke_callback(url, method, request['query'])
+ break
+
+ return add_text_headers(*res)
+
+
+_router_tree = [
+ # Пока ничего лучше не придумал
+ Route(fallback_wrong_method, '/.*', list(set(HTTP_METHODS) ^ {'GET', 'POST'})),
+
+ Route(index_get, '/'),
+
+ Route(divide_get, r'/div/(\d+)/to/(\d+)/?'),
+ Route(divide_post, r'/div/?', ['POST']),
+
+ Route(show_errors_get, r'/show_errors/(\d{1})/?'),
+ Route(show_errors_post, r'/show_errors/?', ['POST']),
+
+ Route(set_cookie_get, r'/set_cookie/=/(.*)/?'),
+ Route(set_cookie_post, r'/set_cookie/=/?', ['POST']),
+
+ Route(short_log_get, r'/short_log/(\d{1})/?'),
+ Route(short_log_post, r'/short_log/?', ['POST']),
+]