// deno-lint-ignore-file require-await no-explicit-any prefer-const import { botId } from "./bot.ts"; import type { DiscordenoChannel } from "./structures/channel.ts"; import type { DiscordenoGuild } from "./structures/guild.ts"; import type { DiscordenoMember } from "./structures/member.ts"; import type { DiscordenoMessage } from "./structures/message.ts"; import type { PresenceUpdate } from "./types/activity/presence_update.ts"; import type { Emoji } from "./types/emojis/emoji.ts"; import { Collection } from "./util/collection.ts"; export const cache = { isReady: false, /** All of the guild objects the bot has access to, mapped by their Ids */ guilds: new Collection([], { sweeper: { filter: guildSweeper, interval: 3600000 } }), /** All of the channel objects the bot has access to, mapped by their Ids */ channels: new Collection(), /** All of the message objects the bot has cached since the bot acquired `READY` state, mapped by their Ids */ messages: new Collection([], { sweeper: { filter: messageSweeper, interval: 300000 } }), /** All of the member objects that have been cached since the bot acquired `READY` state, mapped by their Ids */ members: new Collection([], { sweeper: { filter: memberSweeper, interval: 300000 } }), /** All of the unavailable guilds, mapped by their Ids (id, timestamp) */ unavailableGuilds: new Collection(), /** All of the presence update objects received in PRESENCE_UPDATE gateway event, mapped by their user Id */ presences: new Collection([], { sweeper: { filter: () => true, interval: 300000 } }), fetchAllMembersProcessingRequests: new Collection< string, (value: Collection | PromiseLike>) => void >(), executedSlashCommands: new Set(), get emojis() { return new Collection( this.guilds.reduce((a, b) => [...a, ...b.emojis.map((e) => [e.id, e])], [] as any[]) ); }, activeGuildIds: new Set(), dispatchedGuildIds: new Set(), dispatchedChannelIds: new Set(), }; function messageSweeper(message: DiscordenoMessage) { // DM messages aren't needed if (!message.guildId) return true; // Only delete messages older than 10 minutes return Date.now() - message.timestamp > 600000; } function memberSweeper(member: DiscordenoMember) { // Don't sweep the bot else strange things will happen if (member.id === botId) return false; // Only sweep members who were not active the last 30 minutes return Date.now() - member.cachedAt < 1800000; } function guildSweeper(guild: DiscordenoGuild) { // Reset activity for next interval if (cache.activeGuildIds.delete(guild.id)) return false; guild.channels.forEach((channel) => { cache.channels.delete(channel.id); cache.dispatchedChannelIds.add(channel.id); }); // This is inactive guild. Not a single thing has happened for atleast 30 minutes. // Not a reaction, not a message, not any event! cache.dispatchedGuildIds.add(guild.id); return true; } export let cacheHandlers = { /** Deletes all items from the cache */ async clear(table: TableName) { return cache[table].clear(); }, /** Deletes 1 item from cache using the key */ async delete(table: TableName, key: bigint) { return cache[table].delete(key); }, /** Check if something exists in cache with a key */ async has(table: TableName, key: bigint) { return cache[table].has(key); }, /** Get the number of key-value pairs */ async size(table: TableName) { return cache[table].size; }, // Done differently to have overloads /** Add a key value pair to the cache */ set, /** Get the value from the cache using its key */ get, /** Run a function on all items in this cache */ forEach, /** Allows you to filter our all items in this cache. */ filter, }; export type TableName = "guilds" | "unavailableGuilds" | "channels" | "messages" | "members" | "presences"; function set(table: "guilds", key: bigint, value: DiscordenoGuild): Promise>; function set(table: "channels", key: bigint, value: DiscordenoChannel): Promise>; function set(table: "messages", key: bigint, value: DiscordenoMessage): Promise>; function set(table: "members", key: bigint, value: DiscordenoMember): Promise>; function set(table: "presences", key: bigint, value: PresenceUpdate): Promise>; function set(table: "unavailableGuilds", key: bigint, value: number): Promise>; async function set(table: TableName, key: bigint, value: any) { return cache[table].set(key, value); } function get(table: "guilds", key: bigint): Promise; function get(table: "channels", key: bigint): Promise; function get(table: "messages", key: bigint): Promise; function get(table: "members", key: bigint): Promise; function get(table: "presences", key: bigint): Promise; function get(table: "unavailableGuilds", key: bigint): Promise; async function get(table: TableName, key: bigint) { return cache[table].get(key); } function forEach( table: "guilds", callback: (value: DiscordenoGuild, key: bigint, map: Map) => unknown ): void; function forEach( table: "unavailableGuilds", callback: (value: number, key: bigint, map: Map) => unknown ): void; function forEach( table: "channels", callback: (value: DiscordenoChannel, key: bigint, map: Map) => unknown ): void; function forEach( table: "messages", callback: (value: DiscordenoMessage, key: bigint, map: Map) => unknown ): void; function forEach( table: "members", callback: (value: DiscordenoMember, key: bigint, map: Map) => unknown ): void; function forEach(table: TableName, callback: (value: any, key: bigint, map: Map) => unknown) { return cache[table].forEach(callback); } function filter( table: "guilds", callback: (value: DiscordenoGuild, key: bigint) => boolean ): Promise>; function filter( table: "unavailableGuilds", callback: (value: number, key: bigint) => boolean ): Promise>; function filter( table: "channels", callback: (value: DiscordenoChannel, key: bigint) => boolean ): Promise>; function filter( table: "messages", callback: (value: DiscordenoMessage, key: bigint) => boolean ): Promise>; function filter( table: "members", callback: (value: DiscordenoMember, key: bigint) => boolean ): Promise>; async function filter(table: TableName, callback: (value: any, key: bigint) => boolean) { return cache[table].filter(callback); }