app
FastAPI application factory.
FastAPI application factory.
The app is mounted under settings.PREFIX (default /streaming) so the same
paths work behind nginx, a reverse proxy, or uvicorn directly. Outside dev
mode the built frontend is served as static files at the prefix root; in dev
mode vite serves the frontend instead.
attributelog= logging.getLogger(__name__)attributeROOM_CSP= '; '.join(("default-src 'self'", "script-src 'self' blob:", "worker-src 'self' blob:", "connect-src 'self'", "img-src 'self' data: blob:", "media-src 'self' blob:", "font-src 'self' data:", "style-src 'self'", "style-src-attr 'unsafe-inline'", "frame-src 'self'", "object-src 'none'", "base-uri 'self'", "form-action 'self'"))The room page's Content-Security-Policy, minus frame-ancestors (see _page_csp_headers).
funcenforce_auth_config() -> NoneRefuse to build an app that would serve every endpoint unauthenticated.
Enforced here rather than in the console-script wrapper alone, because
uvicorn and gunicorn are routinely pointed straight at create_app and
would otherwise skip the gate entirely.
Raises
SystemExit: WhenBROKER_SECRETis unset and dev mode is not explicitly enabled.
Returns
Nonefunc_lifespan(_app) -> AsyncIterator[None]Reap an emulator orphaned by a previous broker process before serving.
A fresh broker holds no session, so an emulator recorded by the process that came before is playing to nobody. Killing it here rather than at the next activate is what keeps it killable at all: exit answers 409 without a session, so otherwise the only way out is launching another game.
Also sweeps the shadPS4, RPCS3, ScummVM and PPSSPP extraction scratch dirs left behind by a crashed broker process, before any new extraction can be in flight.
Trims the ROM cache, when it is enabled, to the limits now in force and drops a copy a crashed broker left half written.
Loads the RetroArch core catalog: the bundled one merged with a cache from
a previous refresh, so a cache another process wrote is used right away.
When RETROARCH_CORE_INFO_REFRESH is on, a background task then keeps that
cache current; startup itself never waits on the network for it.
Starts the emulator watch, which logs an ERROR when a session's emulator
exits on its own, unless EMULATOR_WATCH_INTERVAL is 0.
Yields
AsyncIterator[None]: Nothing; control passes to the running application once the orphan is reaped.
param_appFastAPIThe application being started; unused.
Returns
collections.abc.AsyncIterator[None]func_page_csp_headers() -> dict[str, str]Build the CSP headers for an HTML page.
frame-ancestors is always enforced when configured: browsers ignore it
in a report-only policy, so it cannot wait for BROKER_CSP_ENFORCE.
Returns
dictThe header names and values to set; empty of frame-ancestors when
funccreate_app() -> FastAPIBuild the broker application, mounted under the configured prefix.
The lifespan belongs to whichever app is actually served. Starlette never hands the lifespan scope to a mounted sub-app, so a startup hook on the inner app would silently never run behind a prefix.
Raises
SystemExit: When the broker would come up with no authentication at all; seeenforce_auth_config.
Returns
fastapi.FastAPIThe application to serve: a bare root app with the broker mounted at