* Preconditions * ChannelHelper * RestDMChannel * RestGroupChannel * RestBan * RestGroupUser * EntityExtensions * DiscordSocketClient * DiscordSocketClientpull/1923/head
@@ -4,7 +4,7 @@ namespace Discord | |||||
{ | { | ||||
internal static class Preconditions | internal static class Preconditions | ||||
{ | { | ||||
//Objects | |||||
#region Objects | |||||
/// <exception cref="ArgumentNullException"><paramref name="obj"/> must not be <see langword="null"/>.</exception> | /// <exception cref="ArgumentNullException"><paramref name="obj"/> must not be <see langword="null"/>.</exception> | ||||
public static void NotNull<T>(T obj, string name, string msg = null) where T : class { if (obj == null) throw CreateNotNullException(name, msg); } | public static void NotNull<T>(T obj, string name, string msg = null) where T : class { if (obj == null) throw CreateNotNullException(name, msg); } | ||||
/// <exception cref="ArgumentNullException"><paramref name="obj"/> must not be <see langword="null"/>.</exception> | /// <exception cref="ArgumentNullException"><paramref name="obj"/> must not be <see langword="null"/>.</exception> | ||||
@@ -15,8 +15,9 @@ namespace Discord | |||||
if (msg == null) return new ArgumentNullException(paramName: name); | if (msg == null) return new ArgumentNullException(paramName: name); | ||||
else return new ArgumentNullException(paramName: name, message: msg); | else return new ArgumentNullException(paramName: name, message: msg); | ||||
} | } | ||||
#endregion | |||||
//Strings | |||||
#region Strings | |||||
/// <exception cref="ArgumentException"><paramref name="obj"/> cannot be blank.</exception> | /// <exception cref="ArgumentException"><paramref name="obj"/> cannot be blank.</exception> | ||||
public static void NotEmpty(string obj, string name, string msg = null) { if (obj.Length == 0) throw CreateNotEmptyException(name, msg); } | public static void NotEmpty(string obj, string name, string msg = null) { if (obj.Length == 0) throw CreateNotEmptyException(name, msg); } | ||||
/// <exception cref="ArgumentException"><paramref name="obj"/> cannot be blank.</exception> | /// <exception cref="ArgumentException"><paramref name="obj"/> cannot be blank.</exception> | ||||
@@ -58,8 +59,9 @@ namespace Discord | |||||
private static ArgumentException CreateNotEmptyException(string name, string msg) | private static ArgumentException CreateNotEmptyException(string name, string msg) | ||||
=> new ArgumentException(message: msg ?? "Argument cannot be blank.", paramName: name); | => new ArgumentException(message: msg ?? "Argument cannot be blank.", paramName: name); | ||||
#endregion | |||||
//Numerics | |||||
#region Numerics | |||||
/// <exception cref="ArgumentException">Value may not be equal to <paramref name="value"/>.</exception> | /// <exception cref="ArgumentException">Value may not be equal to <paramref name="value"/>.</exception> | ||||
public static void NotEqual(sbyte obj, sbyte value, string name, string msg = null) { if (obj == value) throw CreateNotEqualException(name, msg, value); } | public static void NotEqual(sbyte obj, sbyte value, string name, string msg = null) { if (obj == value) throw CreateNotEqualException(name, msg, value); } | ||||
/// <exception cref="ArgumentException">Value may not be equal to <paramref name="value"/>.</exception> | /// <exception cref="ArgumentException">Value may not be equal to <paramref name="value"/>.</exception> | ||||
@@ -271,8 +273,9 @@ namespace Discord | |||||
private static ArgumentException CreateLessThanException<T>(string name, string msg, T value) | private static ArgumentException CreateLessThanException<T>(string name, string msg, T value) | ||||
=> new ArgumentException(message: msg ?? $"Value must be less than {value}.", paramName: name); | => new ArgumentException(message: msg ?? $"Value must be less than {value}.", paramName: name); | ||||
#endregion | |||||
// Bulk Delete | |||||
#region Bulk Delete | |||||
/// <exception cref="ArgumentOutOfRangeException">Messages are younger than 2 weeks.</exception> | /// <exception cref="ArgumentOutOfRangeException">Messages are younger than 2 weeks.</exception> | ||||
public static void YoungerThanTwoWeeks(ulong[] collection, string name) | public static void YoungerThanTwoWeeks(ulong[] collection, string name) | ||||
{ | { | ||||
@@ -293,5 +296,6 @@ namespace Discord | |||||
throw new ArgumentException(message: "The everyone role cannot be assigned to a user.", paramName: name); | throw new ArgumentException(message: "The everyone role cannot be assigned to a user.", paramName: name); | ||||
} | } | ||||
} | } | ||||
#endregion | |||||
} | } | ||||
} | } |
@@ -12,7 +12,7 @@ namespace Discord.Rest | |||||
{ | { | ||||
internal static class ChannelHelper | internal static class ChannelHelper | ||||
{ | { | ||||
//General | |||||
#region General | |||||
public static async Task DeleteAsync(IChannel channel, BaseDiscordClient client, | public static async Task DeleteAsync(IChannel channel, BaseDiscordClient client, | ||||
RequestOptions options) | RequestOptions options) | ||||
{ | { | ||||
@@ -107,8 +107,9 @@ namespace Discord.Rest | |||||
return await client.ApiClient.ModifyStageInstanceAsync(channel.Id, apiArgs, options); | return await client.ApiClient.ModifyStageInstanceAsync(channel.Id, apiArgs, options); | ||||
} | } | ||||
#endregion | |||||
//Invites | |||||
#region Invites | |||||
public static async Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync(IGuildChannel channel, BaseDiscordClient client, | public static async Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync(IGuildChannel channel, BaseDiscordClient client, | ||||
RequestOptions options) | RequestOptions options) | ||||
{ | { | ||||
@@ -183,8 +184,9 @@ namespace Discord.Rest | |||||
var model = await client.ApiClient.CreateChannelInviteAsync(channel.Id, args, options).ConfigureAwait(false); | var model = await client.ApiClient.CreateChannelInviteAsync(channel.Id, args, options).ConfigureAwait(false); | ||||
return RestInviteMetadata.Create(client, null, channel, model); | return RestInviteMetadata.Create(client, null, channel, model); | ||||
} | } | ||||
#endregion | |||||
//Messages | |||||
#region Messages | |||||
public static async Task<RestMessage> GetMessageAsync(IMessageChannel channel, BaseDiscordClient client, | public static async Task<RestMessage> GetMessageAsync(IMessageChannel channel, BaseDiscordClient client, | ||||
ulong id, RequestOptions options) | ulong id, RequestOptions options) | ||||
{ | { | ||||
@@ -285,12 +287,12 @@ namespace Discord.Rest | |||||
} | } | ||||
} | } | ||||
if(stickers != null) | |||||
if (stickers != null) | |||||
{ | { | ||||
Preconditions.AtMost(stickers.Length, 3, nameof(stickers), "A max of 3 stickers are allowed."); | Preconditions.AtMost(stickers.Length, 3, nameof(stickers), "A max of 3 stickers are allowed."); | ||||
} | } | ||||
var args = new CreateMessageParams(text) { IsTTS = isTTS, Embed = embed?.ToModel(), AllowedMentions = allowedMentions?.ToModel(), MessageReference = messageReference?.ToModel(), Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional<API.ActionRowComponent[]>.Unspecified, Stickers = stickers?.Any() ?? false ? stickers.Select(x => x.Id).ToArray() : Optional<ulong[]>.Unspecified}; | |||||
var args = new CreateMessageParams(text) { IsTTS = isTTS, Embed = embed?.ToModel(), AllowedMentions = allowedMentions?.ToModel(), MessageReference = messageReference?.ToModel(), Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional<API.ActionRowComponent[]>.Unspecified, Stickers = stickers?.Any() ?? false ? stickers.Select(x => x.Id).ToArray() : Optional<ulong[]>.Unspecified }; | |||||
var model = await client.ApiClient.CreateMessageAsync(channel.Id, args, options).ConfigureAwait(false); | var model = await client.ApiClient.CreateMessageAsync(channel.Id, args, options).ConfigureAwait(false); | ||||
return RestUserMessage.Create(client, channel, client.CurrentUser, model); | return RestUserMessage.Create(client, channel, client.CurrentUser, model); | ||||
} | } | ||||
@@ -397,8 +399,9 @@ namespace Discord.Rest | |||||
await client.ApiClient.DeleteMessagesAsync(channel.Id, args, options).ConfigureAwait(false); | await client.ApiClient.DeleteMessagesAsync(channel.Id, args, options).ConfigureAwait(false); | ||||
} | } | ||||
} | } | ||||
#endregion | |||||
//Permission Overwrites | |||||
#region Permission Overwrites | |||||
public static async Task AddPermissionOverwriteAsync(IGuildChannel channel, BaseDiscordClient client, | public static async Task AddPermissionOverwriteAsync(IGuildChannel channel, BaseDiscordClient client, | ||||
IUser user, OverwritePermissions perms, RequestOptions options) | IUser user, OverwritePermissions perms, RequestOptions options) | ||||
{ | { | ||||
@@ -421,8 +424,9 @@ namespace Discord.Rest | |||||
{ | { | ||||
await client.ApiClient.DeleteChannelPermissionAsync(channel.Id, role.Id, options).ConfigureAwait(false); | await client.ApiClient.DeleteChannelPermissionAsync(channel.Id, role.Id, options).ConfigureAwait(false); | ||||
} | } | ||||
#endregion | |||||
//Users | |||||
#region Users | |||||
/// <exception cref="InvalidOperationException">Resolving permissions requires the parent guild to be downloaded.</exception> | /// <exception cref="InvalidOperationException">Resolving permissions requires the parent guild to be downloaded.</exception> | ||||
public static async Task<RestGuildUser> GetUserAsync(IGuildChannel channel, IGuild guild, BaseDiscordClient client, | public static async Task<RestGuildUser> GetUserAsync(IGuildChannel channel, IGuild guild, BaseDiscordClient client, | ||||
ulong id, RequestOptions options) | ulong id, RequestOptions options) | ||||
@@ -467,8 +471,9 @@ namespace Discord.Rest | |||||
count: limit | count: limit | ||||
); | ); | ||||
} | } | ||||
#endregion | |||||
//Typing | |||||
#region Typing | |||||
public static async Task TriggerTypingAsync(IMessageChannel channel, BaseDiscordClient client, | public static async Task TriggerTypingAsync(IMessageChannel channel, BaseDiscordClient client, | ||||
RequestOptions options = null) | RequestOptions options = null) | ||||
{ | { | ||||
@@ -477,8 +482,9 @@ namespace Discord.Rest | |||||
public static IDisposable EnterTypingState(IMessageChannel channel, BaseDiscordClient client, | public static IDisposable EnterTypingState(IMessageChannel channel, BaseDiscordClient client, | ||||
RequestOptions options) | RequestOptions options) | ||||
=> new TypingNotifier(channel, options); | => new TypingNotifier(channel, options); | ||||
#endregion | |||||
//Webhooks | |||||
#region Webhooks | |||||
public static async Task<RestWebhook> CreateWebhookAsync(ITextChannel channel, BaseDiscordClient client, string name, Stream avatar, RequestOptions options) | public static async Task<RestWebhook> CreateWebhookAsync(ITextChannel channel, BaseDiscordClient client, string name, Stream avatar, RequestOptions options) | ||||
{ | { | ||||
var args = new CreateWebhookParams { Name = name }; | var args = new CreateWebhookParams { Name = name }; | ||||
@@ -501,7 +507,9 @@ namespace Discord.Rest | |||||
return models.Select(x => RestWebhook.Create(client, channel, x)) | return models.Select(x => RestWebhook.Create(client, channel, x)) | ||||
.ToImmutableArray(); | .ToImmutableArray(); | ||||
} | } | ||||
// Categories | |||||
#endregion | |||||
#region Categories | |||||
public static async Task<ICategoryChannel> GetCategoryAsync(INestedChannel channel, BaseDiscordClient client, RequestOptions options) | public static async Task<ICategoryChannel> GetCategoryAsync(INestedChannel channel, BaseDiscordClient client, RequestOptions options) | ||||
{ | { | ||||
// if no category id specified, return null | // if no category id specified, return null | ||||
@@ -515,7 +523,8 @@ namespace Discord.Rest | |||||
public static async Task SyncPermissionsAsync(INestedChannel channel, BaseDiscordClient client, RequestOptions options) | public static async Task SyncPermissionsAsync(INestedChannel channel, BaseDiscordClient client, RequestOptions options) | ||||
{ | { | ||||
var category = await GetCategoryAsync(channel, client, options).ConfigureAwait(false); | var category = await GetCategoryAsync(channel, client, options).ConfigureAwait(false); | ||||
if (category == null) throw new InvalidOperationException("This channel does not have a parent channel."); | |||||
if (category == null) | |||||
throw new InvalidOperationException("This channel does not have a parent channel."); | |||||
var apiArgs = new ModifyGuildChannelParams | var apiArgs = new ModifyGuildChannelParams | ||||
{ | { | ||||
@@ -530,5 +539,6 @@ namespace Discord.Rest | |||||
}; | }; | ||||
await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false); | await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false); | ||||
} | } | ||||
#endregion | |||||
} | } | ||||
} | } |
@@ -15,6 +15,7 @@ namespace Discord.Rest | |||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | ||||
public class RestDMChannel : RestChannel, IDMChannel, IRestPrivateChannel, IRestMessageChannel | public class RestDMChannel : RestChannel, IDMChannel, IRestPrivateChannel, IRestMessageChannel | ||||
{ | { | ||||
#region RestDMChannel | |||||
/// <summary> | /// <summary> | ||||
/// Gets the current logged-in user. | /// Gets the current logged-in user. | ||||
/// </summary> | /// </summary> | ||||
@@ -154,20 +155,24 @@ namespace Discord.Rest | |||||
/// </returns> | /// </returns> | ||||
public override string ToString() => $"@{Recipient}"; | public override string ToString() => $"@{Recipient}"; | ||||
private string DebuggerDisplay => $"@{Recipient} ({Id}, DM)"; | private string DebuggerDisplay => $"@{Recipient} ({Id}, DM)"; | ||||
#endregion | |||||
//IDMChannel | |||||
#region IDMChannel | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
IUser IDMChannel.Recipient => Recipient; | IUser IDMChannel.Recipient => Recipient; | ||||
#endregion | |||||
//IRestPrivateChannel | |||||
#region IRestPrivateChannel | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
IReadOnlyCollection<RestUser> IRestPrivateChannel.Recipients => ImmutableArray.Create(Recipient); | IReadOnlyCollection<RestUser> IRestPrivateChannel.Recipients => ImmutableArray.Create(Recipient); | ||||
#endregion | |||||
//IPrivateChannel | |||||
#region IPrivateChannel | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
IReadOnlyCollection<IUser> IPrivateChannel.Recipients => ImmutableArray.Create<IUser>(Recipient); | IReadOnlyCollection<IUser> IPrivateChannel.Recipients => ImmutableArray.Create<IUser>(Recipient); | ||||
#endregion | |||||
//IMessageChannel | |||||
#region IMessageChannel | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
async Task<IMessage> IMessageChannel.GetMessageAsync(ulong id, CacheMode mode, RequestOptions options) | async Task<IMessage> IMessageChannel.GetMessageAsync(ulong id, CacheMode mode, RequestOptions options) | ||||
{ | { | ||||
@@ -212,8 +217,9 @@ namespace Discord.Rest | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
async Task<IUserMessage> IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers) | async Task<IUserMessage> IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers) | ||||
=> await SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference, component, stickers).ConfigureAwait(false); | => await SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference, component, stickers).ConfigureAwait(false); | ||||
#endregion | |||||
//IChannel | |||||
#region IChannel | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
string IChannel.Name => $"@{Recipient}"; | string IChannel.Name => $"@{Recipient}"; | ||||
@@ -223,5 +229,6 @@ namespace Discord.Rest | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) | IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) | ||||
=> ImmutableArray.Create<IReadOnlyCollection<IUser>>(Users).ToAsyncEnumerable(); | => ImmutableArray.Create<IReadOnlyCollection<IUser>>(Users).ToAsyncEnumerable(); | ||||
#endregion | |||||
} | } | ||||
} | } |
@@ -16,6 +16,7 @@ namespace Discord.Rest | |||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | ||||
public class RestGroupChannel : RestChannel, IGroupChannel, IRestPrivateChannel, IRestMessageChannel, IRestAudioChannel | public class RestGroupChannel : RestChannel, IGroupChannel, IRestPrivateChannel, IRestMessageChannel, IRestAudioChannel | ||||
{ | { | ||||
#region RestGroupChannel | |||||
private string _iconId; | private string _iconId; | ||||
private ImmutableDictionary<ulong, RestGroupUser> _users; | private ImmutableDictionary<ulong, RestGroupUser> _users; | ||||
@@ -143,14 +144,17 @@ namespace Discord.Rest | |||||
public override string ToString() => Name; | public override string ToString() => Name; | ||||
private string DebuggerDisplay => $"{Name} ({Id}, Group)"; | private string DebuggerDisplay => $"{Name} ({Id}, Group)"; | ||||
#endregion | |||||
//ISocketPrivateChannel | |||||
#region ISocketPrivateChannel | |||||
IReadOnlyCollection<RestUser> IRestPrivateChannel.Recipients => Recipients; | IReadOnlyCollection<RestUser> IRestPrivateChannel.Recipients => Recipients; | ||||
#endregion | |||||
//IPrivateChannel | |||||
#region IPrivateChannel | |||||
IReadOnlyCollection<IUser> IPrivateChannel.Recipients => Recipients; | IReadOnlyCollection<IUser> IPrivateChannel.Recipients => Recipients; | ||||
#endregion | |||||
//IMessageChannel | |||||
#region IMessageChannel | |||||
async Task<IMessage> IMessageChannel.GetMessageAsync(ulong id, CacheMode mode, RequestOptions options) | async Task<IMessage> IMessageChannel.GetMessageAsync(ulong id, CacheMode mode, RequestOptions options) | ||||
{ | { | ||||
if (mode == CacheMode.AllowDownload) | if (mode == CacheMode.AllowDownload) | ||||
@@ -190,17 +194,20 @@ namespace Discord.Rest | |||||
async Task<IUserMessage> IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers) | async Task<IUserMessage> IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers) | ||||
=> await SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference, component, stickers).ConfigureAwait(false); | => await SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference, component, stickers).ConfigureAwait(false); | ||||
#endregion | |||||
//IAudioChannel | |||||
#region IAudioChannel | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
/// <exception cref="NotSupportedException">Connecting to a group channel is not supported.</exception> | /// <exception cref="NotSupportedException">Connecting to a group channel is not supported.</exception> | ||||
Task<IAudioClient> IAudioChannel.ConnectAsync(bool selfDeaf, bool selfMute, bool external) { throw new NotSupportedException(); } | Task<IAudioClient> IAudioChannel.ConnectAsync(bool selfDeaf, bool selfMute, bool external) { throw new NotSupportedException(); } | ||||
Task IAudioChannel.DisconnectAsync() { throw new NotSupportedException(); } | Task IAudioChannel.DisconnectAsync() { throw new NotSupportedException(); } | ||||
#endregion | |||||
//IChannel | |||||
#region IChannel | |||||
Task<IUser> IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) | Task<IUser> IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) | ||||
=> Task.FromResult<IUser>(GetUser(id)); | => Task.FromResult<IUser>(GetUser(id)); | ||||
IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) | IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) | ||||
=> ImmutableArray.Create<IReadOnlyCollection<IUser>>(Users).ToAsyncEnumerable(); | => ImmutableArray.Create<IReadOnlyCollection<IUser>>(Users).ToAsyncEnumerable(); | ||||
#endregion | |||||
} | } | ||||
} | } |
@@ -9,6 +9,7 @@ namespace Discord.Rest | |||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | ||||
public class RestBan : IBan | public class RestBan : IBan | ||||
{ | { | ||||
#region RestBan | |||||
/// <summary> | /// <summary> | ||||
/// Gets the banned user. | /// Gets the banned user. | ||||
/// </summary> | /// </summary> | ||||
@@ -37,9 +38,11 @@ namespace Discord.Rest | |||||
/// </returns> | /// </returns> | ||||
public override string ToString() => User.ToString(); | public override string ToString() => User.ToString(); | ||||
private string DebuggerDisplay => $"{User}: {Reason}"; | private string DebuggerDisplay => $"{User}: {Reason}"; | ||||
#endregion | |||||
//IBan | |||||
#region IBan | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
IUser IBan.User => User; | IUser IBan.User => User; | ||||
#endregion | |||||
} | } | ||||
} | } |
@@ -10,6 +10,7 @@ namespace Discord.Rest | |||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | ||||
public class RestGroupUser : RestUser, IGroupUser | public class RestGroupUser : RestUser, IGroupUser | ||||
{ | { | ||||
#region RestGroupUser | |||||
internal RestGroupUser(BaseDiscordClient discord, ulong id) | internal RestGroupUser(BaseDiscordClient discord, ulong id) | ||||
: base(discord, id) | : base(discord, id) | ||||
{ | { | ||||
@@ -20,8 +21,9 @@ namespace Discord.Rest | |||||
entity.Update(model); | entity.Update(model); | ||||
return entity; | return entity; | ||||
} | } | ||||
#endregion | |||||
//IVoiceState | |||||
#region IVoiceState | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
bool IVoiceState.IsDeafened => false; | bool IVoiceState.IsDeafened => false; | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
@@ -40,5 +42,6 @@ namespace Discord.Rest | |||||
bool IVoiceState.IsStreaming => false; | bool IVoiceState.IsStreaming => false; | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
DateTimeOffset? IVoiceState.RequestToSpeakTimestamp => null; | DateTimeOffset? IVoiceState.RequestToSpeakTimestamp => null; | ||||
#endregion | |||||
} | } | ||||
} | } |
@@ -24,6 +24,7 @@ namespace Discord.WebSocket | |||||
/// </summary> | /// </summary> | ||||
public partial class DiscordSocketClient : BaseSocketClient, IDiscordClient | public partial class DiscordSocketClient : BaseSocketClient, IDiscordClient | ||||
{ | { | ||||
#region DiscordSocketClient | |||||
private readonly ConcurrentQueue<ulong> _largeGuilds; | private readonly ConcurrentQueue<ulong> _largeGuilds; | ||||
internal readonly JsonSerializer _serializer; | internal readonly JsonSerializer _serializer; | ||||
private readonly DiscordShardedClient _shardedClient; | private readonly DiscordShardedClient _shardedClient; | ||||
@@ -62,6 +63,7 @@ namespace Discord.WebSocket | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public override IActivity Activity { get => _activity.GetValueOrDefault(); protected set => _activity = Optional.Create(value); } | public override IActivity Activity { get => _activity.GetValueOrDefault(); protected set => _activity = Optional.Create(value); } | ||||
private Optional<IActivity> _activity; | private Optional<IActivity> _activity; | ||||
#endregion | |||||
//From DiscordSocketConfig | //From DiscordSocketConfig | ||||
internal int TotalShards { get; private set; } | internal int TotalShards { get; private set; } | ||||
@@ -436,7 +438,7 @@ namespace Discord.WebSocket | |||||
var entity = State.GetOrAddCommand(model.Id, (id) => SocketApplicationCommand.Create(this, model)); | var entity = State.GetOrAddCommand(model.Id, (id) => SocketApplicationCommand.Create(this, model)); | ||||
// update it incase it was cached | |||||
//Update it incase it was cached | |||||
entity.Update(model); | entity.Update(model); | ||||
return entity; | return entity; | ||||
@@ -448,7 +450,7 @@ namespace Discord.WebSocket | |||||
var entities = models.Select(x => SocketApplicationCommand.Create(this, x)); | var entities = models.Select(x => SocketApplicationCommand.Create(this, x)); | ||||
// purge our previous commands | |||||
//Purge our previous commands | |||||
State.PurgeCommands(x => x.IsGlobalCommand); | State.PurgeCommands(x => x.IsGlobalCommand); | ||||
foreach(var entity in entities) | foreach(var entity in entities) | ||||
@@ -513,7 +515,7 @@ namespace Discord.WebSocket | |||||
{ | { | ||||
var guild = State.GetGuild(model.GuildId.Value); | var guild = State.GetGuild(model.GuildId.Value); | ||||
// since the sticker can be from another guild, check if we are in the guild or its in the cache | |||||
//Since the sticker can be from another guild, check if we are in the guild or its in the cache | |||||
if (guild != null) | if (guild != null) | ||||
sticker = guild.AddOrUpdateSticker(model); | sticker = guild.AddOrUpdateSticker(model); | ||||
else | else | ||||
@@ -678,7 +680,7 @@ namespace Discord.WebSocket | |||||
return null; | return null; | ||||
GameModel game = null; | GameModel game = null; | ||||
// Discord only accepts rich presence over RPC, don't even bother building a payload | |||||
//Discord only accepts rich presence over RPC, don't even bother building a payload | |||||
if (activity.GetValueOrDefault() != null) | if (activity.GetValueOrDefault() != null) | ||||
{ | { | ||||
@@ -700,6 +702,7 @@ namespace Discord.WebSocket | |||||
game); | game); | ||||
} | } | ||||
#region ProcessMessageAsync | |||||
private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string type, object payload) | private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string type, object payload) | ||||
{ | { | ||||
if (seq != null) | if (seq != null) | ||||
@@ -772,7 +775,7 @@ namespace Discord.WebSocket | |||||
case GatewayOpCode.Dispatch: | case GatewayOpCode.Dispatch: | ||||
switch (type) | switch (type) | ||||
{ | { | ||||
//Connection | |||||
#region Connection | |||||
case "READY": | case "READY": | ||||
{ | { | ||||
try | try | ||||
@@ -849,8 +852,9 @@ namespace Discord.WebSocket | |||||
await _gatewayLogger.InfoAsync("Resumed previous session").ConfigureAwait(false); | await _gatewayLogger.InfoAsync("Resumed previous session").ConfigureAwait(false); | ||||
} | } | ||||
break; | break; | ||||
#endregion | |||||
//Guilds | |||||
#region Guilds | |||||
case "GUILD_CREATE": | case "GUILD_CREATE": | ||||
{ | { | ||||
var data = (payload as JToken).ToObject<ExtendedGuild>(_serializer); | var data = (payload as JToken).ToObject<ExtendedGuild>(_serializer); | ||||
@@ -1000,8 +1004,9 @@ namespace Discord.WebSocket | |||||
} | } | ||||
} | } | ||||
break; | break; | ||||
#endregion | |||||
//Channels | |||||
#region Channels | |||||
case "CHANNEL_CREATE": | case "CHANNEL_CREATE": | ||||
{ | { | ||||
await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_CREATE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_CREATE)").ConfigureAwait(false); | ||||
@@ -1103,8 +1108,9 @@ namespace Discord.WebSocket | |||||
} | } | ||||
} | } | ||||
break; | break; | ||||
#endregion | |||||
//Members | |||||
#region Members | |||||
case "GUILD_MEMBER_ADD": | case "GUILD_MEMBER_ADD": | ||||
{ | { | ||||
await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_MEMBER_ADD)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_MEMBER_ADD)").ConfigureAwait(false); | ||||
@@ -1275,8 +1281,9 @@ namespace Discord.WebSocket | |||||
} | } | ||||
} | } | ||||
break; | break; | ||||
#endregion | |||||
//Roles | |||||
#region Roles | |||||
case "GUILD_ROLE_CREATE": | case "GUILD_ROLE_CREATE": | ||||
{ | { | ||||
await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_ROLE_CREATE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_ROLE_CREATE)").ConfigureAwait(false); | ||||
@@ -1368,8 +1375,9 @@ namespace Discord.WebSocket | |||||
} | } | ||||
} | } | ||||
break; | break; | ||||
#endregion | |||||
//Bans | |||||
#region Bans | |||||
case "GUILD_BAN_ADD": | case "GUILD_BAN_ADD": | ||||
{ | { | ||||
await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_BAN_ADD)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_BAN_ADD)").ConfigureAwait(false); | ||||
@@ -1422,8 +1430,9 @@ namespace Discord.WebSocket | |||||
} | } | ||||
} | } | ||||
break; | break; | ||||
#endregion | |||||
//Messages | |||||
#region Messages | |||||
case "MESSAGE_CREATE": | case "MESSAGE_CREATE": | ||||
{ | { | ||||
await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_CREATE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_CREATE)").ConfigureAwait(false); | ||||
@@ -1754,8 +1763,9 @@ namespace Discord.WebSocket | |||||
await TimedInvokeAsync(_messagesBulkDeletedEvent, nameof(MessagesBulkDeleted), cacheableList, cacheableChannel).ConfigureAwait(false); | await TimedInvokeAsync(_messagesBulkDeletedEvent, nameof(MessagesBulkDeleted), cacheableList, cacheableChannel).ConfigureAwait(false); | ||||
} | } | ||||
break; | break; | ||||
#endregion | |||||
//Statuses | |||||
#region Statuses | |||||
case "PRESENCE_UPDATE": | case "PRESENCE_UPDATE": | ||||
{ | { | ||||
await _gatewayLogger.DebugAsync("Received Dispatch (PRESENCE_UPDATE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (PRESENCE_UPDATE)").ConfigureAwait(false); | ||||
@@ -1843,8 +1853,9 @@ namespace Discord.WebSocket | |||||
await TimedInvokeAsync(_userIsTypingEvent, nameof(UserIsTyping), cacheableUser, cacheableChannel).ConfigureAwait(false); | await TimedInvokeAsync(_userIsTypingEvent, nameof(UserIsTyping), cacheableUser, cacheableChannel).ConfigureAwait(false); | ||||
} | } | ||||
break; | break; | ||||
#endregion | |||||
//Users | |||||
#region Users | |||||
case "USER_UPDATE": | case "USER_UPDATE": | ||||
{ | { | ||||
await _gatewayLogger.DebugAsync("Received Dispatch (USER_UPDATE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (USER_UPDATE)").ConfigureAwait(false); | ||||
@@ -1863,8 +1874,9 @@ namespace Discord.WebSocket | |||||
} | } | ||||
} | } | ||||
break; | break; | ||||
#endregion | |||||
//Voice | |||||
#region Voice | |||||
case "VOICE_STATE_UPDATE": | case "VOICE_STATE_UPDATE": | ||||
{ | { | ||||
await _gatewayLogger.DebugAsync("Received Dispatch (VOICE_STATE_UPDATE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (VOICE_STATE_UPDATE)").ConfigureAwait(false); | ||||
@@ -1901,7 +1913,7 @@ namespace Discord.WebSocket | |||||
after = SocketVoiceState.Create(null, data); | after = SocketVoiceState.Create(null, data); | ||||
} | } | ||||
// per g250k, this should always be sent, but apparently not always | |||||
//Per g250k, this should always be sent, but apparently not always | |||||
user = guild.GetUser(data.UserId) | user = guild.GetUser(data.UserId) | ||||
?? (data.Member.IsSpecified ? guild.AddOrUpdateUser(data.Member.Value) : null); | ?? (data.Member.IsSpecified ? guild.AddOrUpdateUser(data.Member.Value) : null); | ||||
if (user == null) | if (user == null) | ||||
@@ -1993,8 +2005,9 @@ namespace Discord.WebSocket | |||||
} | } | ||||
break; | break; | ||||
#endregion | |||||
//Invites | |||||
#region Invites | |||||
case "INVITE_CREATE": | case "INVITE_CREATE": | ||||
{ | { | ||||
await _gatewayLogger.DebugAsync("Received Dispatch (INVITE_CREATE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (INVITE_CREATE)").ConfigureAwait(false); | ||||
@@ -2051,8 +2064,9 @@ namespace Discord.WebSocket | |||||
} | } | ||||
} | } | ||||
break; | break; | ||||
#endregion | |||||
// Interactions | |||||
#region Interactions | |||||
case "INTERACTION_CREATE": | case "INTERACTION_CREATE": | ||||
{ | { | ||||
await _gatewayLogger.DebugAsync("Received Dispatch (INTERACTION_CREATE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (INTERACTION_CREATE)").ConfigureAwait(false); | ||||
@@ -2189,8 +2203,9 @@ namespace Discord.WebSocket | |||||
await TimedInvokeAsync(_applicationCommandDeleted, nameof(ApplicationCommandDeleted), applicationCommand).ConfigureAwait(false); | await TimedInvokeAsync(_applicationCommandDeleted, nameof(ApplicationCommandDeleted), applicationCommand).ConfigureAwait(false); | ||||
} | } | ||||
break; | break; | ||||
#endregion | |||||
// Threads | |||||
#region Threads | |||||
case "THREAD_CREATE": | case "THREAD_CREATE": | ||||
{ | { | ||||
await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_CREATE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_CREATE)").ConfigureAwait(false); | ||||
@@ -2251,7 +2266,7 @@ namespace Discord.WebSocket | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
// Thread is updated but was not cached, likely meaning the thread was unarchived. | |||||
//Thread is updated but was not cached, likely meaning the thread was unarchived. | |||||
threadChannel = (SocketThreadChannel)guild.AddChannel(State, data); | threadChannel = (SocketThreadChannel)guild.AddChannel(State, data); | ||||
if (data.ThreadMember.IsSpecified) | if (data.ThreadMember.IsSpecified) | ||||
threadChannel.AddOrUpdateThreadMember(data.ThreadMember.Value, guild.CurrentUser); | threadChannel.AddOrUpdateThreadMember(data.ThreadMember.Value, guild.CurrentUser); | ||||
@@ -2507,8 +2522,9 @@ namespace Discord.WebSocket | |||||
} | } | ||||
} | } | ||||
break; | break; | ||||
#endregion | |||||
//Ignored (User only) | |||||
#region Ignored (User only) | |||||
case "CHANNEL_PINS_ACK": | case "CHANNEL_PINS_ACK": | ||||
await _gatewayLogger.DebugAsync("Ignored Dispatch (CHANNEL_PINS_ACK)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Ignored Dispatch (CHANNEL_PINS_ACK)").ConfigureAwait(false); | ||||
break; | break; | ||||
@@ -2530,11 +2546,13 @@ namespace Discord.WebSocket | |||||
case "WEBHOOKS_UPDATE": | case "WEBHOOKS_UPDATE": | ||||
await _gatewayLogger.DebugAsync("Ignored Dispatch (WEBHOOKS_UPDATE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Ignored Dispatch (WEBHOOKS_UPDATE)").ConfigureAwait(false); | ||||
break; | break; | ||||
#endregion | |||||
//Others | |||||
#region Others | |||||
default: | default: | ||||
await _gatewayLogger.WarningAsync($"Unknown Dispatch ({type})").ConfigureAwait(false); | await _gatewayLogger.WarningAsync($"Unknown Dispatch ({type})").ConfigureAwait(false); | ||||
break; | break; | ||||
#endregion | |||||
} | } | ||||
break; | break; | ||||
default: | default: | ||||
@@ -2548,6 +2566,7 @@ namespace Discord.WebSocket | |||||
Console.WriteLine(ex); | Console.WriteLine(ex); | ||||
} | } | ||||
} | } | ||||
#endregion | |||||
private async Task RunHeartbeatAsync(int intervalMillis, CancellationToken cancelToken) | private async Task RunHeartbeatAsync(int intervalMillis, CancellationToken cancelToken) | ||||
{ | { | ||||
@@ -9,7 +9,7 @@ namespace Discord.WebSocket | |||||
{ | { | ||||
public static IActivity ToEntity(this API.Game model) | public static IActivity ToEntity(this API.Game model) | ||||
{ | { | ||||
// Custom Status Game | |||||
#region Custom Status Game | |||||
if (model.Id.IsSpecified && model.Id.Value == "custom") | if (model.Id.IsSpecified && model.Id.Value == "custom") | ||||
{ | { | ||||
return new CustomStatusGame() | return new CustomStatusGame() | ||||
@@ -21,13 +21,14 @@ namespace Discord.WebSocket | |||||
CreatedAt = DateTimeOffset.FromUnixTimeMilliseconds(model.CreatedAt.Value), | CreatedAt = DateTimeOffset.FromUnixTimeMilliseconds(model.CreatedAt.Value), | ||||
}; | }; | ||||
} | } | ||||
#endregion | |||||
// Spotify Game | |||||
#region Spotify Game | |||||
if (model.SyncId.IsSpecified) | if (model.SyncId.IsSpecified) | ||||
{ | { | ||||
var assets = model.Assets.GetValueOrDefault()?.ToEntity(); | var assets = model.Assets.GetValueOrDefault()?.ToEntity(); | ||||
string albumText = assets?[1]?.Text; | string albumText = assets?[1]?.Text; | ||||
string albumArtId = assets?[1]?.ImageId?.Replace("spotify:",""); | |||||
string albumArtId = assets?[1]?.ImageId?.Replace("spotify:", ""); | |||||
var timestamps = model.Timestamps.IsSpecified ? model.Timestamps.Value.ToEntity() : null; | var timestamps = model.Timestamps.IsSpecified ? model.Timestamps.Value.ToEntity() : null; | ||||
return new SpotifyGame | return new SpotifyGame | ||||
{ | { | ||||
@@ -37,7 +38,7 @@ namespace Discord.WebSocket | |||||
TrackUrl = CDN.GetSpotifyDirectUrl(model.SyncId.Value), | TrackUrl = CDN.GetSpotifyDirectUrl(model.SyncId.Value), | ||||
AlbumTitle = albumText, | AlbumTitle = albumText, | ||||
TrackTitle = model.Details.GetValueOrDefault(), | TrackTitle = model.Details.GetValueOrDefault(), | ||||
Artists = model.State.GetValueOrDefault()?.Split(';').Select(x=>x?.Trim()).ToImmutableArray(), | |||||
Artists = model.State.GetValueOrDefault()?.Split(';').Select(x => x?.Trim()).ToImmutableArray(), | |||||
StartedAt = timestamps?.Start, | StartedAt = timestamps?.Start, | ||||
EndsAt = timestamps?.End, | EndsAt = timestamps?.End, | ||||
Duration = timestamps?.End - timestamps?.Start, | Duration = timestamps?.End - timestamps?.Start, | ||||
@@ -46,8 +47,9 @@ namespace Discord.WebSocket | |||||
Flags = model.Flags.GetValueOrDefault(), | Flags = model.Flags.GetValueOrDefault(), | ||||
}; | }; | ||||
} | } | ||||
#endregion | |||||
// Rich Game | |||||
#region Rich Game | |||||
if (model.ApplicationId.IsSpecified) | if (model.ApplicationId.IsSpecified) | ||||
{ | { | ||||
ulong appId = model.ApplicationId.Value; | ulong appId = model.ApplicationId.Value; | ||||
@@ -66,7 +68,9 @@ namespace Discord.WebSocket | |||||
Flags = model.Flags.GetValueOrDefault() | Flags = model.Flags.GetValueOrDefault() | ||||
}; | }; | ||||
} | } | ||||
// Stream Game | |||||
#endregion | |||||
#region Stream Game | |||||
if (model.StreamUrl.IsSpecified) | if (model.StreamUrl.IsSpecified) | ||||
{ | { | ||||
return new StreamingGame( | return new StreamingGame( | ||||
@@ -77,10 +81,13 @@ namespace Discord.WebSocket | |||||
Details = model.Details.GetValueOrDefault() | Details = model.Details.GetValueOrDefault() | ||||
}; | }; | ||||
} | } | ||||
// Normal Game | |||||
#endregion | |||||
#region Normal Game | |||||
return new Game(model.Name, model.Type.GetValueOrDefault() ?? ActivityType.Playing, | return new Game(model.Name, model.Type.GetValueOrDefault() ?? ActivityType.Playing, | ||||
model.Flags.IsSpecified ? model.Flags.Value : ActivityProperties.None, | model.Flags.IsSpecified ? model.Flags.Value : ActivityProperties.None, | ||||
model.Details.GetValueOrDefault()); | model.Details.GetValueOrDefault()); | ||||
#endregion | |||||
} | } | ||||
// (Small, Large) | // (Small, Large) | ||||