Ctrl K
ComunidadGuías…

asgi.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
"""ASGI entry point — the target for any server that must serve /peer_link.

WHY THIS EXISTS
    `/peer_link` is a WebSocket. A server handed the plain WSGI `app`
    (`hart_intelligence_entry:app`) can never serve it, because WSGI has no
    websocket scope. That is how the waitress systemd unit and the
    gunicorn/gevent cloud image both ended up with PeerLink.accept() never
    firing and PeerLinkManager._links permanently empty.

    Pointing those servers here instead gives them the same ASGI stack that
    `_serve_app` builds -- `peer_link_asgi(AsyncioWSGIMiddleware(app))` via the
    one canonical `core.serve.build_asgi_app` -- WITHOUT running `main()`.
    That distinction is the point: `main()` also does boot integrity
    verification, guardrail hash enforcement (which can refuse to boot),
    EventBus bootstrap, Crossbar subscribers, the skill registry and the agent
    daemon supervisor. Those belong to the full-node launcher, not to "serve
    HTTP + websockets", and turning them on is a separate decision.

HOW TO USE IT
    hypercorn:  hypercorn asgi:application --bind 0.0.0.0:6777
    uvicorn:    uvicorn asgi:application --host 0.0.0.0 --port 6777
    gunicorn:   gunicorn -k uvicorn.workers.UvicornWorker asgi:application

    Do NOT point a pure-WSGI server (waitress, gunicorn's default sync or
    plain-gevent workers) at `hart_intelligence_entry:app` if the node is
    expected to accept peers -- it will serve HTTP correctly and drop every
    websocket, logging nothing.

WHY IMPORTING THIS IS ALLOWED TO FAIL
    `build_asgi_app` imports hypercorn's middleware. If that is missing, this
    module raises at import and the server refuses to start. That is
    deliberate: the alternative is `_serve_app`'s ImportError fallback to
    Waitress, which starts fine and silently has no `/peer_link`. A server that
    will not boot is a better failure than a peer that is invisible to the hive.
    See core/peer_link/server.py and the requirements.txt note on hypercorn's
    subtree (the root Dockerfile installs with --no-deps).

EXECUTOR NOTE
    `_serve_app` installs a ThreadPoolExecutor sized by HEVOLVE_WORKER_THREADS
    (default 256) as the loop's default executor; the bare server CLIs do not,
    so sync Flask handlers run on asyncio's default executor
    (min(32, cpu_count + 4)). For a regional/central node that is a different
    concurrency profile from waitress's threads=50, not a strictly smaller one.
    If a deployment needs the larger pool, launch through
    `python hart_intelligence_entry.py` instead, which runs `_serve_app`.
"""
from core.serve import build_asgi_app

# TID251 bans importing hart_intelligence_entry so that WORKER code cannot
# reach around the singleton accessor (core.safe_hartos_attr.safe_hartos_attr).
# This module is not worker code: it is the server target, and its whole job is
# to hand one specific Flask app to a server. gunicorn already does exactly
# this as `hart_intelligence_entry:app` -- ruff never saw that because it is a
# config string, not an import. safe_hartos_attr is the wrong tool here: it
# tolerates the module being absent, whereas a server pointed at this file must
# either get the real routed app or fail to start.
from hart_intelligence_entry import app  # noqa: TID251

# The name servers target. Built once at import, against a fully-routed app:
# every register_blueprint()/init_social() call in hart_intelligence_entry runs
# at module level (lines ~1016-1177), well before this import completes, which
# is the same reason `hart_intelligence_entry:app` works for gunicorn today.
application = build_asgi_app(app)

# Alias — uvicorn/gunicorn examples in the wild use either name.
asgi_app = application

__all__ = ['application', 'asgi_app']