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)
{