Skip to content

Desktop: gateway cloud endpoints - #4597

Merged
jeff-hykin merged 369 commits into
mainfrom
jeff/feat/gateway_cloud
Nov 10, 2026
Merged

jeff-hykin merged 369 commits into
mainfrom
jeff/feat/gateway_cloud

Conversation

@jeff-hykin

Copy link
Copy Markdown
Member

The gateway's Dimensional cloud endpoints: /cloud/account, /cloud/login and the /cloud/uploads queue.

…rames folded, the project's frames opening in the editor, the raised exceptions in red at its end), fields as chips, and stay pinned to the bottom until scrolled up
…os/), and the probe/port-wait typed for mypy
…t:/socket:, drop the stale Rust server notes, gateway docs curl the unix socket
…m one DIMOS_GATEWAY variable

provides: is generated from the routes (python -m dimos.gateway --write-provides) with a staleness test; openapi.json, api:, the served /dimos/openapi.json and --port are gone.
…C methods (signature, docstring), POST /dimos/rpc/call calls one; start/stop and the coordinator's wiring refused, declared in provides:
…odule RPC methods (signature, docstring), POST /dimos/rpc/call calls one; start/stop and the coordinator's wiring refused, declared in provides:"

This reverts commit 68f3174.
…t it from one DIMOS_GATEWAY variable"

