From d31296d87f86ca817b6d7c41c46bc83fe403a093 Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 28 May 2019 21:58:51 +0400 Subject: =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=20?= =?UTF-8?q?=D0=BC=D0=BE=D0=B4=D1=83=D0=BB=D1=8C=20=D1=80=D0=BE=D1=83=D1=82?= =?UTF-8?q?=D0=B8=D0=BD=D0=B3=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- day7/router.py | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 day7/router.py (limited to 'day7/router.py') 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']), +] -- cgit v1.2.3