[wip][routing] update routes scanner functions in lib.routes

This commit is contained in:
Maxime Alves LIRMM 2020-09-22 14:04:19 +02:00
parent c54101c3e6
commit ba44a01a45

View File

@ -2,7 +2,7 @@
from functools import wraps from functools import wraps
import importlib import importlib
import sys import sys
from typing import Callable, List, Tuple from typing import Callable, List, Tuple, Dict
from halfapi.conf import (PROJECT_NAME, DB_NAME, HOST, PORT, from halfapi.conf import (PROJECT_NAME, DB_NAME, HOST, PORT,
PRODUCTION, DOMAINS) PRODUCTION, DOMAINS)
@ -14,6 +14,7 @@ from halfapi.db import (
AclFunction, AclFunction,
Acl) Acl)
from halfapi.lib.responses import * from halfapi.lib.responses import *
from halfapi.lib.domain import domain_scanner
from starlette.exceptions import HTTPException from starlette.exceptions import HTTPException
from starlette.routing import Mount, Route from starlette.routing import Mount, Route
from starlette.requests import Request from starlette.requests import Request
@ -21,76 +22,49 @@ from starlette.requests import Request
class DomainNotFoundError(Exception): class DomainNotFoundError(Exception):
pass pass
def get_routes(domains=None): def route_decorator(fct: Callable, acls_mod, params: List[Dict]):
""" Procedure to mount the registered domains on their prefixes @wraps(fct)
async def caller(req: Request, *args, **kwargs):
for param in params:
acl_fct = getattr(acls_mod, param['acl'])
if acl_fct(req, *args, **kwargs):
"""
We the 'acl' and 'keys' kwargs values to let the
decorated function know which ACL function answered
True, and which keys the request will return
"""
return await fct(
req, *args,
**{
**kwargs,
**params
})
Parameters: raise HTTPException(401)
- app (ASGIApp): The Starlette instance return caller
- domains (list): The domains to mount, retrieved from the database
with their attributes "name"
Returns: Nothing def gen_starlette_routes():
""" for domain in DOMAINS:
domain_acl_mod = importlib.import_module(
f'{domain}.acl')
( Route(route['path'],
route_decorator(
route['fct'],
domain_acl_mod,
route['params'],
), methods=[route['verb']])
for route in domain_scanner(domain)
)
def route_decorator(fct: Callable, acls_mod, acls: List[Tuple]): for route in gen_routes(domain):
@wraps(fct)
async def caller(req: Request, *args, **kwargs):
for acl_fct_name, keys in acls:
acl_fct = getattr(acls_mod, acl_fct_name)
if acl_fct(req, *args, **kwargs):
"""
We the 'acl' and 'keys' kwargs values to let the
decorated function know which ACL function answered
True, and which keys the request will return
"""
return await fct(
req, *args,
**{
**kwargs,
'acl': f'{acls_mod.__name__}.{acl_fct_name}',
'keys': keys
})
raise HTTPException(401) yield (
Route(route['path'],
return caller route_decorator(
route['fct'],
app_routes = [] domain_acl_mod,
for domain_name in DOMAINS: route['params'],
try: ), methods=[route['verb']])
domain = next(Domain(name=domain_name).select()) )
except StopIteration:
raise DomainNotFoundError(
f"Domain '{domain_name}' not found in '{DB_NAME}' database!")
domain_acl_mod = importlib.import_module(f'{domain["name"]}.acl')
domain_routes = []
for router in APIRouter(domain=domain['name']).select():
router_routes = []
router_mod = importlib.import_module(
'{domain}.routers.{name}'.format(**router))
with APIRoute(domain=domain['name'],
router=router['name']) as routes:
for route in routes.select():
fct_name = route.pop('fct_name')
acls = [ (elt['acl_fct_name'], elt['keys'])
for elt in Acl(**route).select('acl_fct_name', 'keys') ]
router_routes.append(
Route(route['path'],
route_decorator(
getattr(router_mod, fct_name),
domain_acl_mod,
acls
), methods=[route['http_verb']])
)
domain_routes.append(
Mount('/{name}'.format(**router), routes=router_routes))
app_routes.append(Mount('/{name}'.format(**domain),
routes=domain_routes))
return app_routes