Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions Sources/SwiftDiscord/DiscordClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,9 @@ open class DiscordClient : DiscordClientSpec, DiscordDispatchEventHandler, Disco
case .presenceUpdate: handlePresenceUpdate(with: eventData)
case .messageCreate: handleMessageCreate(with: eventData)
case .messageUpdate: handleMessageUpdate(with: eventData)
case .messageReactionAdd: handleMessageReactionAdd(with: eventData)
case .messageReactionRemove: handleMessageReactionRemove(with: eventData)
case .messageReactionRemoveAll: handleMessageReactionRemoveAll(with: eventData)
case .guildMemberAdd: handleGuildMemberAdd(with: eventData)
case .guildMembersChunk: handleGuildMembersChunk(with: eventData)
case .guildMemberUpdate: handleGuildMemberUpdate(with: eventData)
Expand Down Expand Up @@ -819,6 +822,88 @@ open class DiscordClient : DiscordClientSpec, DiscordDispatchEventHandler, Disco
delegate?.client(self, didCreateMessage: message)
}

/// Used to get fields for reaction notifications since add and remove are very similar
/// - parameter mode: A string to identify add/remove when logging errors
private func getReactionInfo(mode: String, from data: [String: Any]) -> (UserID, DiscordTextChannel, MessageID, DiscordEmoji)? {
guard let userID = UserID(data["user_id"] as? String),
let channelID = ChannelID(data["channel_id"] as? String),
let messageID = MessageID(data["message_id"] as? String),
let emoji = (data["emoji"] as? [String: Any]).map(DiscordEmoji.init(emojiObject:))
else {
DefaultDiscordLogger.Logger.log("Failed to get required fields from reaction \(mode)", type: logType)
return nil
}
guard let channel = findChannel(fromId: channelID) as? DiscordTextChannel else {
DefaultDiscordLogger.Logger.log("Failed to get channel from ID in reaction \(mode)", type: logType)
return nil
}
return (userID, channel, messageID, emoji)
}

///
/// Handles reaction adds from Discord. You shouldn't need to call this method directly.
///
/// Override to provide additional customization around this event.
///
/// Calls the `didAddReaction` delegate method.
///
/// - parameter with: The data from the event
///
open func handleMessageReactionAdd(with data: [String: Any]) {
DefaultDiscordLogger.Logger.log("Handling message reaction add", type: logType)

guard let (userID, channel, messageID, emoji) = getReactionInfo(mode: "add", from: data) else { return }

if let guildID = GuildID(data["guild_id"] as? String),
let guild = guilds[guildID],
let member = (data["member"] as? [String: Any]).map({ DiscordGuildMember(guildMemberObject: $0, guildId: guildID) }) {
guild.members[member.user.id] = member
}

delegate?.client(self, didAddReaction: emoji, toMessage: messageID, onChannel: channel, user: userID)
}

///
/// Handles reaction removals from Discord. You shouldn't need to call this method directly.
///
/// Override to provide additional customization around this event.
///
/// Calls the `didRemoveReaction` delegate method.
///
/// - parameter with: The data from the event
///
open func handleMessageReactionRemove(with data: [String: Any]) {
DefaultDiscordLogger.Logger.log("Handling message reaction remove", type: logType)

guard let (userID, channel, messageID, emoji) = getReactionInfo(mode: "remove", from: data) else { return }

delegate?.client(self, didRemoveReaction: emoji, fromMessage: messageID, onChannel: channel, user: userID)
}

