|
|
@@ -1,5 +1,4 @@ |
|
|
|
using Discord.Extensions; |
|
|
|
using System; |
|
|
|
using System; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.ComponentModel; |
|
|
|
using System.IO; |
|
|
@@ -12,7 +11,7 @@ namespace Discord.Net.WebSockets |
|
|
|
{ |
|
|
|
public class DefaultWebSocketClient : IWebSocketClient |
|
|
|
{ |
|
|
|
public const int ReceiveChunkSize = 12 * 1024; //12KB |
|
|
|
public const int ReceiveChunkSize = 16 * 1024; //16KB |
|
|
|
public const int SendChunkSize = 4 * 1024; //4KB |
|
|
|
private const int HR_TIMEOUT = -2147012894; |
|
|
|
|
|
|
@@ -137,50 +136,64 @@ namespace Discord.Net.WebSockets |
|
|
|
private async Task RunAsync(CancellationToken cancelToken) |
|
|
|
{ |
|
|
|
var buffer = new ArraySegment<byte>(new byte[ReceiveChunkSize]); |
|
|
|
var stream = new MemoryStream(); |
|
|
|
|
|
|
|
try |
|
|
|
{ |
|
|
|
while (!cancelToken.IsCancellationRequested) |
|
|
|
{ |
|
|
|
WebSocketReceiveResult result = null; |
|
|
|
do |
|
|
|
WebSocketReceiveResult socketResult = await _client.ReceiveAsync(buffer, cancelToken).ConfigureAwait(false); |
|
|
|
byte[] result; |
|
|
|
int resultCount; |
|
|
|
|
|
|
|
if (socketResult.MessageType == WebSocketMessageType.Close) |
|
|
|
{ |
|
|
|
if (cancelToken.IsCancellationRequested) return; |
|
|
|
var _ = Closed(new WebSocketClosedException((int)socketResult.CloseStatus, socketResult.CloseStatusDescription)); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
try |
|
|
|
{ |
|
|
|
result = await _client.ReceiveAsync(buffer, cancelToken).ConfigureAwait(false); |
|
|
|
} |
|
|
|
catch (Win32Exception ex) when (ex.HResult == HR_TIMEOUT) |
|
|
|
if (!socketResult.EndOfMessage) |
|
|
|
{ |
|
|
|
//This is a large message (likely just READY), lets create a temporary expandable stream |
|
|
|
using (var stream = new MemoryStream()) |
|
|
|
{ |
|
|
|
throw new Exception("Connection timed out."); |
|
|
|
stream.Write(buffer.Array, 0, socketResult.Count); |
|
|
|
do |
|
|
|
{ |
|
|
|
if (cancelToken.IsCancellationRequested) return; |
|
|
|
socketResult = await _client.ReceiveAsync(buffer, cancelToken).ConfigureAwait(false); |
|
|
|
stream.Write(buffer.Array, 0, socketResult.Count); |
|
|
|
} |
|
|
|
while (socketResult == null || !socketResult.EndOfMessage); |
|
|
|
|
|
|
|
//Use the internal buffer if we can get it |
|
|
|
resultCount = (int)stream.Length; |
|
|
|
ArraySegment<byte> streamBuffer; |
|
|
|
if (stream.TryGetBuffer(out streamBuffer)) |
|
|
|
result = streamBuffer.Array; |
|
|
|
else |
|
|
|
result = stream.ToArray(); |
|
|
|
} |
|
|
|
|
|
|
|
if (result.Count > 0) |
|
|
|
stream.Write(buffer.Array, 0, result.Count); |
|
|
|
} |
|
|
|
while (result == null || !result.EndOfMessage); |
|
|
|
|
|
|
|
var array = stream.ToArray(); |
|
|
|
stream.Position = 0; |
|
|
|
stream.SetLength(0); |
|
|
|
else |
|
|
|
{ |
|
|
|
//Small message |
|
|
|
resultCount = socketResult.Count; |
|
|
|
result = buffer.Array; |
|
|
|
} |
|
|
|
|
|
|
|
switch (result.MessageType) |
|
|
|
if (socketResult.MessageType == WebSocketMessageType.Text) |
|
|
|
{ |
|
|
|
case WebSocketMessageType.Binary: |
|
|
|
await BinaryMessage(array, 0, array.Length).ConfigureAwait(false); |
|
|
|
break; |
|
|
|
case WebSocketMessageType.Text: |
|
|
|
string text = Encoding.UTF8.GetString(array, 0, array.Length); |
|
|
|
await TextMessage(text).ConfigureAwait(false); |
|
|
|
break; |
|
|
|
case WebSocketMessageType.Close: |
|
|
|
var _ = Closed(new WebSocketClosedException((int)result.CloseStatus, result.CloseStatusDescription)); |
|
|
|
return; |
|
|
|
string text = Encoding.UTF8.GetString(result, 0, resultCount); |
|
|
|
await TextMessage(text).ConfigureAwait(false); |
|
|
|
} |
|
|
|
else |
|
|
|
await BinaryMessage(result, 0, resultCount).ConfigureAwait(false); |
|
|
|
} |
|
|
|
} |
|
|
|
catch (Win32Exception ex) when (ex.HResult == HR_TIMEOUT) |
|
|
|
{ |
|
|
|
var _ = Closed(new Exception("Connection timed out.", ex)); |
|
|
|
} |
|
|
|
catch (OperationCanceledException) { } |
|
|
|
catch (Exception ex) |
|
|
|
{ |
|
|
|