feat: remove datastores and implement Managers (#3696)

* Initial commit: add 5 initial managers

- Base manager
- GuildChannelManager
- MessageManager
- PresenceManager
- Reaction Manager
- Added LimitedCollection

* Add GuildEmojiManager, various fixes

* Modify some managers and add guildmembermanager

* Initial integration

* Delete old stores

* Integration part two, removed LRUCollection

- Most of the integration has been finished
- TODO typings
- Removed LRUCollection, needless sweeping

* Typings + stuff i somehow missed in ChannelManager

* LimitedCollection typings/ final changes

* Various jsdoc and syntactical fixes, Removed Util.mixin()

* tslint fix

* Grammatical and logical changes

* Delete temporary file placed by mistake

* Grammatical changes

* Add missing type

* Update jsdoc examples

* fix: ChannelManager#remove should call cache#delete not cache#remove

* fix recursive require

* Fix missed cache in util

* fix: more missed cache

* Remove accidental _fetchMany change from #3645

* fix: use .cache.delete() over .remove()

* fix: missing cache in ReactionCollector

* fix: missed cache in client

* fix: members is a collection not a manager

Co-Authored-By: Sugden <28943913+NotSugden@users.noreply.github.com>

* fix: various docs and cache fixes

* fix: missed cache

* fix: missing _roles

* Final testing and debugging

* LimitedCollection: return the Collection instead of undefined on .set

* Add cache to BaseManager in typings

* Commit fixes i forgot to stage yesterday

* Update invite events

* Account for new commit

* fix: MessageReactionRemoveAll should call .cache.clear()

* fix: add .cache at various places, correct return type

* docs: remove mentions of 'store'

* Add extra documented properties to typings

Co-authored-by: Sugden <28943913+NotSugden@users.noreply.github.com>
Co-authored-by: SpaceEEC <spaceeec@yahoo.com>
This commit is contained in:
BorgerKing
2020-02-11 14:21:07 -05:00
committed by GitHub
parent fe7df708e4
commit bbdbc4cfa7
87 changed files with 804 additions and 705 deletions

View File

@@ -11,10 +11,10 @@ const Webhook = require('../structures/Webhook');
const Invite = require('../structures/Invite');
const ClientApplication = require('../structures/ClientApplication');
const ShardClientUtil = require('../sharding/ShardClientUtil');
const UserStore = require('../stores/UserStore');
const ChannelStore = require('../stores/ChannelStore');
const GuildStore = require('../stores/GuildStore');
const GuildEmojiStore = require('../stores/GuildEmojiStore');
const UserManager = require('../managers/UserManager');
const ChannelManager = require('../managers/ChannelManager');
const GuildManager = require('../managers/GuildManager');
const GuildEmojiManager = require('../managers/GuildEmojiManager');
const { Events, browser, DefaultOptions } = require('../util/Constants');
const DataResolver = require('../util/DataResolver');
const Structures = require('../util/Structures');
@@ -99,25 +99,25 @@ class Client extends BaseClient {
/**
* All of the {@link User} objects that have been cached at any point, mapped by their IDs
* @type {UserStore<Snowflake, User>}
* @type {UserManager}
*/
this.users = new UserStore(this);
this.users = new UserManager(this);
/**
* All of the guilds the client is currently handling, mapped by their IDs -
* as long as sharding isn't being used, this will be *every* guild the bot is a member of
* @type {GuildStore<Snowflake, Guild>}
* @type {GuildManager}
*/
this.guilds = new GuildStore(this);
this.guilds = new GuildManager(this);
/**
* All of the {@link Channel}s that the client is currently handling, mapped by their IDs -
* as long as sharding isn't being used, this will be *every* channel in *every* guild the bot
* is a member of. Note that DM channels will not be initially cached, and thus not be present
* in the store without their explicit fetching or use.
* @type {ChannelStore<Snowflake, Channel>}
* in the Manager without their explicit fetching or use.
* @type {ChannelManager}
*/
this.channels = new ChannelStore(this);
this.channels = new ChannelManager(this);
const ClientPresence = Structures.get('ClientPresence');
/**
@@ -159,13 +159,13 @@ class Client extends BaseClient {
/**
* All custom emojis that the client has access to, mapped by their IDs
* @type {GuildEmojiStore<Snowflake, GuildEmoji>}
* @type {GuildEmojiManager}
* @readonly
*/
get emojis() {
const emojis = new GuildEmojiStore({ client: this });
for (const guild of this.guilds.values()) {
if (guild.available) for (const emoji of guild.emojis.values()) emojis.set(emoji.id, emoji);
const emojis = new GuildEmojiManager({ client: this });
for (const guild of this.guilds.cache.values()) {
if (guild.available) for (const emoji of guild.emojis.cache.values()) emojis.cache.set(emoji.id, emoji);
}
return emojis;
}
@@ -298,11 +298,11 @@ class Client extends BaseClient {
let channels = 0;
let messages = 0;
for (const channel of this.channels.values()) {
for (const channel of this.channels.cache.values()) {
if (!channel.messages) continue;
channels++;
messages += channel.messages.sweep(
messages += channel.messages.cache.sweep(
message => now - (message.editedTimestamp || message.createdTimestamp) > lifetimeMs
);
}

View File

@@ -23,10 +23,10 @@ class GenericAction {
return data;
}
getPayload(data, store, id, partialType, cache) {
const existing = store.get(id);
getPayload(data, manager, id, partialType, cache) {
const existing = manager.cache.get(id);
if (!existing && this.client.options.partials.includes(partialType)) {
return store.add(data, cache);
return manager.add(data, cache);
}
return existing;
}

View File

@@ -6,7 +6,7 @@ const { Events } = require('../../util/Constants');
class ChannelCreateAction extends Action {
handle(data) {
const client = this.client;
const existing = client.channels.has(data.id);
const existing = client.channels.cache.has(data.id);
const channel = client.channels.add(data);
if (!existing && channel) {
/**

View File

@@ -12,13 +12,13 @@ class ChannelDeleteAction extends Action {
handle(data) {
const client = this.client;
let channel = client.channels.get(data.id);
let channel = client.channels.cache.get(data.id);
if (channel) {
client.channels.remove(channel.id);
channel.deleted = true;
if (channel.messages && !(channel instanceof DMChannel)) {
for (const message of channel.messages.values()) {
for (const message of channel.messages.cache.values()) {
message.deleted = true;
}
}

View File

@@ -8,16 +8,16 @@ class ChannelUpdateAction extends Action {
handle(data) {
const client = this.client;
let channel = client.channels.get(data.id);
let channel = client.channels.cache.get(data.id);
if (channel) {
const old = channel._update(data);
if (ChannelTypes[channel.type.toUpperCase()] !== data.type) {
const newChannel = Channel.create(this.client, data, channel.guild);
for (const [id, message] of channel.messages) newChannel.messages.set(id, message);
for (const [id, message] of channel.messages.cache) newChannel.messages.cache.set(id, message);
newChannel._typing = new Map(channel._typing);
channel = newChannel;
this.client.channels.set(channel.id, channel);
this.client.channels.cache.set(channel.id, channel);
}
return {

View File

@@ -6,7 +6,7 @@ const { Events } = require('../../util/Constants');
class GuildBanRemove extends Action {
handle(data) {
const client = this.client;
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
const user = client.users.add(data.user);
/**
* Emitted whenever a member is unbanned from a guild.

View File

@@ -6,10 +6,10 @@ class GuildChannelsPositionUpdate extends Action {
handle(data) {
const client = this.client;
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
if (guild) {
for (const partialChannel of data.channels) {
const channel = guild.channels.get(partialChannel.id);
const channel = guild.channels.cache.get(partialChannel.id);
if (channel) channel.rawPosition = partialChannel.position;
}
}

View File

@@ -12,9 +12,9 @@ class GuildDeleteAction extends Action {
handle(data) {
const client = this.client;
let guild = client.guilds.get(data.id);
let guild = client.guilds.cache.get(data.id);
if (guild) {
for (const channel of guild.channels.values()) {
for (const channel of guild.channels.cache.values()) {
if (channel.type === 'text') channel.stopTyping(true);
}
@@ -36,11 +36,11 @@ class GuildDeleteAction extends Action {
};
}
for (const channel of guild.channels.values()) this.client.channels.remove(channel.id);
for (const channel of guild.channels.cache.values()) this.client.channels.remove(channel.id);
if (guild.voice && guild.voice.connection) guild.voice.connection.disconnect();
// Delete guild
client.guilds.remove(guild.id);
client.guilds.cache.delete(guild.id);
guild.deleted = true;
/**

View File

@@ -5,7 +5,7 @@ const { Events } = require('../../util/Constants');
class GuildEmojiDeleteAction extends Action {
handle(emoji) {
emoji.guild.emojis.remove(emoji.id);
emoji.guild.emojis.cache.delete(emoji.id);
emoji.deleted = true;
/**
* Emitted whenever a custom emoji is deleted in a guild.

View File

@@ -4,14 +4,14 @@ const Action = require('./Action');
class GuildEmojisUpdateAction extends Action {
handle(data) {
const guild = this.client.guilds.get(data.guild_id);
const guild = this.client.guilds.cache.get(data.guild_id);
if (!guild || !guild.emojis) return;
const deletions = new Map(guild.emojis);
const deletions = new Map(guild.emojis.cache);
for (const emoji of data.emojis) {
// Determine type of emoji event
const cachedEmoji = guild.emojis.get(emoji.id);
const cachedEmoji = guild.emojis.cache.get(emoji.id);
if (cachedEmoji) {
deletions.delete(emoji.id);
if (!cachedEmoji.equals(emoji)) {

View File

@@ -6,7 +6,7 @@ const { Events } = require('../../util/Constants');
class GuildIntegrationsUpdate extends Action {
handle(data) {
const client = this.client;
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
/**
* Emitted whenever a guild integration is updated
* @event Client#guildIntegrationsUpdate

View File

@@ -6,14 +6,14 @@ const { Events, Status } = require('../../util/Constants');
class GuildMemberRemoveAction extends Action {
handle(data, shard) {
const client = this.client;
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
let member = null;
if (guild) {
member = this.getMember(data, guild);
guild.memberCount--;
if (member) {
member.deleted = true;
guild.members.remove(member.id);
guild.members.cache.delete(member.id);
/**
* Emitted whenever a member leaves a guild, or is kicked.
* @event Client#guildMemberRemove
@@ -21,7 +21,7 @@ class GuildMemberRemoveAction extends Action {
*/
if (shard.status === Status.READY) client.emit(Events.GUILD_MEMBER_REMOVE, member);
}
guild.voiceStates.delete(data.user.id);
guild.voiceStates.cache.delete(data.user.id);
}
return { guild, member };
}

View File

@@ -6,10 +6,10 @@ const { Events } = require('../../util/Constants');
class GuildRoleCreate extends Action {
handle(data) {
const client = this.client;
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
let role;
if (guild) {
const already = guild.roles.has(data.role.id);
const already = guild.roles.cache.has(data.role.id);
role = guild.roles.add(data.role);
/**
* Emitted whenever a role is created.

View File

@@ -6,13 +6,13 @@ const { Events } = require('../../util/Constants');
class GuildRoleDeleteAction extends Action {
handle(data) {
const client = this.client;
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
let role;
if (guild) {
role = guild.roles.get(data.role_id);
role = guild.roles.cache.get(data.role_id);
if (role) {
guild.roles.remove(data.role_id);
guild.roles.cache.delete(data.role_id);
role.deleted = true;
/**
* Emitted whenever a guild role is deleted.

View File

@@ -6,12 +6,12 @@ const { Events } = require('../../util/Constants');
class GuildRoleUpdateAction extends Action {
handle(data) {
const client = this.client;
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
if (guild) {
let old = null;
const role = guild.roles.get(data.role.id);
const role = guild.roles.cache.get(data.role.id);
if (role) {
old = role._update(data.role);
/**

View File

@@ -6,10 +6,10 @@ class GuildRolesPositionUpdate extends Action {
handle(data) {
const client = this.client;
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
if (guild) {
for (const partialRole of data.roles) {
const role = guild.roles.get(partialRole.id);
const role = guild.roles.cache.get(partialRole.id);
if (role) role.rawPosition = partialRole.position;
}
}

View File

@@ -7,7 +7,7 @@ class GuildUpdateAction extends Action {
handle(data) {
const client = this.client;
const guild = client.guilds.get(data.id);
const guild = client.guilds.cache.get(data.id);
if (guild) {
const old = guild._update(data);
/**

View File

@@ -7,8 +7,8 @@ const { Events } = require('../../util/Constants');
class InviteCreateAction extends Action {
handle(data) {
const client = this.client;
const channel = client.channels.get(data.channel_id);
const guild = client.guilds.get(data.guild_id);
const channel = client.channels.cache.get(data.channel_id);
const guild = client.guilds.cache.get(data.guild_id);
if (!channel && !guild) return false;
const inviteData = Object.assign(data, { channel, guild });

View File

@@ -7,8 +7,8 @@ const { Events } = require('../../util/Constants');
class InviteDeleteAction extends Action {
handle(data) {
const client = this.client;
const channel = client.channels.get(data.channel_id);
const guild = client.guilds.get(data.guild_id);
const channel = client.channels.cache.get(data.channel_id);
const guild = client.guilds.cache.get(data.guild_id);
if (!channel && !guild) return false;
const inviteData = Object.assign(data, { channel, guild });

View File

@@ -6,9 +6,9 @@ const { Events } = require('../../util/Constants');
class MessageCreateAction extends Action {
handle(data) {
const client = this.client;
const channel = client.channels.get(data.channel_id);
const channel = client.channels.cache.get(data.channel_id);
if (channel) {
const existing = channel.messages.get(data.id);
const existing = channel.messages.cache.get(data.id);
if (existing) return { message: existing };
const message = channel.messages.add(data);
const user = message.author;

View File

@@ -11,7 +11,7 @@ class MessageDeleteAction extends Action {
if (channel) {
message = this.getMessage(data, channel);
if (message) {
channel.messages.delete(message.id);
channel.messages.cache.delete(message.id);
message.deleted = true;
/**
* Emitted whenever a message is deleted.

View File

@@ -7,7 +7,7 @@ const { Events } = require('../../util/Constants');
class MessageDeleteBulkAction extends Action {
handle(data) {
const client = this.client;
const channel = client.channels.get(data.channel_id);
const channel = client.channels.cache.get(data.channel_id);
if (channel) {
const ids = data.ids;
@@ -20,7 +20,7 @@ class MessageDeleteBulkAction extends Action {
if (message) {
message.deleted = true;
messages.set(message.id, message);
channel.messages.delete(id);
channel.messages.cache.delete(id);
}
}

View File

@@ -13,7 +13,7 @@ class MessageReactionRemoveAll extends Action {
const message = this.getMessage(data, channel);
if (!message) return false;
message.reactions.clear();
message.reactions.cache.clear();
this.client.emit(Events.MESSAGE_REACTION_REMOVE_ALL, message);
return { message };

View File

@@ -13,7 +13,7 @@ class MessageReactionRemoveEmoji extends Action {
const reaction = this.getReaction(data, message);
if (!reaction) return false;
if (!message.partial) message.reactions.delete(reaction.emoji.id || reaction.emoji.name);
if (!message.partial) message.reactions.cache.delete(reaction.emoji.id || reaction.emoji.name);
/**
* Emitted when a bot removes an emoji reaction from a cached message.

View File

@@ -5,7 +5,7 @@ const { Events } = require('../../util/Constants');
class PresenceUpdateAction extends Action {
handle(data) {
let user = this.client.users.get(data.user.id);
let user = this.client.users.cache.get(data.user.id);
if (!user && data.user.username) user = this.client.users.add(data.user);
if (!user) return;
@@ -13,12 +13,12 @@ class PresenceUpdateAction extends Action {
if (!user.equals(data.user)) this.client.actions.UserUpdate.handle(data.user);
}
const guild = this.client.guilds.get(data.guild_id);
const guild = this.client.guilds.cache.get(data.guild_id);
if (!guild) return;
let oldPresence = guild.presences.get(user.id);
let oldPresence = guild.presences.cache.get(user.id);
if (oldPresence) oldPresence = oldPresence._clone();
let member = guild.members.get(user.id);
let member = guild.members.cache.get(user.id);
if (!member && data.status !== 'offline') {
member = guild.members.add({
user,

View File

@@ -7,7 +7,7 @@ class UserUpdateAction extends Action {
handle(data) {
const client = this.client;
const newUser = client.users.get(data.id);
const newUser = client.users.cache.get(data.id);
const oldUser = newUser._update(data);
if (!oldUser.equals(newUser)) {

View File

@@ -7,17 +7,17 @@ const VoiceState = require('../../structures/VoiceState');
class VoiceStateUpdate extends Action {
handle(data) {
const client = this.client;
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
if (guild) {
// Update the state
const oldState = guild.voiceStates.has(data.user_id) ?
guild.voiceStates.get(data.user_id)._clone() :
const oldState = guild.voiceStates.cache.has(data.user_id) ?
guild.voiceStates.cache.get(data.user_id)._clone() :
new VoiceState(guild, { user_id: data.user_id });
const newState = guild.voiceStates.add(data);
// Get the member
let member = guild.members.get(data.user_id);
let member = guild.members.cache.get(data.user_id);
if (member && data.member) {
member._patch(data.member);
} else if (data.member && data.member.user && data.member.joined_at) {

View File

@@ -6,7 +6,7 @@ const { Events } = require('../../util/Constants');
class WebhooksUpdate extends Action {
handle(data) {
const client = this.client;
const channel = client.channels.get(data.channel_id);
const channel = client.channels.cache.get(data.channel_id);
/**
* Emitted whenever a guild text channel has its webhooks changed.
* @event Client#webhookUpdate

View File

@@ -56,7 +56,7 @@ class ClientVoiceManager {
this.connections.delete(guild_id);
return;
}
connection.channel = this.client.channels.get(channel_id);
connection.channel = this.client.channels.cache.get(channel_id);
connection.setSessionID(session_id);
}

View File

@@ -483,7 +483,7 @@ class VoiceConnection extends EventEmitter {
onSpeaking({ user_id, speaking }) {
speaking = new Speaking(speaking).freeze();
const guild = this.channel.guild;
const user = this.client.users.get(user_id);
const user = this.client.users.cache.get(user_id);
const old = this._speaking.get(user_id);
this._speaking.set(user_id, speaking);
/**

View File

@@ -408,7 +408,7 @@ class WebSocketManager extends EventEmitter {
if (this.client.options.fetchAllMembers) {
try {
const promises = this.client.guilds.map(guild => {
const promises = this.client.guilds.cache.map(guild => {
if (guild.available) return guild.members.fetch();
// Return empty promise if guild is unavailable
return Promise.resolve();

View File

@@ -3,7 +3,7 @@
const { Events } = require('../../../util/Constants');
module.exports = (client, { d: data }) => {
const channel = client.channels.get(data.channel_id);
const channel = client.channels.cache.get(data.channel_id);
const time = new Date(data.last_pin_timestamp);
if (channel && !Number.isNaN(time.getTime())) {

View File

@@ -3,7 +3,7 @@
const { Events } = require('../../../util/Constants');
module.exports = (client, { d: data }) => {
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
const user = client.users.add(data.user);
/**

View File

@@ -3,7 +3,7 @@
const { Events, Status } = require('../../../util/Constants');
module.exports = async (client, { d: data }, shard) => {
let guild = client.guilds.get(data.id);
let guild = client.guilds.cache.get(data.id);
if (guild) {
if (!guild.available && !data.unavailable) {
// A newly available guild

View File

@@ -4,7 +4,7 @@ const { Events } = require('../../../util/Constants');
const Collection = require('../../../util/Collection');
module.exports = (client, { d: data }) => {
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
if (!guild) return;
const members = new Collection();

View File

@@ -3,7 +3,7 @@
const { Events, Status } = require('../../../util/Constants');
module.exports = (client, { d: data }, shard) => {
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
if (guild) {
guild.memberCount++;
const member = guild.members.add(data);

View File

@@ -3,9 +3,9 @@
const { Status, Events } = require('../../../util/Constants');
module.exports = (client, { d: data }, shard) => {
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
if (guild) {
const member = guild.members.get(data.user.id);
const member = guild.members.cache.get(data.user.id);
if (member) {
const old = member._update(data);
if (shard.status === Status.READY) {

View File

@@ -9,7 +9,7 @@ module.exports = (client, { d: data }, shard) => {
if (!ClientUser) ClientUser = require('../../../structures/ClientUser');
const clientUser = new ClientUser(client, data.user);
client.user = clientUser;
client.users.set(clientUser.id, clientUser);
client.users.cache.set(clientUser.id, clientUser);
}
for (const guild of data.guilds) {

View File

@@ -3,8 +3,8 @@
const { Events } = require('../../../util/Constants');
module.exports = (client, { d: data }) => {
const channel = client.channels.get(data.channel_id);
const user = client.users.get(data.user_id);
const channel = client.channels.cache.get(data.channel_id);
const user = client.users.cache.get(data.user_id);
if (channel && user) {
/**