Browse Source

Fix message events

pull/1854/head
Paulo 4 years ago
parent
commit
76f507d4e4
4 changed files with 184 additions and 183 deletions
  1. +5
    -4
      src/Discord.Net.Examples/WebSocket/BaseSocketClient.Events.Examples.cs
  2. +14
    -14
      src/Discord.Net.WebSocket/BaseSocketClient.Events.cs
  3. +165
    -149
      src/Discord.Net.WebSocket/DiscordSocketClient.cs
  4. +0
    -16
      src/Discord.Net.WebSocket/DiscordSocketConfig.cs

+ 5
- 4
src/Discord.Net.Examples/WebSocket/BaseSocketClient.Events.Examples.cs View File

@@ -15,7 +15,7 @@ namespace Discord.Net.Examples.WebSocket
=> client.ReactionAdded += HandleReactionAddedAsync; => client.ReactionAdded += HandleReactionAddedAsync;


public async Task HandleReactionAddedAsync(Cacheable<IUserMessage, ulong> cachedMessage, public async Task HandleReactionAddedAsync(Cacheable<IUserMessage, ulong> cachedMessage,
ISocketMessageChannel originChannel, SocketReaction reaction)
Cacheable<ISocketMessageChannel, ulong> originChannel, SocketReaction reaction)
{ {
var message = await cachedMessage.GetOrDownloadAsync(); var message = await cachedMessage.GetOrDownloadAsync();
if (message != null && reaction.User.IsSpecified) if (message != null && reaction.User.IsSpecified)
@@ -100,16 +100,17 @@ namespace Discord.Net.Examples.WebSocket
public void HookMessageDeleted(BaseSocketClient client) public void HookMessageDeleted(BaseSocketClient client)
=> client.MessageDeleted += HandleMessageDelete; => client.MessageDeleted += HandleMessageDelete;


public Task HandleMessageDelete(Cacheable<IMessage, ulong> cachedMessage, ISocketMessageChannel channel)
public async Task HandleMessageDelete(Cacheable<IMessage, ulong> cachedMessage, Cacheable<ISocketMessageChannel, ulong> cachedChannel)
{ {
// check if the message exists in cache; if not, we cannot report what was removed // check if the message exists in cache; if not, we cannot report what was removed
if (!cachedMessage.HasValue) return Task.CompletedTask;
if (!cachedMessage.HasValue) return;
// gets or downloads the channel if it's not in the cache
ISocketMessageChannel channel = await cachedChannel.GetOrDownloadAsync();
var message = cachedMessage.Value; var message = cachedMessage.Value;
Console.WriteLine( Console.WriteLine(
$"A message ({message.Id}) from {message.Author} was removed from the channel {channel.Name} ({channel.Id}):" $"A message ({message.Id}) from {message.Author} was removed from the channel {channel.Name} ({channel.Id}):"
+ Environment.NewLine + Environment.NewLine
+ message.Content); + message.Content);
return Task.CompletedTask;
} }


#endregion #endregion


+ 14
- 14
src/Discord.Net.WebSocket/BaseSocketClient.Events.cs View File

@@ -124,11 +124,11 @@ namespace Discord.WebSocket
/// <code language="cs" region="MessageDeleted" /// <code language="cs" region="MessageDeleted"
/// source="..\Discord.Net.Examples\WebSocket\BaseSocketClient.Events.Examples.cs" /> /// source="..\Discord.Net.Examples\WebSocket\BaseSocketClient.Events.Examples.cs" />
/// </example> /// </example>
public event Func<Cacheable<IMessage, ulong>, ISocketMessageChannel, Task> MessageDeleted {
public event Func<Cacheable<IMessage, ulong>, Cacheable<ISocketMessageChannel, ulong>, Task> MessageDeleted {
add { _messageDeletedEvent.Add(value); } add { _messageDeletedEvent.Add(value); }
remove { _messageDeletedEvent.Remove(value); } remove { _messageDeletedEvent.Remove(value); }
} }
internal readonly AsyncEvent<Func<Cacheable<IMessage, ulong>, ISocketMessageChannel, Task>> _messageDeletedEvent = new AsyncEvent<Func<Cacheable<IMessage, ulong>, ISocketMessageChannel, Task>>();
internal readonly AsyncEvent<Func<Cacheable<IMessage, ulong>, Cacheable<ISocketMessageChannel, ulong>, Task>> _messageDeletedEvent = new AsyncEvent<Func<Cacheable<IMessage, ulong>, Cacheable<ISocketMessageChannel, ulong>, Task>>();
/// <summary> Fired when multiple messages are bulk deleted. </summary> /// <summary> Fired when multiple messages are bulk deleted. </summary>
/// <remarks> /// <remarks>
/// <note> /// <note>
@@ -155,12 +155,12 @@ namespace Discord.WebSocket
/// <see cref="ISocketMessageChannel"/> parameter. /// <see cref="ISocketMessageChannel"/> parameter.
/// </para> /// </para>
/// </remarks> /// </remarks>
public event Func<IReadOnlyCollection<Cacheable<IMessage, ulong>>, ISocketMessageChannel, Task> MessagesBulkDeleted
public event Func<IReadOnlyCollection<Cacheable<IMessage, ulong>>, Cacheable<ISocketMessageChannel, ulong>, Task> MessagesBulkDeleted
{ {
add { _messagesBulkDeletedEvent.Add(value); } add { _messagesBulkDeletedEvent.Add(value); }
remove { _messagesBulkDeletedEvent.Remove(value); } remove { _messagesBulkDeletedEvent.Remove(value); }
} }
internal readonly AsyncEvent<Func<IReadOnlyCollection<Cacheable<IMessage, ulong>>, ISocketMessageChannel, Task>> _messagesBulkDeletedEvent = new AsyncEvent<Func<IReadOnlyCollection<Cacheable<IMessage, ulong>>, ISocketMessageChannel, Task>>();
internal readonly AsyncEvent<Func<IReadOnlyCollection<Cacheable<IMessage, ulong>>, Cacheable<ISocketMessageChannel, ulong>, Task>> _messagesBulkDeletedEvent = new AsyncEvent<Func<IReadOnlyCollection<Cacheable<IMessage, ulong>>, Cacheable<ISocketMessageChannel, ulong>, Task>>();
/// <summary> Fired when a message is updated. </summary> /// <summary> Fired when a message is updated. </summary>
/// <remarks> /// <remarks>
/// <para> /// <para>
@@ -217,23 +217,23 @@ namespace Discord.WebSocket
/// <code language="cs" region="ReactionAdded" /// <code language="cs" region="ReactionAdded"
/// source="..\Discord.Net.Examples\WebSocket\BaseSocketClient.Events.Examples.cs"/> /// source="..\Discord.Net.Examples\WebSocket\BaseSocketClient.Events.Examples.cs"/>
/// </example> /// </example>
public event Func<Cacheable<IUserMessage, ulong>, ISocketMessageChannel, SocketReaction, Task> ReactionAdded {
public event Func<Cacheable<IUserMessage, ulong>, Cacheable<ISocketMessageChannel, ulong>, SocketReaction, Task> ReactionAdded {
add { _reactionAddedEvent.Add(value); } add { _reactionAddedEvent.Add(value); }
remove { _reactionAddedEvent.Remove(value); } remove { _reactionAddedEvent.Remove(value); }
} }
internal readonly AsyncEvent<Func<Cacheable<IUserMessage, ulong>, ISocketMessageChannel, SocketReaction, Task>> _reactionAddedEvent = new AsyncEvent<Func<Cacheable<IUserMessage, ulong>, ISocketMessageChannel, SocketReaction, Task>>();
internal readonly AsyncEvent<Func<Cacheable<IUserMessage, ulong>, Cacheable<ISocketMessageChannel, ulong>, SocketReaction, Task>> _reactionAddedEvent = new AsyncEvent<Func<Cacheable<IUserMessage, ulong>, Cacheable<ISocketMessageChannel, ulong>, SocketReaction, Task>>();
/// <summary> Fired when a reaction is removed from a message. </summary> /// <summary> Fired when a reaction is removed from a message. </summary>
public event Func<Cacheable<IUserMessage, ulong>, ISocketMessageChannel, SocketReaction, Task> ReactionRemoved {
public event Func<Cacheable<IUserMessage, ulong>, Cacheable<ISocketMessageChannel, ulong>, SocketReaction, Task> ReactionRemoved {
add { _reactionRemovedEvent.Add(value); } add { _reactionRemovedEvent.Add(value); }
remove { _reactionRemovedEvent.Remove(value); } remove { _reactionRemovedEvent.Remove(value); }
} }
internal readonly AsyncEvent<Func<Cacheable<IUserMessage, ulong>, ISocketMessageChannel, SocketReaction, Task>> _reactionRemovedEvent = new AsyncEvent<Func<Cacheable<IUserMessage, ulong>, ISocketMessageChannel, SocketReaction, Task>>();
internal readonly AsyncEvent<Func<Cacheable<IUserMessage, ulong>, Cacheable<ISocketMessageChannel, ulong>, SocketReaction, Task>> _reactionRemovedEvent = new AsyncEvent<Func<Cacheable<IUserMessage, ulong>, Cacheable<ISocketMessageChannel, ulong>, SocketReaction, Task>>();
/// <summary> Fired when all reactions to a message are cleared. </summary> /// <summary> Fired when all reactions to a message are cleared. </summary>
public event Func<Cacheable<IUserMessage, ulong>, ISocketMessageChannel, Task> ReactionsCleared {
public event Func<Cacheable<IUserMessage, ulong>, Cacheable<ISocketMessageChannel, ulong>, Task> ReactionsCleared {
add { _reactionsClearedEvent.Add(value); } add { _reactionsClearedEvent.Add(value); }
remove { _reactionsClearedEvent.Remove(value); } remove { _reactionsClearedEvent.Remove(value); }
} }
internal readonly AsyncEvent<Func<Cacheable<IUserMessage, ulong>, ISocketMessageChannel, Task>> _reactionsClearedEvent = new AsyncEvent<Func<Cacheable<IUserMessage, ulong>, ISocketMessageChannel, Task>>();
internal readonly AsyncEvent<Func<Cacheable<IUserMessage, ulong>, Cacheable<ISocketMessageChannel, ulong>, Task>> _reactionsClearedEvent = new AsyncEvent<Func<Cacheable<IUserMessage, ulong>, Cacheable<ISocketMessageChannel, ulong>, Task>>();
/// <summary> /// <summary>
/// Fired when all reactions to a message with a specific emote are removed. /// Fired when all reactions to a message with a specific emote are removed.
/// </summary> /// </summary>
@@ -250,12 +250,12 @@ namespace Discord.WebSocket
/// The emoji that all reactions had and were removed will be passed into the <see cref="IEmote"/> parameter. /// The emoji that all reactions had and were removed will be passed into the <see cref="IEmote"/> parameter.
/// </para> /// </para>
/// </remarks> /// </remarks>
public event Func<Cacheable<IUserMessage, ulong>, ISocketMessageChannel, IEmote, Task> ReactionsRemovedForEmote
public event Func<Cacheable<IUserMessage, ulong>, Cacheable<ISocketMessageChannel, ulong>, IEmote, Task> ReactionsRemovedForEmote
{ {
add { _reactionsRemovedForEmoteEvent.Add(value); } add { _reactionsRemovedForEmoteEvent.Add(value); }
remove { _reactionsRemovedForEmoteEvent.Remove(value); } remove { _reactionsRemovedForEmoteEvent.Remove(value); }
} }
internal readonly AsyncEvent<Func<Cacheable<IUserMessage, ulong>, ISocketMessageChannel, IEmote, Task>> _reactionsRemovedForEmoteEvent = new AsyncEvent<Func<Cacheable<IUserMessage, ulong>, ISocketMessageChannel, IEmote, Task>>();
internal readonly AsyncEvent<Func<Cacheable<IUserMessage, ulong>, Cacheable<ISocketMessageChannel, ulong>, IEmote, Task>> _reactionsRemovedForEmoteEvent = new AsyncEvent<Func<Cacheable<IUserMessage, ulong>, Cacheable<ISocketMessageChannel, ulong>, IEmote, Task>>();


//Roles //Roles
/// <summary> Fired when a role is created. </summary> /// <summary> Fired when a role is created. </summary>
@@ -372,11 +372,11 @@ namespace Discord.WebSocket
} }
internal readonly AsyncEvent<Func<SocketSelfUser, SocketSelfUser, Task>> _selfUpdatedEvent = new AsyncEvent<Func<SocketSelfUser, SocketSelfUser, Task>>(); internal readonly AsyncEvent<Func<SocketSelfUser, SocketSelfUser, Task>> _selfUpdatedEvent = new AsyncEvent<Func<SocketSelfUser, SocketSelfUser, Task>>();
/// <summary> Fired when a user starts typing. </summary> /// <summary> Fired when a user starts typing. </summary>
public event Func<SocketUser, ISocketMessageChannel, Task> UserIsTyping {
public event Func<Cacheable<IUser, ulong>, Cacheable<ISocketMessageChannel, ulong>, Task> UserIsTyping {
add { _userIsTypingEvent.Add(value); } add { _userIsTypingEvent.Add(value); }
remove { _userIsTypingEvent.Remove(value); } remove { _userIsTypingEvent.Remove(value); }
} }
internal readonly AsyncEvent<Func<SocketUser, ISocketMessageChannel, Task>> _userIsTypingEvent = new AsyncEvent<Func<SocketUser, ISocketMessageChannel, Task>>();
internal readonly AsyncEvent<Func<Cacheable<IUser, ulong>, Cacheable<ISocketMessageChannel, ulong>, Task>> _userIsTypingEvent = new AsyncEvent<Func<Cacheable<IUser, ulong>, Cacheable<ISocketMessageChannel, ulong>, Task>>();
/// <summary> Fired when a user joins a group channel. </summary> /// <summary> Fired when a user joins a group channel. </summary>
public event Func<SocketGroupUser, Task> RecipientAdded { public event Func<SocketGroupUser, Task> RecipientAdded {
add { _recipientAddedEvent.Add(value); } add { _recipientAddedEvent.Add(value); }


+ 165
- 149
src/Discord.Net.WebSocket/DiscordSocketClient.cs View File

@@ -71,7 +71,6 @@ namespace Discord.WebSocket
internal WebSocketProvider WebSocketProvider { get; private set; } internal WebSocketProvider WebSocketProvider { get; private set; }
internal bool AlwaysDownloadUsers { get; private set; } internal bool AlwaysDownloadUsers { get; private set; }
internal int? HandlerTimeout { get; private set; } internal int? HandlerTimeout { get; private set; }
internal bool? ExclusiveBulkDelete { get; private set; }


internal new DiscordSocketApiClient ApiClient => base.ApiClient as DiscordSocketApiClient; internal new DiscordSocketApiClient ApiClient => base.ApiClient as DiscordSocketApiClient;
/// <inheritdoc /> /// <inheritdoc />
@@ -132,7 +131,6 @@ namespace Discord.WebSocket
WebSocketProvider = config.WebSocketProvider; WebSocketProvider = config.WebSocketProvider;
AlwaysDownloadUsers = config.AlwaysDownloadUsers; AlwaysDownloadUsers = config.AlwaysDownloadUsers;
HandlerTimeout = config.HandlerTimeout; HandlerTimeout = config.HandlerTimeout;
ExclusiveBulkDelete = config.ExclusiveBulkDelete;
State = new ClientState(0, 0); State = new ClientState(0, 0);
Rest = new DiscordSocketRestClient(config, ApiClient); Rest = new DiscordSocketRestClient(config, ApiClient);
_heartbeatTimes = new ConcurrentQueue<long>(); _heartbeatTimes = new ConcurrentQueue<long>();
@@ -296,6 +294,44 @@ namespace Discord.WebSocket
public override SocketChannel GetChannel(ulong id) public override SocketChannel GetChannel(ulong id)
=> State.GetChannel(id); => State.GetChannel(id);
/// <summary> /// <summary>
/// Gets a generic channel from the cache or does a rest request if unavailable.
/// </summary>
/// <example>
/// <code language="cs" title="Example method">
/// var channel = await _client.GetChannelAsync(381889909113225237);
/// if (channel != null &amp;&amp; channel is IMessageChannel msgChannel)
/// {
/// await msgChannel.SendMessageAsync($"{msgChannel} is created at {msgChannel.CreatedAt}");
/// }
/// </code>
/// </example>
/// <param name="id">The snowflake identifier of the channel (e.g. `381889909113225237`).</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains the channel associated
/// with the snowflake identifier; <c>null</c> when the channel cannot be found.
/// </returns>
public async ValueTask<IChannel> GetChannelAsync(ulong id, RequestOptions options = null)
=> GetChannel(id) ?? (IChannel)await ClientHelper.GetChannelAsync(this, id, options).ConfigureAwait(false);
/// <summary>
/// Gets a user from the cache or does a rest request if unavailable.
/// </summary>
/// <example>
/// <code language="cs" title="Example method">
/// var user = await _client.GetUserAsync(168693960628371456);
/// if (user != null)
/// Console.WriteLine($"{user} is created at {user.CreatedAt}.";
/// </code>
/// </example>
/// <param name="id">The snowflake identifier of the user (e.g. `168693960628371456`).</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains the user associated with
/// the snowflake identifier; <c>null</c> if the user is not found.
/// </returns>
public async ValueTask<IUser> GetUserAsync(ulong id, RequestOptions options = null)
=> await ClientHelper.GetUserAsync(this, id, options).ConfigureAwait(false);
/// <summary>
/// Clears all cached channels from the client. /// Clears all cached channels from the client.
/// </summary> /// </summary>
public void PurgeChannelCache() => State.PurgeAllChannels(); public void PurgeChannelCache() => State.PurgeAllChannels();
@@ -1227,7 +1263,7 @@ namespace Discord.WebSocket
await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_CREATE)").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_CREATE)").ConfigureAwait(false);


