Repository: 1c3t3a/rust-socketio (language: rust)

Issue:
Asynchronous Client: Unexpected Server disconnect leads to panic
## Problem Description

In #314 the stream implementation of the asynchronous socket has been adjusted.
However, when the server now disconnects unexpectedly (e.g. process is killed etc.), the following issue can now be observed:

```
thread 'tokio-runtime-worker' panicked at 'Unfold must not be polled after it returned `Poll::Ready(None)`'
```

## Steps To Reproduce

1. Use client and server from #311 
2. Start the server and then the client
3. Stop the server
4. Observe the panic in the client

## Possible Solution

The loop which polls the stream in the asynchronous client builder needs to stop when the stream returns `None`:

https://github.com/1c3t3a/rust-socketio/blob/cb107ba6770fabb109dce173b74ab36ebe039045/socketio/src/asynchronous/client/builder.rs#L346-L355

Apparently, this issue existed before #314 already.
However, due to the different stream implementation, calls to `stream.next()` after the stream has terminated wouldn't panic but instead always return `None` leading to an infinite loop.
The issue only now surfaced because of the different stream implementation.


Discussion / hints:

Fix patch:
diff --git a/socketio/src/asynchronous/client/builder.rs b/socketio/src/asynchronous/client/builder.rs
index ba85b8eb..e2b0e962 100644
--- a/socketio/src/asynchronous/client/builder.rs
+++ b/socketio/src/asynchronous/client/builder.rs
@@ -343,14 +343,10 @@ impl ClientBuilder {
         // Use thread to consume items in iterator in order to call callbacks
         tokio::runtime::Handle::current().spawn(async move {
             let mut stream = socket_clone.as_stream();
-            loop {
-                // tries to restart a poll cycle whenever a 'normal' error occurs,
-                // it just logs on network errors, in case the poll cycle returned
-                // `Result::Ok`, the server receives a close frame so it's safe to
-                // terminate
-                if let Some(e @ Err(Error::IncompleteResponseFromEngineIo(_))) = stream.next().await
-                {
-                    trace!("Network error occured: {}", e.unwrap_err());
+            // Consume the stream until it returns None and the stream is closed.
+            while let Some(item) = stream.next().await {
+                if let e @ Err(Error::IncompleteResponseFromEngineIo(_)) = item {
+                    trace!("Network error occurred: {}", e.unwrap_err());
                 }
             }
         });


Test patch: