Skip to content

feat(cloud): push per-miner state alongside snapshots#11

Merged
proofofprints merged 1 commit into
mainfrom
claude/wire-push-miners
May 22, 2026
Merged

feat(cloud): push per-miner state alongside snapshots#11
proofofprints merged 1 commit into
mainfrom
claude/wire-push-miners

Conversation

@proofofprints
Copy link
Copy Markdown
Collaborator

Summary

Wire the existing client::push_miners into the cloud sync loop so the portal's miner_states table gets populated. Until now, the desktop pushed farm-rollup snapshots but never pushed per-miner state, so the web Dashboard's "Total Miners" tile always read 0 even when miners were online.

This is a Phase 2 vertical-slice: capture local miner data → stage on CloudState → push from sync loop → queue/drain on transient failure. Full Phase 2 scope (alert sync, command exec, etc.) is still pending — intentionally not in this PR.

What changed

  • src-tauri/src/cloud/mod.rs — Added latest_miners: Mutex<Option<serde_json::Value>> to CloudState, initialized to None. Direct mirror of the existing latest_snapshot field.
  • src-tauri/src/poller.rsbuild_and_persist_snapshot now also calls a new stage_miners_for_cloud(...) after persisting the rollup. That helper takes the same ASIC + mobile + PoPMiner inputs the rollup already uses, maps each into { minerType, minerId, label, coin, online, hashrate, state }, and writes the result to CloudState.latest_miners. The poller's snapshot_loop now takes PopMinerDevicesState (previously discarded as _popminer_state).
  • src-tauri/src/cloud/sync.rs — Added a second push step right after the snapshot push: take() from latest_miners, call push_miners, on transient failure enqueue with kind "miners", on 401/403 set AuthRequired. Extended the queue drain match to handle "miners" items.
  • src-tauri/src/cloud/queue.rs — Relaxed the CHECK constraint to include 'miners', plus a one-shot migration for existing installs (SQLite can't ALTER a CHECK, so we rebuild the table when the existing definition is missing 'miners').

Local capture path

The local data source was already there: poller::build_and_persist_snapshot collects asic (Vec<MinerInfo>) from cache.asic_miners, mobile_miners from mobile_state.miners, and now popminer_devices from popminer_state.saved. No new polling logic; we just serialize what the rollup already iterates over into the /ingest/miners shape.

Minor type mapping

  • ASIC → minerType: "asic", minerId: ip, label from saved miner or hostname, coin from saved miner.
  • Mobile → minerType: "mobile", minerId: device_id, hashrate stays in H/s (no conversion).
  • PoPMiner → minerType: "popminer", minerId: mac, coin omitted (no per-device coin on the ESP32 side yet).

The full miner record (model, firmware, temps, etc.) goes into the optional state field for portal display.

Build verification

cd src-tauri && cargo check passes cleanly (no new warnings; pre-existing dead-code warnings unchanged).

Test plan

  • Build locally (pnpm tauri dev or release build), log in, add at least one ASIC/mobile/PoPMiner miner.
  • Watch the desktop logs for Cloud: miners staged for sync (N entries) followed by Cloud sync: miner state pushed successfully on the next 60s cycle.
  • Verify the portal Dashboard's "Total Miners" tile reflects the actual count within one cycle (~60s).
  • Pull the network cable / block cloud-api.proofofprints.com briefly and confirm a miners row appears in the local queue (cloud_queue.db); restore connectivity and confirm the queue drains.

The desktop already aggregates ASIC, mobile, and PoPMiner state every 60s
to build the farm-rollup snapshot, but only the rollup was being pushed
to the cloud. The miner_states table on the portal stayed empty, so the
web Dashboard's "Total Miners" tile rendered 0 even when miners were
online.

Wire push_miners (already present in client.rs) into the sync loop:

- Add CloudState.latest_miners staging slot, mirroring latest_snapshot.
- Build the /ingest/miners payload at the end of build_and_persist_snapshot
  in poller.rs from the same ASIC + mobile + PoPMiner data the rollup uses.
  Map each source to the asic/mobile/popminer enum the server expects.
- Push latest_miners in sync.rs right after the snapshot push; on transient
  failure, enqueue with kind "miners". Extend the queue drain branch and
  the SQLite CHECK constraint (with a one-shot migration for existing
  installs) to handle the new kind.

Phase 2 vertical-slice only — alert sync, command exec, etc. remain TODO.
@proofofprints proofofprints merged commit 54cbe40 into main May 22, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant