Ejemplo n.º 1
0
def dataset_not_found(handler: RequestHandler, name: str):
    handler.clear()
    handler.set_status(404)
    handler.write({
        'message': f'Cannot find dataset {repr(name)}!'
    })
async def perform_search(handler: RequestHandler,
                         search_path: str,
                         method: str,
                         dataset_search: bool = False):
    # TODO: Implement federated GET search

    request = get_request_json(handler.request.body)

    if request is None or (dataset_search
                           and "data_type_queries" not in request
                           or "join_query" not in request):
        print(
            f"[{SERVICE_NAME} {datetime.now()}] Request error: Invalid request {request}",
            flush=True,
            file=sys.stderr)
        handler.set_status(400)
        await handler.finish(
            bad_request_error(
                "Invalid request format (missing body or data_type_queries or join_query)"
                if dataset_search else "Invalid request format (missing body)")
        )
        return

    try:
        if dataset_search:
            # Check for query errors if we know that this request should be of a specific
            # (dataset search) format.

            # Try compiling join query to make sure it works (if it's not null, i.e. unspecified)
            if request["join_query"] is not None:
                convert_query_to_ast_and_preprocess(request["join_query"])

            for q in request["data_type_queries"].values():
                # Try compiling each query to make sure it works
                convert_query_to_ast_and_preprocess(q)

        auth_header = get_auth_header(handler.request.headers)

        # noinspection PyUnresolvedReferences
        peer_queue = iterable_to_queue(await handler.peer_manager.get_peers())
        responses = []
        workers = tornado.gen.multi([
            _search_worker(peer_queue, search_path, handler.request.body,
                           method, auth_header, responses)
            for _ in range(WORKERS)
        ])
        await peer_queue.join()

        try:
            await handler.finish({
                "results": {
                    n: r["results"] if r is not None else None
                    for n, r in responses
                }
            })

        except KeyError as e:
            print(f"[{SERVICE_NAME} {datetime.now()}] Key error: {str(e)}",
                  flush=True,
                  file=sys.stderr)
            handler.clear()
            handler.set_status(400)
            await handler.finish(bad_request_error()
                                 )  # TODO: What message to send?

        # Trigger exit for all workers
        for _ in range(WORKERS):
            peer_queue.put_nowait(None)

        # Wait for workers to exit
        await workers

    except (TypeError, ValueError,
            SyntaxError) as e:  # errors from query processing
        print(
            f"[{SERVICE_NAME} {datetime.now()}] TypeError / ValueError / SyntaxError: {str(e)}",
            flush=True,
            file=sys.stderr)
        handler.set_status(400)
        await handler.finish(
            bad_request_error(f"Query processing error: {str(e)}")
        )  # TODO: Better message