var data = (payload as JToken).ToObject<API.Message>(_serializer); var data = (payload as JToken).ToObject<API.Message>(_serializer);
var channel = State.GetChannel(data.ChannelId) as ISocketMessageChannel;
var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;


var guild = (channel as SocketGuildChannel)?.Guild; var guild = (channel as SocketGuildChannel)?.Guild;
if (guild != null && !guild.IsSynced) if (guild != null && !guild.IsSynced)
@@ -1291,7 +1327,7 @@ namespace Discord.WebSocket
await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_UPDATE)").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_UPDATE)").ConfigureAwait(false);


var data = (payload as JToken).ToObject<API.Message>(_serializer); var data = (payload as JToken).ToObject<API.Message>(_serializer);
var channel = State.GetChannel(data.ChannelId) as ISocketMessageChannel;
var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;


var guild = (channel as SocketGuildChannel)?.Guild; var guild = (channel as SocketGuildChannel)?.Guild;
if (guild != null && !guild.IsSynced) if (guild != null && !guild.IsSynced)
@@ -1369,26 +1405,22 @@ namespace Discord.WebSocket
await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_DELETE)").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_DELETE)").ConfigureAwait(false);


var data = (payload as JToken).ToObject<API.Message>(_serializer); var data = (payload as JToken).ToObject<API.Message>(_serializer);
if (State.GetChannel(data.ChannelId) is ISocketMessageChannel channel)
{
var guild = (channel as SocketGuildChannel)?.Guild;
if (!(guild?.IsSynced ?? true))
{
await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
return;
}

var msg = SocketChannelHelper.RemoveMessage(channel, this, data.Id);
bool isCached = msg != null;
var cacheable = new Cacheable<IMessage, ulong>(msg, data.Id, isCached, async () => await channel.GetMessageAsync(data.Id).ConfigureAwait(false));
var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;


await TimedInvokeAsync(_messageDeletedEvent, nameof(MessageDeleted), cacheable, channel).ConfigureAwait(false);
}
else
var guild = (channel as SocketGuildChannel)?.Guild;
if (!(guild?.IsSynced ?? true))
{ {
await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false);
await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
return; return;
} }

SocketMessage msg = null;
if (channel != null)
msg = SocketChannelHelper.RemoveMessage(channel, this, data.Id);
var cacheableMsg = new Cacheable<IMessage, ulong>(msg, data.Id, msg != null, () => Task.FromResult((IMessage)null));
var cacheableChannel = new Cacheable<ISocketMessageChannel, ulong>(channel, data.ChannelId, channel != null, async () => await GetChannelAsync(data.Id).ConfigureAwait(false) as ISocketMessageChannel);

await TimedInvokeAsync(_messageDeletedEvent, nameof(MessageDeleted), cacheableMsg, cacheableChannel).ConfigureAwait(false);
} }
break; break;
case "MESSAGE_REACTION_ADD": case "MESSAGE_REACTION_ADD":
@@ -1396,40 +1428,39 @@ namespace Discord.WebSocket
await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_REACTION_ADD)").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_REACTION_ADD)").ConfigureAwait(false);


var data = (payload as JToken).ToObject<API.Gateway.Reaction>(_serializer); var data = (payload as JToken).ToObject<API.Gateway.Reaction>(_serializer);
if (State.GetChannel(data.ChannelId) is ISocketMessageChannel channel)
{
var cachedMsg = channel.GetCachedMessage(data.MessageId) as SocketUserMessage;
bool isCached = cachedMsg != null;
var user = await channel.GetUserAsync(data.UserId, CacheMode.CacheOnly).ConfigureAwait(false);
var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;


var optionalMsg = !isCached
? Optional.Create<SocketUserMessage>()
: Optional.Create(cachedMsg);
var cachedMsg = channel.GetCachedMessage(data.MessageId) as SocketUserMessage;
bool isMsgCached = cachedMsg != null;
var user = await channel.GetUserAsync(data.UserId, CacheMode.CacheOnly).ConfigureAwait(false);


if (data.Member.IsSpecified)
{
var guild = (channel as SocketGuildChannel)?.Guild;
if (guild != null)
user = guild.AddOrUpdateUser(data.Member.Value);
}
var optionalMsg = !isMsgCached
? Optional.Create<SocketUserMessage>()
: Optional.Create(cachedMsg);


var optionalUser = user is null
? Optional.Create<IUser>()
: Optional.Create(user);
if (data.Member.IsSpecified)
{
var guild = (channel as SocketGuildChannel)?.Guild;


var reaction = SocketReaction.Create(data, channel, optionalMsg, optionalUser);
var cacheable = new Cacheable<IUserMessage, ulong>(cachedMsg, data.MessageId, isCached, async () => await channel.GetMessageAsync(data.MessageId).ConfigureAwait(false) as IUserMessage);
if (guild != null)
user = guild.AddOrUpdateUser(data.Member.Value);
}


cachedMsg?.AddReaction(reaction);
var optionalUser = user is null
? Optional.Create<IUser>()
: Optional.Create(user);


await TimedInvokeAsync(_reactionAddedEvent, nameof(ReactionAdded), cacheable, channel, reaction).ConfigureAwait(false);
}
else
var cacheableChannel = new Cacheable<ISocketMessageChannel, ulong>(channel, data.ChannelId, channel != null, async () => await GetChannelAsync(data.ChannelId).ConfigureAwait(false) as ISocketMessageChannel);
var cacheableMsg = new Cacheable<IUserMessage, ulong>(cachedMsg, data.MessageId, isMsgCached, async () =>
{ {
await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false);
return;
}
var channelObj = await cacheableChannel.GetOrDownloadAsync().ConfigureAwait(false);
return await channelObj.GetMessageAsync(data.MessageId).ConfigureAwait(false) as IUserMessage;
});
var reaction = SocketReaction.Create(data, channel, optionalMsg, optionalUser);

