bacommontools package

Tools functionality shared by all Ballistica components.

Submodules

bacommontools.bacloud module

A tool for interacting with ballistica’s cloud services. This facilitates workflows such as creating asset-packages, etc.

class bacommontools.bacloud.App[source]

Bases: object

Context for a run of the tool.

run() int[source]

Run the tool.

run_interactive_command(cwd: str, args: list[str]) None[source]

Run a single user command to completion.

class bacommontools.bacloud.StateData(login_token: str | None = None)[source]

Bases: object

Persistent state data stored to disk.

login_token: str | None = None
bacommontools.bacloud.get_tz_offset_seconds() float[source]

Return the offset between utc and local time in seconds.

bacommontools.bacloud.run_bacloud_main() None[source]

Do the thing.

bacommontools.pcommands module

Pcommands for bacommontools.

bacommontools.pcommands.bacurl() None[source]

Run curl with the Ballistica API key injected.

Usage: bacurl [curl-args…] <url>

Reads ballistica_api_key from pconfig/localconfig.json and passes it as a Bearer token in the Authorization header. All arguments are forwarded to curl. The -s (silent) flag is added automatically.

Examples:

bacurl https://dev.ballistica.net/api/v1/admin/stats/catalog
bacurl -X POST -H 'Content-Type: application/json' \
    -d '{"dry_run":true}' \
    https://dev.ballistica.net/api/v1/admin/stats/flush
bacommontools.pcommands.require_ballistica_api_key() None[source]

Verify a Ballistica API key is available; error if not.

bacommontools.streamws module

WebSocket-based stream consumer for bacloud (Phase 2).

A stream-mode bacloud kickoff lands at a basn node, which injects a StreamWS into the response pointing at its own /streamcall/<call_id> WebSocket endpoint. We open that WS, print StreamOutput frames live as they arrive, and return the terminal StreamFinal so the caller can splice it back into bacloud’s existing response-handling flow.

On a non-terminal close (network blip, abnormal close, expired token) we reconnect — refreshing the token via POST /streamcall/<call_id>/refresh-token first if the close code says the token is expired (4001). Reconnects use exponential backoff up to a configurable wall-clock budget (default 60s, override via BACLOUD_RECONNECT_BUDGET_SECONDS); past the budget we surface CleanError. Token-bad / call-id-mismatch / no-token closes (4002/4003/4004) are fatal — no retry.

v0 reconnect doesn’t ask basn to replay the cursor: a reconnecting client may miss frames that landed during the disconnect window. In practice the stream still completes (the basn-side subscription keeps polling regardless of WS attachments), and bacloud renders the terminal StreamFinal correctly. Cursor-aware resume is Phase 3 territory.

Test-only env vars:

  • BACLOUD_TEST_FORCE_DROP_AFTER_SECONDS=N — force the WS closed N seconds after open; the reconnect path then runs as it would on a real drop.

  • BACLOUD_TEST_BREAK_RECONNECT=1 — point the reconnect URL at a guaranteed-unreachable host (127.0.0.1:1); reconnects fail until the budget expires.

bacommontools.streamws.consume_via_ws(response: ResponseData, *, bearer: str | None, host: str) ResponseData[source]

Drain a stream over WebSocket and return a terminal-only response.

The returned ResponseData carries the terminal StreamFinal in stream_frames so bacloud’s existing stream_frames loop falls through to the usual terminal handling (message/error/end_command).

host is the bacloud client’s resolved kickoff hostname (the basn the kickoff went to); used to construct the WS URL when the producer didn’t pin one.

Caller must check response.stream_ws is not None first. Raises CleanError on unrecoverable WS failure (token-bad, reconnect-budget exhausted, etc.).