From 37431ba6ac433838e39558c2ad3573839209effc Mon Sep 17 00:00:00 2001 From: James Grant Date: Tue, 9 Jun 2020 14:59:21 +1000 Subject: [PATCH] Added async disposable interface to various components --- src/Discord.Net.Core/IDiscordClient.cs | 2 +- src/Discord.Net.Rest/BaseDiscordClient.cs | 15 ++++++++++ src/Discord.Net.Rest/DiscordRestApiClient.cs | 23 ++++++++++++++- src/Discord.Net.Rest/DiscordRestClient.cs | 8 +++++ .../Net/Queue/RequestQueue.cs | 18 ++++++++++-- .../DiscordShardedClient.cs | 20 +++++++++++++ .../DiscordSocketApiClient.cs | 29 +++++++++++++++++++ .../DiscordSocketClient.cs | 19 ++++++++++++ 8 files changed, 130 insertions(+), 4 deletions(-) diff --git a/src/Discord.Net.Core/IDiscordClient.cs b/src/Discord.Net.Core/IDiscordClient.cs index f972cd71d..848a97405 100644 --- a/src/Discord.Net.Core/IDiscordClient.cs +++ b/src/Discord.Net.Core/IDiscordClient.cs @@ -8,7 +8,7 @@ namespace Discord /// /// Represents a generic Discord client. /// - public interface IDiscordClient : IDisposable + public interface IDiscordClient : IDisposable, IAsyncDisposable { /// /// Gets the current state of connection. diff --git a/src/Discord.Net.Rest/BaseDiscordClient.cs b/src/Discord.Net.Rest/BaseDiscordClient.cs index 1837e38c0..500b55e28 100644 --- a/src/Discord.Net.Rest/BaseDiscordClient.cs +++ b/src/Discord.Net.Rest/BaseDiscordClient.cs @@ -145,9 +145,24 @@ namespace Discord.Rest _isDisposed = true; } } + + internal virtual async ValueTask DisposeAsync(bool disposing) + { + if (!_isDisposed) + { +#pragma warning disable IDISP007 + await ApiClient.DisposeAsync().ConfigureAwait(false); +#pragma warning restore IDISP007 + _stateLock?.Dispose(); + _isDisposed = true; + } + } + /// public void Dispose() => Dispose(true); + public ValueTask DisposeAsync() => DisposeAsync(true); + /// public Task GetRecommendedShardCountAsync(RequestOptions options = null) => ClientHelper.GetRecommendShardCountAsync(this, options); diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs index 732cb5f17..3a3d87f00 100644 --- a/src/Discord.Net.Rest/DiscordRestApiClient.cs +++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs @@ -22,7 +22,7 @@ using System.Threading.Tasks; namespace Discord.API { - internal class DiscordRestApiClient : IDisposable + internal class DiscordRestApiClient : IDisposable, IAsyncDisposable { private static readonly ConcurrentDictionary> _bucketIdGenerators = new ConcurrentDictionary>(); @@ -106,8 +106,29 @@ namespace Discord.API _isDisposed = true; } } + + internal virtual async ValueTask DisposeAsync(bool disposing) + { + if (!_isDisposed) + { + if (disposing) + { + _loginCancelToken?.Dispose(); + RestClient?.Dispose(); + + if (!(RequestQueue is null)) + await RequestQueue.DisposeAsync().ConfigureAwait(false); + + _stateLock?.Dispose(); + } + _isDisposed = true; + } + } + public void Dispose() => Dispose(true); + public ValueTask DisposeAsync() => DisposeAsync(true); + public async Task LoginAsync(TokenType tokenType, string token, RequestOptions options = null) { await _stateLock.WaitAsync().ConfigureAwait(false); diff --git a/src/Discord.Net.Rest/DiscordRestClient.cs b/src/Discord.Net.Rest/DiscordRestClient.cs index 4c29d1625..da4bb27d1 100644 --- a/src/Discord.Net.Rest/DiscordRestClient.cs +++ b/src/Discord.Net.Rest/DiscordRestClient.cs @@ -41,6 +41,14 @@ namespace Discord.Rest base.Dispose(disposing); } + internal override async ValueTask DisposeAsync(bool disposing) + { + if (disposing) + await ApiClient.DisposeAsync().ConfigureAwait(false); + + base.Dispose(disposing); + } + /// internal override async Task OnLoginAsync(TokenType tokenType, string token) { diff --git a/src/Discord.Net.Rest/Net/Queue/RequestQueue.cs b/src/Discord.Net.Rest/Net/Queue/RequestQueue.cs index 6560b049d..8ddb79596 100644 --- a/src/Discord.Net.Rest/Net/Queue/RequestQueue.cs +++ b/src/Discord.Net.Rest/Net/Queue/RequestQueue.cs @@ -1,3 +1,4 @@ +using Newtonsoft.Json.Bson; using System; using System.Collections.Concurrent; #if DEBUG_LIMITS @@ -10,7 +11,7 @@ using System.Threading.Tasks; namespace Discord.Net.Queue { - internal class RequestQueue : IDisposable + internal class RequestQueue : IDisposable, IAsyncDisposable { public event Func RateLimitTriggered; @@ -143,12 +144,25 @@ namespace Discord.Net.Queue if (!(_cancelTokenSource is null)) { _cancelTokenSource.Cancel(); - _cancelTokenSource?.Dispose(); + _cancelTokenSource.Dispose(); _cleanupTask.GetAwaiter().GetResult(); } _tokenLock?.Dispose(); _clearToken?.Dispose(); _requestCancelTokenSource?.Dispose(); } + + public async ValueTask DisposeAsync() + { + if (!(_cancelTokenSource is null)) + { + _cancelTokenSource.Cancel(); + _cancelTokenSource.Dispose(); + await _cleanupTask.ConfigureAwait(false); + } + _tokenLock?.Dispose(); + _clearToken?.Dispose(); + _requestCancelTokenSource?.Dispose(); + } } } diff --git a/src/Discord.Net.WebSocket/DiscordShardedClient.cs b/src/Discord.Net.WebSocket/DiscordShardedClient.cs index 8359ca048..b61929210 100644 --- a/src/Discord.Net.WebSocket/DiscordShardedClient.cs +++ b/src/Discord.Net.WebSocket/DiscordShardedClient.cs @@ -402,5 +402,25 @@ namespace Discord.WebSocket base.Dispose(disposing); } + + internal override ValueTask DisposeAsync(bool disposing) + { + if (!_isDisposed) + { + if (disposing) + { + if (_shards != null) + { + foreach (var client in _shards) + client?.Dispose(); + } + _connectionGroupLock?.Dispose(); + } + + _isDisposed = true; + } + + return base.DisposeAsync(disposing); + } } } diff --git a/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs b/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs index ef97615e2..3434ddeaf 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs @@ -114,6 +114,35 @@ namespace Discord.API base.Dispose(disposing); } +#if NETSTANDARD2_1 + internal override async ValueTask DisposeAsync(bool disposing) +#else + internal override ValueTask DisposeAsync(bool disposing) +#endif + { + if (!_isDisposed) + { + if (disposing) + { + _connectCancelToken?.Dispose(); + (WebSocketClient as IDisposable)?.Dispose(); +#if NETSTANDARD2_1 + if (!(_decompressor is null)) + await _decompressor.DisposeAsync().ConfigureAwait(false); +#else + _decompressor?.Dispose(); +#endif + } + _isDisposed = true; + } + +#if NETSTANDARD2_1 + await base.DisposeAsync(disposing).ConfigureAwait(false); +#else + return base.DisposeAsync(disposing); +#endif + } + public async Task ConnectAsync() { await _stateLock.WaitAsync().ConfigureAwait(false); diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.cs index b56498061..a21d3aef9 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketClient.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketClient.cs @@ -197,6 +197,25 @@ namespace Discord.WebSocket base.Dispose(disposing); } + internal override async ValueTask DisposeAsync(bool disposing) + { + if (!_isDisposed) + { + if (disposing) + { + await StopAsync().ConfigureAwait(false); + + if (!(ApiClient is null)) + await ApiClient.DisposeAsync().ConfigureAwait(false); + + _stateLock?.Dispose(); + } + _isDisposed = true; + } + + await base.DisposeAsync(disposing).ConfigureAwait(false); + } + /// internal override async Task OnLoginAsync(TokenType tokenType, string token) {