From f4d5e8f78833fc37a53740f47a1f8838a88395dc Mon Sep 17 00:00:00 2001 From: Yuzu Date: Tue, 12 Jul 2022 08:30:17 -0500 Subject: [PATCH] feat(cache): improvements --- packages/biscuit/Actions.ts | 4 +- packages/cache/mod.ts | 146 ++++++++++++++++++++++++++++++++---- 2 files changed, 135 insertions(+), 15 deletions(-) diff --git a/packages/biscuit/Actions.ts b/packages/biscuit/Actions.ts index db49438..7c2bf62 100644 --- a/packages/biscuit/Actions.ts +++ b/packages/biscuit/Actions.ts @@ -346,7 +346,7 @@ export const GUILD_SCHEDULED_EVENT_USER_REMOVE: RawHandler = (session, shardId, data) => { - session.emit("raw", data, shardId); + session.emit("raw", data as { t: string, d: unknown }, shardId); }; export interface Ready extends Omit { @@ -404,7 +404,7 @@ export interface Events { "guildScheduledEventDelete": Handler<[ScheduledEvent]>; "guildScheduledEventUserAdd": Handler<[{scheduledEventId: Snowflake, userId: Snowflake, guildId: Snowflake}]> "guildScheduledEventUserRemove": Handler<[{scheduledEventId: Snowflake, userId: Snowflake, guildId: Snowflake}]> - "raw": Handler<[unknown, number]>; + "raw": Handler<[{ t: string, d: unknown }, number]>; "webhooksUpdate": Handler<[{ guildId: Snowflake, channelId: Snowflake }]>; "userUpdate": Handler<[User]>; "presenceUpdate": Handler<[Presence]>; diff --git a/packages/cache/mod.ts b/packages/cache/mod.ts index 7347c70..149a93a 100644 --- a/packages/cache/mod.ts +++ b/packages/cache/mod.ts @@ -1,5 +1,6 @@ import type { ChannelTypes, + DiscordMessage, DiscordChannel, DiscordEmoji, DiscordGuild, @@ -37,47 +38,82 @@ export interface CachedMember extends Omit { } export interface CachedGuild extends Omit { - channels: Map; - members: Map; + channels: StructCache; + members: StructCache; } export interface CachedGuildChannel extends Omit { type: ChannelTypes; - messages: Map; + messages: StructCache; } export interface CachedGuildChannel extends Omit { type: ChannelTypes; - messages: Map; + messages: StructCache; } export interface CachedGuildChannel extends Omit { type: ChannelTypes; - messages: Map; + messages: StructCache; } export interface CachedGuildChannel extends Omit { type: ChannelTypes; - messages: Map; + messages: StructCache; +} + +export interface CachedDMChannel extends DMChannel { + messages: StructCache; } export interface SessionCache extends SymCache { guilds: StructCache; users: StructCache; - dms: StructCache; + dms: StructCache; emojis: StructCache; session: Session; } export default function (session: Session): SessionCache { - return { + const cache = { guilds: new StructCache(session), users: new StructCache(session), - dms: new StructCache(session), + dms: new StructCache(session), emojis: new StructCache(session), cache: cache_sym, session, }; + + session.on("raw", (data) => { + // deno-lint-ignore no-explicit-any + const raw = data.d as any; + + switch (data.t) { + case "MESSAGE_CREATE": + messageBootstrapper(cache, raw, false); + break; + case "MESSAGE_UPDATE": + messageBootstrapper(cache, raw, !raw.edited_timestamp); + break; + case "CHANNEL_CREATE": + // DMChannelBootstrapper(cache, raw); + break; + case "GUILD_MEMBER_ADD": + memberBootstrapper(cache, raw, raw.guild_id); + break; + case "GUILD_CREATE": + guildBootstrapper(cache, raw); + break; + case "GUILD_DELETE": + cache.guilds.delete(raw.id); + break; + case "MESSAGE_DELETE": + // pass + break; + } + }); + + return cache; } export class StructCache extends Map { @@ -85,6 +121,7 @@ export class StructCache extends Map { super(entries); this.session = session; } + readonly session: Session; get(key: Snowflake): V | undefined { @@ -230,6 +267,36 @@ export class StructCache extends Map { get empty(): boolean { return this.size === 0; } + + updateFields(key: Snowflake, obj: Partial) { + const value = this.get(key); + + if (!value) { + return; + } + + for (const prop in obj) { + if (obj[prop]) { + value[prop] = obj[prop]!; + } + } + + return this.set(key, value); + } + + getOr(key: Snowflake, or: V): V | undefined { + return this.get(key) ?? or; + } + + retrieve(key: Snowflake, fn: (value: V) => T) { + const value = this.get(key); + + if (!value) { + return; + } + + return fn(value); + } } export function userBootstrapper(cache: SessionCache, user: DiscordUser) { @@ -242,11 +309,64 @@ export function emojiBootstrapper(cache: SessionCache, emoji: DiscordEmoji, guil } export function DMChannelBootstrapper(cache: SessionCache, channel: DiscordChannel) { - cache.dms.set(channel.id, new DMChannel(cache.session, channel)); + cache.dms.set(channel.id, Object.assign( + new DMChannel(cache.session, channel), + { messages: new StructCache(cache.session) } + )); } -export function guildBootstrapper(guild: DiscordGuild, cache: SessionCache) { - const members = new Map(guild.members?.map((data) => { +export function memberBootstrapper(cache: SessionCache, member: DiscordMemberWithUser, guildId: Snowflake) { + cache.guilds.retrieve(guildId, (guild) => { + guild.members.set(member.user.id, Object.assign( + new Member(cache.session, member, guildId), + { + userId: member.user.id, + get user(): User | undefined { + return cache.users.get(this.userId); + } + } + )); + }); +} + +export function messageBootstrapper(cache: SessionCache, message: DiscordMessage, partial: boolean) { + if (message.member) { + const member: DiscordMemberWithUser = Object.assign(message.member, { user: message.author }); + + memberBootstrapper(cache, member, message.guild_id!); + } + + if (cache.dms.has(message.channel_id)) { + // is dm + cache.dms.retrieve(message.channel_id, (dm) => { + dm.messages[partial ? "updateFields" : "set"](message.id, Object.assign( + new Message(cache.session, message), + { + authorId: message.author.id, + get author(): User | undefined { + return cache.users.get(this.authorId); + }, + } + )); + }); + } else { + // is not dm + cache.guilds.retrieve(message.guild_id!, (guild) => guild.channels.retrieve(message.channel_id, (dm) => { + dm.messages[partial ? "updateFields" : "set"](message.id, Object.assign( + new Message(cache.session, message), + { + authorId: message.author.id, + get author(): User | undefined { + return cache.users.get(this.authorId); + }, + } + )); + })); + } +} + +export function guildBootstrapper(cache: SessionCache, guild: DiscordGuild) { + const members = new StructCache(cache.session, guild.members?.map((data) => { const obj: CachedMember = Object.assign(new Member(cache.session, data as DiscordMemberWithUser, guild.id), { userId: data.user!.id, get user(): User | undefined { @@ -257,7 +377,7 @@ export function guildBootstrapper(guild: DiscordGuild, cache: SessionCache) { return [data.user!.id, obj as CachedMember]; })); - const channels = new Map(guild.channels?.map((data) => { + const channels = new StructCache(cache.session, guild.channels?.map((data) => { const obj = Object.assign(ChannelFactory.from(cache.session, data), { messages: new Map(), });