mirror of
https://github.com/spartanz51/tutabridge.git
synced 2026-06-24 10:54:32 +02:00
Drop the last two timers: prefetch and the UI stats poll go event-driven
Phase 2.5 — `prefetch_loop` no longer wakes every 30s. It subscribes to `MailStore::subscribe()` and only catches up missing bodies when the generation counter ticks (event-bus delta, sync_folder finishing, bootstrap). When the store is quiet — every cached mail has its .eml on disk — the loop sleeps indefinitely on the watch channel. The `PREFETCH_INTERVAL` constant is gone. Phase 2.6 — the dashboard 1s `setInterval` is gone too. `BridgeHandle` gets a `stats_dirty_tx: broadcast::Sender<()>` that pulses on every `MailStore` bump, every `WsState` transition, and the start / stop status transitions. A small watcher task inside `start()` plumbs the two `watch::Receiver`s into the broadcast. The Tauri layer (`stream_stats`) subscribes via `BridgeHandle::subscribe_stats()`, takes a stats + status snapshot on every pulse (and once at startup), and emits two events `bridge://stats` / `bridge://status` to the webview. The React hook replaces `setInterval(refresh, 1000)` with two `listen()` subscriptions; the initial `refresh()` still seeds the state for the first frame. Backend now has zero `time::sleep`-driven polling loops: the syncer is driven by Phase 0 + bootstrap + the event bus, prefetch is driven by store changes, and the UI is driven by pushes. The only remaining delays are throttling (`INTER_FOLDER_DELAY`, `INTER_REQUEST_DELAY`) and reconnect backoff, which are not polls. 166 bridge lib tests, full workspace builds, UI tsc clean.
This commit is contained in:
@@ -18,6 +18,7 @@ fn main() {
|
||||
|
||||
let handle = BridgeHandle::new();
|
||||
let log_rx = handle.subscribe_logs();
|
||||
let stats_rx = handle.subscribe_stats();
|
||||
let shared = Arc::new(Mutex::new(handle));
|
||||
|
||||
tauri::Builder::default()
|
||||
@@ -40,6 +41,12 @@ fn main() {
|
||||
stream_logs(app_handle, log_rx).await;
|
||||
});
|
||||
|
||||
let app_handle = app.handle().clone();
|
||||
let stats_state = app.state::<BridgeState>().inner().clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
stream_stats(app_handle, stats_rx, stats_state).await;
|
||||
});
|
||||
|
||||
let state = app.state::<BridgeState>().inner().clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
auto_start(state).await;
|
||||
@@ -75,6 +82,36 @@ async fn auto_start(state: Arc<Mutex<BridgeHandle>>) {
|
||||
}
|
||||
}
|
||||
|
||||
async fn stream_stats(
|
||||
app: tauri::AppHandle,
|
||||
mut rx: tokio::sync::broadcast::Receiver<()>,
|
||||
state: BridgeState,
|
||||
) {
|
||||
use tauri::Emitter;
|
||||
// Emit a single snapshot covering both bridge status and stats. Status
|
||||
// transitions (start / stop) and stats changes (new mail, ws state) all
|
||||
// pulse the same channel, so the UI replaces its periodic poll with one
|
||||
// listen per topic.
|
||||
async fn emit_snapshot(app: &tauri::AppHandle, state: &BridgeState) {
|
||||
let handle = state.lock().await;
|
||||
let status = handle.status().await;
|
||||
let stats = handle.stats().await;
|
||||
drop(handle);
|
||||
let _ = app.emit("bridge://stats", &stats);
|
||||
let _ = app.emit("bridge://status", &status);
|
||||
}
|
||||
|
||||
emit_snapshot(&app, &state).await;
|
||||
loop {
|
||||
match rx.recv().await {
|
||||
Ok(()) | Err(tokio::sync::broadcast::error::RecvError::Lagged(_)) => {
|
||||
emit_snapshot(&app, &state).await;
|
||||
}
|
||||
Err(tokio::sync::broadcast::error::RecvError::Closed) => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn stream_logs(
|
||||
app: tauri::AppHandle,
|
||||
mut rx: tokio::sync::broadcast::Receiver<String>,
|
||||
|
||||
Reference in New Issue
Block a user