NucelarMonitor/Python/Managers/RoutesManager.py

102 lines
3.4 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Any, Sequence
from re import Match as REMatch
from mimetypes import guess_type as get_mime_by_extension
from Interfaces.Application.NucelarMonitorInterface import NucelarMonitorInterface
from Models.RouteModel import RouteModel
from Models.ResponseModel import ResponseModel
from Models.RequestModel import RequestModel
class RoutesManager:
def __init__(self:Self, nucelar_monitor:NucelarMonitorInterface) -> None:
self.nucelar_monitor:NucelarMonitorInterface = nucelar_monitor
key:str
self.__routes:list[RouteModel] = []
for key in (
"default_routes_files", "routes_files",
"default_routes", "routes"
):
self.add(self.nucelar_monitor.settings.get(key, None, []), True)
def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None:
route:str|Sequence[str|list[str]|RouteModel]
for route in self.nucelar_monitor.files.load_json(inputs, False):
item:RouteModel = route if isinstance(route, RouteModel) else RouteModel(self.nucelar_monitor, route)
if item.error:
self.add(route, overwrite)
continue
exists:RouteModel
done:bool = False
for exists in self.__routes:
if exists.method == item.method and exists.route == item.route:
if overwrite:
done = True
self.__routes.remove(exists)
else:
break
if not done:
self.__routes.append(item)
def get(self:Self, request:RequestModel, response:ResponseModel) -> None:
route:RouteModel
for route in self.__routes:
if route.method != request.method:
continue
matches:REMatch[str]|None = route.route.match(request.request)
if not matches:
continue
request.set_uri_variables(route.variables, matches)
if route.action:
try:
route.action(request, response)
except Exception as exception:
response.build({
"ok" : False,
"code" : 500,
"message" : "Internal server error",
"error" : str(exception)
}, "application/json", 500, "Internal server error")
self.nucelar_monitor.exception(exception, "nucelar_monitor_routes_manager_get_exception", {
"request" : request.request,
"method" : request.method
})
return
if route.path:
index:str
for index in request.index_files:
full_path = route.path + request.request + ("" if index == "" else "/" + index)
if (response_data := self.nucelar_monitor.files.load_file(full_path, "rb")) is not None:
response.set_data(
response_data,
get_mime_by_extension(full_path)[0] or "application/octet-stream"
)
return
response.build({
"ok" : False,
"code" : 404,
"message" : "Not found"
}, "application/json", 404, "Not found")