| @@ -39,4 +39,3 @@ jobs: | |||||
| steps: | steps: | ||||
| - template: azure/build.yml | - template: azure/build.yml | ||||
| - template: azure/deploy.yml | - template: azure/deploy.yml | ||||
| - template: azure/docs.yml | |||||
| @@ -10,7 +10,7 @@ namespace Discord | |||||
| public interface IMessage : ISnowflakeEntity, IDeletable | public interface IMessage : ISnowflakeEntity, IDeletable | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// Gets the type of this system message. | |||||
| /// Gets the type of this message. | |||||
| /// </summary> | /// </summary> | ||||
| MessageType Type { get; } | MessageType Type { get; } | ||||
| /// <summary> | /// <summary> | ||||
| @@ -16,7 +16,7 @@ namespace Discord.Rest | |||||
| /// <summary> | /// <summary> | ||||
| /// Gets the logged-in user. | /// Gets the logged-in user. | ||||
| /// </summary> | /// </summary> | ||||
| public new RestSelfUser CurrentUser => base.CurrentUser as RestSelfUser; | |||||
| public new RestSelfUser CurrentUser { get => base.CurrentUser as RestSelfUser; internal set => base.CurrentUser = value; } | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public DiscordRestClient() : this(new DiscordRestConfig()) { } | public DiscordRestClient() : this(new DiscordRestConfig()) { } | ||||
| @@ -71,6 +71,8 @@ namespace Discord.Rest | |||||
| public MessageReference Reference { get; private set; } | public MessageReference Reference { get; private set; } | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public MessageFlags? Flags { get; private set; } | public MessageFlags? Flags { get; private set; } | ||||
| /// <inheritdoc/> | |||||
| public MessageType Type { get; private set; } | |||||
| internal RestMessage(BaseDiscordClient discord, ulong id, IMessageChannel channel, IUser author, MessageSource source) | internal RestMessage(BaseDiscordClient discord, ulong id, IMessageChannel channel, IUser author, MessageSource source) | ||||
| : base(discord, id) | : base(discord, id) | ||||
| @@ -88,6 +90,8 @@ namespace Discord.Rest | |||||
| } | } | ||||
| internal virtual void Update(Model model) | internal virtual void Update(Model model) | ||||
| { | { | ||||
| Type = model.Type; | |||||
| if (model.Timestamp.IsSpecified) | if (model.Timestamp.IsSpecified) | ||||
| _timestampTicks = model.Timestamp.Value.UtcTicks; | _timestampTicks = model.Timestamp.Value.UtcTicks; | ||||
| @@ -166,8 +170,6 @@ namespace Discord.Rest | |||||
| /// </returns> | /// </returns> | ||||
| public override string ToString() => Content; | public override string ToString() => Content; | ||||
| /// <inheritdoc /> | |||||
| MessageType IMessage.Type => MessageType.Default; | |||||
| IUser IMessage.Author => Author; | IUser IMessage.Author => Author; | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| IReadOnlyCollection<IAttachment> IMessage.Attachments => Attachments; | IReadOnlyCollection<IAttachment> IMessage.Attachments => Attachments; | ||||
| @@ -9,9 +9,6 @@ namespace Discord.Rest | |||||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | ||||
| public class RestSystemMessage : RestMessage, ISystemMessage | public class RestSystemMessage : RestMessage, ISystemMessage | ||||
| { | { | ||||
| /// <inheritdoc /> | |||||
| public MessageType Type { get; private set; } | |||||
| internal RestSystemMessage(BaseDiscordClient discord, ulong id, IMessageChannel channel, IUser author) | internal RestSystemMessage(BaseDiscordClient discord, ulong id, IMessageChannel channel, IUser author) | ||||
| : base(discord, id, channel, author, MessageSource.System) | : base(discord, id, channel, author, MessageSource.System) | ||||
| { | { | ||||
| @@ -25,8 +22,6 @@ namespace Discord.Rest | |||||
| internal override void Update(Model model) | internal override void Update(Model model) | ||||
| { | { | ||||
| base.Update(model); | base.Update(model); | ||||
| Type = model.Type; | |||||
| } | } | ||||
| private string DebuggerDisplay => $"{Author}: {Content} ({Id}, {Type})"; | private string DebuggerDisplay => $"{Author}: {Content} ({Id}, {Type})"; | ||||
| @@ -75,11 +75,6 @@ namespace Discord | |||||
| nextReconnectDelay = 1000; //Reset delay | nextReconnectDelay = 1000; //Reset delay | ||||
| await _connectionPromise.Task.ConfigureAwait(false); | 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) | catch (Exception ex) | ||||
| { | { | ||||
| Error(ex); //In case this exception didn't come from another Error call | Error(ex); //In case this exception didn't come from another Error call | ||||
| @@ -143,16 +138,7 @@ namespace Discord | |||||
| catch (OperationCanceledException) { } | 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); | await _logger.InfoAsync("Connected").ConfigureAwait(false); | ||||
| State = ConnectionState.Connected; | State = ConnectionState.Connected; | ||||
| @@ -188,9 +188,9 @@ namespace Discord.API | |||||
| catch { } | catch { } | ||||
| if (ex is GatewayReconnectException) | if (ex is GatewayReconnectException) | ||||
| await WebSocketClient.DisconnectAsync(4000); | |||||
| await WebSocketClient.DisconnectAsync(4000).ConfigureAwait(false); | |||||
| else | else | ||||
| await WebSocketClient.DisconnectAsync().ConfigureAwait(false); | |||||
| await WebSocketClient.DisconnectAsync().ConfigureAwait(false); | |||||
| ConnectionState = ConnectionState.Disconnected; | ConnectionState = ConnectionState.Disconnected; | ||||
| } | } | ||||
| @@ -618,6 +618,7 @@ namespace Discord.WebSocket | |||||
| var activities = _activity.IsSpecified ? ImmutableList.Create(_activity.Value) : null; | var activities = _activity.IsSpecified ? ImmutableList.Create(_activity.Value) : null; | ||||
| currentUser.Presence = new SocketPresence(Status, null, activities); | currentUser.Presence = new SocketPresence(Status, null, activities); | ||||
| ApiClient.CurrentUserId = currentUser.Id; | ApiClient.CurrentUserId = currentUser.Id; | ||||
| Rest.CurrentUser = RestSelfUser.Create(this, data.User); | |||||
| int unavailableGuilds = 0; | int unavailableGuilds = 0; | ||||
| for (int i = 0; i < data.Guilds.Length; i++) | for (int i = 0; i < data.Guilds.Length; i++) | ||||
| { | { | ||||
| @@ -61,6 +61,9 @@ namespace Discord.WebSocket | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public MessageFlags? Flags { get; private set; } | public MessageFlags? Flags { get; private set; } | ||||
| /// <inheritdoc/> | |||||
| public MessageType Type { get; private set; } | |||||
| /// <summary> | /// <summary> | ||||
| /// Returns all attachments included in this message. | /// Returns all attachments included in this message. | ||||
| /// </summary> | /// </summary> | ||||
| @@ -122,6 +125,8 @@ namespace Discord.WebSocket | |||||
| } | } | ||||
| internal virtual void Update(ClientState state, Model model) | internal virtual void Update(ClientState state, Model model) | ||||
| { | { | ||||
| Type = model.Type; | |||||
| if (model.Timestamp.IsSpecified) | if (model.Timestamp.IsSpecified) | ||||
| _timestampTicks = model.Timestamp.Value.UtcTicks; | _timestampTicks = model.Timestamp.Value.UtcTicks; | ||||
| @@ -185,8 +190,6 @@ namespace Discord.WebSocket | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| IMessageChannel IMessage.Channel => Channel; | IMessageChannel IMessage.Channel => Channel; | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| MessageType IMessage.Type => MessageType.Default; | |||||
| /// <inheritdoc /> | |||||
| IReadOnlyCollection<IAttachment> IMessage.Attachments => Attachments; | IReadOnlyCollection<IAttachment> IMessage.Attachments => Attachments; | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| IReadOnlyCollection<IEmbed> IMessage.Embeds => Embeds; | IReadOnlyCollection<IEmbed> IMessage.Embeds => Embeds; | ||||
| @@ -9,9 +9,6 @@ namespace Discord.WebSocket | |||||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | ||||
| public class SocketSystemMessage : SocketMessage, ISystemMessage | public class SocketSystemMessage : SocketMessage, ISystemMessage | ||||
| { | { | ||||
| /// <inheritdoc /> | |||||
| public MessageType Type { get; private set; } | |||||
| internal SocketSystemMessage(DiscordSocketClient discord, ulong id, ISocketMessageChannel channel, SocketUser author) | internal SocketSystemMessage(DiscordSocketClient discord, ulong id, ISocketMessageChannel channel, SocketUser author) | ||||
| : base(discord, id, channel, author, MessageSource.System) | : base(discord, id, channel, author, MessageSource.System) | ||||
| { | { | ||||
| @@ -25,8 +22,6 @@ namespace Discord.WebSocket | |||||
| internal override void Update(ClientState state, Model model) | internal override void Update(ClientState state, Model model) | ||||
| { | { | ||||
| base.Update(state, model); | base.Update(state, model); | ||||
| Type = model.Type; | |||||
| } | } | ||||
| private string DebuggerDisplay => $"{Author}: {Content} ({Id}, {Type})"; | private string DebuggerDisplay => $"{Author}: {Content} ({Id}, {Type})"; | ||||
| @@ -125,12 +125,16 @@ namespace Discord.WebSocket | |||||
| { | { | ||||
| var entity = new SocketGuildUser(guild, guild.Discord.GetOrCreateUser(state, model.User)); | var entity = new SocketGuildUser(guild, guild.Discord.GetOrCreateUser(state, model.User)); | ||||
| entity.Update(state, model); | entity.Update(state, model); | ||||
| if (!model.Roles.IsSpecified) | |||||
| entity.UpdateRoles(new ulong[0]); | |||||
| return entity; | return entity; | ||||
| } | } | ||||
| internal static SocketGuildUser Create(SocketGuild guild, ClientState state, PresenceModel model) | internal static SocketGuildUser Create(SocketGuild guild, ClientState state, PresenceModel model) | ||||
| { | { | ||||
| var entity = new SocketGuildUser(guild, guild.Discord.GetOrCreateUser(state, model.User)); | var entity = new SocketGuildUser(guild, guild.Discord.GetOrCreateUser(state, model.User)); | ||||
| entity.Update(state, model, false); | entity.Update(state, model, false); | ||||
| if (!model.Roles.IsSpecified) | |||||
| entity.UpdateRoles(new ulong[0]); | |||||
| return entity; | return entity; | ||||
| } | } | ||||
| internal void Update(ClientState state, MemberModel model) | internal void Update(ClientState state, MemberModel model) | ||||
| @@ -108,11 +108,11 @@ namespace Discord.Net.WebSockets | |||||
| } | } | ||||
| private async Task DisconnectInternalAsync(int closeCode = 1000, bool isDisposing = false) | private async Task DisconnectInternalAsync(int closeCode = 1000, bool isDisposing = false) | ||||
| { | { | ||||
| _isDisconnecting = true; | |||||
| try { _disconnectTokenSource.Cancel(false); } | try { _disconnectTokenSource.Cancel(false); } | ||||
| catch { } | catch { } | ||||
| _isDisconnecting = true; | |||||
| if (_client != null) | if (_client != null) | ||||
| { | { | ||||
| if (!isDisposing) | if (!isDisposing) | ||||
| @@ -166,7 +166,14 @@ namespace Discord.Net.WebSockets | |||||
| public async Task SendAsync(byte[] data, int index, int count, bool isText) | 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 | try | ||||
| { | { | ||||
| if (_client == null) return; | if (_client == null) return; | ||||
| @@ -201,7 +208,7 @@ namespace Discord.Net.WebSockets | |||||
| { | { | ||||
| while (!cancelToken.IsCancellationRequested) | while (!cancelToken.IsCancellationRequested) | ||||
| { | { | ||||
| WebSocketReceiveResult socketResult = await _client.ReceiveAsync(buffer, CancellationToken.None).ConfigureAwait(false); | |||||
| WebSocketReceiveResult socketResult = await _client.ReceiveAsync(buffer, cancelToken).ConfigureAwait(false); | |||||
| byte[] result; | byte[] result; | ||||
| int resultCount; | int resultCount; | ||||