Tauri + Rust core spike (issue #360)#361
Open
etiennechabert wants to merge 7 commits into
Open
Conversation
Boots the existing React renderer verbatim on a Tauri/Rust backend that serves the analytical views from the fixture Parquet via the native duckdb crate. Additive — the Electron app and TS core are untouched. - packages/tauri-shell: Vite frontend (bridge.ts installs window.costgoblin backed by Tauri invoke, replacing only the Electron preload seam) + Rust backend (CostApi read path ported from core's query builders, run over the fixtures with the duckdb crate; AWS/sync/sharing/update/MCP stubbed) - specs/rust-tauri-migration.md: decision + phased migration plan - bump version to 0.3.2 (first PR of the cycle past tag v0.3.1)
… threading fix Extends the spike (issue #360) from the read-only core to full fidelity, validated on a real CUR dataset (18 months, 138 org accounts): - query.rs/config.rs/commands.rs: org-account join (resource->account tag fallback, account names via accountNameFromTag, account-only/OU-path dims), cost-metric selection (unblended/list/amortized) + cost-scope exclusion rules -> numbers match Electron - aws_org.rs: real read-only AWS Organizations sync (aws-sdk-organizations + aws-config SSO/profile) - query_savings: cost-optimization recommendations from local Parquet - querylog.rs: Debug panel query log (recorded in db::query_map) - list_aws_profiles: real ~/.aws read - all commands are #[tauri::command(async)] so DuckDB/AWS work runs off the main thread (fixes UI freeze; sync Tauri commands run on the main thread) - vite: strip crossorigin so the release bundle renders under tauri://localhost - docs: README + migration spec updated (scope, threading, footprint ~6x smaller bundle)
- mcp.rs: token-authed JSON-RPC MCP server (tiny_http, loopback) over the query layer — get_cost_overview / query_costs / list_dimensions / get_filter_values; HTTP-level test (mcp_server_responds). - Persist UI / explorer / savings preferences; Open/Reveal folder via OS opener. - bridge.ts routes the MCP + prefs + folder methods to real invokes. - Docs: README + migration spec mark MCP + prefs as real.
- config_write.rs: ports the core *ConfigToYaml transformers (dimensions / views / cost-scope) onto serde_json Values so saved YAML round-trips with the same stable, undefined-omitting shape; serde_json preserve_order keeps key order. saveDimensionsConfig / saveViewsConfig / saveCostScope + the surgical updateAwsProfile are now real writes (3 unit tests). - aws_ssm.rs: real read-only SSM region-name enrichment (GetParametersByPath + batched GetParameters), profile-region resolution from ~/.aws/config, cached to region-names.json. org sync now piggybacks it (matches Electron); adds syncRegionNames / getRegionNamesInfo / clearOrgData. - Cargo: serde_json preserve_order, aws-sdk-s3, aws-sdk-ssm, sha2, chrono, tauri-plugin-dialog (S3/sharing land next).
- sync.rs: faithful port of the desktop sync — bulk download shells out to the
'aws s3 sync' CLI (reuses SSO, multipart, incremental skips; files land
directly in aws/raw/{tier}-{period}/, no repartitioning). cost-optimization
tier mirrors the per-date staging + usage_date=* copy. etag files persisted
({period:{key:hash}}). Cancellable via a per-syncId flag that kills the child.
- Remote inventory via aws-sdk-s3 ListObjectsV2 (period grouping + local-status
diff vs saved etags), with a local-only fallback when offline / no SSO.
- Progress flows through a shared per-syncId status map polled by getSyncStatus
(mirrors Electron's state.syncStatuses + sync:status).
- Commands: sync_periods / cancel_sync / delete_local_period / get_sync_status /
sso_login; get_data_inventory now does the real remote listing. Bridge wired.
- 3 unit tests (period/prefix/date extraction, completed-bytes, s3 path).
- bundle.rs: ports the core bundle transformers + SHA-256 fingerprint. Builds the same canonical sections YAML-object form (reusing the *_to_yaml transformers) and hashes its compact JSON, so serde_json preserve_order yields fingerprints that match JS JSON.stringify — round-tripped bundles re-import as fingerprintValid. parse_bundle validates kind/schemaVersion structurally; summarize + materialize (with credential re-injection). 2 unit tests. - sharing.rs: S3 get/put of the bundle object (aws-sdk-s3), pre-import backup to config/backups/<ts>/, s3 location parsing + beacon-absence classification. - Commands: export / preview (native dialogs via tauri-plugin-dialog) / fetch / apply / publish / check-beacon. Bridge wired to real invokes.
- Auto-updater command surface (check_for_updates / download_update / quit_and_install) + a real bridge state machine with a working onStatusChanged subscription, so the ReleaseNotesModal works end-to-end. A check honestly reports 'idle': finding an update needs a Tauri-format signed release feed (the GitHub releases are electron-builder format) — the one genuine blocker, documented in the spec. - README + migration spec: all Phase 3/4 desktop-main features now marked ported (config writes, SSM, S3 sync, config sharing, prefs, MCP); honest caveats for the auto-updater feed blocker, SSO/CLI requirements, and wizard-only stubs. - 11 Rust tests pass (8 unit + full-fidelity + MCP HTTP smoke).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #360 — a Tauri + Rust spike that runs the existing React renderer verbatim on a Rust backend. Additive: the Electron app and the TS
coreare untouched. Decision + phased plan:specs/rust-tauri-migration.md; package details:packages/tauri-shell/README.md.It started as the read-only core and — driven against a real CUR dataset (18 months, 138 org accounts) — grew to cover most of migration Phases 1–3.
What's real
cost-scope.yaml(unblended/list/amortized), cost-scope exclusion rules, and the org-account join (resource→account tag fallback, account display names viaaccountNameFromTag, account-only/OU-path dims).aws-sdk-organizations+aws-config(SSO/profile) — validates the issue's "AWS SDK for Rust is mature" claim end-to-end (read-only).~/.aws), data inventory, tag/column discovery, filter values, and a live Debug query log.How the seam works
The UI reads
window.costgoblin(installed by Electron's preload). The spike swaps only that seam:src/bridge.tsinstalls the same globals backed by Tauriinvoke;src/main.tsxrenders the realApp(no fork). Rust backend insrc-tauri/src(commands.rs,query.rs,config.rs,aws_org.rs,querylog.rs,db.rs).Notable findings
#[tauri::command(async)](off-main-thread, concurrent). No result cache / materialized base yet, so repeat queries are slower than Electron but never block (Phase-2 work).tauri buildbundle renders; Vite'scrossoriginattribute is stripped so embedded assets load undertauri://localhost..app~70 MB vs 409 MB (~6×); download ~22–30 MB vs 158 MB; runtime RSS ~2.6 GB vs ~3.3 GB (both DuckDB-dominated — the "much lower idle memory" claim is overstated for real workloads; the clear win is bundle/distribution size).Still stubbed (Phase 3/4)
S3 CUR download sync, SSM region names, config-sharing, auto-updater, MCP server, and
save*writes.Run it
First build compiles bundled DuckDB + AWS SDK from source (~several min). Point at real data via
COSTGOBLIN_DATA_DIR/COSTGOBLIN_CONFIG_DIR.Notes
0.3.2; the new package has nobuildscript so release/CI's--workspaces --if-presentskips it. Not wired into CI.npm run checkpasses (607 tests). Reversible — behind the existingCostApiboundary.