rewrite routing logic

This commit is contained in:
Jakob Ketterl 2020-02-23 17:53:02 +01:00
parent 451eb99f8a
commit 42191f4e77

View File

@ -17,6 +17,7 @@ from owrx.controllers.metrics import MetricsController
from http.server import BaseHTTPRequestHandler from http.server import BaseHTTPRequestHandler
from urllib.parse import urlparse, parse_qs from urllib.parse import urlparse, parse_qs
import re import re
from abc import ABC, abstractmethod
import logging import logging
@ -37,46 +38,74 @@ class RequestHandler(BaseHTTPRequestHandler):
class Request(object): class Request(object):
def __init__(self, query=None, matches=None): def __init__(self, url):
self.query = query self.path = url.path
self.query = parse_qs(url.query)
self.matches = None
def setMatches(self, matches):
self.matches = matches self.matches = matches
class Router(object): class Route(ABC):
mappings = [ def __init__(self, controller):
{"route": "/", "controller": IndexController}, self.controller = controller
{"route": "/status", "controller": StatusController},
{"route": "/status.json", "controller": StatusJsonController},
{"regex": "/static/(.+)", "controller": OwrxAssetsController},
{"regex": "/aprs-symbols/(.+)", "controller": AprsSymbolsController},
{"route": "/ws/", "controller": WebSocketController},
{"regex": "(/favicon.ico)", "controller": OwrxAssetsController},
# backwards compatibility for the sdr.hu portal
{"regex": "/(gfx/openwebrx-avatar.png)", "controller": OwrxAssetsController},
{"route": "/map", "controller": MapController},
{"route": "/features", "controller": FeatureController},
{"route": "/api/features", "controller": ApiController},
{"route": "/metrics", "controller": MetricsController},
]
def find_controller(self, path): @abstractmethod
for m in Router.mappings: def matches(self, request):
if "route" in m: pass
if m["route"] == path:
return (m["controller"], None)
if "regex" in m: class StaticRoute(Route):
regex = re.compile(m["regex"]) def __init__(self, route, controller):
matches = regex.match(path) self.route = route
if matches: super().__init__(controller)
return (m["controller"], matches)
def matches(self, request):
return request.path == self.route
class RegexRoute(Route):
def __init__(self, regex, controller):
self.regex = re.compile(regex)
super().__init__(controller)
def matches(self, request):
matches = self.regex.match(request.path)
# this is probably not the cleanest way to do it...
request.setMatches(matches)
return matches is not None
class Router(object):
def __init__(self):
self.routes = [
StaticRoute("/", IndexController),
StaticRoute("/status", StatusController),
StaticRoute("/status.json", StatusJsonController),
RegexRoute("/static/(.+)", OwrxAssetsController),
RegexRoute("/aprs-symbols/(.+)", AprsSymbolsController),
StaticRoute("/ws/", WebSocketController),
RegexRoute("(/favicon.ico)", OwrxAssetsController),
# backwards compatibility for the sdr.hu portal
RegexRoute("(/gfx/openwebrx-avatar.png)", OwrxAssetsController),
StaticRoute("/map", MapController),
StaticRoute("/features", FeatureController),
StaticRoute("/api/features", ApiController),
StaticRoute("/metrics", MetricsController),
]
def find_route(self, request):
for r in self.routes:
if r.matches(request):
return r
def route(self, handler): def route(self, handler):
url = urlparse(handler.path) url = urlparse(handler.path)
res = self.find_controller(url.path) request = Request(url)
if res is not None: route = self.find_route(request)
(controller, matches) = res if route is not None:
query = parse_qs(url.query) controller = route.controller
request = Request(query, matches)
controller(handler, request).handle_request() controller(handler, request).handle_request()
else: else:
handler.send_error(404, "Not Found", "The page you requested could not be found.") handler.send_error(404, "Not Found", "The page you requested could not be found.")