cachedMsg?.AddReaction(reaction);

await TimedInvokeAsync(_reactionAddedEvent, nameof(ReactionAdded), cacheableMsg, cacheableChannel, reaction).ConfigureAwait(false);
} }
break; break;
case "MESSAGE_REACTION_REMOVE": case "MESSAGE_REACTION_REMOVE":
@@ -1437,32 +1468,31 @@ namespace Discord.WebSocket
await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_REACTION_REMOVE)").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_REACTION_REMOVE)").ConfigureAwait(false);


var data = (payload as JToken).ToObject<API.Gateway.Reaction>(_serializer); var data = (payload as JToken).ToObject<API.Gateway.Reaction>(_serializer);
if (State.GetChannel(data.ChannelId) is ISocketMessageChannel channel)
{
var cachedMsg = channel.GetCachedMessage(data.MessageId) as SocketUserMessage;
bool isCached = cachedMsg != null;
var user = await channel.GetUserAsync(data.UserId, CacheMode.CacheOnly).ConfigureAwait(false);

var optionalMsg = !isCached
? Optional.Create<SocketUserMessage>()
: Optional.Create(cachedMsg);
var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;


var optionalUser = user is null
? Optional.Create<IUser>()
: Optional.Create(user);
var cachedMsg = channel.GetCachedMessage(data.MessageId) as SocketUserMessage;
bool isMsgCached = cachedMsg != null;
var user = await channel.GetUserAsync(data.UserId, CacheMode.CacheOnly).ConfigureAwait(false);


var reaction = SocketReaction.Create(data, channel, optionalMsg, optionalUser);
var cacheable = new Cacheable<IUserMessage, ulong>(cachedMsg, data.MessageId, isCached, async () => await channel.GetMessageAsync(data.MessageId).ConfigureAwait(false) as IUserMessage);
var optionalMsg = !isMsgCached
? Optional.Create<SocketUserMessage>()
: Optional.Create(cachedMsg);


cachedMsg?.RemoveReaction(reaction);
var optionalUser = user is null
? Optional.Create<IUser>()
: Optional.Create(user);


await TimedInvokeAsync(_reactionRemovedEvent, nameof(ReactionRemoved), cacheable, channel, reaction).ConfigureAwait(false);
}
else
var cacheableChannel = new Cacheable<ISocketMessageChannel, ulong>(channel, data.ChannelId, channel != null, async () => await GetChannelAsync(data.ChannelId).ConfigureAwait(false) as ISocketMessageChannel);
var cacheableMsg = new Cacheable<IUserMessage, ulong>(cachedMsg, data.MessageId, isMsgCached, async () =>
{ {
await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false);
return;
}
var channelObj = await cacheableChannel.GetOrDownloadAsync().ConfigureAwait(false);
return await channelObj.GetMessageAsync(data.MessageId).ConfigureAwait(false) as IUserMessage;
});
var reaction = SocketReaction.Create(data, channel, optionalMsg, optionalUser);

cachedMsg?.RemoveReaction(reaction);

await TimedInvokeAsync(_reactionRemovedEvent, nameof(ReactionRemoved), cacheableMsg, cacheableChannel, reaction).ConfigureAwait(false);
} }
break; break;
case "MESSAGE_REACTION_REMOVE_ALL": case "MESSAGE_REACTION_REMOVE_ALL":
@@ -1470,21 +1500,20 @@ namespace Discord.WebSocket
await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_REACTION_REMOVE_ALL)").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_REACTION_REMOVE_ALL)").ConfigureAwait(false);


var data = (payload as JToken).ToObject<RemoveAllReactionsEvent>(_serializer); var data = (payload as JToken).ToObject<RemoveAllReactionsEvent>(_serializer);
if (State.GetChannel(data.ChannelId) is ISocketMessageChannel channel)
var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;

var cacheableChannel = new Cacheable<ISocketMessageChannel, ulong>(channel, data.ChannelId, channel != null, async () => await GetChannelAsync(data.ChannelId).ConfigureAwait(false) as ISocketMessageChannel);
var cachedMsg = channel.GetCachedMessage(data.MessageId) as SocketUserMessage;
bool isMsgCached = cachedMsg != null;
var cacheableMsg = new Cacheable<IUserMessage, ulong>(cachedMsg, data.MessageId, isMsgCached, async () =>
{ {
var cachedMsg = channel.GetCachedMessage(data.MessageId) as SocketUserMessage;
bool isCached = cachedMsg != null;
var cacheable = new Cacheable<IUserMessage, ulong>(cachedMsg, data.MessageId, isCached, async () => (await channel.GetMessageAsync(data.MessageId).ConfigureAwait(false)) as IUserMessage);
var channelObj = await cacheableChannel.GetOrDownloadAsync().ConfigureAwait(false);
return await channelObj.GetMessageAsync(data.MessageId).ConfigureAwait(false) as IUserMessage;
});


cachedMsg?.ClearReactions();
cachedMsg?.ClearReactions();


await TimedInvokeAsync(_reactionsClearedEvent, nameof(ReactionsCleared), cacheable, channel).ConfigureAwait(false);
}
else
{
await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false);
return;
}
await TimedInvokeAsync(_reactionsClearedEvent, nameof(ReactionsCleared), cacheableMsg, cacheableChannel).ConfigureAwait(false);
} }
break; break;
case "MESSAGE_REACTION_REMOVE_EMOJI": case "MESSAGE_REACTION_REMOVE_EMOJI":
@@ -1492,70 +1521,55 @@ namespace Discord.WebSocket
await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_REACTION_REMOVE_EMOJI)").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_REACTION_REMOVE_EMOJI)").ConfigureAwait(false);


var data = (payload as JToken).ToObject<API.Gateway.RemoveAllReactionsForEmoteEvent>(_serializer); var data = (payload as JToken).ToObject<API.Gateway.RemoveAllReactionsForEmoteEvent>(_serializer);
if (State.GetChannel(data.ChannelId) is ISocketMessageChannel channel)
{
var cachedMsg = channel.GetCachedMessage(data.MessageId) as SocketUserMessage;
bool isCached = cachedMsg != null;

var optionalMsg = !isCached
? Optional.Create<SocketUserMessage>()
: Optional.Create(cachedMsg);
var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;


var cacheable = new Cacheable<IUserMessage, ulong>(cachedMsg, data.MessageId, isCached, async () => await channel.GetMessageAsync(data.MessageId).ConfigureAwait(false) as IUserMessage);
var emote = data.Emoji.ToIEmote();
var cachedMsg = channel.GetCachedMessage(data.MessageId) as SocketUserMessage;
bool isMsgCached = cachedMsg != null;


cachedMsg?.RemoveReactionsForEmote(emote);
var optionalMsg = !isMsgCached
? Optional.Create<SocketUserMessage>()
: Optional.Create(cachedMsg);


await TimedInvokeAsync(_reactionsRemovedForEmoteEvent, nameof(ReactionsRemovedForEmote), cacheable, channel, emote).ConfigureAwait(false);
}
else
var cacheableChannel = new Cacheable<ISocketMessageChannel, ulong>(channel, data.ChannelId, channel != null, async () => await GetChannelAsync(data.ChannelId).ConfigureAwait(false) as ISocketMessageChannel);
var cacheableMsg = new Cacheable<IUserMessage, ulong>(cachedMsg, data.MessageId, isMsgCached, async () =>
{ {
await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false);
return;
}
var channelObj = await cacheableChannel.GetOrDownloadAsync().ConfigureAwait(false);
return await channelObj.GetMessageAsync(data.MessageId).ConfigureAwait(false) as IUserMessage;
});
var emote = data.Emoji.ToIEmote();

cachedMsg?.RemoveReactionsForEmote(emote);

await TimedInvokeAsync(_reactionsRemovedForEmoteEvent, nameof(ReactionsRemovedForEmote), cacheableMsg, cacheableChannel, emote).ConfigureAwait(false);
} }
break; break;
case "MESSAGE_DELETE_BULK": case "MESSAGE_DELETE_BULK":
{ {
await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_DELETE_BULK)").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_DELETE_BULK)").ConfigureAwait(false);


if (!ExclusiveBulkDelete.HasValue)
{
await _gatewayLogger.WarningAsync("A bulk delete event has been received, but the event handling behavior has not been set. " +
"To suppress this message, set the ExclusiveBulkDelete configuration property. " +
"This message will appear only once.");
ExclusiveBulkDelete = false;
}

var data = (payload as JToken).ToObject<MessageDeleteBulkEvent>(_serializer); var data = (payload as JToken).ToObject<MessageDeleteBulkEvent>(_serializer);
if (State.GetChannel(data.ChannelId) is ISocketMessageChannel channel)
{
var guild = (channel as SocketGuildChannel)?.Guild;
if (!(guild?.IsSynced ?? true))
{
await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
return;
}

var cacheableList = new List<Cacheable<IMessage, ulong>>(data.Ids.Length);
foreach (ulong id in data.Ids)
{
var msg = SocketChannelHelper.RemoveMessage(channel, this, id);
bool isCached = msg != null;
var cacheable = new Cacheable<IMessage, ulong>(msg, id, isCached, async () => await channel.GetMessageAsync(id).ConfigureAwait(false));
cacheableList.Add(cacheable);
var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;


if (!ExclusiveBulkDelete ?? false) // this shouldn't happen, but we'll play it safe anyways
await TimedInvokeAsync(_messageDeletedEvent, nameof(MessageDeleted), cacheable, channel).ConfigureAwait(false);
}

await TimedInvokeAsync(_messagesBulkDeletedEvent, nameof(MessagesBulkDeleted), cacheableList, channel).ConfigureAwait(false);
}
else
var guild = (channel as SocketGuildChannel)?.Guild;
if (!(guild?.IsSynced ?? true))
{ {
await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false);
await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
return; return;
} }

var cacheableChannel = new Cacheable<ISocketMessageChannel, ulong>(channel, data.ChannelId, channel != null, async () => await GetChannelAsync(data.ChannelId).ConfigureAwait(false) as ISocketMessageChannel);
var cacheableList = new List<Cacheable<IMessage, ulong>>(data.Ids.Length);
foreach (ulong id in data.Ids)
{
SocketMessage msg = null;
if (channel != null)
msg = SocketChannelHelper.RemoveMessage(channel, this, id);
bool isMsgCached = msg != null;
var cacheableMsg = new Cacheable<IMessage, ulong>(msg, id, isMsgCached, () => Task.FromResult((IMessage)null));
cacheableList.Add(cacheableMsg);
}

await TimedInvokeAsync(_messagesBulkDeletedEvent, nameof(MessagesBulkDeleted), cacheableList, cacheableChannel).ConfigureAwait(false);
} }
break; break;


@@ -1624,24 +1638,26 @@ namespace Discord.WebSocket
await _gatewayLogger.DebugAsync("Received Dispatch (TYPING_START)").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Received Dispatch (TYPING_START)").ConfigureAwait(false);


var data = (payload as JToken).ToObject<TypingStartEvent>(_serializer); var data = (payload as JToken).ToObject<TypingStartEvent>(_serializer);
if (State.GetChannel(data.ChannelId) is ISocketMessageChannel channel)
var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;

var guild = (channel as SocketGuildChannel)?.Guild;
if (!(guild?.IsSynced ?? true))
{ {
var guild = (channel as SocketGuildChannel)?.Guild;
if (!(guild?.IsSynced ?? true))
{
await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
return;
}
await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
return;
}


var user = (channel as SocketChannel).GetUser(data.UserId);
if (user == null)
{
if (guild != null)
user = guild.AddOrUpdateUser(data.Member);
}
if (user != null)
await TimedInvokeAsync(_userIsTypingEvent, nameof(UserIsTyping), user, channel).ConfigureAwait(false);
var cacheableChannel = new Cacheable<ISocketMessageChannel, ulong>(channel, data.ChannelId, channel != null, async () => await GetChannelAsync(data.ChannelId).ConfigureAwait(false) as ISocketMessageChannel);

var user = (channel as SocketChannel)?.GetUser(data.UserId);
if (user == null)
{
if (guild != null)
user = guild.AddOrUpdateUser(data.Member);
} }
var cacheableUser = new Cacheable<IUser, ulong>(user, data.UserId, user != null, async () => await GetUserAsync(data.UserId).ConfigureAwait(false));

await TimedInvokeAsync(_userIsTypingEvent, nameof(UserIsTyping), cacheableUser, cacheableChannel).ConfigureAwait(false);
} }
break; break;


@@ -1713,7 +1729,7 @@ namespace Discord.WebSocket
} }
else else
{ {
var groupChannel = State.GetChannel(data.ChannelId.Value) as SocketGroupChannel;
var groupChannel = GetChannel(data.ChannelId.Value) as SocketGroupChannel;
if (groupChannel == null) if (groupChannel == null)
{ {
await UnknownChannelAsync(type, data.ChannelId.Value).ConfigureAwait(false); await UnknownChannelAsync(type, data.ChannelId.Value).ConfigureAwait(false);
@@ -2138,8 +2154,8 @@ namespace Discord.WebSocket
=> await GetApplicationInfoAsync().ConfigureAwait(false); => await GetApplicationInfoAsync().ConfigureAwait(false);


/// <inheritdoc /> /// <inheritdoc />
Task<IChannel> IDiscordClient.GetChannelAsync(ulong id, CacheMode mode, RequestOptions options)
=> Task.FromResult<IChannel>(GetChannel(id));
async Task<IChannel> IDiscordClient.GetChannelAsync(ulong id, CacheMode mode, RequestOptions options)
=> mode == CacheMode.AllowDownload ? await GetChannelAsync(id, options).ConfigureAwait(false) : GetChannel(id);
/// <inheritdoc /> /// <inheritdoc />
Task<IReadOnlyCollection<IPrivateChannel>> IDiscordClient.GetPrivateChannelsAsync(CacheMode mode, RequestOptions options) Task<IReadOnlyCollection<IPrivateChannel>> IDiscordClient.GetPrivateChannelsAsync(CacheMode mode, RequestOptions options)
=> Task.FromResult<IReadOnlyCollection<IPrivateChannel>>(PrivateChannels); => Task.FromResult<IReadOnlyCollection<IPrivateChannel>>(PrivateChannels);
@@ -2169,8 +2185,8 @@ namespace Discord.WebSocket
=> await CreateGuildAsync(name, region, jpegIcon).ConfigureAwait(false); => await CreateGuildAsync(name, region, jpegIcon).ConfigureAwait(false);


/// <inheritdoc /> /// <inheritdoc />
Task<IUser> IDiscordClient.GetUserAsync(ulong id, CacheMode mode, RequestOptions options)
=> Task.FromResult<IUser>(GetUser(id));
async Task<IUser> IDiscordClient.GetUserAsync(ulong id, CacheMode mode, RequestOptions options)
=> mode == CacheMode.AllowDownload ? await GetUserAsync(id, options).ConfigureAwait(false) : GetUser(id);
/// <inheritdoc /> /// <inheritdoc />
Task<IUser> IDiscordClient.GetUserAsync(string username, string discriminator, RequestOptions options) Task<IUser> IDiscordClient.GetUserAsync(string username, string discriminator, RequestOptions options)
=> Task.FromResult<IUser>(GetUser(username, discriminator)); => Task.FromResult<IUser>(GetUser(username, discriminator));


+ 0
- 16
src/Discord.Net.WebSocket/DiscordSocketConfig.cs View File

@@ -111,22 +111,6 @@ namespace Discord.WebSocket
/// </summary> /// </summary>
public int? HandlerTimeout { get; set; } = 3000; public int? HandlerTimeout { get; set; } = 3000;


/// <summary>
/// Gets or sets the behavior for <see cref="BaseSocketClient.MessageDeleted"/> on bulk deletes.
/// </summary>
/// <remarks>
/// <para>
/// If <c>true</c>, the <see cref="BaseSocketClient.MessageDeleted"/> event will not be raised for bulk
/// deletes, and only the <see cref="BaseSocketClient.MessagesBulkDeleted"/> will be raised. If <c>false</c>
/// , both events will be raised.
/// </para>
/// <para>
/// If unset, both events will be raised, but a warning will be raised the first time a bulk delete event is
/// received.
/// </para>
/// </remarks>
public bool? ExclusiveBulkDelete { get; set; } = null;

/// <summary> /// <summary>
/// Gets or sets the maximum identify concurrency. /// Gets or sets the maximum identify concurrency.
/// </summary> /// </summary>


Loading…
Cancel
Save