Skip to content

Commit 87bba80

Browse files
authored
Close WS and Dispose if the connection attempt failed + Add aborting WS connection if it's in a connecting state during cleanup (#155)
1 parent 099b023 commit 87bba80

File tree

2 files changed

+65
-42
lines changed

2 files changed

+65
-42
lines changed

Assets/Plugins/StreamChat/Libs/Websockets/WebsocketClient.cs

Lines changed: 65 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public async Task ConnectAsync(Uri serverUri, int timeout = 3)
5050

5151
try
5252
{
53-
await TryDisposeResourcesAsync(WebSocketCloseStatus.NormalClosure,
53+
await TryCloseAndDisposeAsync(WebSocketCloseStatus.NormalClosure,
5454
"Clean up resources before connecting");
5555
_connectionCts = new CancellationTokenSource();
5656

@@ -67,15 +67,15 @@ await TryDisposeResourcesAsync(WebSocketCloseStatus.NormalClosure,
6767

6868
// We handle timeout this way because ConnectAsync was hanging after multiple attempts on Unity 2022.3.29 & Android 14 and cancellation via passed token didn't work
6969
var finishedTask = await Task.WhenAny(connectTask, timeoutTask);
70-
70+
7171
if (finishedTask == timeoutTask)
7272
{
7373
#if STREAM_DEBUG_ENABLED
7474
_logs.Warning("Internal WS Connection attempt timed out.");
7575
#endif
7676
throw new TimeoutException($"Connection attempt timed out after {timeout} seconds.");
7777
}
78-
78+
7979
if (_connectionCts == null || _connectionCts.Token.IsCancellationRequested)
8080
{
8181
#if STREAM_DEBUG_ENABLED
@@ -90,30 +90,10 @@ await TryDisposeResourcesAsync(WebSocketCloseStatus.NormalClosure,
9090
ws.Stop();
9191
_logs.Warning($"Internal WS ConnectAsync COMPLETED in {ws.ElapsedMilliseconds} ms.");
9292
#endif
93-
94-
}
95-
catch (OperationCanceledException e)
96-
{
97-
LogExceptionIfDebugMode(e);
98-
OnConnectionFailed();
99-
return;
100-
}
101-
catch (WebSocketException e)
102-
{
103-
LogExceptionIfDebugMode(e);
104-
OnConnectionFailed();
105-
return;
106-
}
107-
catch (SocketException e)
108-
{
109-
LogExceptionIfDebugMode(e);
110-
OnConnectionFailed();
111-
return;
11293
}
11394
catch (Exception e)
11495
{
115-
_logs.Exception(e);
116-
OnConnectionFailed();
96+
await HandleConnectionFailedAsync(e);
11797
return;
11898
}
11999

@@ -135,7 +115,7 @@ public void Update()
135115
{
136116
#if STREAM_DEBUG_ENABLED
137117

138-
if(_internalClient != null && _internalClient.State != _lastState)
118+
if (_internalClient != null && _internalClient.State != _lastState)
139119
{
140120
_logs.Warning($"Internal WS state -> changed from {_lastState} to " + _internalClient.State);
141121
_lastState = _internalClient.State;
@@ -166,22 +146,22 @@ public void Update()
166146
public async Task DisconnectAsync(WebSocketCloseStatus closeStatus, string closeMessage)
167147
{
168148
LogInfoIfDebugMode("Disconnect");
169-
await TryDisposeResourcesAsync(closeStatus, closeMessage);
149+
await TryCloseAndDisposeAsync(closeStatus, closeMessage);
170150

171151
Disconnected?.Invoke();
172152
}
173153

174154
public void Dispose()
175155
{
176-
LogInfoIfDebugMode("Dispose " + Thread.CurrentThread.ManagedThreadId);
177-
178-
if(_internalClient != null && !_clientClosedStates.Contains(_internalClient.State))
156+
LogInfoIfDebugMode("Dispose " + Thread.CurrentThread.ManagedThreadId);
157+
158+
if (_internalClient != null && !_clientClosedStates.Contains(_internalClient.State))
179159
{
180160
DisconnectAsync(WebSocketCloseStatus.NormalClosure, "WebSocket client is disposed")
181161
.ContinueWith(t => LogExceptionIfDebugMode(t.Exception), TaskContinuationOptions.OnlyOnFaulted);
182162
}
183163
}
184-
164+
185165
private const int UpdatesPerSecond = 20;
186166
private const int UpdatePeriod = 1000 / UpdatesPerSecond;
187167
private const int UpdatePeriodOffset = UpdatePeriod / 2;
@@ -299,22 +279,28 @@ private async void ReceiveMessagesCallback(object state)
299279
}
300280
}
301281

302-
private async Task TryDisposeResourcesAsync(WebSocketCloseStatus closeStatus, string closeMessage)
282+
private async Task TryCloseAndDisposeAsync(WebSocketCloseStatus closeStatus, string closeMessage)
303283
{
304284
try
305285
{
306-
_backgroundReceiveTimer?.Dispose();
307-
_backgroundReceiveTimer = null;
286+
if (_backgroundReceiveTimer != null)
287+
{
288+
await _backgroundReceiveTimer.DisposeAsync();
289+
_backgroundReceiveTimer = null;
290+
}
308291
}
309292
catch (Exception e)
310293
{
311294
LogExceptionIfDebugMode(e);
312295
}
313-
296+
314297
try
315298
{
316-
_backgroundSendTimer?.Dispose();
317-
_backgroundSendTimer = null;
299+
if (_backgroundSendTimer != null)
300+
{
301+
await _backgroundSendTimer.DisposeAsync();
302+
_backgroundSendTimer = null;
303+
}
318304
}
319305
catch (Exception e)
320306
{
@@ -325,7 +311,11 @@ private async Task TryDisposeResourcesAsync(WebSocketCloseStatus closeStatus, st
325311
{
326312
if (_connectionCts != null)
327313
{
328-
_connectionCts.Cancel();
314+
if (!_connectionCts.IsCancellationRequested)
315+
{
316+
_connectionCts.Cancel();
317+
}
318+
329319
_connectionCts.Dispose();
330320
_connectionCts = null;
331321
}
@@ -342,13 +332,21 @@ private async Task TryDisposeResourcesAsync(WebSocketCloseStatus closeStatus, st
342332

343333
try
344334
{
345-
if (!_clientClosedStates.Contains(_internalClient.State))
335+
if (_internalClient.State == WebSocketState.Open)
346336
{
347337
#if STREAM_DEBUG_ENABLED
348-
_logs.Warning("Internal WS - Close in state: " + _internalClient.State);
338+
_logs.Warning("Internal WS - Disposing; Is open -> CloseOutputAsync");
349339
#endif
350340
await _internalClient.CloseOutputAsync(closeStatus, closeMessage, CancellationToken.None);
351341
}
342+
343+
if (_internalClient.State == WebSocketState.Connecting)
344+
{
345+
#if STREAM_DEBUG_ENABLED
346+
_logs.Warning("Internal WS - Disposing; Is Connecting -> Abort");
347+
#endif
348+
_internalClient.Abort();
349+
}
352350
}
353351
catch (Exception e)
354352
{
@@ -364,7 +362,34 @@ private async Task TryDisposeResourcesAsync(WebSocketCloseStatus closeStatus, st
364362
}
365363
}
366364

367-
private void OnConnectionFailed() => ConnectionFailed?.Invoke();
365+
private async Task HandleConnectionFailedAsync(Exception exception)
366+
{
367+
#if STREAM_DEBUG_ENABLED
368+
_logs.Warning("Internal WS - Connection Failed - trigger ConnectionFailed event");
369+
#endif
370+
371+
try
372+
{
373+
await TryCloseAndDisposeAsync(WebSocketCloseStatus.ProtocolError,
374+
"Closing due to exception thrown during connection attempt: " + exception.Message);
375+
}
376+
catch (Exception e)
377+
{
378+
_logs.Exception(exception);
379+
}
380+
381+
var isHandledExceptionType = exception is OperationCanceledException || exception is WebSocketException || exception is SocketException;
382+
if (isHandledExceptionType)
383+
{
384+
LogExceptionIfDebugMode(exception);
385+
}
386+
else
387+
{
388+
_logs.Exception(exception);
389+
}
390+
391+
ConnectionFailed?.Invoke();
392+
}
368393

369394
// Called from a background thread
370395
private void OnReceivedCloseMessage()

Assets/Plugins/StreamChat/SampleProject/Scripts/Views/ConsoleView.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,6 @@ private void OnConnectionStateChanged(ConnectionState prev, ConnectionState curr
9999
UpdateEventsLog();
100100
}
101101

102-
Debug.LogWarning($"Connection changed from `{prev}` to `{current}`");
103-
104102
UpdateConnectionLog();
105103
}
106104

0 commit comments

Comments
 (0)