This reverts commit 5eb19e2.
… the alignment test doesn't depend on two subscriptions decoding in step
…ut last on its command line (after Desktop's defaults and the overrides, so they win), checked first by POST /dimos/blueprints/{name}/args with dimos's own parser; kept for restart, secret-named values shown as ••• (API 1.17.0)
…ver started it (other DIMOS_HOMEs' registries, unregistered `dimos run` processes; registry, owner, command, ours, stoppable, whyNot), and seenOnBus for runs only heard on the bus; POST /dimos/runs/stop and the log route take those runs too; a registry entry with a reused pid is left out (API 1.18.0)
… new blueprints (go2-sim, unitree-go2-joystick-record, xarm-sim), messages and rerun_save
…ree TCP port is taken on UDP (QUIC shares it), instead of failing; this was server_test's 'Address already in use' flake
…mes, so a slow runner still aligns >=2 pairs
…a busy machine running behind) no longer has its successor disposed by the late SerialDisposable assignment, which stalled the replay for good (test_timestamp_alignment's macOS hang); the test shares one playback between both sides and keeps a buffer longer than the processor's latency
…y 90 frames, so a slow runner still aligns >=2 pairs"

This reverts commit 1149625.
…time, so the alignment test doesn't depend on two subscriptions decoding in step"

This reverts commit 40dadcc.
…ver emits, so a stalled CI thread can't race it"

This reverts commit 66a56d5.
…eturns (a busy machine running behind) no longer has its successor disposed by the late SerialDisposable assignment, which stalled the replay for good (test_timestamp_alignment's macOS hang); the test shares one playback between both sides and keeps a buffer longer than the processor's latency"

This reverts commit 649b1c2.
…e OS's free TCP port is taken on UDP (QUIC shares it), instead of failing; this was server_test's 'Address already in use' flake"

This reverts commit 75135be.
…his PR (recordings are main's again until jeff/feat/one_recordings_dir lands); one-line docstrings
…enohNamespace, zenohConnect), else <home>/config.yaml; DIMOS_HOME is not read. GET /history/recordings: the configured dir, else the served checkout's standard one
…PP, else config.yaml; tests: the new ones are gone, the existing config test also checks DIMOS_APP wins
# Conflicts:
#	experimental/gateway/annotations.yaml
…ass-through is gone); a relative recordings.dir is under the served checkout, where launches run
…ery caller uses that (Desktop restarts the gateway when they change)
… still launchable (known_names uses the scan's registry names, not error text)
… name is refused before anything spawns, and known names come only from a fresh scan
…dge the gateway

`api_key()` read the OS keyring with no timeout. On Linux that is SecretService over
D-Bus, and a *locked* collection answers an ordinary read with an unlock prompt and then
waits for whoever is at the screen. In a service nobody is, so the read never returns.

py-spy on a wedged gateway found 14 threads parked in `exec_prompt`: every poll of
GET /cloud/account took another thread from the pool, and the upload worker was in the
same place, which is why an upload sat at "preparing" with 0 bytes done, never opened the
file it was sending, and ignored a cancel.

Each keyring call now runs on a thread we are willing to abandon, bounded by the new
`CloudConfig.keyring_timeout` (5 s, DIMOS_CLOUD_KEYRING_TIMEOUT). A keyring that misses
its deadline reads as no keyring at all and falls through to the 0600 credentials file
that headless machines already use, saying so in the log. The backend is probed once and
the stall remembered for a minute rather than paid per lookup, and re-probed after that so
a login stored later is still found.
…an't be read

Two things that turned one stalled keyring read into a dead page and an upload nobody
could get rid of. The keyring itself is bounded now, but nothing here should depend on
that: a blocking call in a worker thread is always able to outlive the request that
started it.

GET /cloud/account shares one in-flight lookup between every caller instead of putting
each poll on its own pool thread, and gives up after ACCOUNT_TIMEOUT_S with a logged-out
answer that says why. Late is a nuisance; never is a page that shows nothing forever.

A cancel is now something the event loop can see as well as the worker: the transfer gets
UPLOAD_CANCEL_GRACE_S to notice the flag and unwind — long enough that one waiting on the
cloud's last answer still reports the upload id it was given — and is then left to finish
into nothing. Before, the flag was only read inside tick(), so a transfer blocked before
its first byte never looked at it and DELETE returned 200 and changed nothing.
dim-controller writes ros2-profile mcaps, where its h264 cameras are lcm-encoded on a
channel with no schema (LCM has no ros2msg schema to give) and a plain topic name like
/front_camera that describes nothing. It does say what it put there — channel metadata
`lcm_type: foxglove_msgs.CompressedVideo` — and we were not reading it, so every frame of
every M20 recording came back as raw bytes and the console preview had no camera at all.
Two reasons a recording from an M20 got no preview.

Its cameras record foxglove CompressedVideo (h264), not single jpeg frames, and the
preview only ever looked for a stream of Image. h264 is inter-frame, so packets become
pictures only by running the ordered stream through one decoder: `_camera()` does that
and hands back both halves, because counts and timestamps have to come from the packets —
asking a decoded stream how long it is decodes the whole recording to find out. The
timelapse matches frames to their slots by timestamp rather than position for the same
reason: a decoder drops the P-frames before the first keyframe, so the two don't line up.
H264Decoder takes its codec from the packets' own `format` now, so h265 or vp9 work too,
and a camera whose packets never decode leaves no half-written mp4 behind.

And the preview copy was named preview.db whatever the recording was called, while
open_store dispatches on the extension — so an .mcap was handed to SqliteStore and died
before any of the above could matter.

Checked against the 3 GB M20 recording this started from: 23 thumbnails, a 60 s timelapse
at 4.7x, 298 KB of preview JSON. Its lidar and odometry are ros2 cdr and still undecoded,
so that preview has a camera but no map or path yet.
The console-preview fixes (h264 cameras, opening an .mcap at all) landed here by accident of where
they were written. They are not about the cloud endpoints and they do not belong in this PR; they
continue on their own branch.
Comment thread experimental/gateway/uploads.py Resolved
Comment thread experimental/gateway/uploads.py Resolved
Comment thread experimental/gateway/uploads.py Resolved
Comment thread experimental/gateway/uploads.py Resolved
…raw dicts, whoami through requests, the console link from urlsplit, and a NotLoggedInError in place of catching any PermissionError

This branch was successfully deployed

No deployments
cachix — 6d231cbc Deployed Nov 10, 2026 by jeff-hykin via cachix-build-macos #16757
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-merge Required CI checks have passed on this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants