From 2cfb4b951bd066967fccd9765f271edc482a3ac4 Mon Sep 17 00:00:00 2001 From: MARCROCK22 <57925328+MARCROCK22@users.noreply.github.com> Date: Sun, 7 Apr 2024 16:48:19 -0400 Subject: [PATCH] feat: ignore property when declaring command & flush method --- src/cache/adapters/default.ts | 5 +++++ src/cache/adapters/redis.ts | 25 +++++++++++++++++++++++++ src/cache/adapters/types.ts | 2 ++ src/cache/adapters/workeradapter.ts | 4 ++++ src/cache/index.ts | 8 ++++++-- src/client/base.ts | 14 ++++++++------ src/client/onmessagecreate.ts | 7 +++++-- src/commands/applications/chat.ts | 3 +++ src/commands/applications/shared.ts | 5 +++++ src/commands/decorators.ts | 5 ++++- src/websocket/discord/worker.ts | 1 + 11 files changed, 68 insertions(+), 11 deletions(-) diff --git a/src/cache/adapters/default.ts b/src/cache/adapters/default.ts index 9fab9e4..ce88de6 100644 --- a/src/cache/adapters/default.ts +++ b/src/cache/adapters/default.ts @@ -104,6 +104,11 @@ export class MemoryAdapter implements Adapter { } } + flush(): void { + this.storage.clear(); + this.relationships.clear(); + } + contains(to: string, keys: string): boolean { return this.getToRelationship(to).includes(keys); } diff --git a/src/cache/adapters/redis.ts b/src/cache/adapters/redis.ts index dbea944..b2ddbeb 100644 --- a/src/cache/adapters/redis.ts +++ b/src/cache/adapters/redis.ts @@ -27,6 +27,23 @@ export class RedisAdapter implements Adapter { this.namespace = data.namespace ?? 'seyfert'; } + private __scanSets(query: string, returnKeys?: false): Promise; + private __scanSets(query: string, returnKeys: true): Promise; + private __scanSets(query: string, returnKeys = false) { + const match = this.buildKey(query); + return new Promise((r, j) => { + const stream = this.client.scanStream({ + match, + type: 'set', + }); + const keys: string[] = []; + stream + .on('data', resultKeys => keys.push(...resultKeys)) + .on('end', () => (returnKeys ? r(keys.map(x => this.buildKey(x))) : r(this.get(keys)))) + .on('error', err => j(err)); + }); + } + scan(query: string, returnKeys?: false): Promise; scan(query: string, returnKeys: true): Promise; scan(query: string, returnKeys = false) { @@ -156,6 +173,14 @@ export class RedisAdapter implements Adapter { await this.client.del(...keys.map(x => this.buildKey(x))); } + async flush(): Promise { + await this.remove( + await Promise.all([this.scan(this.buildKey('*'), true), this.__scanSets(this.buildKey('*'), true)]).then(x => + x.flat(), + ), + ); + } + async contains(to: string, keys: string): Promise { return (await this.client.sismember(`${this.buildKey(to)}:set`, keys)) === 1; } diff --git a/src/cache/adapters/types.ts b/src/cache/adapters/types.ts index 3f0c47b..7079515 100644 --- a/src/cache/adapters/types.ts +++ b/src/cache/adapters/types.ts @@ -27,6 +27,8 @@ export interface Adapter { remove(keys: string | string[]): Awaitable; + flush(): Awaitable; + contains(to: string, keys: string): Awaitable; getToRelationship(to: string): Awaitable; diff --git a/src/cache/adapters/workeradapter.ts b/src/cache/adapters/workeradapter.ts index 9eb0d27..28f24a8 100644 --- a/src/cache/adapters/workeradapter.ts +++ b/src/cache/adapters/workeradapter.ts @@ -77,6 +77,10 @@ export class WorkerAdapter implements Adapter { return this.send('remove', ...rest); } + flush() { + return this.send('flush'); + } + contains(...rest: any[]) { return this.send('contains', ...rest); } diff --git a/src/cache/index.ts b/src/cache/index.ts index 6f427ed..37ea27e 100644 --- a/src/cache/index.ts +++ b/src/cache/index.ts @@ -16,12 +16,12 @@ import { Threads } from './resources/threads'; import { VoiceStates } from './resources/voice-states'; import { + ChannelType, + GatewayIntentBits, type APIEmoji, type APISticker, type APIThreadChannel, - ChannelType, type GatewayDispatchPayload, - GatewayIntentBits, type GatewayReadyDispatchData, } from 'discord-api-types/v10'; import type { InternalOptions, UsingClient } from '../commands'; @@ -166,6 +166,10 @@ export class Cache { this.stageInstances?.__setClient(client); } + flush(): ReturnCache { + return this.adapter.flush() as void; + } + // internal use ./structures hasIntent(intent: keyof typeof GatewayIntentBits) { return (this.intents & GatewayIntentBits[intent]) === GatewayIntentBits[intent]; diff --git a/src/client/base.ts b/src/client/base.ts index 997e990..36e42d1 100644 --- a/src/client/base.ts +++ b/src/client/base.ts @@ -3,7 +3,7 @@ import { ApiHandler, Router } from '../api'; import type { Adapter } from '../cache'; import { Cache, MemoryAdapter } from '../cache'; import type { Command, ContextMenuCommand, RegisteredMiddlewares } from '../commands'; -import type { InferWithPrefix, MiddlewareContext } from '../commands/applications/shared'; +import { IgnoreCommand, type InferWithPrefix, type MiddlewareContext } from '../commands/applications/shared'; import { CommandHandler, type CommandHandlerLike } from '../commands/handler'; import { ChannelShorter, @@ -204,17 +204,17 @@ export class BaseClient { applicationId ??= await this.getRC().then(x => x.applicationId ?? this.applicationId); BaseClient.assertString(applicationId, 'applicationId is not a string'); - const commands = this.commands!.values.map(x => x.toJSON()); - const filter = filterSplit(commands, command => !command.guild_id); + const commands = this.commands!.values; + const filter = filterSplit(commands, command => !command.guildId); await this.proxy.applications(applicationId).commands.put({ - body: filter.expect, + body: filter.expect.filter(cmd => !('ignore' in cmd) || cmd.ignore !== IgnoreCommand.Slash).map(x => x.toJSON()), }); const guilds = new Set(); for (const command of filter.never) { - for (const guild_id of command.guild_id!) { + for (const guild_id of command.guildId!) { guilds.add(guild_id); } } @@ -224,7 +224,9 @@ export class BaseClient { .applications(applicationId) .guilds(guild) .commands.put({ - body: filter.never.filter(x => x.guild_id?.includes(guild)), + body: filter.never + .filter(cmd => cmd.guildId?.includes(guild) && (!('ignore' in cmd) || cmd.ignore !== IgnoreCommand.Slash)) + .map(x => x.toJSON()), }); } } diff --git a/src/client/onmessagecreate.ts b/src/client/onmessagecreate.ts index 90fe8b5..f4402de 100644 --- a/src/client/onmessagecreate.ts +++ b/src/client/onmessagecreate.ts @@ -7,6 +7,7 @@ import { import { Command, CommandContext, + IgnoreCommand, InteractionContextTypes, OptionResolver, SubCommand, @@ -34,7 +35,9 @@ function getCommandFromContent( const parentName = commandRaw[0]; const groupName = commandRaw.length === 3 ? commandRaw[1] : undefined; const subcommandName = groupName ? commandRaw[2] : commandRaw[1]; - const parent = self.commands!.values.find(x => x.name === parentName); + const parent = self.commands!.values.find( + x => (!('ignore' in x) || x.ignore !== IgnoreCommand.Message) && x.name === parentName, + ); const fullCommandName = `${parentName}${ groupName ? ` ${groupName} ${subcommandName}` : `${subcommandName ? ` ${subcommandName}` : ''}` }`; @@ -73,7 +76,7 @@ export async function onMessageCreate( ) { if (!self.options?.commands) return; const message = new Message(self, rawMessage); - const prefixes = ((await self.options.commands.prefix?.(message)) ?? []).sort((a, b) => b.length - a.length); + const prefixes = (await self.options.commands.prefix(message)).sort((a, b) => b.length - a.length); const prefix = prefixes.find(x => message.content.startsWith(x)); if (!prefix || !message.content.startsWith(prefix)) return; diff --git a/src/commands/applications/chat.ts b/src/commands/applications/chat.ts index 14d2277..a431035 100644 --- a/src/commands/applications/chat.ts +++ b/src/commands/applications/chat.ts @@ -15,6 +15,7 @@ import type { OptionResolver } from '../optionresolver'; import type { CommandContext } from './chatcontext'; import type { DefaultLocale, + IgnoreCommand, OKFunction, OnOptionsReturnObject, PassFunction, @@ -131,6 +132,8 @@ class BaseCommand { options?: CommandOption[] | SubCommand[]; + ignore?: IgnoreCommand; + /** @internal */ async __runOptions( ctx: CommandContext<{}, never>, diff --git a/src/commands/applications/shared.ts b/src/commands/applications/shared.ts index 298ce36..8d21bab 100644 --- a/src/commands/applications/shared.ts +++ b/src/commands/applications/shared.ts @@ -52,3 +52,8 @@ export type OnOptionsReturnObject = Record< value: string; } >; + +export enum IgnoreCommand { + Slash = 0, + Message = 1, +} diff --git a/src/commands/decorators.ts b/src/commands/decorators.ts index b9e4462..8dc02a8 100644 --- a/src/commands/decorators.ts +++ b/src/commands/decorators.ts @@ -1,7 +1,7 @@ import { ApplicationCommandType, PermissionFlagsBits, type LocaleString } from 'discord-api-types/v10'; import type { FlatObjectKeys, PermissionStrings } from '../common'; import type { CommandOption, OptionsRecord, SubCommand } from './applications/chat'; -import type { DefaultLocale, MiddlewareContext } from './applications/shared'; +import type { DefaultLocale, IgnoreCommand, MiddlewareContext } from './applications/shared'; export interface RegisteredMiddlewares {} @@ -25,6 +25,7 @@ type DeclareOptions = nsfw?: boolean; integrationTypes?: (keyof typeof IntegrationTypes)[]; contexts?: (keyof typeof InteractionContextTypes)[]; + ignore?: IgnoreCommand; } | (Omit< { @@ -150,11 +151,13 @@ export function Declare(declare: DeclareOptions) { description = ''; type: ApplicationCommandType = ApplicationCommandType.ChatInput; guildId?: string[]; + ignore?: IgnoreCommand; constructor(...args: any[]) { super(...args); if ('description' in declare) this.description = declare.description; if ('type' in declare) this.type = declare.type; if ('guildId' in declare) this.guildId = declare.guildId; + if ('ignore' in declare) this.ignore = declare.ignore; // check if all properties are valid } }; diff --git a/src/websocket/discord/worker.ts b/src/websocket/discord/worker.ts index 4c6fc0c..b3da894 100644 --- a/src/websocket/discord/worker.ts +++ b/src/websocket/discord/worker.ts @@ -34,6 +34,7 @@ export type WorkerSendCacheRequest = CreateWorkerMessage< | 'keys' | 'count' | 'remove' + | 'flush' | 'contains' | 'getToRelationship' | 'bulkAddToRelationShip'