///
/// Handles reaction remove alls from Discord. You shouldn't need to call this method directly.
///
/// Override to provide additional customization around this event.
///
/// Calls the `didRemoveAllReactionsFrom` delegate method.
///
/// - parameter with: The data from the event
///
open func handleMessageReactionRemoveAll(with data: [String: Any]) {
guard let channelID = ChannelID(data["channel_id"] as? String),
let messageID = MessageID(data["message_id"] as? String)
else {
DefaultDiscordLogger.Logger.log("Failed to get required fields from reaction remove all", type: logType)
return
}
guard let channel = findChannel(fromId: channelID) as? DiscordTextChannel else {
DefaultDiscordLogger.Logger.log("Failed to get channel from ID in reaction remove all", type: logType)
return
}

delegate?.client(self, didRemoveAllReactionsFrom: messageID, onChannel: channel)
}

///
/// Handles presence updates from Discord. You shouldn't need to call this method directly.
///
Expand Down
40 changes: 40 additions & 0 deletions Sources/SwiftDiscord/DiscordClientDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,37 @@ public protocol DiscordClientDelegate : class {
///
func client(_ client: DiscordClient, didCreateMessage message: DiscordMessage)

///
/// Called when a user adds a reaction to a message.
///
/// - parameter client: The client that is calling.
/// - parameter reaction: The reaction that was added.
/// - parameter messageID: The ID of the message the reaction was added to.
/// - parameter channel: The channel the message was on.
/// - parameter userID: The ID of the user who added the reaction.
///
func client(_ client: DiscordClient, didAddReaction reaction: DiscordEmoji, toMessage messageID: MessageID, onChannel channel: DiscordTextChannel, user userID: UserID)

///
/// Called when a user removes a reaction to a message.
///
/// - parameter client: The client that is calling.
/// - parameter reaction: The reaction that was added.
/// - parameter messageID: The ID of the message the reaction was removed from.
/// - parameter channel: The channel the message was on.
/// - parameter userID: The ID of the user who added the reaction.
///
func client(_ client: DiscordClient, didRemoveReaction reaction: DiscordEmoji, fromMessage messageID: MessageID, onChannel channel: DiscordTextChannel, user userID: UserID)

///
/// Called when all reactions are removed from a message.
///
/// - parameter client: The client that is calling.
/// - parameter messageID: The ID of the message all
/// - parameter channel: The channel the message was on
///
func client(_ client: DiscordClient, didRemoveAllReactionsFrom messageID: MessageID, onChannel channel: DiscordTextChannel)

///
/// Called when the client adds a new role.
///
Expand Down Expand Up @@ -304,6 +335,15 @@ public extension DiscordClientDelegate {
/// Default.
func client(_ client: DiscordClient, didCreateMessage message: DiscordMessage) { }

/// Default.
func client(_ client: DiscordClient, didAddReaction reaction: DiscordEmoji, toMessage messageID: MessageID, onChannel channel: DiscordTextChannel, user userID: UserID) { }

/// Default.
func client(_ client: DiscordClient, didRemoveReaction reaction: DiscordEmoji, fromMessage messageID: MessageID, onChannel channel: DiscordTextChannel, user userID: UserID) { }

/// Default.
func client(_ client: DiscordClient, didRemoveAllReactionsFrom messageID: MessageID, onChannel channel: DiscordTextChannel) { }

/// Default.
func client(_ client: DiscordClient, didReceivePresenceUpdate presence: DiscordPresence) { }

Expand Down
6 changes: 3 additions & 3 deletions Sources/SwiftDiscord/Gateway/DiscordEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ public enum DiscordDispatchEvent : String {
/// Message Delete Bulk (Not handled)
case messageDeleteBulk = "MESSAGE_DELETE_BULK"

/// Message Reaction Add (Not handled)
/// Message Reaction Add (Handled)
case messageReactionAdd = "MESSAGE_REACTION_ADD"

/// Message Reaction Remove All (Not handled)
/// Message Reaction Remove All (Handled)
case messageReactionRemoveAll = "MESSAGE_REACTION_REMOVE_ALL"

/// Message Reaction Remove (Not handled)
/// Message Reaction Remove (Handled)
case messageReactionRemove = "MESSAGE_REACTION_REMOVE"

/// Message Update (Not handled)
Expand Down