From 8aa01c9c8e5b69e89c84423da826e328346b7fa5 Mon Sep 17 00:00:00 2001 From: Sarah Hoffmann Date: Fri, 2 Dec 2022 17:28:46 +0100 Subject: [PATCH] add support for falcon as server framework --- nominatim/cli.py | 21 ++++++---- nominatim/server/falcon/__init__.py | 0 nominatim/server/falcon/server.py | 62 +++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 8 deletions(-) create mode 100644 nominatim/server/falcon/__init__.py create mode 100644 nominatim/server/falcon/server.py diff --git a/nominatim/cli.py b/nominatim/cli.py index c134ca18..34abb617 100644 --- a/nominatim/cli.py +++ b/nominatim/cli.py @@ -221,11 +221,7 @@ class AdminServe: def run(self, args: NominatimArgs) -> int: if args.engine == 'php': run_php_server(args.server, args.project_dir / 'website') - elif args.engine == 'sanic': - import nominatim.server.sanic.server - - app = nominatim.server.sanic.server.get_application(args.project_dir) - + else: server_info = args.server.split(':', 1) host = server_info[0] if len(server_info) > 1: @@ -234,9 +230,18 @@ class AdminServe: port = int(server_info[1]) else: port = 8088 - app.run(host=host, port=port, debug=True) - elif args.engine == 'falcon': - raise NotImplementedError('Support for falcon not yet available.') + + if args.engine == 'sanic': + import nominatim.server.sanic.server + + app = nominatim.server.sanic.server.get_application(args.project_dir) + app.run(host=host, port=port, debug=True) + elif args.engine == 'falcon': + import uvicorn + import nominatim.server.falcon.server + + app = nominatim.server.falcon.server.get_application(args.project_dir) + uvicorn.run(app, host=host, port=port) return 0 diff --git a/nominatim/server/falcon/__init__.py b/nominatim/server/falcon/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/nominatim/server/falcon/server.py b/nominatim/server/falcon/server.py new file mode 100644 index 00000000..a1ae9c6d --- /dev/null +++ b/nominatim/server/falcon/server.py @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# This file is part of Nominatim. (https://nominatim.org) +# +# Copyright (C) 2022 by the Nominatim developer community. +# For a full list of authors see the git log. +""" +Server implementation using the falcon webserver framework. +""" +from pathlib import Path + +import falcon.asgi + +from nominatim.api import NominatimAPIAsync +from nominatim.apicmd.status import StatusResult +import nominatim.result_formatter.v1 as formatting + +CONTENT_TYPE = { + 'text': falcon.MEDIA_TEXT, + 'xml': falcon.MEDIA_XML +} + +class NominatimV1: + + def __init__(self, project_dir: Path): + self.api = NominatimAPIAsync(project_dir) + self.formatters = {} + + for rtype in (StatusResult, ): + self.formatters[rtype] = formatting.create(rtype) + + def parse_format(self, req, rtype, default): + req.context.format = req.get_param('format', default=default) + req.context.formatter = self.formatters[rtype] + + if not req.context.formatter.supports_format(req.context.format): + raise falcon.HTTPBadRequest( + description="Parameter 'format' must be one of: " + + ', '.join(req.context.formatter.list_formats())) + + + def format_response(self, req, resp, result): + resp.text = req.context.formatter.format(result, req.context.format) + resp.content_type = CONTENT_TYPE.get(req.context.format, falcon.MEDIA_JSON) + + + async def on_get_status(self, req, resp): + self.parse_format(req, StatusResult, 'text') + + result = await self.api.status() + + self.format_response(req, resp, result) + + +def get_application(project_dir: Path) -> falcon.asgi.App: + app = falcon.asgi.App() + + api = NominatimV1(project_dir) + + app.add_route('/status', api, suffix='status') + + return app