risotto/src/risotto/http.py

134 lines
4.6 KiB
Python
Raw Permalink Normal View History

2019-11-29 09:13:16 +01:00
from aiohttp.web import Application, Response, get, post, HTTPBadRequest, HTTPInternalServerError, HTTPNotFound
from json import dumps
2019-12-07 16:21:20 +01:00
from traceback import print_exc
from tiramisu import Config
2019-11-28 14:50:53 +01:00
from .dispatcher import dispatcher
from .utils import _
from .context import Context
2019-12-02 10:29:40 +01:00
from .error import CallError, NotAllowedError, RegistrationError
2019-11-29 09:13:16 +01:00
from .message import get_messages
from .logger import log
2019-12-02 10:29:40 +01:00
from .config import DEBUG, HTTP_PORT
2019-12-07 16:21:20 +01:00
from .services import load_services
2019-11-28 14:50:53 +01:00
2019-12-02 10:29:40 +01:00
def create_context(request):
risotto_context = Context()
risotto_context.username = request.match_info.get('username', "Anonymous")
return risotto_context
def register(version: str,
path: str):
""" Decorator to register function to the http route
"""
def decorator(function):
if path in extra_routes:
raise RegistrationError(f'the route {path} is already registered')
extra_routes[path] = {'function': function,
'version': version}
return decorator
class extra_route_handler:
async def __new__(cls, request):
kwargs = dict(request.match_info)
kwargs['request'] = request
kwargs['risotto_context'] = create_context(request)
kwargs['risotto_context'].version = cls.version
kwargs['risotto_context'].paths.append(cls.path)
kwargs['risotto_context'].type = 'http_get'
function_name = cls.function.__module__
# if not 'api' function
if function_name != 'risotto.http':
module_name = function_name.split('.')[-2]
kwargs['self'] = dispatcher.injected_self[module_name]
try:
returns = await cls.function(**kwargs)
except NotAllowedError as err:
raise HTTPNotFound(reason=str(err))
except CallError as err:
raise HTTPBadRequest(reason=str(err))
except Exception as err:
if DEBUG:
print_exc()
raise HTTPInternalServerError(reason=str(err))
log.info_msg(kwargs['risotto_context'],
dict(request.match_info))
return Response(text=dumps(returns))
2019-11-28 14:50:53 +01:00
async def handle(request):
2019-11-29 09:13:16 +01:00
version, uri = request.match_info.get_info()['path'].rsplit('/', 2)[-2:]
2019-12-02 10:29:40 +01:00
risotto_context = create_context(request)
2019-11-29 09:13:16 +01:00
kwargs = await request.json()
2019-11-28 14:50:53 +01:00
try:
2019-11-28 16:51:56 +01:00
text = await dispatcher.call(version,
uri,
2019-12-02 10:29:40 +01:00
risotto_context,
2019-11-29 09:13:16 +01:00
public_only=True,
**kwargs)
2019-11-28 14:50:53 +01:00
except NotAllowedError as err:
2019-11-28 16:51:56 +01:00
raise HTTPNotFound(reason=str(err))
2019-11-28 14:50:53 +01:00
except CallError as err:
raise HTTPBadRequest(reason=str(err))
except Exception as err:
2019-11-29 14:20:03 +01:00
if DEBUG:
print_exc()
2019-11-28 14:50:53 +01:00
raise HTTPInternalServerError(reason=str(err))
2019-11-29 09:13:16 +01:00
return Response(text=dumps({'response': text}))
2019-12-02 10:29:40 +01:00
async def api(request, risotto_context):
2019-11-29 09:13:16 +01:00
global tiramisu
if not tiramisu:
config = Config(get_messages(load_shortarg=True,
only_public=True)[1])
2019-11-29 16:38:33 +01:00
config.property.read_write()
2019-11-29 09:13:16 +01:00
tiramisu = config.option.dict(remotable='none')
2019-12-02 10:29:40 +01:00
return tiramisu
2019-11-28 14:50:53 +01:00
2019-12-02 10:29:40 +01:00
extra_routes = {'': {'function': api,
'version': 'v1'}}
2019-11-28 14:50:53 +01:00
2019-12-02 10:29:40 +01:00
async def get_app(loop):
2019-11-28 16:51:56 +01:00
""" build all routes
"""
2019-12-02 10:29:40 +01:00
global extra_routes
2019-12-07 16:21:20 +01:00
load_services()
2019-12-02 10:29:40 +01:00
app = Application(loop=loop)
2019-11-28 14:50:53 +01:00
routes = []
2019-12-02 10:29:40 +01:00
for version, messages in dispatcher.messages.items():
2019-11-28 14:50:53 +01:00
print()
print(_('======== Registered messages ========'))
2019-12-02 10:29:40 +01:00
for message in messages:
web_message = f'/api/{version}/{message}'
if dispatcher.messages[version][message]['public']:
print(f' - {web_message}')
2019-11-28 14:50:53 +01:00
else:
2019-12-02 10:29:40 +01:00
pattern = dispatcher.messages[version][message]['pattern']
print(f' - {web_message} (private {pattern})')
routes.append(post(web_message, handle))
print()
print(_('======== Registered extra routes ========'))
for path, extra in extra_routes.items():
version = extra['version']
path = f'/api/{version}{path}'
extra['path'] = path
extra_handler = type(path, (extra_route_handler,), extra)
routes.append(get(path, extra_handler))
print(f' - {path} (http_get)')
# routes.append(get(f'/api/{version}', api))
2019-11-28 14:50:53 +01:00
print()
2019-12-02 10:29:40 +01:00
del extra_routes
2019-11-28 14:50:53 +01:00
app.add_routes(routes)
2019-12-02 10:29:40 +01:00
await dispatcher.on_join()
return await loop.create_server(app.make_handler(), '*', HTTP_PORT)
2019-11-29 09:13:16 +01:00
tiramisu = None