Merged
Conversation
Optimizes the client structure by removing unnecessary Arc wrappers and changing method signatures to accept references instead of ownership. Enhances robustness by gracefully handling channel closures and deserialization errors during reconnection, and cleans up subscription management logic.
Simplifies the internal state management by replacing Arc<Mutex> with Mutex for fields, as the client itself is shared via Arc. Rewrites the connection loop to better handle session resumption and adds error checks for frontend channel communication.
Prevents panics by checking for closed channels before sending messages in the event loop and client methods. Switches to wrapping addition for connection IDs to avoid potential overflow errors.
There was a problem hiding this comment.
Pull request overview
Refactors the EventSub, 7TV, and IRC connection code to be more idiomatic Rust by removing unnecessary Arc patterns and unwrap() calls, while making error paths actually reachable (notably by removing double-spawns in websocket connect() implementations).
Changes:
- Fixes previously-dead error handling by removing inner
tokio::spawnusage in websocketconnect()paths and improving error logging. - Replaces multiple
unwrap()/expect()usages with structured error handling or warning logs across EventSub/7TV/IRC. - Adjusts APIs to avoid unnecessary allocations (e.g.,
subscribe_allnow takes a slice;unsubscribenow takes&str) and simplifies iterator-based collection logic.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src-tauri/src/seventv/mod.rs | Makes 7TV connection failures observable/logged and avoids panicking when frontend channel closes. |
| src-tauri/src/seventv/client.rs | Refactors 7TV client internals (removes extra Arc<Mutex<...>>, Arc<Self> method receivers) and improves error handling/logging. |
| src-tauri/src/irc/mod.rs | Avoids panic when IRC frontend channel closes by handling send errors. |
| src-tauri/src/irc/client/mod.rs | Replaces unwrap()s in IRC client commands with graceful handling/logging when the loop is stopped. |
| src-tauri/src/irc/client/event_loop.rs | Small refactor for clarity (wrapping_add) and avoids panic on forwarding-task send failure. |
| src-tauri/src/eventsub/mod.rs | Makes EventSub connection failures observable/logged and avoids panicking when frontend channel closes. |
| src-tauri/src/eventsub/client.rs | Removes double-spawn, switches methods to &self, improves deserialization/reconnect handling, and adjusts subscription APIs to slices/borrows. |
| src-tauri/src/api.rs | Updates call sites to match the new EventSubClient::subscribe_all(&[..]) signature. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
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.
Attempting to see how far AI gets me...
EventSub Module Refactoring
Bug Fix: Double-spawn made error handling dead code
The original
connectmethod spawned an innertokio::spawnand always returnedOk(()), so the error check inmod.rscould never trigger. Removed the inner spawn soconnectruns directly in the caller's spawned task, making the error path functional.client.rs— Major Changes1. Eliminated
self: Arc<Self>pattern —process_stream,handle_text,handle_message, andreconnectall changed fromself: Arc<Self>to&self. All interior mutation already usesMutex,AtomicBool, andmpsc::UnboundedSenderwhich work through shared references. This removed ~6 unnecessaryArc::clonecalls.2. Fixed
unwrap()/expect()in production code:self.sender.send(payload).unwrap()→ logs a warning if the receiver is dropped.expect("missing reconnect_url")→ returns a properError::Generic3. Replaced silent error swallowing in
handle_text— Deserialization failures were silently dropped. Now logs awarnwith the error before returningOk(None).4. Simplified confusing
compare_exchangelogic — The invertedcompare_exchange(...).is_err()for checking "is initial connection" was replaced withself.reconnecting.swap(false, ...)and a clearif was_reconnecting/elsebranch.5. Removed unnecessary allocation — Eliminated
TWITCH_EVENTSUB_WS_URI.to_string()sinceconnect_asyncaccepts&str.6. Made
Keepalivematch explicit — Replaced_ => ()wildcard withWs::Keepalive => ()so the compiler catches any future variant additions.7. Changed
subscribe_allto accept&[(EventType, &serde_json::Value)]— Avoids requiring callers to allocate aVec.8. Changed
unsubscribeto acceptevent: &str— Avoids requiring callers to clone/own the event string.9. Simplified
unsubscribe_all— Combinedstarts_with+strip_prefix+unwrapinto a singlefilter_mapwithstrip_prefix. Also used iterator chain withfilter_map+flatteninstead of a manualforloop for collecting results.10. Made
set_connectedprivate — Only used internally.11. Simplified subscription restoration — Replaced the nested
if !map.is_empty()+forloop + manualVecwith adrain().filter_map().collect()iterator chain.mod.rs— Changes12. Fixed
channel.send(message).unwrap()— Now handles the error gracefully by logging and breaking the loop when the frontend channel closes.13. Connection errors are now logged — Changed
is_err()toif let Err(err)withtracing::error!.14. Removed
Ok::<_, Error>(())— No longer needed since the spawn block now returns()directly.api.rs— Caller UpdatesUpdated both
subscribe_allcall sites to pass&events/&subs_ref(slice) instead of ownedVec.IRC Module Refactoring
irc/mod.rsFixed
channel.send(message).unwrap()— Now handles the error gracefully by logging a warning and breaking the forwarding loop when the frontend channel closes, instead of panicking.irc/client/mod.rsReplaced 3
unwrap()calls inconnect,join,part— These would panic if theClientLoopWorkerstopped. Now they log descriptive errors and return gracefully. This prevents cascading panics when the IRC connection is in a degraded state.irc/client/event_loop.rsUsed
wrapping_add(1)instead ofoverflowing_add(1).0— Semantically clearer; both are equivalent butwrapping_adddirectly communicates intent.Fixed
unwrap()on send inrun_incoming_forward_task— If theclient_loop_txsend fails, the loop now breaks cleanly instead of panicking. Also flattened the nestedif letchain intolet...elseguards for better readability.IRC message module — No changes
The message parsing code (
commands.rs,prefix.rs,tags.rs,twitch.rs) is well-structured with comprehensive error types, clean extension trait patterns, and appropriate use of?propagation. No refactoring needed.7TV Module Refactoring
seventv/client.rs— Major RefactorBug fix: Removed double-spawn (same bug as eventsub) —
connectspawned an innertokio::spawnand always returnedOk(()), making the error handling inmod.rsdead code. Nowconnectruns the reconnection loop directly, and errors propagate to the caller.Changed
connectfromself: Arc<Self>to&self— All internal mutation usesMutex,AtomicBool, andmpsc::UnboundedSenderwhich work through shared references. This eliminated theArc::clonecalls inside the method.Removed unnecessary
Arcwrappers on fields —session_id,subscriptions, andmessage_rxwereArc<Mutex<...>>but the struct itself lives behindArc<SeventTvClient>. Simplified to justMutex<...>.Extracted
handle_ws_messagemethod — The deeply nested opcode handling was inlined in the WebSocket read loop. Extracted into a dedicatedasync fn handle_ws_message(&self, msg: WebSocketMessage)for clarity.Fixed silent error swallowing — Deserialization failures (
serde_json::from_str) were silently dropped withif let Ok(...). Now logs a warning on failure.Fixed
.split_once(':').unwrap()— When restoring subscriptions after a failed resume, a malformed key would panic. Now useslet Some(...) else { continue }with a warning log.Simplified
unsubscribe_all— Replacedstarts_with+strip_prefix+unwrapwith a singlefilter_map+strip_prefix.seventv/mod.rsFixed dead error path — Changed
Arc::clone(&client).connect().await.is_err()toclient.connect().awaitwithif let Err(err)to actually log and handle the error.Fixed
channel.send(message).unwrap()— Handles gracefully with a warning log and loop break.