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;