Skip to content

Commit 70b8379

Browse files
committed
issue 419 - websocket should be closed
1 parent d99dd12 commit 70b8379

8 files changed

Lines changed: 61 additions & 4 deletions

File tree

src/SocketIOClient/Protocol/WebSocket/IWebSocketAdapter.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ public interface IWebSocketAdapter : IProtocolAdapter
99
{
1010
Task ConnectAsync(Uri uri, CancellationToken cancellationToken);
1111
Task SendAsync(ProtocolMessage message, CancellationToken cancellationToken);
12+
Task CloseAsync(CancellationToken cancellationToken);
1213
}

src/SocketIOClient/Protocol/WebSocket/IWebSocketClientAdapter.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ public interface IWebSocketClientAdapter
1010
Task SendAsync(byte[] data, WebSocketMessageType messageType, CancellationToken cancellationToken);
1111
Task<WebSocketMessage> ReceiveAsync(CancellationToken cancellationToken);
1212
void SetDefaultHeader(string name, string value);
13+
Task CloseAsync(CancellationToken cancellationToken);
1314
}

src/SocketIOClient/Protocol/WebSocket/SystemClientWebSocketAdapter.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,10 @@ public async Task<WebSocketMessage> ReceiveAsync(CancellationToken cancellationT
5757
}
5858

5959
public void SetDefaultHeader(string name, string value) => ws.SetDefaultHeader(name, value);
60+
61+
public async Task CloseAsync(CancellationToken cancellationToken)
62+
{
63+
await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "io client disconnect", cancellationToken)
64+
.ConfigureAwait(false);
65+
}
6066
}

src/SocketIOClient/Protocol/WebSocket/WebSocketAdapter.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ private async Task ReceiveAsync(CancellationToken cancellationToken)
5555

5656
public async Task SendAsync(ProtocolMessage message, CancellationToken cancellationToken)
5757
{
58-
var isTextButNull = message.Type == ProtocolMessageType.Text && message.Text == null;
59-
var isBytesButNull = message.Type == ProtocolMessageType.Bytes && message.Bytes == null;
58+
var isTextButNull = message is { Type: ProtocolMessageType.Text, Text: null };
59+
var isBytesButNull = message is { Type: ProtocolMessageType.Bytes, Bytes: null };
6060
if (isTextButNull || isBytesButNull)
6161
{
6262
throw new ArgumentNullException();
@@ -77,6 +77,11 @@ await clientAdapter
7777
logger.LogDebug("Sent {type} message.", message.Type);
7878
}
7979

80+
public async Task CloseAsync(CancellationToken cancellationToken)
81+
{
82+
await clientAdapter.CloseAsync(cancellationToken).ConfigureAwait(false);
83+
}
84+
8085
public override void SetDefaultHeader(string name, string value) => clientAdapter.SetDefaultHeader(name, value);
8186

8287
public void Dispose()

src/SocketIOClient/Session/WebSocket/WebSocketSession.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,15 @@ public override async Task DisconnectAsync(CancellationToken cancellationToken)
122122
{
123123
var content = string.IsNullOrEmpty(Options.Namespace) ? "41" : $"41{Options.Namespace},";
124124
var message = new ProtocolMessage { Text = content };
125-
await _wsAdapter.SendAsync(message, cancellationToken).ConfigureAwait(false);
125+
try
126+
{
127+
await _wsAdapter.SendAsync(message, cancellationToken).ConfigureAwait(false);
128+
}
129+
catch (Exception e)
130+
{
131+
_logger.LogError("Failed to send '{content}'", content);
132+
_logger.LogError(e.ToString());
133+
}
134+
await _wsAdapter.CloseAsync(cancellationToken).ConfigureAwait(false);
126135
}
127136
}

tests/SocketIOClient.UnitTests/Protocol/WebSocket/SystemClientWebSocketAdapterTests.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,14 @@ public void SetDefaultHeader_WhenCalled_AlwaysWsClientSetDefaultHeader()
115115

116116
_ws.Received().SetDefaultHeader("name", "value");
117117
}
118+
119+
[Fact]
120+
public async Task CloseAsync_WhenCalled_AlwaysPass()
121+
{
122+
using var cts = new CancellationTokenSource();
123+
var token = cts.Token;
124+
await _adapter.CloseAsync(token);
125+
126+
await _ws.Received(1).CloseAsync(WebSocketCloseStatus.NormalClosure, "io client disconnect", token);
127+
}
118128
}

tests/SocketIOClient.UnitTests/Protocol/WebSocket/WebSocketAdapterTests.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ public async Task ConnectAsync_ReceivedTextMessage_NotifyToObserver()
145145
_clientAdapter.ReceiveAsync(Arg.Is<CancellationToken>(c => c != CancellationToken.None))
146146
.Returns(async _ =>
147147
{
148-
await Task.Delay(20).ConfigureAwait(false);
148+
await Task.Delay(100).ConfigureAwait(false);
149149
return new WebSocketMessage
150150
{
151151
Type = WebSocketMessageType.Text,
@@ -254,4 +254,14 @@ public void UnSubscribe_GivenNull_AlwaysPass()
254254
.Should()
255255
.NotThrow();
256256
}
257+
258+
[Fact]
259+
public async Task CloseAsync_WhenCalled_AlwaysPass()
260+
{
261+
using var cts = new CancellationTokenSource();
262+
var token = cts.Token;
263+
await _wsAdapter.CloseAsync(token);
264+
265+
await _clientAdapter.Received(1).CloseAsync(token);
266+
}
257267
}

tests/SocketIOClient.UnitTests/Session/WebSocket/WebSocketSessionTests.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,21 @@ public async Task DisconnectAsync_NoNamespace_SendDisconnectToServer()
208208
await _wsAdapter.Received(1)
209209
.SendAsync(Arg.Is<ProtocolMessage>(m =>
210210
m.Type == ProtocolMessageType.Text && m.Text == "41"), token);
211+
await _wsAdapter.Received(1).CloseAsync(token);
212+
}
213+
214+
[Fact]
215+
public async Task DisconnectAsync_FailedToSend41_StillCloseAsync()
216+
{
217+
using var cts = new CancellationTokenSource();
218+
var token = cts.Token;
219+
var session = NewSession();
220+
_wsAdapter.SendAsync(Arg.Any<ProtocolMessage>(), token)
221+
.Returns(Task.FromException(new Exception()));
222+
223+
await session.DisconnectAsync(token);
224+
225+
await _wsAdapter.Received(1).CloseAsync(token);
211226
}
212227

213228
[Fact]

0 commit comments

Comments
 (0)