diff options
| author | Andrew <saintruler@gmail.com> | 2019-05-28 21:58:51 +0400 |
|---|---|---|
| committer | Andrew <saintruler@gmail.com> | 2019-05-28 21:58:51 +0400 |
| commit | d31296d87f86ca817b6d7c41c46bc83fe403a093 (patch) | |
| tree | 88a99b27bfee6b81096333769ce71a288e4b1b44 /day7/router.py | |
| parent | d83efe142c1d95ac04a52b03498b32b2df33c53e (diff) | |
Добавлен модуль роутинга.
Diffstat (limited to 'day7/router.py')
| -rw-r--r-- | day7/router.py | 87 |
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']), +] |