mirror of
https://github.com/sern-handler/handler
synced 2026-06-06 01:16:55 +00:00
feat: more support for event loading!!
This commit is contained in:
@@ -36,7 +36,7 @@ export type CommandPlugin<T extends keyof ModuleDefs = keyof ModuleDefs> = {
|
||||
{
|
||||
type: PluginType.Command;
|
||||
execute: (
|
||||
wrapper: Client,
|
||||
wrapper: K extends CommandType.External ? EventEmitter : Client,
|
||||
module: DefinitelyDefined<ModuleDefs[T], 'name' | 'description'>,
|
||||
controller: Controller,
|
||||
) => Awaitable<Result<void, void>>;
|
||||
@@ -77,9 +77,8 @@ function isCommandPlugin<T extends CommandType>(
|
||||
): e is CommandPlugin<T> {
|
||||
return !isEventPlugin(e);
|
||||
}
|
||||
|
||||
// TODO: Do better typings
|
||||
export function sernModule<T extends CommandType>(
|
||||
//TODO: I WANT BETTER TYPINGS AHHHHHHHHHHHHHHH
|
||||
export function sernModule<T extends keyof ModuleDefs>(
|
||||
plugin: (CommandPlugin<T> | EventPlugin<T>)[],
|
||||
mod: ModuleNoPlugins[T],
|
||||
): Module {
|
||||
|
||||
@@ -1,36 +1,96 @@
|
||||
import type { DiscordEvent, EventEmitterRegister, SernEvent } from '../types/handler';
|
||||
|
||||
import type Wrapper from './structures/wrapper';
|
||||
import { fromEvent } from 'rxjs';
|
||||
import { onReady } from './events/readyEvent';
|
||||
import { onMessageCreate } from './events/messageEvent';
|
||||
import { onInteractionCreate } from './events/interactionCreate';
|
||||
import { Err, Ok } from 'ts-results';
|
||||
import { isDiscordEvent, isSernEvent } from './utilities/predicates';
|
||||
import { buildData } from './utilities/readFile';
|
||||
import type { EventModule } from './structures/module';
|
||||
import { from, fromEvent, map, throwError } from 'rxjs';
|
||||
import { match } from 'ts-pattern';
|
||||
import { errTap } from './events/observableHandling';
|
||||
import { isDiscordEvent, isExternalEvent, isSernEvent } from './utilities/predicates';
|
||||
import { SernError } from './structures/errors';
|
||||
import type { SpreadParams } from '../types/handler';
|
||||
import * as Files from './utilities/readFile';
|
||||
import { basename } from 'path';
|
||||
|
||||
export function init(wrapper: Wrapper) {
|
||||
const { events } = wrapper;
|
||||
if (events !== undefined) {
|
||||
eventObserver(wrapper, events);
|
||||
processEvents(wrapper, events);
|
||||
}
|
||||
onReady(wrapper);
|
||||
onMessageCreate(wrapper);
|
||||
onInteractionCreate(wrapper);
|
||||
}
|
||||
|
||||
function eventObserver(
|
||||
{ client, sernEmitter }: Wrapper,
|
||||
events: (DiscordEvent | EventEmitterRegister | SernEvent)[],
|
||||
function processEvents(wrapper: Wrapper, events: string | EventModule[] | (() => EventModule[])) {
|
||||
const eventStream = eventObservable$(wrapper, events);
|
||||
const processPlugins$ = eventStream.pipe(map(mod => mod)); //for now, until i figure out what to do with how plugins are registered
|
||||
const normalize$ = processPlugins$.pipe(
|
||||
map(({ mod, absPath }) => {
|
||||
return {
|
||||
name: mod?.name ?? Files.fmtFileName(basename(absPath)),
|
||||
description: mod?.description ?? '...',
|
||||
...mod,
|
||||
};
|
||||
}),
|
||||
);
|
||||
const processAndLoadEvents$ = normalize$.pipe(
|
||||
map(mod => {
|
||||
return match(mod as EventModule)
|
||||
.when(isSernEvent, m => {
|
||||
if (wrapper.sernEmitter === undefined) {
|
||||
return throwError(() => SernError.UndefinedSernEmitter);
|
||||
}
|
||||
return fromEvent(
|
||||
wrapper.sernEmitter,
|
||||
m.name!,
|
||||
m.execute as SpreadParams<typeof m.execute>,
|
||||
);
|
||||
})
|
||||
.when(isDiscordEvent, m =>
|
||||
fromEvent(
|
||||
wrapper.client,
|
||||
mod.name!,
|
||||
m.execute as SpreadParams<typeof m.execute>,
|
||||
),
|
||||
)
|
||||
.when(isExternalEvent, m => fromEvent(m.emitter, m.name!, m.execute))
|
||||
.run();
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function eventObservable$(
|
||||
{ sernEmitter }: Wrapper,
|
||||
events: string | EventModule[] | (() => EventModule[]),
|
||||
) {
|
||||
events.forEach(event => {
|
||||
if (isDiscordEvent(event)) {
|
||||
fromEvent(client, event[0], event[1]).subscribe();
|
||||
} else if (isSernEvent(event)) {
|
||||
sernEmitter && fromEvent(sernEmitter, event[0], event[1]).subscribe();
|
||||
} else {
|
||||
fromEvent(event[0], event[1], event[2]).subscribe();
|
||||
}
|
||||
});
|
||||
return match(events)
|
||||
.when(Array.isArray, (arr: EventModule[]) => {
|
||||
return from(arr.map(self => ({ mod: self, absPath: __filename })));
|
||||
})
|
||||
.when(
|
||||
e => typeof e === 'string',
|
||||
(eventsDir: string) => {
|
||||
return buildData<EventModule>(eventsDir).pipe(
|
||||
errTap(reason =>
|
||||
sernEmitter?.emit('module.register', {
|
||||
type: 'failure',
|
||||
module: undefined,
|
||||
reason,
|
||||
}),
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
.when(
|
||||
e => typeof e === 'function',
|
||||
(evs: () => EventModule[]) => {
|
||||
return from(evs().map(self => ({ mod: self, absPath: __filename })));
|
||||
},
|
||||
)
|
||||
.run();
|
||||
}
|
||||
|
||||
export const controller = {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import type { Module } from './structures/module';
|
||||
|
||||
type Payload =
|
||||
export type Payload =
|
||||
| { type: 'success'; module: Module }
|
||||
| { type: 'failure'; module: Module | undefined; reason: string | Error };
|
||||
export type SernEventsMapping = {
|
||||
|
||||
@@ -5,4 +5,5 @@ export enum SernError {
|
||||
NotSupportedInteraction = `This interaction is not supported.`,
|
||||
PluginFailure = `A plugin failed to call controller.next()`,
|
||||
MismatchEvent = `You cannot use message when an interaction fired or vice versa`,
|
||||
UndefinedSernEmitter = `Could not find a Sern emitter`,
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { CommandPlugin, EventPlugin } from '../plugins/plugin';
|
||||
import type { CommandType } from './enums';
|
||||
import type { SernEventsMapping } from '../sernEmitter';
|
||||
import type { Awaitable, ClientEvents } from 'discord.js';
|
||||
import type { EventEmitter } from 'events';
|
||||
|
||||
export type SernEventCommand<T extends keyof SernEventsMapping = keyof SernEventsMapping> =
|
||||
Override<
|
||||
@@ -31,6 +32,7 @@ export type ExternalEventCommand = Override<
|
||||
BaseModule,
|
||||
{
|
||||
type: CommandType.External;
|
||||
emitter: EventEmitter;
|
||||
onEvent: EventPlugin<CommandType.External>[];
|
||||
plugins: CommandPlugin[];
|
||||
execute(...args: unknown[]): Awaitable<void | unknown>;
|
||||
|
||||
@@ -9,7 +9,11 @@ import type {
|
||||
SelectMenuInteraction,
|
||||
UserContextMenuCommandInteraction,
|
||||
} from 'discord.js';
|
||||
import type { DiscordEventCommand, SernEventCommand } from '../structures/events';
|
||||
import type {
|
||||
DiscordEventCommand,
|
||||
ExternalEventCommand,
|
||||
SernEventCommand,
|
||||
} from '../structures/events';
|
||||
import { CommandType } from '../..';
|
||||
|
||||
export function correctModuleType<T extends keyof ModuleDefs>(
|
||||
@@ -57,6 +61,10 @@ export function isSernEvent(el: EventModule): el is SernEventCommand {
|
||||
return !isDiscordEvent(el);
|
||||
}
|
||||
|
||||
export function isExternalEvent(el: EventModule): el is ExternalEventCommand {
|
||||
return !isDiscordEvent(el) && !isSernEvent(el);
|
||||
}
|
||||
|
||||
export function isEventModule(module: Module): module is EventModule {
|
||||
return [CommandType.Discord, CommandType.Sern, CommandType.External].includes(module.type);
|
||||
}
|
||||
|
||||
@@ -48,14 +48,16 @@ type IsOptional<T> = {
|
||||
[K in keyof T]-?: T[K] extends Required<T>[K] ? false : true;
|
||||
};
|
||||
|
||||
export type UnionToIntersection<T> = (T extends unknown ? (x: T) => unknown : never) extends (
|
||||
x: infer R,
|
||||
) => unknown
|
||||
? R
|
||||
: never;
|
||||
export type ConformedEditOptions = Override<
|
||||
MessageEditOptions | WebhookEditMessageOptions,
|
||||
{
|
||||
embeds?: (JSONEncodable<APIEmbed> | APIEmbed)[];
|
||||
}
|
||||
>;
|
||||
/**
|
||||
* Turns a function with a union of array of args into a single union
|
||||
* [ T , V , B ] | [ A ] => T | V | B | A
|
||||
*/
|
||||
export type SpreadParams<T extends (...args: any) => unknown> = (
|
||||
args: Parameters<T>[number],
|
||||
) => unknown;
|
||||
|
||||
Reference in New Issue
Block a user