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']), ]