Source code for genro_asgi.server.handler_executor

# Copyright 2025 Softwell S.r.l.
# Licensed under the Apache License, Version 2.0

"""HandlerExecutor — ASGI app that executes a pre-resolved router node.

Used as innermost app in per-app middleware chains. The Dispatcher sets
scope["_handler_node"] before invoking the per-app chain.
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Any

from genro_routes import is_result_wrapper
from genro_toolbox.smartasync import smartasync

if TYPE_CHECKING:
    from .server import AsgiServer
    from ..types import Receive, Scope, Send

__all__ = ["HandlerExecutor"]


[docs] class HandlerExecutor: """ASGI app that executes a pre-resolved router node. Expects scope["_handler_node"] set by Dispatcher before invocation. Retrieves the current request from server.request_registry. """ __slots__ = ("server",)
[docs] def __init__(self, server: AsgiServer) -> None: """Args: server: Parent AsgiServer instance (provides request_registry). """ self.server = server
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: """Execute pre-resolved handler node and send ASGI response. Args: scope: ASGI scope with "_handler_node" set by Dispatcher. receive: ASGI receive callable. send: ASGI send callable. """ node = scope["_handler_node"] request = self.server.request_registry.current assert request is not None result = await smartasync(node)(**dict(request.query)) if is_result_wrapper(result): metadata: dict[str, Any] = {**node.metadata, **result.metadata} request.response.set_result(result.value, metadata) else: request.response.set_result(result, node.metadata) await request.response(scope, receive, send)
if __name__ == "__main__": pass