@@ -36,6 +36,7 @@ namespace Discord.Rest | |||
entity.Update(model); | |||
return entity; | |||
} | |||
internal void Update(Model model) | |||
{ | |||
base.Update(model); | |||
@@ -0,0 +1,13 @@ | |||
using Newtonsoft.Json; | |||
namespace Discord.API | |||
{ | |||
internal class InviteEvent : InviteMetadata | |||
{ | |||
[JsonProperty("channel_id")] | |||
public ulong ChannelId { get; set; } | |||
[JsonProperty("guild_id")] | |||
public ulong GuildId { get; set; } | |||
} | |||
} |
@@ -235,6 +235,14 @@ namespace Discord.WebSocket | |||
} | |||
internal readonly AsyncEvent<Func<Cacheable<IUserMessage, ulong>, ISocketMessageChannel, Task>> _reactionsClearedEvent = new AsyncEvent<Func<Cacheable<IUserMessage, ulong>, ISocketMessageChannel, Task>>(); | |||
/// <summary> Fired when all reactions of a specific reaction are removed.</summary> | |||
public event Func<Cacheable<IUserMessage, ulong>, ISocketMessageChannel, SocketReaction, Task> ReactionsClearedEmoji { | |||
add { _reactionsClearedEmojiEvent.Add(value); } | |||
remove { _reactionsClearedEmojiEvent.Remove(value); } | |||
} | |||
internal readonly AsyncEvent<Func<Cacheable<IUserMessage, ulong>, ISocketMessageChannel, SocketReaction, Task>> _reactionsClearedEmojiEvent = new AsyncEvent<Func<Cacheable<IUserMessage, ulong>, ISocketMessageChannel, SocketReaction, Task>>(); | |||
//Roles | |||
/// <summary> Fired when a role is created. </summary> | |||
public event Func<SocketRole, Task> RoleCreated { | |||
@@ -293,6 +301,21 @@ namespace Discord.WebSocket | |||
} | |||
internal readonly AsyncEvent<Func<SocketGuild, SocketGuild, Task>> _guildUpdatedEvent = new AsyncEvent<Func<SocketGuild, SocketGuild, Task>>(); | |||
//Invites | |||
/// <summary> Fired when an invite is created.</summary | |||
public event Func<SocketInvite, Task> InviteCreated { | |||
add { _inviteCreatedEvent.Add(value); } | |||
remove { _inviteCreatedEvent.Remove(value); } | |||
} | |||
internal readonly AsyncEvent<Func<SocketInvite, Task>> _inviteCreatedEvent = new AsyncEvent<Func<SocketInvite, Task>>(); | |||
/// <summary>Fired when an invite is deleted.</summary> | |||
public event Func<SocketInvite, Task> InviteDeleted | |||
{ | |||
add { _inviteDeletedEvent.Add(value); } | |||
remove { _inviteDeletedEvent.Remove(value); } | |||
} | |||
internal readonly AsyncEvent<Func<SocketInvite, Task>> _inviteDeletedEvent = new AsyncEvent<Func<SocketInvite, Task>>(); | |||
//Users | |||
/// <summary> Fired when a user joins a guild. </summary> | |||
public event Func<SocketGuildUser, Task> UserJoined { | |||
@@ -313,6 +313,7 @@ namespace Discord.WebSocket | |||
client.ReactionAdded += (cache, channel, reaction) => _reactionAddedEvent.InvokeAsync(cache, channel, reaction); | |||
client.ReactionRemoved += (cache, channel, reaction) => _reactionRemovedEvent.InvokeAsync(cache, channel, reaction); | |||
client.ReactionsCleared += (cache, channel) => _reactionsClearedEvent.InvokeAsync(cache, channel); | |||
client.ReactionsClearedEmoji += (cache, channel, reaction) => _reactionsClearedEmojiEvent.InvokeAsync(cache, channel, reaction); | |||
client.RoleCreated += (role) => _roleCreatedEvent.InvokeAsync(role); | |||
client.RoleDeleted += (role) => _roleDeletedEvent.InvokeAsync(role); | |||
@@ -325,6 +326,9 @@ namespace Discord.WebSocket | |||
client.GuildMembersDownloaded += (guild) => _guildMembersDownloadedEvent.InvokeAsync(guild); | |||
client.GuildUpdated += (oldGuild, newGuild) => _guildUpdatedEvent.InvokeAsync(oldGuild, newGuild); | |||
client.InviteCreated += (invite) => _inviteCreatedEvent.InvokeAsync(invite); | |||
client.InviteDeleted += (invite) => _inviteDeletedEvent.InvokeAsync(invite); | |||
client.UserJoined += (user) => _userJoinedEvent.InvokeAsync(user); | |||
client.UserLeft += (user) => _userLeftEvent.InvokeAsync(user); | |||
client.UserBanned += (user, guild) => _userBannedEvent.InvokeAsync(user, guild); | |||
@@ -882,7 +882,6 @@ namespace Discord.WebSocket | |||
await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false); | |||
return; | |||
} | |||
if (user != null) | |||
{ | |||
var before = user.Clone(); | |||
@@ -1213,7 +1212,6 @@ namespace Discord.WebSocket | |||
case "MESSAGE_UPDATE": | |||
{ | |||
await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_UPDATE)").ConfigureAwait(false); | |||
var data = (payload as JToken).ToObject<API.Message>(_serializer); | |||
if (State.GetChannel(data.ChannelId) is ISocketMessageChannel channel) | |||
{ | |||
@@ -1378,6 +1376,41 @@ namespace Discord.WebSocket | |||
} | |||
} | |||
break; | |||
case "MESSAGE_REACTION_REMOVE_EMOJI": | |||
{ | |||
await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_REACTION_REMOVE_EMOJI)").ConfigureAwait(false); | |||
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 optionalUser = user is null | |||
? Optional.Create<IUser>() | |||
: Optional.Create(user); | |||
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); | |||
cachedMsg?.ClearReactionsEmoji(reaction); | |||
await TimedInvokeAsync(_reactionsClearedEmojiEvent, nameof(ReactionsClearedEmoji), cacheable, channel, reaction).ConfigureAwait(false); | |||
} | |||
else | |||
{ | |||
await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false); | |||
return; | |||
} | |||
} | |||
break; | |||
case "MESSAGE_DELETE_BULK": | |||
{ | |||
await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_DELETE_BULK)").ConfigureAwait(false); | |||
@@ -1422,6 +1455,53 @@ namespace Discord.WebSocket | |||
} | |||
break; | |||
//Invites | |||
case "INVITE_CREATE": | |||
{ | |||
await _gatewayLogger.DebugAsync("Received Dispatch (INVITE_CREATE)").ConfigureAwait(false); | |||
var data = (payload as JToken).ToObject<InviteEvent>(_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 inviter = State.GetUser(data.Inviter.Id) as SocketUser; | |||
var invite = SocketInvite.Create(this, data, inviter, guild, channel); | |||
await TimedInvokeAsync(_inviteCreatedEvent, nameof(InviteCreated), invite); | |||
} | |||
else | |||
await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false); | |||
} | |||
break; | |||
case "INVITE_DELETE": | |||
{ | |||
await _gatewayLogger.DebugAsync("Received Dispatch (INVITE_DELETE)").ConfigureAwait(false); | |||
var data = (payload as JToken).ToObject<InviteEvent>(_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 invite = SocketInvite.Create(this, data, guild, channel); | |||
await TimedInvokeAsync(_inviteDeletedEvent, nameof(InviteDeleted), invite).ConfigureAwait(false); | |||
} | |||
else | |||
await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false); | |||
} | |||
break; | |||
//Statuses | |||
case "PRESENCE_UPDATE": | |||
{ | |||
@@ -0,0 +1,79 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
using Model = Discord.API.InviteEvent; | |||
namespace Discord.WebSocket | |||
{ | |||
public class SocketInvite : SocketEntity<string> | |||
{ | |||
public ISocketMessageChannel Channel { get; private set; } | |||
public ulong ChannelId { get; private set; } | |||
public IGuild Guild { get; private set; } | |||
public ulong GuildId { get; private set; } | |||
public string Code { get; private set; } | |||
public SocketUser Inviter { get; private set; } | |||
public DateTimeOffset CreatedAt { get; private set; } | |||
public int MaxAge { get; private set; } | |||
public int MaxUses { get; private set; } | |||
public int Uses { get; set; } | |||
public bool Temporary { get; private set; } | |||
internal SocketInvite(DiscordSocketClient discord, Model model) | |||
: base(discord, model.Code) | |||
{ | |||
} | |||
internal static SocketInvite Create(DiscordSocketClient discord, Model model, SocketUser inviter, IGuild guild, ISocketMessageChannel channel) | |||
{ | |||
var entity = new SocketInvite(discord, model); | |||
entity.Update(model, inviter, guild, channel); | |||
return entity; | |||
} | |||
internal static SocketInvite Create(DiscordSocketClient discord, Model model, IGuild guild, ISocketMessageChannel channel) | |||
{ | |||
var entity = new SocketInvite(discord, model); | |||
entity.Update(model.Code, guild, channel); | |||
return entity; | |||
} | |||
internal void Update(Model model, SocketUser inviter, IGuild guild, ISocketMessageChannel channel) | |||
{ | |||
Channel = channel; | |||
ChannelId = model.ChannelId; | |||
Guild = guild; | |||
GuildId = model.GuildId; | |||
Code = model.Code; | |||
Inviter = inviter; | |||
CreatedAt = model.CreatedAt.Value; | |||
MaxAge = model.MaxAge.Value; | |||
MaxUses = model.MaxUses.Value; | |||
Uses = model.Uses.Value; | |||
Temporary = model.Temporary; | |||
} | |||
internal void Update(string code, IGuild guild, ISocketMessageChannel channel) | |||
{ | |||
Code = code; | |||
Guild = guild; | |||
GuildId = guild.Id; | |||
Channel = channel; | |||
ChannelId = channel.Id; | |||
} | |||
} | |||
} |
@@ -197,9 +197,10 @@ namespace Discord.WebSocket | |||
_reactions.Remove(reaction); | |||
} | |||
internal void ClearReactions() | |||
{ | |||
_reactions.Clear(); | |||
} | |||
=> _reactions.Clear(); | |||
internal void ClearReactionsEmoji(SocketReaction reaction) | |||
=> _reactions.RemoveAll(r => r.Emote.Equals(reaction)); | |||
/// <inheritdoc /> | |||
public Task AddReactionAsync(IEmote emote, RequestOptions options = null) | |||