diff --git a/src/client/actions/Action.js b/src/client/actions/Action.js index d9519b5c7..18be1944c 100644 --- a/src/client/actions/Action.js +++ b/src/client/actions/Action.js @@ -81,23 +81,23 @@ class GenericAction { } getMember(data, guild) { - const id = data.user.id; - return this.getPayload( - { - user: { - id, - }, - }, - guild.members, - id, - PartialTypes.GUILD_MEMBER, - ); + return this.getPayload(data, guild.members, data.user.id, PartialTypes.GUILD_MEMBER); } getUser(data) { const id = data.user_id; return data.user || this.getPayload({ id }, this.client.users, id, PartialTypes.USER); } + + getUserFromMember(data) { + if (data.guild_id) { + const guild = this.client.guilds.cache.get(data.guild_id); + if (guild) { + return this.getMember(data.member, guild).user; + } + } + return this.getUser(data); + } } module.exports = GenericAction; diff --git a/src/client/actions/ActionsManager.js b/src/client/actions/ActionsManager.js index 7e1df121f..a5193c932 100644 --- a/src/client/actions/ActionsManager.js +++ b/src/client/actions/ActionsManager.js @@ -35,6 +35,7 @@ class ActionsManager { this.register(require('./GuildChannelsPositionUpdate')); this.register(require('./GuildIntegrationsUpdate')); this.register(require('./WebhooksUpdate')); + this.register(require('./TypingStart')); } register(Action) { diff --git a/src/client/actions/GuildMemberRemove.js b/src/client/actions/GuildMemberRemove.js index f0fe3b385..b690446aa 100644 --- a/src/client/actions/GuildMemberRemove.js +++ b/src/client/actions/GuildMemberRemove.js @@ -9,7 +9,7 @@ class GuildMemberRemoveAction extends Action { const guild = client.guilds.cache.get(data.guild_id); let member = null; if (guild) { - member = this.getMember(data, guild); + member = this.getMember({ user: data.user }, guild); guild.memberCount--; if (member) { member.deleted = true; diff --git a/src/client/actions/MessageReactionAdd.js b/src/client/actions/MessageReactionAdd.js index 92350f14e..54929f661 100644 --- a/src/client/actions/MessageReactionAdd.js +++ b/src/client/actions/MessageReactionAdd.js @@ -15,7 +15,7 @@ class MessageReactionAdd extends Action { handle(data) { if (!data.emoji) return false; - const user = this.getUser(data); + const user = this.getUserFromMember(data); if (!user) return false; // Verify channel diff --git a/src/client/actions/TypingStart.js b/src/client/actions/TypingStart.js new file mode 100644 index 000000000..b56aff770 --- /dev/null +++ b/src/client/actions/TypingStart.js @@ -0,0 +1,55 @@ +'use strict'; + +const Action = require('./Action'); +const { Events } = require('../../util/Constants'); +const textBasedChannelTypes = ['dm', 'text', 'news']; + +class TypingStart extends Action { + handle(data) { + const channel = this.getChannel(data); + if (!textBasedChannelTypes.includes(channel.type)) { + this.client.emit(Events.WARN, `Discord sent a typing packet to a ${channel.type} channel ${channel.id}`); + return; + } + + const user = this.getUserFromMember(data); + const timestamp = new Date(data.timestamp * 1000); + + if (channel && user) { + if (channel._typing.has(user.id)) { + const typing = channel._typing.get(user.id); + + typing.lastTimestamp = timestamp; + typing.elapsedTime = Date.now() - typing.since; + this.client.clearTimeout(typing.timeout); + typing.timeout = this.tooLate(channel, user); + } else { + const since = new Date(); + const lastTimestamp = new Date(); + channel._typing.set(user.id, { + user, + since, + lastTimestamp, + elapsedTime: Date.now() - since, + timeout: this.tooLate(channel, user), + }); + + /** + * Emitted whenever a user starts typing in a channel. + * @event Client#typingStart + * @param {Channel} channel The channel the user started typing in + * @param {User} user The user that started typing + */ + this.client.emit(Events.TYPING_START, channel, user); + } + } + } + + tooLate(channel, user) { + return channel.client.setTimeout(() => { + channel._typing.delete(user.id); + }, 10000); + } +} + +module.exports = TypingStart; diff --git a/src/client/websocket/handlers/TYPING_START.js b/src/client/websocket/handlers/TYPING_START.js index 28c8f840f..9a56a5458 100644 --- a/src/client/websocket/handlers/TYPING_START.js +++ b/src/client/websocket/handlers/TYPING_START.js @@ -1,50 +1,5 @@ 'use strict'; -const { Events } = require('../../../util/Constants'); -const textBasedChannelTypes = ['dm', 'text', 'news']; - -module.exports = (client, { d: data }) => { - const channel = client.channels.cache.get(data.channel_id); - const user = client.users.cache.get(data.user_id); - const timestamp = new Date(data.timestamp * 1000); - - if (channel && user) { - if (!textBasedChannelTypes.includes(channel.type)) { - client.emit(Events.WARN, `Discord sent a typing packet to a ${channel.type} channel ${channel.id}`); - return; - } - - if (channel._typing.has(user.id)) { - const typing = channel._typing.get(user.id); - - typing.lastTimestamp = timestamp; - typing.elapsedTime = Date.now() - typing.since; - client.clearTimeout(typing.timeout); - typing.timeout = tooLate(channel, user); - } else { - const since = new Date(); - const lastTimestamp = new Date(); - channel._typing.set(user.id, { - user, - since, - lastTimestamp, - elapsedTime: Date.now() - since, - timeout: tooLate(channel, user), - }); - - /** - * Emitted whenever a user starts typing in a channel. - * @event Client#typingStart - * @param {Channel} channel The channel the user started typing in - * @param {User} user The user that started typing - */ - client.emit(Events.TYPING_START, channel, user); - } - } +module.exports = (client, packet) => { + client.actions.TypingStart.handle(packet.d); }; - -function tooLate(channel, user) { - return channel.client.setTimeout(() => { - channel._typing.delete(user.id); - }, 10000); -}