Make more things async

This commit is contained in:
Bond_009 2019-02-09 15:39:17 +01:00
parent 2fc97212a7
commit 449074e73f
6 changed files with 163 additions and 178 deletions

View file

@ -43,10 +43,11 @@ namespace Jellyfin.Server.SocketSharp
socket.OnMessage += socket_OnMessage; socket.OnMessage += socket_OnMessage;
socket.OnClose += socket_OnClose; socket.OnClose += socket_OnClose;
socket.OnError += socket_OnError; socket.OnError += socket_OnError;
WebSocket.ConnectAsServer();
} }
public Task ConnectAsServerAsync()
=> WebSocket.ConnectAsServer();
public Task StartReceive() public Task StartReceive()
{ {
return _taskCompletionSource.Task; return _taskCompletionSource.Task;
@ -133,7 +134,7 @@ namespace Jellyfin.Server.SocketSharp
_cancellationTokenSource.Cancel(); _cancellationTokenSource.Cancel();
WebSocket.Close(); WebSocket.CloseAsync().GetAwaiter().GetResult();
} }
} }

View file

@ -34,9 +34,16 @@ namespace Jellyfin.Server.SocketSharp
private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource(); private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource();
private CancellationToken _disposeCancellationToken; private CancellationToken _disposeCancellationToken;
public WebSocketSharpListener(ILogger logger, X509Certificate certificate, IStreamHelper streamHelper, public WebSocketSharpListener(
INetworkManager networkManager, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, ILogger logger,
bool enableDualMode, IFileSystem fileSystem, IEnvironmentInfo environment) X509Certificate certificate,
IStreamHelper streamHelper,
INetworkManager networkManager,
ISocketFactory socketFactory,
ICryptoProvider cryptoProvider,
bool enableDualMode,
IFileSystem fileSystem,
IEnvironmentInfo environment)
{ {
_logger = logger; _logger = logger;
_certificate = certificate; _certificate = certificate;
@ -61,7 +68,9 @@ namespace Jellyfin.Server.SocketSharp
public void Start(IEnumerable<string> urlPrefixes) public void Start(IEnumerable<string> urlPrefixes)
{ {
if (_listener == null) if (_listener == null)
{
_listener = new HttpListener(_logger, _cryptoProvider, _socketFactory, _networkManager, _streamHelper, _fileSystem, _environment); _listener = new HttpListener(_logger, _cryptoProvider, _socketFactory, _networkManager, _streamHelper, _fileSystem, _environment);
}
_listener.EnableDualMode = _enableDualMode; _listener.EnableDualMode = _enableDualMode;
@ -70,22 +79,14 @@ namespace Jellyfin.Server.SocketSharp
_listener.LoadCert(_certificate); _listener.LoadCert(_certificate);
} }
foreach (var prefix in urlPrefixes) _logger.LogInformation("Adding HttpListener prefixes {Prefixes}", urlPrefixes);
{ _listener.Prefixes.AddRange(urlPrefixes);
_logger.LogInformation("Adding HttpListener prefix " + prefix);
_listener.Prefixes.Add(prefix);
}
_listener.OnContext = ProcessContext; _listener.OnContext = async c => await InitTask(c, _disposeCancellationToken).ConfigureAwait(false);
_listener.Start(); _listener.Start();
} }
private void ProcessContext(HttpListenerContext context)
{
var _ = Task.Run(async () => await InitTask(context, _disposeCancellationToken));
}
private static void LogRequest(ILogger logger, HttpListenerRequest request) private static void LogRequest(ILogger logger, HttpListenerRequest request)
{ {
var url = request.Url.ToString(); var url = request.Url.ToString();
@ -139,10 +140,7 @@ namespace Jellyfin.Server.SocketSharp
Endpoint = endpoint Endpoint = endpoint
}; };
if (WebSocketConnecting != null) WebSocketConnecting?.Invoke(connectingArgs);
{
WebSocketConnecting(connectingArgs);
}
if (connectingArgs.AllowConnection) if (connectingArgs.AllowConnection)
{ {
@ -153,6 +151,7 @@ namespace Jellyfin.Server.SocketSharp
if (WebSocketConnected != null) if (WebSocketConnected != null)
{ {
var socket = new SharpWebSocket(webSocketContext.WebSocket, _logger); var socket = new SharpWebSocket(webSocketContext.WebSocket, _logger);
await socket.ConnectAsServerAsync().ConfigureAwait(false);
WebSocketConnected(new WebSocketConnectEventArgs WebSocketConnected(new WebSocketConnectEventArgs
{ {
@ -162,7 +161,7 @@ namespace Jellyfin.Server.SocketSharp
Endpoint = endpoint Endpoint = endpoint
}); });
await ReceiveWebSocket(ctx, socket).ConfigureAwait(false); await ReceiveWebSocketAsync(ctx, socket).ConfigureAwait(false);
} }
} }
else else
@ -180,7 +179,7 @@ namespace Jellyfin.Server.SocketSharp
} }
} }
private async Task ReceiveWebSocket(HttpListenerContext ctx, SharpWebSocket socket) private async Task ReceiveWebSocketAsync(HttpListenerContext ctx, SharpWebSocket socket)
{ {
try try
{ {

View file

@ -4,7 +4,6 @@ using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Net; using System.Net;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
using HttpStatusCode = SocketHttpListener.Net.HttpStatusCode; using HttpStatusCode = SocketHttpListener.Net.HttpStatusCode;
@ -75,27 +74,6 @@ namespace SocketHttpListener
} }
} }
private static byte[] readBytes(this Stream stream, byte[] buffer, int offset, int length)
{
var len = stream.Read(buffer, offset, length);
if (len < 1)
return buffer.SubArray(0, offset);
var tmp = 0;
while (len < length)
{
tmp = stream.Read(buffer, offset + len, length - len);
if (tmp < 1)
break;
len += tmp;
}
return len < length
? buffer.SubArray(0, offset + len)
: buffer;
}
private static async Task<byte[]> ReadBytesAsync(this Stream stream, byte[] buffer, int offset, int length) private static async Task<byte[]> ReadBytesAsync(this Stream stream, byte[] buffer, int offset, int length)
{ {
var len = await stream.ReadAsync(buffer, offset, length).ConfigureAwait(false); var len = await stream.ReadAsync(buffer, offset, length).ConfigureAwait(false);
@ -119,15 +97,6 @@ namespace SocketHttpListener
: buffer; : buffer;
} }
private static bool readBytes(this Stream stream, byte[] buffer, int offset, int length, Stream dest)
{
var bytes = stream.readBytes(buffer, offset, length);
var len = bytes.Length;
dest.Write(bytes, 0, len);
return len == offset + length;
}
private static async Task<bool> ReadBytesAsync(this Stream stream, byte[] buffer, int offset, int length, Stream dest) private static async Task<bool> ReadBytesAsync(this Stream stream, byte[] buffer, int offset, int length, Stream dest)
{ {
var bytes = await stream.ReadBytesAsync(buffer, offset, length).ConfigureAwait(false); var bytes = await stream.ReadBytesAsync(buffer, offset, length).ConfigureAwait(false);
@ -141,16 +110,16 @@ namespace SocketHttpListener
#region Internal Methods #region Internal Methods
internal static byte[] Append(this ushort code, string reason) internal static async Task<byte[]> AppendAsync(this ushort code, string reason)
{ {
using (var buffer = new MemoryStream()) using (var buffer = new MemoryStream())
{ {
var tmp = code.ToByteArrayInternally(ByteOrder.Big); var tmp = code.ToByteArrayInternally(ByteOrder.Big);
buffer.Write(tmp, 0, 2); await buffer.WriteAsync(tmp, 0, 2).ConfigureAwait(false);
if (reason != null && reason.Length > 0) if (reason != null && reason.Length > 0)
{ {
tmp = Encoding.UTF8.GetBytes(reason); tmp = Encoding.UTF8.GetBytes(reason);
buffer.Write(tmp, 0, tmp.Length); await buffer.WriteAsync(tmp, 0, tmp.Length).ConfigureAwait(false);
} }
return buffer.ToArray(); return buffer.ToArray();

View file

@ -36,6 +36,25 @@ namespace SocketHttpListener.Net
HttpEndPointManager.AddPrefix(_logger, uriPrefix, listener); HttpEndPointManager.AddPrefix(_logger, uriPrefix, listener);
} }
public void AddRange(IEnumerable<string> uriPrefixes)
{
listener.CheckDisposed();
//ListenerPrefix.CheckUri(uriPrefix);
foreach (var uriPrefix in uriPrefixes)
{
if (prefixes.Contains(uriPrefix))
{
continue;
}
prefixes.Add(uriPrefix);
if (listener.IsListening)
{
HttpEndPointManager.AddPrefix(_logger, uriPrefix, listener);
}
}
}
public void Clear() public void Clear()
{ {
listener.CheckDisposed(); listener.CheckDisposed();

View file

@ -30,9 +30,9 @@ namespace SocketHttpListener
private CookieCollection _cookies; private CookieCollection _cookies;
private AutoResetEvent _exitReceiving; private AutoResetEvent _exitReceiving;
private object _forConn; private object _forConn;
private object _forEvent; private readonly SemaphoreSlim _forEvent = new SemaphoreSlim(1, 1);
private object _forMessageEventQueue; private object _forMessageEventQueue;
private object _forSend; private readonly SemaphoreSlim _forSend = new SemaphoreSlim(1, 1);
private const string _guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; private const string _guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
private Queue<MessageEventArgs> _messageEventQueue; private Queue<MessageEventArgs> _messageEventQueue;
private string _protocol; private string _protocol;
@ -109,12 +109,15 @@ namespace SocketHttpListener
#region Private Methods #region Private Methods
private void close(CloseStatusCode code, string reason, bool wait) private async Task CloseAsync(CloseStatusCode code, string reason, bool wait)
{ {
close(new PayloadData(((ushort)code).Append(reason)), !code.IsReserved(), wait); await CloseAsync(new PayloadData(
await ((ushort)code).AppendAsync(reason).ConfigureAwait(false)),
!code.IsReserved(),
wait).ConfigureAwait(false);
} }
private void close(PayloadData payload, bool send, bool wait) private async Task CloseAsync(PayloadData payload, bool send, bool wait)
{ {
lock (_forConn) lock (_forConn)
{ {
@ -126,11 +129,12 @@ namespace SocketHttpListener
_readyState = WebSocketState.CloseSent; _readyState = WebSocketState.CloseSent;
} }
var e = new CloseEventArgs(payload); var e = new CloseEventArgs(payload)
e.WasClean = {
closeHandshake( WasClean = await CloseHandshakeAsync(
send ? WebSocketFrame.CreateCloseFrame(Mask.Unmask, payload).ToByteArray() : null, send ? WebSocketFrame.CreateCloseFrame(Mask.Unmask, payload).ToByteArray() : null,
wait ? 1000 : 0); wait ? 1000 : 0).ConfigureAwait(false)
};
_readyState = WebSocketState.Closed; _readyState = WebSocketState.Closed;
try try
@ -143,9 +147,9 @@ namespace SocketHttpListener
} }
} }
private bool closeHandshake(byte[] frameAsBytes, int millisecondsTimeout) private async Task<bool> CloseHandshakeAsync(byte[] frameAsBytes, int millisecondsTimeout)
{ {
var sent = frameAsBytes != null && writeBytes(frameAsBytes); var sent = frameAsBytes != null && await WriteBytesAsync(frameAsBytes).ConfigureAwait(false);
var received = var received =
millisecondsTimeout == 0 || millisecondsTimeout == 0 ||
(sent && _exitReceiving != null && _exitReceiving.WaitOne(millisecondsTimeout)); (sent && _exitReceiving != null && _exitReceiving.WaitOne(millisecondsTimeout));
@ -221,7 +225,7 @@ namespace SocketHttpListener
// CLOSE // CLOSE
if (frame.IsClose) if (frame.IsClose)
return processCloseFrame(frame); return await ProcessCloseFrameAsync(frame).ConfigureAwait(false);
} }
else else
{ {
@ -236,10 +240,10 @@ namespace SocketHttpListener
} }
// ? // ?
return processUnsupportedFrame( return await ProcessUnsupportedFrameAsync(
frame, frame,
CloseStatusCode.IncorrectData, CloseStatusCode.IncorrectData,
"An incorrect data has been received while receiving fragmented data."); "An incorrect data has been received while receiving fragmented data.").ConfigureAwait(false);
} }
return true; return true;
@ -299,44 +303,42 @@ namespace SocketHttpListener
_compression = CompressionMethod.None; _compression = CompressionMethod.None;
_cookies = new CookieCollection(); _cookies = new CookieCollection();
_forConn = new object(); _forConn = new object();
_forEvent = new object();
_forSend = new object();
_messageEventQueue = new Queue<MessageEventArgs>(); _messageEventQueue = new Queue<MessageEventArgs>();
_forMessageEventQueue = ((ICollection)_messageEventQueue).SyncRoot; _forMessageEventQueue = ((ICollection)_messageEventQueue).SyncRoot;
_readyState = WebSocketState.Connecting; _readyState = WebSocketState.Connecting;
} }
private void open() private async Task OpenAsync()
{ {
try try
{ {
startReceiving(); startReceiving();
lock (_forEvent)
{
try
{
if (OnOpen != null)
{
OnOpen(this, EventArgs.Empty);
}
}
catch (Exception ex)
{
processException(ex, "An exception has occurred while OnOpen.");
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {
processException(ex, "An exception has occurred while opening."); await ProcessExceptionAsync(ex, "An exception has occurred while opening.").ConfigureAwait(false);
}
await _forEvent.WaitAsync().ConfigureAwait(false);
try
{
OnOpen?.Invoke(this, EventArgs.Empty);
}
catch (Exception ex)
{
await ProcessExceptionAsync(ex, "An exception has occurred while OnOpen.").ConfigureAwait(false);
}
finally
{
_forEvent.Release();
} }
} }
private bool processCloseFrame(WebSocketFrame frame) private async Task<bool> ProcessCloseFrameAsync(WebSocketFrame frame)
{ {
var payload = frame.PayloadData; var payload = frame.PayloadData;
close(payload, !payload.ContainsReservedCloseStatusCode, false); await CloseAsync(payload, !payload.ContainsReservedCloseStatusCode, false).ConfigureAwait(false);
return false; return false;
} }
@ -352,7 +354,7 @@ namespace SocketHttpListener
return true; return true;
} }
private void processException(Exception exception, string message) private async Task ProcessExceptionAsync(Exception exception, string message)
{ {
var code = CloseStatusCode.Abnormal; var code = CloseStatusCode.Abnormal;
var reason = message; var reason = message;
@ -365,9 +367,13 @@ namespace SocketHttpListener
error(message ?? code.GetMessage(), exception); error(message ?? code.GetMessage(), exception);
if (_readyState == WebSocketState.Connecting) if (_readyState == WebSocketState.Connecting)
Close(HttpStatusCode.BadRequest); {
await CloseAsync(HttpStatusCode.BadRequest).ConfigureAwait(false);
}
else else
close(code, reason ?? code.GetMessage(), false); {
await CloseAsync(code, reason ?? code.GetMessage(), false).ConfigureAwait(false);
}
} }
private Task<bool> ProcessFragmentedFrameAsync(WebSocketFrame frame) private Task<bool> ProcessFragmentedFrameAsync(WebSocketFrame frame)
@ -414,36 +420,37 @@ namespace SocketHttpListener
return true; return true;
} }
private bool processUnsupportedFrame(WebSocketFrame frame, CloseStatusCode code, string reason) private async Task<bool> ProcessUnsupportedFrameAsync(WebSocketFrame frame, CloseStatusCode code, string reason)
{ {
processException(new WebSocketException(code, reason), null); await ProcessExceptionAsync(new WebSocketException(code, reason), null).ConfigureAwait(false);
return false; return false;
} }
private async Task<bool> ProcessWebSocketFrameAsync(WebSocketFrame frame) private Task<bool> ProcessWebSocketFrameAsync(WebSocketFrame frame)
{ {
return frame.IsCompressed && _compression == CompressionMethod.None return frame.IsCompressed && _compression == CompressionMethod.None
? processUnsupportedFrame( ? ProcessUnsupportedFrameAsync(
frame, frame,
CloseStatusCode.IncorrectData, CloseStatusCode.IncorrectData,
"A compressed data has been received without available decompression method.") "A compressed data has been received without available decompression method.")
: frame.IsFragmented : frame.IsFragmented
? await ProcessFragmentedFrameAsync(frame).ConfigureAwait(false) ? ProcessFragmentedFrameAsync(frame)
: frame.IsData : frame.IsData
? processDataFrame(frame) ? Task.FromResult(processDataFrame(frame))
: frame.IsPing : frame.IsPing
? processPingFrame(frame) ? Task.FromResult(processPingFrame(frame))
: frame.IsPong : frame.IsPong
? processPongFrame(frame) ? Task.FromResult(processPongFrame(frame))
: frame.IsClose : frame.IsClose
? processCloseFrame(frame) ? ProcessCloseFrameAsync(frame)
: processUnsupportedFrame(frame, CloseStatusCode.PolicyViolation, null); : ProcessUnsupportedFrameAsync(frame, CloseStatusCode.PolicyViolation, null);
} }
private bool send(Opcode opcode, Stream stream) private async Task<bool> SendAsync(Opcode opcode, Stream stream)
{ {
lock (_forSend) await _forSend.WaitAsync().ConfigureAwait(false);
try
{ {
var src = stream; var src = stream;
var compressed = false; var compressed = false;
@ -456,7 +463,7 @@ namespace SocketHttpListener
compressed = true; compressed = true;
} }
sent = send(opcode, Mask.Unmask, stream, compressed); sent = await SendAsync(opcode, Mask.Unmask, stream, compressed).ConfigureAwait(false);
if (!sent) if (!sent)
error("Sending a data has been interrupted."); error("Sending a data has been interrupted.");
} }
@ -474,16 +481,20 @@ namespace SocketHttpListener
return sent; return sent;
} }
finally
{
_forSend.Release();
}
} }
private bool send(Opcode opcode, Mask mask, Stream stream, bool compressed) private async Task<bool> SendAsync(Opcode opcode, Mask mask, Stream stream, bool compressed)
{ {
var len = stream.Length; var len = stream.Length;
/* Not fragmented */ /* Not fragmented */
if (len == 0) if (len == 0)
return send(Fin.Final, opcode, mask, new byte[0], compressed); return await SendAsync(Fin.Final, opcode, mask, new byte[0], compressed).ConfigureAwait(false);
var quo = len / FragmentLength; var quo = len / FragmentLength;
var rem = (int)(len % FragmentLength); var rem = (int)(len % FragmentLength);
@ -492,26 +503,26 @@ namespace SocketHttpListener
if (quo == 0) if (quo == 0)
{ {
buff = new byte[rem]; buff = new byte[rem];
return stream.Read(buff, 0, rem) == rem && return await stream.ReadAsync(buff, 0, rem).ConfigureAwait(false) == rem &&
send(Fin.Final, opcode, mask, buff, compressed); await SendAsync(Fin.Final, opcode, mask, buff, compressed).ConfigureAwait(false);
} }
buff = new byte[FragmentLength]; buff = new byte[FragmentLength];
if (quo == 1 && rem == 0) if (quo == 1 && rem == 0)
return stream.Read(buff, 0, FragmentLength) == FragmentLength && return await stream.ReadAsync(buff, 0, FragmentLength).ConfigureAwait(false) == FragmentLength &&
send(Fin.Final, opcode, mask, buff, compressed); await SendAsync(Fin.Final, opcode, mask, buff, compressed).ConfigureAwait(false);
/* Send fragmented */ /* Send fragmented */
// Begin // Begin
if (stream.Read(buff, 0, FragmentLength) != FragmentLength || if (await stream.ReadAsync(buff, 0, FragmentLength).ConfigureAwait(false) != FragmentLength ||
!send(Fin.More, opcode, mask, buff, compressed)) !await SendAsync(Fin.More, opcode, mask, buff, compressed).ConfigureAwait(false))
return false; return false;
var n = rem == 0 ? quo - 2 : quo - 1; var n = rem == 0 ? quo - 2 : quo - 1;
for (long i = 0; i < n; i++) for (long i = 0; i < n; i++)
if (stream.Read(buff, 0, FragmentLength) != FragmentLength || if (await stream.ReadAsync(buff, 0, FragmentLength).ConfigureAwait(false) != FragmentLength ||
!send(Fin.More, Opcode.Cont, mask, buff, compressed)) !await SendAsync(Fin.More, Opcode.Cont, mask, buff, compressed).ConfigureAwait(false))
return false; return false;
// End // End
@ -520,47 +531,27 @@ namespace SocketHttpListener
else else
buff = new byte[rem]; buff = new byte[rem];
return stream.Read(buff, 0, rem) == rem && return await stream.ReadAsync(buff, 0, rem).ConfigureAwait(false) == rem &&
send(Fin.Final, Opcode.Cont, mask, buff, compressed); await SendAsync(Fin.Final, Opcode.Cont, mask, buff, compressed).ConfigureAwait(false);
} }
private bool send(Fin fin, Opcode opcode, Mask mask, byte[] data, bool compressed) private Task<bool> SendAsync(Fin fin, Opcode opcode, Mask mask, byte[] data, bool compressed)
{ {
lock (_forConn) lock (_forConn)
{ {
if (_readyState != WebSocketState.Open) if (_readyState != WebSocketState.Open)
{ {
return false; return Task.FromResult(false);
} }
return writeBytes( return WriteBytesAsync(
WebSocketFrame.CreateWebSocketFrame(fin, opcode, mask, data, compressed).ToByteArray()); WebSocketFrame.CreateWebSocketFrame(fin, opcode, mask, data, compressed).ToByteArray());
} }
} }
private Task sendAsync(Opcode opcode, Stream stream)
{
var completionSource = new TaskCompletionSource<bool>();
Task.Run(() =>
{
try
{
send(opcode, stream);
completionSource.TrySetResult(true);
}
catch (Exception ex)
{
completionSource.TrySetException(ex);
}
});
return completionSource.Task;
}
// As server // As server
private bool sendHttpResponse(HttpResponse response) private Task<bool> SendHttpResponseAsync(HttpResponse response)
{ => WriteBytesAsync(response.ToByteArray());
return writeBytes(response.ToByteArray());
}
private void startReceiving() private void startReceiving()
{ {
@ -583,37 +574,45 @@ namespace SocketHttpListener
receive(); receive();
if (!frame.IsData) if (!frame.IsData)
return;
lock (_forEvent)
{ {
try return;
}
await _forEvent.WaitAsync().ConfigureAwait(false);
try
{
var e = dequeueFromMessageEventQueue();
if (e != null && _readyState == WebSocketState.Open)
{ {
var e = dequeueFromMessageEventQueue(); OnMessage.Emit(this, e);
if (e != null && _readyState == WebSocketState.Open)
OnMessage.Emit(this, e);
}
catch (Exception ex)
{
processException(ex, "An exception has occurred while OnMessage.");
} }
} }
catch (Exception ex)
{
await ProcessExceptionAsync(ex, "An exception has occurred while OnMessage.").ConfigureAwait(false);
}
finally
{
_forEvent.Release();
}
} }
else if (_exitReceiving != null) else if (_exitReceiving != null)
{ {
_exitReceiving.Set(); _exitReceiving.Set();
} }
}, },
ex => processException(ex, "An exception has occurred while receiving a message.")); async ex => await ProcessExceptionAsync(ex, "An exception has occurred while receiving a message.")).ConfigureAwait(false);
receive(); receive();
} }
private bool writeBytes(byte[] data) private async Task<bool> WriteBytesAsync(byte[] data)
{ {
try try
{ {
_stream.Write(data, 0, data.Length); await _stream.WriteAsync(data, 0, data.Length).ConfigureAwait(false);
return true; return true;
} }
catch (Exception) catch (Exception)
@ -627,10 +626,10 @@ namespace SocketHttpListener
#region Internal Methods #region Internal Methods
// As server // As server
internal void Close(HttpResponse response) internal async Task CloseAsync(HttpResponse response)
{ {
_readyState = WebSocketState.CloseSent; _readyState = WebSocketState.CloseSent;
sendHttpResponse(response); await SendHttpResponseAsync(response).ConfigureAwait(false);
closeServerResources(); closeServerResources();
@ -638,22 +637,20 @@ namespace SocketHttpListener
} }
// As server // As server
internal void Close(HttpStatusCode code) internal Task CloseAsync(HttpStatusCode code)
{ => CloseAsync(createHandshakeCloseResponse(code));
Close(createHandshakeCloseResponse(code));
}
// As server // As server
public void ConnectAsServer() public async Task ConnectAsServer()
{ {
try try
{ {
_readyState = WebSocketState.Open; _readyState = WebSocketState.Open;
open(); await OpenAsync().ConfigureAwait(false);
} }
catch (Exception ex) catch (Exception ex)
{ {
processException(ex, "An exception has occurred while connecting."); await ProcessExceptionAsync(ex, "An exception has occurred while connecting.").ConfigureAwait(false);
} }
} }
@ -664,18 +661,18 @@ namespace SocketHttpListener
/// <summary> /// <summary>
/// Closes the WebSocket connection, and releases all associated resources. /// Closes the WebSocket connection, and releases all associated resources.
/// </summary> /// </summary>
public void Close() public Task CloseAsync()
{ {
var msg = _readyState.CheckIfClosable(); var msg = _readyState.CheckIfClosable();
if (msg != null) if (msg != null)
{ {
error(msg); error(msg);
return; return Task.CompletedTask;
} }
var send = _readyState == WebSocketState.Open; var send = _readyState == WebSocketState.Open;
close(new PayloadData(), send, send); return CloseAsync(new PayloadData(), send, send);
} }
/// <summary> /// <summary>
@ -693,11 +690,11 @@ namespace SocketHttpListener
/// <param name="reason"> /// <param name="reason">
/// A <see cref="string"/> that represents the reason for the close. /// A <see cref="string"/> that represents the reason for the close.
/// </param> /// </param>
public void Close(CloseStatusCode code, string reason) public async Task CloseAsync(CloseStatusCode code, string reason)
{ {
byte[] data = null; byte[] data = null;
var msg = _readyState.CheckIfClosable() ?? var msg = _readyState.CheckIfClosable() ??
(data = ((ushort)code).Append(reason)).CheckIfValidControlData("reason"); (data = await ((ushort)code).AppendAsync(reason).ConfigureAwait(false)).CheckIfValidControlData("reason");
if (msg != null) if (msg != null)
{ {
@ -707,7 +704,7 @@ namespace SocketHttpListener
} }
var send = _readyState == WebSocketState.Open && !code.IsReserved(); var send = _readyState == WebSocketState.Open && !code.IsReserved();
close(new PayloadData(data), send, send); await CloseAsync(new PayloadData(data), send, send).ConfigureAwait(false);
} }
/// <summary> /// <summary>
@ -732,7 +729,7 @@ namespace SocketHttpListener
throw new Exception(msg); throw new Exception(msg);
} }
return sendAsync(Opcode.Binary, new MemoryStream(data)); return SendAsync(Opcode.Binary, new MemoryStream(data));
} }
/// <summary> /// <summary>
@ -757,7 +754,7 @@ namespace SocketHttpListener
throw new Exception(msg); throw new Exception(msg);
} }
return sendAsync(Opcode.Text, new MemoryStream(Encoding.UTF8.GetBytes(data))); return SendAsync(Opcode.Text, new MemoryStream(Encoding.UTF8.GetBytes(data)));
} }
#endregion #endregion
@ -772,7 +769,7 @@ namespace SocketHttpListener
/// </remarks> /// </remarks>
void IDisposable.Dispose() void IDisposable.Dispose()
{ {
Close(CloseStatusCode.Away, null); CloseAsync(CloseStatusCode.Away, null).GetAwaiter().GetResult();
} }
#endregion #endregion

View file

@ -303,10 +303,10 @@ namespace SocketHttpListener
return new WebSocketFrame(Opcode.Close, mask, payload); return new WebSocketFrame(Opcode.Close, mask, payload);
} }
internal static WebSocketFrame CreateCloseFrame(Mask mask, CloseStatusCode code, string reason) internal static async Task<WebSocketFrame> CreateCloseFrameAsync(Mask mask, CloseStatusCode code, string reason)
{ {
return new WebSocketFrame( return new WebSocketFrame(
Opcode.Close, mask, new PayloadData(((ushort)code).Append(reason))); Opcode.Close, mask, new PayloadData(await ((ushort)code).AppendAsync(reason).ConfigureAwait(false)));
} }
internal static WebSocketFrame CreatePingFrame(Mask mask) internal static WebSocketFrame CreatePingFrame(Mask mask)