diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 2fe5abfe8..9aa0e5788 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -39,4 +39,3 @@ jobs:
steps:
- template: azure/build.yml
- template: azure/deploy.yml
- - template: azure/docs.yml
diff --git a/src/Discord.Net.Core/Entities/Messages/IMessage.cs b/src/Discord.Net.Core/Entities/Messages/IMessage.cs
index cba8ce29f..f80abbe38 100644
--- a/src/Discord.Net.Core/Entities/Messages/IMessage.cs
+++ b/src/Discord.Net.Core/Entities/Messages/IMessage.cs
@@ -10,7 +10,7 @@ namespace Discord
public interface IMessage : ISnowflakeEntity, IDeletable
{
///
- /// Gets the type of this system message.
+ /// Gets the type of this message.
///
MessageType Type { get; }
///
diff --git a/src/Discord.Net.Rest/DiscordRestClient.cs b/src/Discord.Net.Rest/DiscordRestClient.cs
index 75d829ba0..5ac18ff57 100644
--- a/src/Discord.Net.Rest/DiscordRestClient.cs
+++ b/src/Discord.Net.Rest/DiscordRestClient.cs
@@ -16,7 +16,7 @@ namespace Discord.Rest
///
/// Gets the logged-in user.
///
- public new RestSelfUser CurrentUser => base.CurrentUser as RestSelfUser;
+ public new RestSelfUser CurrentUser { get => base.CurrentUser as RestSelfUser; internal set => base.CurrentUser = value; }
///
public DiscordRestClient() : this(new DiscordRestConfig()) { }
diff --git a/src/Discord.Net.Rest/Entities/Messages/RestMessage.cs b/src/Discord.Net.Rest/Entities/Messages/RestMessage.cs
index 4ce655fcb..fd4b1ffb4 100644
--- a/src/Discord.Net.Rest/Entities/Messages/RestMessage.cs
+++ b/src/Discord.Net.Rest/Entities/Messages/RestMessage.cs
@@ -72,6 +72,8 @@ namespace Discord.Rest
public MessageReference Reference { get; private set; }
///
public MessageFlags? Flags { get; private set; }
+ ///
+ public MessageType Type { get; private set; }
///
public IReadOnlyCollection Components { get; private set; }
@@ -92,6 +94,8 @@ namespace Discord.Rest
}
internal virtual void Update(Model model)
{
+ Type = model.Type;
+
if (model.Timestamp.IsSpecified)
_timestampTicks = model.Timestamp.Value.UtcTicks;
@@ -219,8 +223,6 @@ namespace Discord.Rest
///
public override string ToString() => Content;
- ///
- MessageType IMessage.Type => MessageType.Default;
IUser IMessage.Author => Author;
///
IReadOnlyCollection IMessage.Attachments => Attachments;
diff --git a/src/Discord.Net.Rest/Entities/Messages/RestSystemMessage.cs b/src/Discord.Net.Rest/Entities/Messages/RestSystemMessage.cs
index 89a651eb7..1c59d4f45 100644
--- a/src/Discord.Net.Rest/Entities/Messages/RestSystemMessage.cs
+++ b/src/Discord.Net.Rest/Entities/Messages/RestSystemMessage.cs
@@ -9,9 +9,6 @@ namespace Discord.Rest
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestSystemMessage : RestMessage, ISystemMessage
{
- ///
- public MessageType Type { get; private set; }
-
internal RestSystemMessage(BaseDiscordClient discord, ulong id, IMessageChannel channel, IUser author)
: base(discord, id, channel, author, MessageSource.System)
{
@@ -25,8 +22,6 @@ namespace Discord.Rest
internal override void Update(Model model)
{
base.Update(model);
-
- Type = model.Type;
}
private string DebuggerDisplay => $"{Author}: {Content} ({Id}, {Type})";
diff --git a/src/Discord.Net.WebSocket/ConnectionManager.cs b/src/Discord.Net.WebSocket/ConnectionManager.cs
index 2237e2d1f..e444f359f 100644
--- a/src/Discord.Net.WebSocket/ConnectionManager.cs
+++ b/src/Discord.Net.WebSocket/ConnectionManager.cs
@@ -75,11 +75,6 @@ namespace Discord
nextReconnectDelay = 1000; //Reset delay
await _connectionPromise.Task.ConfigureAwait(false);
}
- catch (OperationCanceledException ex)
- {
- Cancel(); //In case this exception didn't come from another Error call
- await DisconnectAsync(ex, !reconnectCancelToken.IsCancellationRequested).ConfigureAwait(false);
- }
catch (Exception ex)
{
Error(ex); //In case this exception didn't come from another Error call
@@ -143,16 +138,7 @@ namespace Discord
catch (OperationCanceledException) { }
});
- try
- {
- await _onConnecting().ConfigureAwait(false);
- }
- catch (TaskCanceledException ex)
- {
- Exception innerEx = ex.InnerException ?? new OperationCanceledException("Failed to connect.");
- Error(innerEx);
- throw innerEx;
- }
+ await _onConnecting().ConfigureAwait(false);
await _logger.InfoAsync("Connected").ConfigureAwait(false);
State = ConnectionState.Connected;
diff --git a/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs b/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs
index d1407da01..65fd23d3f 100644
--- a/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs
+++ b/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs
@@ -188,9 +188,9 @@ namespace Discord.API
catch { }
if (ex is GatewayReconnectException)
- await WebSocketClient.DisconnectAsync(4000);
+ await WebSocketClient.DisconnectAsync(4000).ConfigureAwait(false);
else
- await WebSocketClient.DisconnectAsync().ConfigureAwait(false);
+ await WebSocketClient.DisconnectAsync().ConfigureAwait(false);
ConnectionState = ConnectionState.Disconnected;
}
diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.cs
index be468fe30..f9eaeb005 100644
--- a/src/Discord.Net.WebSocket/DiscordSocketClient.cs
+++ b/src/Discord.Net.WebSocket/DiscordSocketClient.cs
@@ -621,6 +621,7 @@ namespace Discord.WebSocket
var activities = _activity.IsSpecified ? ImmutableList.Create(_activity.Value) : null;
currentUser.Presence = new SocketPresence(Status, null, activities);
ApiClient.CurrentUserId = currentUser.Id;
+ Rest.CurrentUser = RestSelfUser.Create(this, data.User);
int unavailableGuilds = 0;
for (int i = 0; i < data.Guilds.Length; i++)
{
diff --git a/src/Discord.Net.WebSocket/Entities/Invites/ISocketInvite.cs b/src/Discord.Net.WebSocket/Entities/Invites/ISocketInvite.cs
deleted file mode 100644
index 8fe82b089..000000000
--- a/src/Discord.Net.WebSocket/Entities/Invites/ISocketInvite.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Discord.WebSocket
-{
- public interface ISocketInvite
- {
- ///
- /// Gets the unique identifier for this invite.
- ///
- ///
- /// A string containing the invite code (e.g. FTqNnyS).
- ///
- string Code { get; }
- ///
- /// Gets the URL used to accept this invite
- ///
- ///
- /// A string containing the full invite URL (e.g. https://discord.gg/FTqNnyS).
- ///
- string Url { get; }
-
- ///
- /// Gets the channel this invite is linked to.
- ///
- ///
- /// A generic channel that the invite points to.
- ///
- SocketGuildChannel Channel { get; }
-
- ///
- /// Gets the guild this invite is linked to.
- ///
- ///
- /// A guild object representing the guild that the invite points to.
- ///
- SocketGuild Guild { get; }
- }
-}
diff --git a/src/Discord.Net.WebSocket/Entities/Invites/InviteCache.cs b/src/Discord.Net.WebSocket/Entities/Invites/InviteCache.cs
deleted file mode 100644
index a203b780f..000000000
--- a/src/Discord.Net.WebSocket/Entities/Invites/InviteCache.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Discord.WebSocket
-{
- internal class InviteCache
- {
- private readonly ConcurrentDictionary _invites;
- private readonly ConcurrentQueue _queue;
- private static int _size;
-
- public InviteCache(DiscordSocketClient client)
- {
- //NOTE:
- //This should be an option in the client config. default for now is 20 invites per guild
- _size = client.Guilds.Count * 20;
-
- _invites = new ConcurrentDictionary();
- _queue = new ConcurrentQueue();
- }
- public void Add(SocketGuildInvite invite)
- {
- if(_invites.TryAdd(invite.Code, invite))
- {
- _queue.Enqueue(invite.Code);
-
- while (_queue.Count > _size && _queue.TryDequeue(out string invCode))
- _invites.TryRemove(invCode, out _);
- }
- }
- public SocketGuildInvite Remove(string inviteCode)
- {
- _invites.TryRemove(inviteCode, out SocketGuildInvite inv);
- return inv;
- }
- public SocketGuildInvite Get(string inviteCode)
- {
- if(_invites.TryGetValue(inviteCode, out SocketGuildInvite inv))
- return inv;
- return null;
- }
- }
-}
diff --git a/src/Discord.Net.WebSocket/Entities/Invites/SocketGuildInvite.cs b/src/Discord.Net.WebSocket/Entities/Invites/SocketGuildInvite.cs
deleted file mode 100644
index 35fdf237c..000000000
--- a/src/Discord.Net.WebSocket/Entities/Invites/SocketGuildInvite.cs
+++ /dev/null
@@ -1,112 +0,0 @@
-using Discord.Rest;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.Serialization.Formatters;
-using System.Text;
-using System.Threading.Tasks;
-using InviteUpdate = Discord.API.Gateway.InviteCreatedEvent;
-
-namespace Discord.WebSocket
-{
- ///
- /// Represents a guild invite
- ///
- public class SocketGuildInvite : SocketEntity, ISocketInvite
- {
- public string Code { get; private set; }
- public string Url => $"{DiscordConfig.InviteUrl}{Code}";
- public SocketGuildChannel Channel { get; private set; }
- public SocketGuild Guild { get; private set; }
- ///
- /// Gets the unique invite code
- ///
- /// Returns the unique invite code
- ///
- ///
- public string Id => Code;
- ///
- /// Gets the user who created the invite
- ///
- /// Returns the user who created the invite
- ///
- ///
- public SocketGuildUser Inviter { get; private set; }
- ///
- /// Gets the maximum number of times the invite can be used, if there is no limit then the value will be 0
- ///
- /// Returns the maximum number of times the invite can be used, if there is no limit then the value will be 0
- ///
- ///
- public int? MaxUses { get; private set; }
- ///
- /// Gets whether or not the invite is temporary (invited users will be kicked on disconnect unless they're assigned a role)
- ///
- /// Returns whether or not the invite is temporary (invited users will be kicked on disconnect unless they're assigned a role)
- ///
- ///
- public bool Temporary { get; private set; }
- ///
- /// Gets the time at which the invite was created
- ///
- /// Returns the time at which the invite was created
- ///
- ///
- public DateTimeOffset? CreatedAt { get; private set; }
- ///
- /// Gets how long the invite is valid for
- ///
- /// Returns how long the invite is valid for (in seconds)
- ///
- ///
- public TimeSpan? MaxAge { get; private set; }
-
- internal SocketGuildInvite(DiscordSocketClient _client, SocketGuild guild, SocketGuildChannel channel, string inviteCode, RestInviteMetadata rest) : base(_client, inviteCode)
- {
- Code = inviteCode;
- Guild = guild;
- Channel = channel;
- CreatedAt = rest.CreatedAt;
- Temporary = rest.IsTemporary;
- MaxUses = rest.MaxUses;
- Inviter = guild.GetUser(rest.Inviter.Id);
- if (rest.MaxAge.HasValue)
- MaxAge = TimeSpan.FromSeconds(rest.MaxAge.Value);
- }
- internal SocketGuildInvite(DiscordSocketClient _client, SocketGuild guild, SocketGuildChannel channel, string inviteCode, InviteUpdate Update) : base(_client, inviteCode)
- {
- Code = inviteCode;
- Guild = guild;
- Channel = channel;
-
- if (Update.RawTimestamp.IsSpecified)
- CreatedAt = Update.RawTimestamp.Value;
- else
- CreatedAt = DateTimeOffset.Now;
-
- if (Update.inviter.IsSpecified)
- Inviter = guild.GetUser(Update.inviter.Value.Id);
-
- Temporary = Update.TempInvite;
- MaxUses = Update.MaxUsers;
- MaxAge = TimeSpan.FromSeconds(Update.RawAge);
- }
- internal static SocketGuildInvite Create(DiscordSocketClient _client, SocketGuild guild, SocketGuildChannel channel, string inviteCode, InviteUpdate Update)
- {
- var invite = new SocketGuildInvite(_client, guild, channel, inviteCode, Update);
- return invite;
- }
- internal static SocketGuildInvite CreateFromRest(DiscordSocketClient _client, SocketGuild guild, SocketGuildChannel channel, string inviteCode, RestInviteMetadata rest)
- {
- var invite = new SocketGuildInvite(_client, guild, channel, inviteCode, rest);
- return invite;
- }
- ///
- /// Deletes the invite
- ///
- ///
- ///
- public Task DeleteAsync(RequestOptions options = null)
- => SocketInviteHelper.DeleteAsync(this, Discord, options);
- }
-}
diff --git a/src/Discord.Net.WebSocket/Entities/Invites/SocketInviteHelper.cs b/src/Discord.Net.WebSocket/Entities/Invites/SocketInviteHelper.cs
deleted file mode 100644
index 3781739a9..000000000
--- a/src/Discord.Net.WebSocket/Entities/Invites/SocketInviteHelper.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Discord.WebSocket
-{
- internal class SocketInviteHelper
- {
- public static async Task DeleteAsync(ISocketInvite invite, BaseSocketClient client,
- RequestOptions options)
- {
- await client.ApiClient.DeleteInviteAsync(invite.Code, options).ConfigureAwait(false);
- }
- }
-}
diff --git a/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs b/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs
index 8ec18d49e..b6619421b 100644
--- a/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs
+++ b/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs
@@ -65,6 +65,9 @@ namespace Discord.WebSocket
///
public MessageFlags? Flags { get; private set; }
+ ///
+ public MessageType Type { get; private set; }
+
///
/// Returns all attachments included in this message.
///
@@ -126,6 +129,8 @@ namespace Discord.WebSocket
}
internal virtual void Update(ClientState state, Model model)
{
+ Type = model.Type;
+
if (model.Timestamp.IsSpecified)
_timestampTicks = model.Timestamp.Value.UtcTicks;
@@ -238,8 +243,6 @@ namespace Discord.WebSocket
///
IMessageChannel IMessage.Channel => Channel;
///
- MessageType IMessage.Type => MessageType.Default;
- ///
IReadOnlyCollection IMessage.Attachments => Attachments;
///
IReadOnlyCollection IMessage.Embeds => Embeds;
diff --git a/src/Discord.Net.WebSocket/Entities/Messages/SocketSystemMessage.cs b/src/Discord.Net.WebSocket/Entities/Messages/SocketSystemMessage.cs
index d0ce5025b..ec22a7703 100644
--- a/src/Discord.Net.WebSocket/Entities/Messages/SocketSystemMessage.cs
+++ b/src/Discord.Net.WebSocket/Entities/Messages/SocketSystemMessage.cs
@@ -9,9 +9,6 @@ namespace Discord.WebSocket
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class SocketSystemMessage : SocketMessage, ISystemMessage
{
- ///
- public MessageType Type { get; private set; }
-
internal SocketSystemMessage(DiscordSocketClient discord, ulong id, ISocketMessageChannel channel, SocketUser author)
: base(discord, id, channel, author, MessageSource.System)
{
@@ -25,8 +22,6 @@ namespace Discord.WebSocket
internal override void Update(ClientState state, Model model)
{
base.Update(state, model);
-
- Type = model.Type;
}
private string DebuggerDisplay => $"{Author}: {Content} ({Id}, {Type})";
diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs
index 9263fe642..444c76ffa 100644
--- a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs
+++ b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs
@@ -125,12 +125,16 @@ namespace Discord.WebSocket
{
var entity = new SocketGuildUser(guild, guild.Discord.GetOrCreateUser(state, model.User));
entity.Update(state, model);
+ if (!model.Roles.IsSpecified)
+ entity.UpdateRoles(new ulong[0]);
return entity;
}
internal static SocketGuildUser Create(SocketGuild guild, ClientState state, PresenceModel model)
{
var entity = new SocketGuildUser(guild, guild.Discord.GetOrCreateUser(state, model.User));
entity.Update(state, model, false);
+ if (!model.Roles.IsSpecified)
+ entity.UpdateRoles(new ulong[0]);
return entity;
}
internal void Update(ClientState state, MemberModel model)
diff --git a/src/Discord.Net.WebSocket/Net/DefaultWebSocketClient.cs b/src/Discord.Net.WebSocket/Net/DefaultWebSocketClient.cs
index 4723ae57a..82e2f0573 100644
--- a/src/Discord.Net.WebSocket/Net/DefaultWebSocketClient.cs
+++ b/src/Discord.Net.WebSocket/Net/DefaultWebSocketClient.cs
@@ -108,11 +108,11 @@ namespace Discord.Net.WebSockets
}
private async Task DisconnectInternalAsync(int closeCode = 1000, bool isDisposing = false)
{
+ _isDisconnecting = true;
+
try { _disconnectTokenSource.Cancel(false); }
catch { }
- _isDisconnecting = true;
-
if (_client != null)
{
if (!isDisposing)
@@ -166,7 +166,14 @@ namespace Discord.Net.WebSockets
public async Task SendAsync(byte[] data, int index, int count, bool isText)
{
- await _lock.WaitAsync().ConfigureAwait(false);
+ try
+ {
+ await _lock.WaitAsync(_cancelToken).ConfigureAwait(false);
+ }
+ catch (TaskCanceledException)
+ {
+ return;
+ }
try
{
if (_client == null) return;
@@ -201,7 +208,7 @@ namespace Discord.Net.WebSockets
{
while (!cancelToken.IsCancellationRequested)
{
- WebSocketReceiveResult socketResult = await _client.ReceiveAsync(buffer, CancellationToken.None).ConfigureAwait(false);
+ WebSocketReceiveResult socketResult = await _client.ReceiveAsync(buffer, cancelToken).ConfigureAwait(false);
byte[] result;
int resultCount;