"""
Server implementation using the falcon webserver framework.
"""
-from typing import Type, Any
+from typing import Type, Any, Optional, Mapping
from pathlib import Path
import falcon
""" Implementation of V1 version of the Nominatim API.
"""
- def __init__(self, project_dir: Path) -> None:
- self.api = NominatimAPIAsync(project_dir)
+ def __init__(self, project_dir: Path, environ: Optional[Mapping[str, str]]) -> None:
+ self.api = NominatimAPIAsync(project_dir, environ)
self.formatters = {}
for rtype in (StatusResult, ):
self.format_response(req, resp, result)
-def get_application(project_dir: Path) -> falcon.asgi.App:
+def get_application(project_dir: Path,
+ environ: Optional[Mapping[str, str]] = None) -> falcon.asgi.App:
""" Create a Nominatim falcon ASGI application.
"""
app = falcon.asgi.App()
- api = NominatimV1(project_dir)
+ api = NominatimV1(project_dir, environ)
app.add_route('/status', api, suffix='status')
"""
Server implementation using the sanic webserver framework.
"""
-from typing import Any, Optional
+from typing import Any, Optional, Mapping
from pathlib import Path
import sanic
return api_response(request,await request.app.ctx.api.status())
-def get_application(project_dir: Path) -> sanic.Sanic:
+def get_application(project_dir: Path,
+ environ: Optional[Mapping[str, str]] = None) -> sanic.Sanic:
""" Create a Nominatim sanic ASGI application.
"""
app = sanic.Sanic("NominatimInstance")
- app.ctx.api = NominatimAPIAsync(project_dir)
+ app.ctx.api = NominatimAPIAsync(project_dir, environ)
app.ctx.formatters = {}
for rtype in (StatusResult, ):
app.ctx.formatters[rtype] = formatting.create(rtype)
"""
Server implementation using the starlette webserver framework.
"""
-from typing import Any, Type
+from typing import Any, Type, Optional, Mapping
from pathlib import Path
from starlette.applications import Starlette
Route('/status', endpoint=on_status)
]
-def get_application(project_dir: Path) -> Starlette:
+def get_application(project_dir: Path,
+ environ: Optional[Mapping[str, str]] = None) -> Starlette:
""" Create a Nominatim falcon ASGI application.
"""
app = Starlette(debug=True, routes=V1_ROUTES)
- app.state.API = NominatimAPIAsync(project_dir)
+ app.state.API = NominatimAPIAsync(project_dir, environ)
return app
'SERVER_MODULE_PATH' : None,
'TOKENIZER' : None, # Test with a custom tokenizer
'STYLE' : 'extratags',
+ 'API_ENGINE': 'php',
'PHPCOV' : False, # set to output directory to enable code coverage
}
# Copyright (C) 2022 by the Nominatim developer community.
# For a full list of authors see the git log.
from pathlib import Path
+import importlib
import sys
import tempfile
+from asgi_lifespan import LifespanManager
+import httpx
+
import psycopg2
import psycopg2.extras
self.api_db_done = False
self.website_dir = None
+ self.api_engine = None
+ if config['API_ENGINE'] != 'php':
+ if not hasattr(self, f"create_api_request_func_{config['API_ENGINE']}"):
+ raise RuntimeError(f"Unknown API engine '{config['API_ENGINE']}'")
+ self.api_engine = getattr(self, f"create_api_request_func_{config['API_ENGINE']}")()
+
def connect_database(self, dbname):
""" Return a connection to the database with the given name.
Uses configured host, user and port.
WHERE class='place' and type='houses'
and osm_type='W'
and ST_GeometryType(geometry) = 'ST_LineString'""")
+
+
+ def create_api_request_func_starlette(self):
+ import nominatim.server.starlette.server
+
+ async def _request(endpoint, params, project_dir, environ):
+ app = nominatim.server.starlette.server.get_application(project_dir, environ)
+
+ async with LifespanManager(app):
+ async with httpx.AsyncClient(app=app, base_url="http://nominatim.test") as client:
+ response = await client.get(f"/{endpoint}", params=params)
+
+ return response.text, response.status_code
+
+ return _request
+
+
+ def create_api_request_func_sanic(self):
+ import nominatim.server.sanic.server
+
+ async def _request(endpoint, params, project_dir, environ):
+ app = nominatim.server.sanic.server.get_application(project_dir, environ)
+
+ _, response = await app.asgi_client.get(f"/{endpoint}", params=params)
+
+ return response.text, response.status_code
+
+ return _request
+
+
+ def create_api_request_func_falcon(self):
+ import nominatim.server.falcon.server
+ import falcon.testing
+
+ async def _request(endpoint, params, project_dir, environ):
+ app = nominatim.server.falcon.server.get_application(project_dir, environ)
+
+ async with falcon.testing.ASGIConductor(app) as conductor:
+ response = await conductor.get(f"/{endpoint}", params=params)
+
+ return response.text, response.status_code
+
+ return _request
+
+
+
Queries may either be run directly via PHP using the query script
or via the HTTP interface using php-cgi.
"""
+from pathlib import Path
import json
import os
import re
import logging
+import asyncio
from urllib.parse import urlencode
from utils import run_script
for h in context.table.headings:
params[h] = context.table[0][h]
+ if context.nominatim.api_engine is None:
+ return send_api_query_php(endpoint, params, context)
+
+ return asyncio.run(context.nominatim.api_engine(endpoint, params,
+ Path(context.nominatim.website_dir.name),
+ context.nominatim.test_env))
+
+
+
+def send_api_query_php(endpoint, params, context):
env = dict(BASE_SERVER_ENV)
env['QUERY_STRING'] = urlencode(params)