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 Route(ABC):
def __init__(self, controller):
self.controller = controller
@abstractmethod
def matches(self, request):
pass
class StaticRoute(Route):
def __init__(self, route, controller):
self.route = route
super().__init__(controller)
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): class Router(object):
mappings = [ def __init__(self):
{"route": "/", "controller": IndexController}, self.routes = [
{"route": "/status", "controller": StatusController}, StaticRoute("/", IndexController),
{"route": "/status.json", "controller": StatusJsonController}, StaticRoute("/status", StatusController),
{"regex": "/static/(.+)", "controller": OwrxAssetsController}, StaticRoute("/status.json", StatusJsonController),
{"regex": "/aprs-symbols/(.+)", "controller": AprsSymbolsController}, RegexRoute("/static/(.+)", OwrxAssetsController),
{"route": "/ws/", "controller": WebSocketController}, RegexRoute("/aprs-symbols/(.+)", AprsSymbolsController),
{"regex": "(/favicon.ico)", "controller": OwrxAssetsController}, StaticRoute("/ws/", WebSocketController),
RegexRoute("(/favicon.ico)", OwrxAssetsController),
# backwards compatibility for the sdr.hu portal # backwards compatibility for the sdr.hu portal
{"regex": "/(gfx/openwebrx-avatar.png)", "controller": OwrxAssetsController}, RegexRoute("(/gfx/openwebrx-avatar.png)", OwrxAssetsController),
{"route": "/map", "controller": MapController}, StaticRoute("/map", MapController),
{"route": "/features", "controller": FeatureController}, StaticRoute("/features", FeatureController),
{"route": "/api/features", "controller": ApiController}, StaticRoute("/api/features", ApiController),
{"route": "/metrics", "controller": MetricsController}, StaticRoute("/metrics", MetricsController),
] ]
def find_controller(self, path): def find_route(self, request):
for m in Router.mappings: for r in self.routes:
if "route" in m: if r.matches(request):
if m["route"] == path: return r
return (m["controller"], None)
if "regex" in m:
regex = re.compile(m["regex"])
matches = regex.match(path)
if matches:
return (m["controller"], matches)
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.")