diff --git a/src/Discord.Net.Providers.WebSocketSharp/WebSocketSharpClient.cs b/src/Discord.Net.Providers.WebSocketSharp/WebSocketSharpClient.cs index 40aeed644..1bbb63fde 100644 --- a/src/Discord.Net.Providers.WebSocketSharp/WebSocketSharpClient.cs +++ b/src/Discord.Net.Providers.WebSocketSharp/WebSocketSharpClient.cs @@ -12,212 +12,212 @@ using WebSocketSharp; namespace Discord.Providers.WebSocketSharp { /// - /// WebSocket provider using websocket-sharp. - /// - internal class WebSocketSharpClient : IWebSocketClient, IDisposable - { - /// - public event Func BinaryMessage; - - /// - public event Func TextMessage; - - /// - public event Func Closed; - - private readonly SemaphoreSlim _lock; - private readonly Dictionary _headers; - private readonly ManualResetEventSlim _waitUntilConnect; - - private WebSocket _client; - private CancellationTokenSource _cancelTokenSource; - private CancellationToken _cancelToken; - private CancellationToken _parentToken; - - private bool _isDisposed; - - /// - /// Initializes a new instance of the class. - /// - public WebSocketSharpClient() - { - _headers = new Dictionary(); - _lock = new SemaphoreSlim(1, 1); - _cancelTokenSource = new CancellationTokenSource(); - _cancelToken = CancellationToken.None; - _parentToken = CancellationToken.None; - _waitUntilConnect = new ManualResetEventSlim(); - } - - /// - public void SetHeader(string key, string value) - { - _headers[key] = value; - } - - /// - public void SetCancelToken(CancellationToken cancelToken) - { - _parentToken = cancelToken; - _cancelToken = CancellationTokenSource.CreateLinkedTokenSource - ( - _parentToken, - _cancelTokenSource.Token - ) - .Token; - } - - /// - public async Task ConnectAsync(string host) - { - await _lock.WaitAsync().ConfigureAwait(false); - try - { - await ConnectInternalAsync(host).ConfigureAwait(false); - } - finally - { - _lock.Release(); - } - } - - private async Task ConnectInternalAsync(string host) - { - await DisconnectInternalAsync().ConfigureAwait(false); - - _cancelTokenSource = new CancellationTokenSource(); - _cancelToken = CancellationTokenSource.CreateLinkedTokenSource - ( - _parentToken, - _cancelTokenSource.Token - ) - .Token; - - _client = new WebSocket(host) - { - CustomHeaders = _headers.ToList() - }; - _client.SslConfiguration.EnabledSslProtocols = SslProtocols.Tls12; - - _client.OnMessage += OnMessage; - _client.OnOpen += OnConnected; - _client.OnClose += OnClosed; - - _client.Connect(); - _waitUntilConnect.Wait(_cancelToken); - } - - /// - public async Task DisconnectAsync() - { - await _lock.WaitAsync().ConfigureAwait(false); - try - { - await DisconnectInternalAsync().ConfigureAwait(false); - } - finally - { - _lock.Release(); - } - } - - private Task DisconnectInternalAsync() - { - _cancelTokenSource.Cancel(); - if (_client is null) - { - return Task.CompletedTask; - } - - if (_client.ReadyState == WebSocketState.Open) - { - _client.Close(); - } - - _client.OnMessage -= OnMessage; - _client.OnOpen -= OnConnected; - _client.OnClose -= OnClosed; - - _client = null; - _waitUntilConnect.Reset(); - - return Task.CompletedTask; - } - - private void OnMessage(object sender, MessageEventArgs messageEventArgs) - { - if (messageEventArgs.IsBinary) - { - OnBinaryMessage(messageEventArgs); - } - else if (messageEventArgs.IsText) - { - OnTextMessage(messageEventArgs); - } - } - - /// - public async Task SendAsync(byte[] data, int index, int count, bool isText) - { - await _lock.WaitAsync(_cancelToken).ConfigureAwait(false); - try - { - if (isText) - { - _client.Send(Encoding.UTF8.GetString(data, index, count)); - } - else - { - _client.Send(data.Skip(index).Take(count).ToArray()); - } - } - finally - { - _lock.Release(); - } - } - - private void OnTextMessage(MessageEventArgs e) - { - TextMessage?.Invoke(e.Data).GetAwaiter().GetResult(); - } - - private void OnBinaryMessage(MessageEventArgs e) - { - BinaryMessage?.Invoke(e.RawData, 0, e.RawData.Length).GetAwaiter().GetResult(); - } - - private void OnConnected(object sender, EventArgs e) - { - _waitUntilConnect.Set(); - } - - private void OnClosed(object sender, CloseEventArgs e) - { - if (e.WasClean) - { - Closed?.Invoke(null).GetAwaiter().GetResult(); - return; - } - - var ex = new WebSocketClosedException(e.Code, e.Reason); - Closed?.Invoke(ex).GetAwaiter().GetResult(); - } - - /// - public void Dispose() - { - if (_isDisposed) - { - return; - } - - DisconnectInternalAsync().GetAwaiter().GetResult(); - - ((IDisposable)_client)?.Dispose(); - _client = null; - - _isDisposed = true; - } - } + /// WebSocket provider using websocket-sharp. + /// + internal class WebSocketSharpClient : IWebSocketClient, IDisposable + { + /// + public event Func BinaryMessage; + + /// + public event Func TextMessage; + + /// + public event Func Closed; + + private readonly SemaphoreSlim _lock; + private readonly Dictionary _headers; + private readonly ManualResetEventSlim _waitUntilConnect; + + private WebSocket _client; + private CancellationTokenSource _cancelTokenSource; + private CancellationToken _cancelToken; + private CancellationToken _parentToken; + + private bool _isDisposed; + + /// + /// Initializes a new instance of the class. + /// + public WebSocketSharpClient() + { + _headers = new Dictionary(); + _lock = new SemaphoreSlim(1, 1); + _cancelTokenSource = new CancellationTokenSource(); + _cancelToken = CancellationToken.None; + _parentToken = CancellationToken.None; + _waitUntilConnect = new ManualResetEventSlim(); + } + + /// + public void SetHeader(string key, string value) + { + _headers[key] = value; + } + + /// + public void SetCancelToken(CancellationToken cancelToken) + { + _parentToken = cancelToken; + _cancelToken = CancellationTokenSource.CreateLinkedTokenSource + ( + _parentToken, + _cancelTokenSource.Token + ) + .Token; + } + + /// + public async Task ConnectAsync(string host) + { + await _lock.WaitAsync().ConfigureAwait(false); + try + { + await ConnectInternalAsync(host).ConfigureAwait(false); + } + finally + { + _lock.Release(); + } + } + + private async Task ConnectInternalAsync(string host) + { + await DisconnectInternalAsync().ConfigureAwait(false); + + _cancelTokenSource = new CancellationTokenSource(); + _cancelToken = CancellationTokenSource.CreateLinkedTokenSource + ( + _parentToken, + _cancelTokenSource.Token + ) + .Token; + + _client = new WebSocket(host) + { + CustomHeaders = _headers.ToList() + }; + _client.SslConfiguration.EnabledSslProtocols = SslProtocols.Tls12; + + _client.OnMessage += OnMessage; + _client.OnOpen += OnConnected; + _client.OnClose += OnClosed; + + _client.Connect(); + _waitUntilConnect.Wait(_cancelToken); + } + + /// + public async Task DisconnectAsync() + { + await _lock.WaitAsync().ConfigureAwait(false); + try + { + await DisconnectInternalAsync().ConfigureAwait(false); + } + finally + { + _lock.Release(); + } + } + + private Task DisconnectInternalAsync() + { + _cancelTokenSource.Cancel(); + if (_client is null) + { + return Task.CompletedTask; + } + + if (_client.ReadyState == WebSocketState.Open) + { + _client.Close(); + } + + _client.OnMessage -= OnMessage; + _client.OnOpen -= OnConnected; + _client.OnClose -= OnClosed; + + _client = null; + _waitUntilConnect.Reset(); + + return Task.CompletedTask; + } + + private void OnMessage(object sender, MessageEventArgs messageEventArgs) + { + if (messageEventArgs.IsBinary) + { + OnBinaryMessage(messageEventArgs); + } + else if (messageEventArgs.IsText) + { + OnTextMessage(messageEventArgs); + } + } + + /// + public async Task SendAsync(byte[] data, int index, int count, bool isText) + { + await _lock.WaitAsync(_cancelToken).ConfigureAwait(false); + try + { + if (isText) + { + _client.Send(Encoding.UTF8.GetString(data, index, count)); + } + else + { + _client.Send(data.Skip(index).Take(count).ToArray()); + } + } + finally + { + _lock.Release(); + } + } + + private void OnTextMessage(MessageEventArgs e) + { + TextMessage?.Invoke(e.Data).GetAwaiter().GetResult(); + } + + private void OnBinaryMessage(MessageEventArgs e) + { + BinaryMessage?.Invoke(e.RawData, 0, e.RawData.Length).GetAwaiter().GetResult(); + } + + private void OnConnected(object sender, EventArgs e) + { + _waitUntilConnect.Set(); + } + + private void OnClosed(object sender, CloseEventArgs e) + { + if (e.WasClean) + { + Closed?.Invoke(null).GetAwaiter().GetResult(); + return; + } + + var ex = new WebSocketClosedException(e.Code, e.Reason); + Closed?.Invoke(ex).GetAwaiter().GetResult(); + } + + /// + public void Dispose() + { + if (_isDisposed) + { + return; + } + + DisconnectInternalAsync().GetAwaiter().GetResult(); + + ((IDisposable)_client)?.Dispose(); + _client = null; + + _isDisposed = true; + } + } }