Async client + UI refactor: eliminate polling, context-based state#2
Merged
Conversation
…nt crate Eliminates the 16ms command polling timer in the WASM network loop. Commands are now awaited directly via futures::select!. Removes ClientNotification enum and profile_broadcast_counter (to be replaced by async timers in ClientEventLoop later). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduces SharedState (Rc<RefCell<>>) and ClientHandle (cloneable). All 48+ public methods moved from Client to ClientHandle with &self signatures (mutation through RefCell). Client struct removed. ClientEventLoop stub defined for Task 3. Key changes: - SharedState holds all mutable state (ClientState, Identity, config, etc.) - ClientHandle wraps Rc<RefCell<SharedState>> + cmd_tx + event_rx - Methods returning borrowed data (peers(), active_voice_channel(), active_server_id()) now return owned types - state()/state_mut() removed; roles_data() accessor added - on_connected(), reconcile_topic_map(), init_event_state_for_server(), apply_event_shared(), emit_client_events_for() extracted as free functions taking explicit parameters - All 116 tests pass, doc-test passes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move the synchronous poll() method from ClientHandle into an async run() loop on ClientEventLoop. Network events are awaited via futures::select!, drained into batches for efficiency, processed through process_batch(), and forwarded as ClientEvents. Profile re-broadcasts use real async timers (tokio on native, gloo-timers on WASM) instead of tick counting. State verification after sync is handled outside the batch borrow to avoid RefCell conflicts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Defines structured signal containers for context-based state management. create_signals() produces all 30 signal pairs grouped into sub-structs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…d state - Create event_processing.rs with process_event_batch() and refresh_all_signals() - Create handlers.rs with action handler constructors (send, edit, delete, react, channel switch, server switch, pin) - Rewrite App component: replace set_interval poll loop with spawn_local async event processing via ClientEventLoop - Replace 30+ loose signal declarations with state::create_signals() - Migrate 8 components from ClientHandle prop to use_context::<WebClientHandle>() (sidebar, member_list, welcome, add_server, server_settings, settings, file_share, roles) - Add accessor methods to ClientHandle (server_owner, has_permission, current_channel, unread_counts) for component access without exposing SharedState internals - Replace ClientHandle = SendWrapper<Rc<RefCell<Client>>> with WebClientHandle = SendWrapper<willow_client::ClientHandle> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This was referenced Apr 24, 2026
intendednull
added a commit
that referenced
this pull request
Apr 26, 2026
lifecycle, fix IrohBlobStore spec drift, track 4 new follow-ups Round 2 review (two fresh agents) verified all 15 round-1 fixes land cleanly with no regressions, then surfaced 8 new findings (0 critical, 3 medium, 5 low) by widening scope to cross-component interactions, perf, and API surface. Fixed inline (trivial doc / spec): - Add an "Actor coordination signal" row to the spec decision tree + CLAUDE.md table covering tokio::sync::watch / oneshot / broadcast / Notify, with the explicit rule that tokio::sync::Mutex is forbidden for business state on the same terms as std/parking_lot Mutex. Closes the spec gap that left contributors without guidance on async channels. (round-2 #3) - Reconcile spec § 184 with the corrected IrohBlobStore comment (round-1 fixed the code, missed the spec). The blob store is not an iroh-callback boundary — it's an interim stub. The relay- status timestamp Mutex stays in the iroh boundary list. (round-2 #4) - Document the web `_event_loop` drop pattern in `crates/web/src/app.rs` so future readers see explicitly that the actor System is process- scoped on web (page reload tears everything down) and that any actor needing pre-close cleanup must route via `beforeunload`, not Drop. (round-2 #8) Tracked as new follow-ups in spec § Follow-up work: - F5. SearchActor head-of-line + rebuild-storm fix. Rebuild blocks Query in FIFO order; the rebuild Effect has no debounce. Fix is chunked-Rebuild + Debounce<Rebuild> wrap. (round-2 #1, #2 — Med) - F6. Browser-tier coverage for SearchIndexHandle consumers. The spawn_local + Effect path has no wasm-pack test. (round-2 #6) - F7. Sealed ClientSpawner to narrow the system() API surface, rather than exposing the full SystemHandle. (round-2 #7) - F8. Search-query debouncing-flicker fix via generation tag or Leptos Resource migration. (round-2 #5) Each follow-up has a "Trigger:" line naming the dedicated PR title. `just check` green: clippy zero warnings, 1003+ tests pass, WASM compile clean. Loop terminates here per the user's two-round cap; no Critical issues remain. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced Apr 28, 2026
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.
Summary
std::sync::mpscwithfutures::channel::mpscinwillow-client, eliminating the 16ms command poll timer (WASM) and enabling zero-latency async event deliveryClientstruct intoSharedState+ClientHandle(cloneable) +ClientEventLoop(async)set_intervalpoll loop in the Leptos UI withspawn_localevent processingAppStatecontext with grouped sub-structs (ChatState,NetworkState,ServerState,UiState,VoiceState), replacing 30 prop-drilled signalsClientHandleprop touse_contextevent_processing.rsandhandlers.rsfrom the 800-lineAppmonolithTest plan
just checkpasses (fmt + clippy + test + WASM)just test-browser)🤖 Generated with Claude Code