webstation-broker
DeveloperPython reference

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() -> None

Refuse 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: When BROKER_SECRET is unset and dev mode is not explicitly enabled.

Returns

None
func_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_appFastAPI

The 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

dict

The header names and values to set; empty of frame-ancestors when

funccreate_app() -> FastAPI

Build 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; see enforce_auth_config.

Returns

fastapi.FastAPI

The application to serve: a bare root app with the broker mounted at