refactor(core): Phase 2 — introduce in-process EventBus for metric snapshots (#1404)#1413
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
✅ Files skipped from review due to trivial changes (2)
📝 WalkthroughWalkthroughThis PR introduces an in-process Changes
Sequence Diagram(s)sequenceDiagram
participant Monitor as SystemMonitorController
participant Bus as EventBus
participant Adapter as WindowAdapter
participant Tauri as Tauri AppHandle
participant Frontend as Frontend Window
Monitor->>Monitor: collect metrics (CPU, memory, GPUs)
Monitor->>Monitor: build MetricsSnapshot
Monitor->>Bus: publish(snapshot)
Bus->>Adapter: broadcast snapshot to subscribers
Adapter->>Adapter: convert snapshot → HardwareMonitorUpdate
Adapter->>Tauri: emit("hardware-monitor-update", payload)
Tauri->>Frontend: deliver event to frontend
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Review rate limit: 3/5 reviews remaining, refill in 17 minutes and 8 seconds. Comment |
There was a problem hiding this comment.
Pull request overview
Introduces a Tauri-independent in-process EventBus in the new core/ crate and refactors the real-time monitoring pipeline so the collector publishes MetricsSnapshot to the bus, while a new Tauri-side WindowAdapter is solely responsible for translating snapshots into the existing HardwareMonitorUpdate event (wire format unchanged).
Changes:
- Added
hwviz_core::event_bus::EventBus(tokio broadcast) and Tauri-independent snapshot models (MetricsSnapshot,GpuMetric) incore/. - Refactored
SystemMonitorControllerto publish snapshots to the bus instead of emitting Tauri events directly. - Added
app::adapters::window::WindowAdapterto subscribe to the bus and emit the existingHardwareMonitorUpdate, and wired it into startup/shutdown viaWorkersState.
Reviewed changes
Copilot reviewed 11 out of 12 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src-tauri/src/workers/system_monitor.rs | Collector now builds MetricsSnapshot + publishes to EventBus; GPU builder renamed to return Core metrics type. |
| src-tauri/src/workers/mod.rs | WorkersState now owns a WindowAdapter and terminates it during shutdown. |
| src-tauri/src/lib.rs | Wires up the bus, starts WindowAdapter, then starts the monitor with the bus and stores both in WorkersState. |
| src-tauri/src/app/mod.rs | Makes app::adapters a real module (Phase 2 population). |
| src-tauri/src/app/adapters/window.rs | New adapter task subscribing to bus and emitting HardwareMonitorUpdate; includes translation unit tests. |
| src-tauri/src/app/adapters/mod.rs | Exposes the window adapter module. |
| core/src/models/mod.rs | New Core models module exporting metric snapshot types. |
| core/src/models/metrics.rs | Defines GpuMetric + MetricsSnapshot as Tauri-independent shapes. |
| core/src/lib.rs | Exposes the new event_bus and models modules from the core crate. |
| core/src/event_bus.rs | Implements EventBus wrapper around tokio::sync::broadcast with unit tests. |
| core/Cargo.toml | Adds tokio dependency (sync) + dev-dependency (macros/rt) for core tests. |
| Cargo.lock | Updates lockfile for core’s new tokio dependency. |
Rust Backend Coverage ReportCoverage Details |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@core/src/event_bus.rs`:
- Around line 27-29: The constructor with_capacity should guard against zero to
avoid tokio::sync::broadcast::channel(0) panicking; update the with_capacity
function to check if capacity == 0 and replace it with 1 (or otherwise coerce to
a non-zero value) before calling broadcast::channel, e.g. compute let cap = if
capacity == 0 { 1 } else { capacity } and then call broadcast::channel(cap) and
construct Self { tx } as before.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: f9aed0ad-dfb2-44c5-ac1e-dfe7936a9fbe
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (11)
core/Cargo.tomlcore/src/event_bus.rscore/src/lib.rscore/src/models/metrics.rscore/src/models/mod.rssrc-tauri/src/app/adapters/mod.rssrc-tauri/src/app/adapters/window.rssrc-tauri/src/app/mod.rssrc-tauri/src/lib.rssrc-tauri/src/workers/mod.rssrc-tauri/src/workers/system_monitor.rs
|
Force-pushing this branch shortly to drop the
Rationale: with Core promoted to a workspace crate in #1411, the entire |
Phase 2 of #1402. Introduce a Tauri-independent `hwviz_core::event_bus::EventBus` that fans out a `MetricsSnapshot` to every in-process subscriber. The collector no longer emits Tauri events directly; the new `adapters::window::WindowAdapter` is the sole place that translates a Core snapshot into the existing `HardwareMonitorUpdate` Tauri event. The wire format stays unchanged. - Add `core::event_bus::EventBus` over `tokio::sync::broadcast` and `core::models::{MetricsSnapshot, GpuMetric}`. `core` gains a `tokio` dependency with the `sync` feature; the dep graph still has no Tauri. - Replace `payload.emit(app_handle)` inside `workers::system_monitor::SystemMonitorController` with `bus.publish(snapshot)`. Rename the GPU payload builder to `build_gpu_metrics`. The collector still consults `AppState` for the user's `temperature_unit`; that lookup moves to the adapter in Phase 3.5. - Add `adapters::window::WindowAdapter`, a long-running task that subscribes to the bus and emits `HardwareMonitorUpdate` per snapshot. Logs and skips on `Lagged`; exits cleanly on `Closed` or stop signal. - Track the adapter in `WorkersState`; `terminate_all` stops the collector first (no further publishes), then drains the adapter, then the archive worker. - Unit tests under `core/` exercise EventBus fan-out, late-subscriber semantics, and zero-subscriber publish without a Tauri runtime. - Drop the `src-tauri/src/app/` namespace introduced as a placeholder in #1411. With Core promoted to a workspace crate, the entire `src-tauri/` crate is Tauri-aware by construction, so `adapters/` lives directly under `src-tauri/src/`. See discussion on #1402. Refs #1402, closes #1404
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src-tauri/src/workers/system_monitor.rs`:
- Around line 71-78: The doc comment in system_monitor.rs references the old
module path app::adapters::window::WindowAdapter; update that reference to the
new path crate::adapters::window::WindowAdapter in the setup/docs block (the
parameter list describing `bus` and translation to `HardwareMonitorUpdate`) so
the documentation points to the relocated adapter symbol.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: 3110e110-0063-4284-ae30-2fd6b1457b18
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (11)
core/Cargo.tomlcore/src/event_bus.rscore/src/lib.rscore/src/models/metrics.rscore/src/models/mod.rssrc-tauri/src/adapters/mod.rssrc-tauri/src/adapters/window.rssrc-tauri/src/app/mod.rssrc-tauri/src/lib.rssrc-tauri/src/workers/mod.rssrc-tauri/src/workers/system_monitor.rs
💤 Files with no reviewable changes (1)
- src-tauri/src/app/mod.rs
✅ Files skipped from review due to trivial changes (2)
- core/src/models/mod.rs
- core/Cargo.toml
🚧 Files skipped from review as they are similar to previous changes (5)
- core/src/lib.rs
- core/src/models/metrics.rs
- src-tauri/src/lib.rs
- src-tauri/src/workers/mod.rs
- core/src/event_bus.rs
- core::event_bus: document the zero-capacity panic on `EventBus::with_capacity` and add an explicit assert with a clearer message. Add a `#[should_panic]` test pinning the contract. - adapters::window: drop a redundant `continue;` in the `Lagged` arm. The select! arm naturally falls through to the next loop iteration. - adapters::window / workers::system_monitor: refresh stale `app::adapters::window::*` references in log labels and a doc comment to match the post-rename `crate::adapters::window::*` namespace.
Summary
Phase 2 of #1402. Introduce
hwviz_core::event_bus::EventBus, a Tauri-independent in-process broadcast channel forMetricsSnapshot. The collector no longer emits Tauri events directly; the newadapters::window::WindowAdapteris the sole place that translates a Core snapshot into the existingHardwareMonitorUpdateTauri event. The wire format is unchanged.This PR also drops the
src-tauri/src/app/namespace introduced as a placeholder in #1411 — with Core promoted to a workspace crate, the entiresrc-tauri/crate is Tauri-aware by construction, soadapters/lives directly undersrc-tauri/src/. See the discussion on #1402.Closes #1404. Refs #1402.
Changes
core/core::event_bus::EventBus— wrapstokio::sync::broadcast::Sender<MetricsSnapshot>.publish/subscribe/subscriber_count, default capacity 16.Cloneso it can be cheaply handed to multiple producers.core::models::{MetricsSnapshot, GpuMetric}— Tauri-independent data shape mirroring the existing wire payload. Noserde/spectaderives; that ceremony stays App-side.tokiodep — added tocore/Cargo.tomlwith only thesyncfeature in[dependencies];["macros", "rt"]in[dev-dependencies]for#[tokio::test]. Verifiedcargo tree -p hwviz-core | grep -ic tauri == 0.src-tauri/workers::system_monitor—payload.emit(app_handle)becomesbus.publish(snapshot).SystemMonitorController::setupnow takes anEventBus. The GPU payload builder is renamedbuild_gpu_metricsand returnsVec<GpuMetric>. Theapp_handleparameter is retained this phase only for thetemperature_unitlookup; Phase 3.5 moves that to the adapter.adapters::window::WindowAdapter— long-running tokio task that subscribes to the bus and emitsHardwareMonitorUpdate. HandlesLagged(warn + skip) andClosed(exit).terminate()uses the samewatch::Sender<bool>pattern as the collector.WorkersState— gains awindow_adapterslot.terminate_allorder: collector first (stop sources) → adapter (drain consumer) → archive worker.run()wiring — creates the bus, startsWindowAdapterwithbus.subscribe(), then starts the collector withbus.src-tauri/src/app/placeholder — empty Phase 1 module deleted;mod app;replaced bymod adapters;inlib.rs.Notable choices
MetricsSnapshotis a fresh Core type rather than re-exportingHardwareMonitorUpdate. Sharing the type would forcecoreto depend onserde/specta(and through specta, on Tauri-adjacent crates). The 1:1 field translation lives inWindowAdapterand is unit-tested.app_handlestays on the collector to readtemperature_unit. Removing it (and pushing °C-only snapshots through the bus, with adapter-side conversion) is explicitly Phase 3.5 — keeping it here avoids changing wire-format-relevant behavior in this PR.WorkersStateownership of the adapter keeps the existing shutdown path unchanged for callers;on_window_event(CloseRequested)still callsterminate_alland the adapter is now part of that.app.manage(...)yet. Phase 4 (persistence) is the natural place to make the bus shared state; until then, scoping it tosetup()keeps the surface minimal.app/namespace — see Epic: split backend into Tauri-independent Core and thin App adapters #1402 (Change Log entry).Test plan
cargo build --workspacesucceedscargo tauri-lintsucceedscargo tauri-fmt -- --checksucceedscargo llvm-cov --workspace --no-report -- --test-threads=1 --nocapture: 279 src-tauri tests + 6 hwviz-core tests pass (was 276 + 0 before this PR)cargo test -p hwviz-coreruns without a Tauri runtimecargo tree -p hwviz-core | grep -ic taurireturns0.emit(/Emitter::emit/AppHandle::emitremains inworkers/system_monitor.rstauri dev: dashboard updates indistinguishably fromdevelop(please verify on Windows during review — host platform dictates which sensors are exercised)lint-backend/test-backend/test-buildOut of scope (later phases)
app_handlefrom the collector / pushing temperature-unit conversion to the adapter — Phase 3.5 (refactor(core): Phase 3.5 — split settings into core (consumer) and app (UI) buckets #1406).core/— Phase 3 (refactor(core): Phase 3 — relocate collector and history state into core::collector #1405).HardwareMonitorUpdateto a Core-aligned wire format — deferred per the issue's "Out of Scope".Summary by CodeRabbit
New Features
Refactor