feat: Add basic event handling, no plugins checked yet!

This commit is contained in:
Jacob Nguyen
2022-06-24 00:21:35 -05:00
parent c56c3c9a8f
commit 8e037988d5
2 changed files with 143 additions and 61 deletions

View File

@@ -1,25 +1,19 @@
import { CommandType } from '../structures/enums';
import { concatMap, from, fromEvent, map, of, throwError } from 'rxjs';
import { from, fromEvent, map, throwError } from 'rxjs';
import { SernError } from '../structures/errors';
import * as Files from '../utilities/readFile';
import { buildData, ExternalEventEmitters } from '../utilities/readFile';
import { controller } from '../sern';
import type {
DefinedEventModule,
DefinedModule,
Override,
SpreadParams,
} from '../../types/handler';
import type { DefinedEventModule, DefinedModule, SpreadParams } from '../../types/handler';
import type { EventModule } from '../structures/module';
import type Wrapper from '../structures/wrapper';
import { basename } from 'path';
import { match, P } from 'ts-pattern';
import { isDiscordEvent, isExternalEvent, isSernEvent } from '../utilities/predicates';
import { errTap } from './observableHandling';
import type { CommandPlugin, Controller } from '../plugins/plugin';
import type { Awaitable, Client } from 'discord.js';
import type { Result } from 'ts-results';
import { isDiscordEvent, isSernEvent } from '../utilities/predicates';
import type { CommandPlugin } from '../plugins/plugin';
import { Err, Ok } from 'ts-results';
import { errTap } from './observableHandling';
/**
* Utility function to process command plugins for all Modules
* @param client
@@ -80,7 +74,10 @@ export function processCommandPlugins$<T extends DefinedModule>(
export function processEvents(
wrapper: Wrapper,
events: string | EventModule[] | (() => EventModule[]),
events:
| string
| { mod: EventModule; absPath: string }[]
| (() => { mod: EventModule; absPath: string }[]),
) {
const eventStream$ = eventObservable$(wrapper, events);
const normalize$ = eventStream$.pipe(
@@ -92,57 +89,139 @@ export function processEvents(
};
}),
);
const processPlugins$ = normalize$.pipe(
concatMap(mod => {
const cmdPluginRes = processCommandPlugins$(wrapper, mod);
if (cmdPluginRes.err) {
return cmdPluginRes.val;
}
return of({ mod, cmdPluginRes: cmdPluginRes.val });
}),
);
const processAndLoadEvents$ = processPlugins$.pipe(
concatMap(({ mod, cmdPluginRes }) => {
return match(mod as DefinedEventModule)
.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 => {
return fromEvent(
wrapper.client,
m.name!,
m.execute as SpreadParams<typeof m.execute>,
);
})
.when(isExternalEvent, m => {
if (!ExternalEventEmitters.has(m.emitter)) {
throw Error(
SernError.UndefinedSernEmitter +
`Could not locate
a dependency ${m.emitter} to call this event listener`,
);
}
return fromEvent(ExternalEventEmitters.get(m.emitter)!, m.name!, m.execute);
})
.run();
}),
);
normalize$.subscribe(e => {
const emitter = isSernEvent(e)
? wrapper?.sernEmitter
: isDiscordEvent(e)
? wrapper.client
: ExternalEventEmitters.get(e.emitter);
if (emitter === undefined) {
throw new Error(`Cannot find ${emitter}`);
}
fromEvent(emitter, e.name, e.execute as SpreadParams<typeof e.execute>).subscribe();
});
// TODO
// const processPlugins$ = normalize$.pipe(
// concatMap(mod => {
// const cmdPluginRes = processCommandPlugins$(wrapper, mod);
// if (cmdPluginRes.err) {
// return cmdPluginRes.val;
// }
//
// return of({ mod, cmdPluginRes });
// }),
// );
// const processAndLoadEvents$ = processPlugins$.pipe(
// concatMap(async ({ mod, cmdPluginRes }) => {
// return {
// mod,
// cmdPluginRes,
// eventLoaded: match(mod as DefinedEventModule)
// .when(isSernEvent, m => {
// if (wrapper.sernEmitter === undefined) {
// return throwError(() => SernError.UndefinedSernEmitter);
// }
// return fromEvent(
// wrapper.sernEmitter,
// m.name!,
// m.execute as SpreadParams<typeof m.execute>,
// ).pipe(
// concatMap(event => {
// return of(
// m.onEvent.map(plug => ({
// ...plug,
// name: plug?.name ?? 'Unnamed Plugin',
// description: plug?.description ?? '..',
// execute: plug.execute(
// [event] as [string | Error] | [Payload],
// controller,
// ),
// })),
// );
// }),
// );
// })
// .when(isDiscordEvent, m => {
// return fromEvent(
// wrapper.client,
// m.name!,
// m.execute as SpreadParams<typeof m.execute>,
// ).pipe(
// concatMap(event => {
// return of(
// m.onEvent.map(plug => ({
// ...plug,
// name: plug?.name ?? 'Unnamed Plugin',
// description: plug?.description ?? '..',
// execute: plug.execute(
// [event] as ClientEvents[keyof ClientEvents],
// controller,
// ),
// })),
// );
// }),
// );
// })
// .when(isExternalEvent, m => {
// if (!ExternalEventEmitters.has(m.emitter)) {
// throw Error(
// SernError.UndefinedSernEmitter +
// `Could not locate
// a dependency ${m.emitter} to call this event listener`,
// );
// }
// return fromEvent(
// ExternalEventEmitters.get(m.emitter)!,
// m.name!,
// m.execute,
// ).pipe(
// concatMap(event => {
// return of(
// m.onEvent.map(plug => ({
// ...plug,
// name: plug?.name ?? 'Unnamed Plugin',
// description: plug?.description ?? '..',
// execute: plug.execute([event], controller),
// })),
// );
// }),
// );
// })
// .run(),
// };
// }),
// );
// // Cannot send to Sern's emitter because it hasn't been turned on yet. Don't know if
// // this will be changed.
// processAndLoadEvents$.subscribe({
// async next({ cmdPluginRes, eventLoaded, mod }) {
// for (const pl of cmdPluginRes) {
// const res = isPromise(pl.execute) ? await pl.execute : pl.execute;
// if (res.err) {
// throw Error(
// 'Could not load an event module correctly, a plugin called controller.stop()',
// );
// }
// }
// eventLoaded.subscribe();
// },
// error(e) {
// wrapper.sernEmitter?.emit('error', e);
// },
// });
}
function eventObservable$(
{ sernEmitter }: Wrapper,
events: string | EventModule[] | (() => EventModule[]),
events:
| string
| { mod: EventModule; absPath: string }[]
| (() => { mod: EventModule; absPath: string }[]),
) {
return match(events)
.when(Array.isArray, (arr: EventModule[]) => {
return from(arr.map(self => ({ mod: self, absPath: __filename })));
.when(Array.isArray, (arr: { mod: EventModule; absPath: string }[]) => {
return from(arr);
})
.when(
e => typeof e === 'string',
@@ -160,8 +239,8 @@ function eventObservable$(
)
.when(
e => typeof e === 'function',
(evs: () => EventModule[]) => {
return from(evs().map(self => ({ mod: self, absPath: __filename })));
(evs: () => { mod: EventModule; absPath: string }[]) => {
return from(evs());
},
)
.run();

View File

@@ -16,7 +16,10 @@ interface Wrapper {
readonly sernEmitter?: SernEmitter;
readonly defaultPrefix?: string;
readonly commands: string;
readonly events?: EventModule[] | string | (() => EventModule[]);
readonly events?:
| string
| { mod: EventModule; absPath: string }[]
| (() => { mod: EventModule; absPath: string }[]);
}
export default Wrapper;