mirror of
https://github.com/tiramisulabs/seyfert.git
synced 2025-07-01 20:46:08 +00:00
feat: handlers update
This commit is contained in:
parent
d31ec27bbb
commit
9724d3eb9f
@ -2,9 +2,9 @@ import { join } from 'node:path';
|
||||
import { ApiHandler, Router } from '../api';
|
||||
import type { Adapter } from '../cache';
|
||||
import { Cache, MemoryAdapter } from '../cache';
|
||||
import type { Command, ContextMenuCommand, RegisteredMiddlewares } from '../commands';
|
||||
import type { RegisteredMiddlewares } from '../commands';
|
||||
import { IgnoreCommand, type InferWithPrefix, type MiddlewareContext } from '../commands/applications/shared';
|
||||
import { CommandHandler, type CommandHandlerLike } from '../commands/handler';
|
||||
import { CommandHandler } from '../commands/handler';
|
||||
import {
|
||||
ChannelShorter,
|
||||
EmojiShorter,
|
||||
@ -25,9 +25,8 @@ import {
|
||||
|
||||
import type { LocaleString } from 'discord-api-types/rest/v10';
|
||||
import type { DeepPartial, IntentStrings, OmitInsert, When } from '../common/types/util';
|
||||
import type { ComponentCommand, ModalCommand } from '../components';
|
||||
import { ComponentHandler, type ComponentHandlerLike } from '../components/handler';
|
||||
import { LangsHandler, type LangsHandlerLike } from '../langs/handler';
|
||||
import { ComponentHandler } from '../components/handler';
|
||||
import { LangsHandler } from '../langs/handler';
|
||||
import type {
|
||||
ChatInputCommandInteraction,
|
||||
ComponentInteraction,
|
||||
@ -57,9 +56,9 @@ export class BaseClient {
|
||||
name: '[Seyfert]',
|
||||
});
|
||||
|
||||
langs?: LangsHandlerLike = new LangsHandler(this.logger);
|
||||
commands?: CommandHandlerLike = new CommandHandler(this.logger, this);
|
||||
components?: ComponentHandlerLike = new ComponentHandler(this.logger, this);
|
||||
langs? = new LangsHandler(this.logger);
|
||||
commands? = new CommandHandler(this.logger, this);
|
||||
components? = new ComponentHandler(this.logger, this);
|
||||
|
||||
private _applicationId?: string;
|
||||
private _botId?: string;
|
||||
@ -121,8 +120,8 @@ export class BaseClient {
|
||||
if (!handlers.components) {
|
||||
this.components = undefined;
|
||||
} else if (typeof handlers.components === 'function') {
|
||||
this.components = new ComponentHandler(this.logger, this);
|
||||
(this.components as ComponentHandler).__callback = handlers.components;
|
||||
this.components ??= new ComponentHandler(this.logger, this);
|
||||
this.components.setHandlers({ callback: handlers.components });
|
||||
} else {
|
||||
this.components = handlers.components;
|
||||
}
|
||||
@ -130,9 +129,9 @@ export class BaseClient {
|
||||
if ('commands' in handlers) {
|
||||
if (!handlers.commands) {
|
||||
this.commands = undefined;
|
||||
} else if (typeof handlers.commands === 'function') {
|
||||
this.commands = new CommandHandler(this.logger, this);
|
||||
(this.commands as CommandHandler).__callback = handlers.commands;
|
||||
} else if (typeof handlers.commands === 'object') {
|
||||
this.commands ??= new CommandHandler(this.logger, this);
|
||||
this.commands.setHandlers(handlers.commands);
|
||||
} else {
|
||||
this.commands = handlers.commands;
|
||||
}
|
||||
@ -141,8 +140,8 @@ export class BaseClient {
|
||||
if (!handlers.langs) {
|
||||
this.langs = undefined;
|
||||
} else if (typeof handlers.langs === 'function') {
|
||||
this.langs = new LangsHandler(this.logger);
|
||||
(this.langs as LangsHandler).__callback = handlers.langs;
|
||||
this.langs ??= new LangsHandler(this.logger);
|
||||
this.langs.setHandlers({ callback: handlers.langs });
|
||||
} else {
|
||||
this.langs = handlers.langs;
|
||||
}
|
||||
@ -348,8 +347,8 @@ export interface ServicesOptions {
|
||||
};
|
||||
middlewares?: Record<string, MiddlewareContext>;
|
||||
handlers?: {
|
||||
components?: ComponentHandlerLike | ((component: ComponentCommand | ModalCommand) => any);
|
||||
commands?: CommandHandlerLike | ((command: Command | ContextMenuCommand) => any);
|
||||
langs?: LangsHandlerLike | ((locale: string, record: Record<string, unknown>) => any);
|
||||
components?: ComponentHandler | ComponentHandler['callback'];
|
||||
commands?: CommandHandler | Parameters<CommandHandler['setHandlers']>[0];
|
||||
langs?: LangsHandler | LangsHandler['callback'];
|
||||
};
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { GatewayIntentBits, type GatewayDispatchPayload, type GatewayPresenceUpdateData } from 'discord-api-types/v10';
|
||||
import { parentPort, workerData } from 'node:worker_threads';
|
||||
import type { ClientEvent, Command, CommandContext, EventHandlerLike, Message, SubCommand } from '..';
|
||||
import type { Command, CommandContext, Message, SubCommand } from '..';
|
||||
import type { DeepPartial, If, WatcherPayload, WatcherSendToShard } from '../common';
|
||||
import { EventHandler } from '../events';
|
||||
import { ClientUser } from '../structures';
|
||||
@ -15,7 +15,7 @@ import { onMessageCreate } from './onmessagecreate';
|
||||
export class Client<Ready extends boolean = boolean> extends BaseClient {
|
||||
private __handleGuilds?: Set<string> = new Set();
|
||||
gateway!: ShardManager;
|
||||
events?: EventHandlerLike = new EventHandler(this.logger);
|
||||
events? = new EventHandler(this.logger);
|
||||
me!: If<Ready, ClientUser>;
|
||||
declare options: ClientOptions | undefined;
|
||||
memberUpdateHandler = new MemberUpdateHandler();
|
||||
@ -31,7 +31,7 @@ export class Client<Ready extends boolean = boolean> extends BaseClient {
|
||||
}: ServicesOptions & {
|
||||
gateway?: ShardManager;
|
||||
handlers?: ServicesOptions['handlers'] & {
|
||||
events?: EventHandlerLike | ((event: ClientEvent) => any);
|
||||
events?: EventHandler['callback'];
|
||||
};
|
||||
}) {
|
||||
super.setServices(rest);
|
||||
@ -49,7 +49,9 @@ export class Client<Ready extends boolean = boolean> extends BaseClient {
|
||||
this.events = undefined;
|
||||
} else if (typeof rest.handlers.events === 'function') {
|
||||
this.events = new EventHandler(this.logger);
|
||||
(this.events as EventHandler).__callback = rest.handlers.events;
|
||||
this.events.setHandlers({
|
||||
callback: rest.handlers.events,
|
||||
});
|
||||
} else {
|
||||
this.events = rest.handlers.events;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import { ApiHandler, Logger } from '..';
|
||||
import type { Cache } from '../cache';
|
||||
import { WorkerAdapter } from '../cache';
|
||||
import { LogLevels, type DeepPartial, type When } from '../common';
|
||||
import { EventHandler, type EventHandlerLike } from '../events';
|
||||
import { EventHandler } from '../events';
|
||||
import { ClientUser } from '../structures';
|
||||
import { Shard, type ShardManagerOptions, type WorkerData } from '../websocket';
|
||||
import type {
|
||||
@ -46,7 +46,7 @@ export class WorkerClient<Ready extends boolean = boolean> extends BaseClient {
|
||||
name: `[Worker #${workerData.workerId}]`,
|
||||
});
|
||||
|
||||
events?: EventHandlerLike = new EventHandler(this.logger);
|
||||
events? = new EventHandler(this.logger);
|
||||
me!: When<Ready, ClientUser>;
|
||||
promises = new Map<string, { resolve: (value: any) => void; timeout: NodeJS.Timeout }>();
|
||||
|
||||
@ -102,12 +102,21 @@ export class WorkerClient<Ready extends boolean = boolean> extends BaseClient {
|
||||
...rest
|
||||
}: ServicesOptions & {
|
||||
handlers?: ServicesOptions['handlers'] & {
|
||||
events?: EventHandlerLike;
|
||||
events?: EventHandler['callback'];
|
||||
};
|
||||
}) {
|
||||
super.setServices(rest);
|
||||
if (rest.handlers && 'events' in rest.handlers) {
|
||||
this.events = rest.handlers.events;
|
||||
if (!rest.handlers.events) {
|
||||
this.events = undefined;
|
||||
} else if (typeof rest.handlers.events === 'function') {
|
||||
this.events = new EventHandler(this.logger);
|
||||
this.events.setHandlers({
|
||||
callback: rest.handlers.events,
|
||||
});
|
||||
} else {
|
||||
this.events = rest.handlers.events;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,13 +6,6 @@ import { Command, SubCommand } from './applications/chat';
|
||||
import { ContextMenuCommand } from './applications/menu';
|
||||
import type { UsingClient } from './applications/shared';
|
||||
|
||||
export interface CommandHandlerLike {
|
||||
values: CommandHandler['values'];
|
||||
load: CommandHandler['load'];
|
||||
reload: CommandHandler['reload'];
|
||||
reloadAll: CommandHandler['reloadAll'];
|
||||
}
|
||||
|
||||
export class CommandHandler extends BaseHandler {
|
||||
values: (Command | ContextMenuCommand)[] = [];
|
||||
protected filter = (path: string) => path.endsWith('.js') || (!path.endsWith('.d.ts') && path.endsWith('.ts'));
|
||||
@ -45,17 +38,15 @@ export class CommandHandler extends BaseHandler {
|
||||
|
||||
async load(commandsDir: string, client: UsingClient) {
|
||||
const result = (
|
||||
await this.loadFilesK<typeof Command | typeof SubCommand | typeof ContextMenuCommand>(
|
||||
await this.getFiles(commandsDir),
|
||||
)
|
||||
await this.loadFilesK<{ new (): Command | SubCommand | ContextMenuCommand }>(await this.getFiles(commandsDir))
|
||||
).filter(x => x.file);
|
||||
this.values = [];
|
||||
|
||||
for (const command of result) {
|
||||
let commandInstance;
|
||||
try {
|
||||
//@ts-expect-error abstract class
|
||||
commandInstance = new command.file();
|
||||
commandInstance = this.onCommand(command.file);
|
||||
if (!commandInstance) continue;
|
||||
} catch (e) {
|
||||
if (e instanceof Error && e.message === 'command.file is not a constructor') {
|
||||
this.logger.warn(
|
||||
@ -70,7 +61,6 @@ export class CommandHandler extends BaseHandler {
|
||||
if (commandInstance instanceof ContextMenuCommand) {
|
||||
this.values.push(commandInstance);
|
||||
commandInstance.__filePath = command.path;
|
||||
await this.__callback?.(commandInstance);
|
||||
continue;
|
||||
}
|
||||
if (!(commandInstance instanceof Command)) {
|
||||
@ -86,9 +76,8 @@ export class CommandHandler extends BaseHandler {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
//@ts-expect-error abstract class
|
||||
const subCommand = new (result.find(x => x.path === option)!.file)();
|
||||
if (subCommand instanceof SubCommand) {
|
||||
const subCommand = this.onSubCommand(result.find(x => x.path === option)!.file as { new (): SubCommand });
|
||||
if (subCommand && subCommand instanceof SubCommand) {
|
||||
subCommand.__filePath = option;
|
||||
commandInstance.options.push(subCommand);
|
||||
}
|
||||
@ -124,8 +113,6 @@ export class CommandHandler extends BaseHandler {
|
||||
this.__parseCommandLocales(i, client);
|
||||
}
|
||||
}
|
||||
|
||||
await this.__callback?.(commandInstance);
|
||||
}
|
||||
|
||||
return this.values;
|
||||
@ -212,4 +199,22 @@ export class CommandHandler extends BaseHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setHandlers({
|
||||
onCommand,
|
||||
onSubCommand,
|
||||
}: {
|
||||
onCommand?: CommandHandler['onCommand'];
|
||||
onSubCommand?: CommandHandler['onSubCommand'];
|
||||
}) {
|
||||
if (onCommand) this.onCommand = onCommand;
|
||||
if (onSubCommand) this.onSubCommand = onSubCommand;
|
||||
}
|
||||
|
||||
onCommand = (file: { new (): Command | SubCommand | ContextMenuCommand }):
|
||||
| Command
|
||||
| SubCommand
|
||||
| ContextMenuCommand
|
||||
| false => new file();
|
||||
onSubCommand = (file: { new (): SubCommand }): SubCommand | false => new file();
|
||||
}
|
||||
|
@ -94,7 +94,6 @@ export function filterSplit<Element, Predicate extends (value: Element) => boole
|
||||
* Represents a base handler class.
|
||||
*/
|
||||
export class BaseHandler {
|
||||
__callback?: (...args: any[]) => any;
|
||||
/**
|
||||
* Initializes a new instance of the BaseHandler class.
|
||||
* @param logger The logger instance.
|
||||
|
@ -15,30 +15,6 @@ type COMPONENTS = {
|
||||
__run: (customId: string | string[] | RegExp, callback: ComponentCallback) => any;
|
||||
};
|
||||
|
||||
export interface ComponentHandlerLike {
|
||||
readonly values: Map<string, COMPONENTS>;
|
||||
readonly commands: (ComponentCommand | ModalCommand)[];
|
||||
readonly modals: Map<string, ModalSubmitCallback> | LimitedCollection<string, ModalSubmitCallback>;
|
||||
|
||||
onFail: ComponentHandler['onFail'];
|
||||
|
||||
createComponentCollector: ComponentHandler['createComponentCollector'];
|
||||
|
||||
hasModal: ComponentHandler['hasModal'];
|
||||
onModalSubmit: ComponentHandler['onModalSubmit'];
|
||||
executeModal: ComponentHandler['executeModal'];
|
||||
|
||||
hasComponent: ComponentHandler['hasComponent'];
|
||||
executeComponent: ComponentHandler['executeComponent'];
|
||||
onComponent: ComponentHandler['onComponent'];
|
||||
|
||||
load: ComponentHandler['load'];
|
||||
reload: ComponentHandler['reload'];
|
||||
reloadAll: ComponentHandler['reloadAll'];
|
||||
|
||||
onMessageDelete: ComponentHandler['onMessageDelete'];
|
||||
}
|
||||
|
||||
export class ComponentHandler extends BaseHandler {
|
||||
onFail: OnFailCallback = err => this.logger.warn('<Client>.components.onFail', err);
|
||||
readonly values = new Map<string, COMPONENTS>();
|
||||
@ -177,7 +153,8 @@ export class ComponentHandler extends BaseHandler {
|
||||
for (let i = 0; i < paths.length; i++) {
|
||||
let component;
|
||||
try {
|
||||
component = new paths[i].file();
|
||||
component = this.callback(paths[i].file);
|
||||
if (!component) continue;
|
||||
} catch (e) {
|
||||
if (e instanceof Error && e.message === 'paths[i].file is not a constructor') {
|
||||
this.logger.warn(
|
||||
@ -192,7 +169,6 @@ export class ComponentHandler extends BaseHandler {
|
||||
if (!(component instanceof ModalCommand) && !(component instanceof ComponentCommand)) continue;
|
||||
component.__filePath = paths[i].path;
|
||||
this.commands.push(component);
|
||||
await this.__callback?.(component);
|
||||
}
|
||||
}
|
||||
|
||||
@ -254,4 +230,10 @@ export class ComponentHandler extends BaseHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setHandlers({ callback }: { callback: ComponentHandler['callback'] }) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
callback = (file: { new (): ModalCommand | ComponentCommand }): ModalCommand | ComponentCommand | false => new file();
|
||||
}
|
||||
|
@ -5,41 +5,25 @@ import type {
|
||||
GatewayMessageDeleteDispatch,
|
||||
} from 'discord-api-types/v10';
|
||||
import type { Client, WorkerClient } from '../client';
|
||||
import {
|
||||
BaseHandler,
|
||||
ReplaceRegex,
|
||||
magicImport,
|
||||
type MakeRequired,
|
||||
type OnFailCallback,
|
||||
type SnakeCase,
|
||||
} from '../common';
|
||||
import { BaseHandler, ReplaceRegex, magicImport, type MakeRequired, type SnakeCase } from '../common';
|
||||
import type { ClientEvents } from '../events/hooks';
|
||||
import * as RawEvents from '../events/hooks';
|
||||
import type { ClientEvent, ClientNameEvents } from './event';
|
||||
|
||||
type EventValue = MakeRequired<ClientEvent, '__filePath'> & { fired?: boolean };
|
||||
export type EventValue = MakeRequired<ClientEvent, '__filePath'> & { fired?: boolean };
|
||||
|
||||
type GatewayEvents = Uppercase<SnakeCase<keyof ClientEvents>>;
|
||||
|
||||
export interface EventHandlerLike {
|
||||
runEvent: EventHandler['runEvent'];
|
||||
execute: EventHandler['execute'];
|
||||
load: EventHandler['load'];
|
||||
reload: EventHandler['reload'];
|
||||
reloadAll: EventHandler['reloadAll'];
|
||||
values: EventHandler['values'];
|
||||
onFail: EventHandler['onFail'];
|
||||
}
|
||||
export type GatewayEvents = Uppercase<SnakeCase<keyof ClientEvents>>;
|
||||
|
||||
export class EventHandler extends BaseHandler {
|
||||
onFail: OnFailCallback = err => this.logger.warn('<Client>.events.onFail', err);
|
||||
onFail = (event: GatewayEvents, err: unknown) => this.logger.warn('<Client>.events.onFail', err, event);
|
||||
protected filter = (path: string) => path.endsWith('.js') || (!path.endsWith('.d.ts') && path.endsWith('.ts'));
|
||||
|
||||
values: Partial<Record<GatewayEvents, EventValue>> = {};
|
||||
|
||||
async load(eventsDir: string) {
|
||||
for (const i of await this.loadFilesK<ClientEvent>(await this.getFiles(eventsDir))) {
|
||||
const instance = i.file;
|
||||
const instance = this.callback(i.file);
|
||||
if (!instance) continue;
|
||||
if (typeof instance?.run !== 'function') {
|
||||
this.logger.warn(
|
||||
i.path.split(process.cwd()).slice(1).join(process.cwd()),
|
||||
@ -49,7 +33,6 @@ export class EventHandler extends BaseHandler {
|
||||
}
|
||||
instance.__filePath = i.path;
|
||||
this.values[ReplaceRegex.snake(instance.data.name).toUpperCase() as GatewayEvents] = instance as EventValue;
|
||||
await this.__callback?.(instance);
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,7 +90,7 @@ export class EventHandler extends BaseHandler {
|
||||
const hook = await RawEvents[name]?.(client, packet as never);
|
||||
await Event.run(...[hook, client, shardId]);
|
||||
} catch (e) {
|
||||
await this.onFail(e);
|
||||
await this.onFail(name, e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,4 +110,10 @@ export class EventHandler extends BaseHandler {
|
||||
await this.reload(ReplaceRegex.camel(i) as ClientNameEvents);
|
||||
}
|
||||
}
|
||||
|
||||
setHandlers({ callback }: { callback: EventHandler['callback'] }) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
callback = (file: ClientEvent): ClientEvent | false => file;
|
||||
}
|
||||
|
@ -2,15 +2,6 @@ import type { Locale, LocaleString } from 'discord-api-types/v10';
|
||||
import { BaseHandler } from '../common';
|
||||
import { LangRouter } from './router';
|
||||
|
||||
export interface LangsHandlerLike {
|
||||
getKey: LangsHandler['getKey'];
|
||||
load: LangsHandler['load'];
|
||||
values: LangsHandler['values'];
|
||||
aliases: LangsHandler['aliases'];
|
||||
get: LangsHandler['get'];
|
||||
defaultLang?: LangsHandler['defaultLang'];
|
||||
}
|
||||
|
||||
export class LangsHandler extends BaseHandler {
|
||||
values: Partial<Record<string, any>> = {};
|
||||
protected filter = (path: string) =>
|
||||
@ -49,8 +40,14 @@ export class LangsHandler extends BaseHandler {
|
||||
const files = await this.loadFilesK<Record<string, any>>(await this.getFiles(dir));
|
||||
for (const i of files) {
|
||||
const locale = i.name.split('.').slice(0, -1).join('.');
|
||||
this.values[locale] = i.file;
|
||||
await this.__callback?.(locale, i.file);
|
||||
const result = this.callback(locale, i.file);
|
||||
if (result) this.values[locale] = result;
|
||||
}
|
||||
}
|
||||
|
||||
setHandlers({ callback }: { callback: LangsHandler['callback'] }) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
callback = (_locale: string, file: Record<string, any>): Record<string, any> | false => file;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user