feat(cache): improvements

This commit is contained in:
Yuzu 2022-07-12 08:30:17 -05:00
parent 33380a0b35
commit f4d5e8f788
2 changed files with 135 additions and 15 deletions

View File

@ -346,7 +346,7 @@ export const GUILD_SCHEDULED_EVENT_USER_REMOVE: RawHandler<DiscordScheduledEvent
}; };
export const raw: RawHandler<unknown> = (session, shardId, data) => { export const raw: RawHandler<unknown> = (session, shardId, data) => {
session.emit("raw", data, shardId); session.emit("raw", data as { t: string, d: unknown }, shardId);
}; };
export interface Ready extends Omit<DiscordReady, "user"> { export interface Ready extends Omit<DiscordReady, "user"> {
@ -404,7 +404,7 @@ export interface Events {
"guildScheduledEventDelete": Handler<[ScheduledEvent]>; "guildScheduledEventDelete": Handler<[ScheduledEvent]>;
"guildScheduledEventUserAdd": Handler<[{scheduledEventId: Snowflake, userId: Snowflake, guildId: Snowflake}]> "guildScheduledEventUserAdd": Handler<[{scheduledEventId: Snowflake, userId: Snowflake, guildId: Snowflake}]>
"guildScheduledEventUserRemove": 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 }]>; "webhooksUpdate": Handler<[{ guildId: Snowflake, channelId: Snowflake }]>;
"userUpdate": Handler<[User]>; "userUpdate": Handler<[User]>;
"presenceUpdate": Handler<[Presence]>; "presenceUpdate": Handler<[Presence]>;

146
packages/cache/mod.ts vendored
View File

@ -1,5 +1,6 @@
import type { import type {
ChannelTypes, ChannelTypes,
DiscordMessage,
DiscordChannel, DiscordChannel,
DiscordEmoji, DiscordEmoji,
DiscordGuild, DiscordGuild,
@ -37,47 +38,82 @@ export interface CachedMember extends Omit<Member, "user"> {
} }
export interface CachedGuild extends Omit<Guild, "members" | "channels"> { export interface CachedGuild extends Omit<Guild, "members" | "channels"> {
channels: Map<Snowflake, CachedGuildChannel>; channels: StructCache<CachedGuildChannel>;
members: Map<Snowflake, CachedMember>; members: StructCache<CachedMember>;
} }
export interface CachedGuildChannel extends Omit<GuildTextChannel, "type"> { export interface CachedGuildChannel extends Omit<GuildTextChannel, "type"> {
type: ChannelTypes; type: ChannelTypes;
messages: Map<Snowflake, CachedMessage>; messages: StructCache<CachedMessage>;
} }
export interface CachedGuildChannel extends Omit<VoiceChannel, "type"> { export interface CachedGuildChannel extends Omit<VoiceChannel, "type"> {
type: ChannelTypes; type: ChannelTypes;
messages: Map<Snowflake, CachedMessage>; messages: StructCache<CachedMessage>;
} }
export interface CachedGuildChannel extends Omit<NewsChannel, "type"> { export interface CachedGuildChannel extends Omit<NewsChannel, "type"> {
type: ChannelTypes; type: ChannelTypes;
messages: Map<Snowflake, CachedMessage>; messages: StructCache<CachedMessage>;
} }
export interface CachedGuildChannel extends Omit<ThreadChannel, "type"> { export interface CachedGuildChannel extends Omit<ThreadChannel, "type"> {
type: ChannelTypes; type: ChannelTypes;
messages: Map<Snowflake, CachedMessage>; messages: StructCache<CachedMessage>;
}
export interface CachedDMChannel extends DMChannel {
messages: StructCache<CachedMessage>;
} }
export interface SessionCache extends SymCache { export interface SessionCache extends SymCache {
guilds: StructCache<CachedGuild>; guilds: StructCache<CachedGuild>;
users: StructCache<User>; users: StructCache<User>;
dms: StructCache<DMChannel>; dms: StructCache<CachedDMChannel>;
emojis: StructCache<GuildEmoji>; emojis: StructCache<GuildEmoji>;
session: Session; session: Session;
} }
export default function (session: Session): SessionCache { export default function (session: Session): SessionCache {
return { const cache = {
guilds: new StructCache<CachedGuild>(session), guilds: new StructCache<CachedGuild>(session),
users: new StructCache<User>(session), users: new StructCache<User>(session),
dms: new StructCache<DMChannel>(session), dms: new StructCache<CachedDMChannel>(session),
emojis: new StructCache<GuildEmoji>(session), emojis: new StructCache<GuildEmoji>(session),
cache: cache_sym, cache: cache_sym,
session, 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<V> extends Map<Snowflake, V> { export class StructCache<V> extends Map<Snowflake, V> {
@ -85,6 +121,7 @@ export class StructCache<V> extends Map<Snowflake, V> {
super(entries); super(entries);
this.session = session; this.session = session;
} }
readonly session: Session; readonly session: Session;
get(key: Snowflake): V | undefined { get(key: Snowflake): V | undefined {
@ -230,6 +267,36 @@ export class StructCache<V> extends Map<Snowflake, V> {
get empty(): boolean { get empty(): boolean {
return this.size === 0; return this.size === 0;
} }
updateFields(key: Snowflake, obj: Partial<V>) {
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<T>(key: Snowflake, fn: (value: V) => T) {
const value = this.get(key);
if (!value) {
return;
}
return fn(value);
}
} }
export function userBootstrapper(cache: SessionCache, user: DiscordUser) { 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) { 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<CachedMessage>(cache.session) }
));
} }
export function guildBootstrapper(guild: DiscordGuild, cache: SessionCache) { export function memberBootstrapper(cache: SessionCache, member: DiscordMemberWithUser, guildId: Snowflake) {
const members = new Map(guild.members?.map((data) => { 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), { const obj: CachedMember = Object.assign(new Member(cache.session, data as DiscordMemberWithUser, guild.id), {
userId: data.user!.id, userId: data.user!.id,
get user(): User | undefined { get user(): User | undefined {
@ -257,7 +377,7 @@ export function guildBootstrapper(guild: DiscordGuild, cache: SessionCache) {
return [data.user!.id, obj as CachedMember]; 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), { const obj = Object.assign(ChannelFactory.from(cache.session, data), {
messages: new Map(), messages: new Map(),
}); });