Replaced by the /ws WebSocket channel. Deletes the SSE connection manager,
the vendored sse_starlette, and the unused /bitcoin/block-sub and
/system/hardware-info-sub streaming endpoints. Also removes the
test_block_sub_error.py regression test, which exclusively covered the
now-deleted handle_block_sub per-request generator (handle_block_sub_redis,
which broadcasts over /ws, is retained and unaffected).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Same #277 root cause in the block-subscription path: Bitcoin Core 28+
uses strict JSON-RPC 2.0, so an errored getblock/getbestblockhash reply
has no 'result' key. handle_block_sub and handle_block_sub_redis accessed
r['result'] unguarded, so a transient RPC error would raise
KeyError: 'result' and kill the block stream / block-update task.
Skip and log the block when the reply has no result instead of crashing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
get_event_loop() is deprecated on Python 3.11+ when there is no running
loop and is slated to change behaviour further.
- SSEManager.setup() ran at import time (app.api.utils) via
get_event_loop(); this only worked because uvicorn imports the app
inside its loop and would break when imported without a running loop
(e.g. a Celery worker). Start the broadcast consumer lazily from
within a running loop instead.
- everywhere else the pattern was get_event_loop().create_task(x)
inside a coroutine; replace with asyncio.create_task(x).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
If the environment variable BAPI_ENV_PATH is set, the config system will
try to read configs from the given path instead of .env in pwd
If no file is found .env in pwd will be used as a fallback
Env variables will always override settings in .env files.