feat(handler) : More work toward event plugins, added typings for it

This commit is contained in:
Jacob Nguyen
2022-04-19 00:48:24 -05:00
parent 70bd12dd61
commit eeabecb4e2
6 changed files with 76 additions and 38 deletions

View File

@@ -12,11 +12,12 @@ export const onInteractionCreate = ( wrapper : Wrapper ) => {
(<Observable<Interaction>> fromEvent(client, 'interactionCreate'))
.pipe(
concatMap ( interaction => {
concatMap (async interaction => {
interaction.type
if (interaction.isChatInputCommand()) {
return of(Files.Commands.get(interaction.commandName))
.pipe(
filterTap(CommandType.Slash, mod => {
filterTap(CommandType.Slash, (mod) => {
const ctx = Context.wrap(interaction);
mod.execute(ctx, ['slash', interaction.options]);
}),
@@ -25,7 +26,7 @@ export const onInteractionCreate = ( wrapper : Wrapper ) => {
if (interaction.isContextMenuCommand()) {
return of(Files.ContextMenuUser.get(interaction.commandName))
.pipe(
filterTap(CommandType.MenuUser, mod => {
filterTap(CommandType.MenuUser, (mod) => {
mod.execute(interaction);
}),
);
@@ -33,7 +34,7 @@ export const onInteractionCreate = ( wrapper : Wrapper ) => {
if (interaction.isMessageContextMenuCommand()) {
return of(Files.ContextMenuMsg.get(interaction.commandName))
.pipe(
filterTap(CommandType.MenuMsg, mod => {
filterTap(CommandType.MenuMsg, (mod, plugs) => {
mod.execute(interaction);
}),
);
@@ -41,7 +42,7 @@ export const onInteractionCreate = ( wrapper : Wrapper ) => {
if (interaction.isButton()) {
return of(Files.Buttons.get(interaction.customId))
.pipe(
filterTap(CommandType.Button, mod => {
filterTap(CommandType.Button, (mod, plugs) => {
mod.execute(interaction);
})
);
@@ -49,7 +50,7 @@ export const onInteractionCreate = ( wrapper : Wrapper ) => {
if (interaction.isSelectMenu()) {
return of(Files.SelectMenus.get(interaction.customId))
.pipe(
filterTap(CommandType.MenuSelect, mod => {
filterTap(CommandType.MenuSelect, (mod, plugs) => {
mod.execute(interaction);
})
);
@@ -60,9 +61,9 @@ export const onInteractionCreate = ( wrapper : Wrapper ) => {
error(e){
throw e;
},
next(command) {
//log on each command emitted
console.log(command);
next(_command) {
//every command that gets triggered ends up here
//console.log(command);
},
});
};

View File

@@ -1,32 +1,44 @@
import type { Message } from 'discord.js';
import { fromEvent, Observable, of, concatMap } from 'rxjs';
import { fromEvent, Observable, of, concatMap, mergeMap } from 'rxjs';
import { Err, Ok } from 'ts-results';
import { CommandType } from '../sern';
import Context from '../structures/context';
import type Wrapper from '../structures/wrapper';
import { fmt } from '../utilities/messageHelpers';
import * as Files from '../utilities/readFile';
import { filterTap, ignoreNonBot } from './observableHandling';
import { filterCorrectModule, filterTap, ignoreNonBot } from './observableHandling';
export const onMessageCreate = (wrapper : Wrapper) => {
const { client, defaultPrefix } = wrapper;
(<Observable<Message>> fromEvent( client, 'messageCreate'))
.pipe (
.pipe(
ignoreNonBot(defaultPrefix),
concatMap ( m => {
concatMap (async m => {
const [ prefix, ...data ] = fmt(m, defaultPrefix);
const posMod = Files.Commands.get(prefix) ?? Files.Alias.get(prefix);
const ctx = Context.wrap(m);
return of( posMod )
.pipe (
filterTap(CommandType.Text, mod => {
const ctx = Context.wrap(m);
mod.execute(ctx, ['text', data]);
filterCorrectModule(CommandType.Text),
filterTap(CommandType.Text, async (mod,plugins) => {
const res = await Promise.all(
plugins.map(async pl => ({
...pl,
execute : await pl.execute([ctx, ['text', data] ], {
next : () => Ok.EMPTY,
stop : () => Err.EMPTY
}),
}))
);
if (res.every(pl => pl.execute.ok)) {
mod.execute(ctx, ['text', data]);
}
})
);
})
).subscribe ({
error(e) {
//log things
throw e;
},
next(command) {
@@ -35,5 +47,4 @@ export const onMessageCreate = (wrapper : Wrapper) => {
},
});
};

View File

@@ -1,19 +1,39 @@
import type { Awaitable, Message } from 'discord.js';
import type { CommandType } from '../sern';
import type { Module } from '../structures/structxports';
import { Observable, throwError } from 'rxjs';
import type { ModuleDefs } from '../structures/modules/commands/moduleHandler';
import { SernError } from '../structures/errors';
import { isNotFromBot } from '../utilities/messageHelpers';
import type { PluggedModule } from '../structures/modules/module';
import type { SernPlugin } from '../plugins/plugin';
import type { EventPlugin, SernPlugin } from '../plugins/plugin';
export function match(plug: PluggedModule | undefined, type : CommandType) : boolean {
return plug !== undefined && (plug.mod.type & type) != 0;
}
export function filterCorrectModule<T extends keyof ModuleDefs>(cmdType : T) {
return (src : Observable<PluggedModule|undefined>) =>
new Observable<PluggedModule>( subscriber => {
return src.subscribe({
next(modul) {
if(match(modul, cmdType)) {
subscriber.next(modul);
} else {
if (modul === undefined) {
return throwError(() => SernError.UndefinedModule);
}
return throwError(() => SernError.MismatchModule);
}
},
error: (e) => subscriber.error(e),
complete: () => subscriber.complete()
});
});
}
export function filterTap<T extends keyof ModuleDefs>(
cmdType : T,
tap: (mod : ModuleDefs[T], plugins : SernPlugin[]) => Awaitable<void>
tap: (mod : ModuleDefs[T], plugins : EventPlugin[]) => Awaitable<void>
) {
return (src : Observable<PluggedModule|undefined>) =>
new Observable<PluggedModule|undefined>( subscriber => {
@@ -21,7 +41,7 @@ export function filterTap<T extends keyof ModuleDefs>(
next(modul) {
if(match(modul, cmdType)) {
const asModT = <ModuleDefs[T]> modul!.mod;
tap(asModT, modul!.plugins);
tap(asModT, modul!.plugins as EventPlugin[]);
subscriber.next(modul);
} else {
if (modul === undefined) {
@@ -70,3 +90,6 @@ export function partition<T,U extends T,V extends T>
}

View File

@@ -31,17 +31,18 @@ export const onReady = ( wrapper : Wrapper ) => {
})
return { res, plugged : <PluggedModule>{ mod, plugins } }
})
}),
);
})
);
(concat(ready$,processCommandFiles$) as Observable<{
res : Awaitable<Result<void, void>>, plugged : PluggedModule
}>).pipe(
mergeMap(async( {res, plugged} ) => ({ res:await res, plugged }) )
).subscribe(
res : Promise<Result<void, void>>, plugged : PluggedModule
}>)
.subscribe(
({ res, plugged: { mod, plugins }}) => {
if(res.ok) {
res.then( result => {
if(result.ok) {
console.log(`${mod.name!} has been registered`)
registerModule(mod.name!, mod, plugins)
} else {
// TODO: add event emitter for command failures
@@ -49,6 +50,7 @@ export const onReady = ( wrapper : Wrapper ) => {
console.log(`Did not register command ${mod.name!}`)
console.log(mod);
}
});
})
}

View File

@@ -14,6 +14,8 @@
import type { Awaitable, Client } from "discord.js";
import type { Err, Ok, Result } from "ts-results";
import type { Module, Override, Wrapper } from "../..";
import type { CommandType } from "../sern";
import type { ModuleDefs } from "../structures/modules/commands/moduleHandler";
import type { BaseModule, PluggedModule } from "../structures/modules/module";
export enum PluginType {
@@ -41,9 +43,12 @@ export type CommandPlugin = {
) => Awaitable<Result<void,void>>
}>;
export type EventPlugin = {
type : PluginType.Event
} & BasePlugin;
export type EventPlugin<T extends CommandType = 1> = {
type : PluginType.Event,
modTy : T
} & Override<BasePlugin, {
execute : ( event : Parameters<ModuleDefs[T]['execute']>, controller: Controller ) => Awaitable<Result<void,void>>
} >;
export type SernPlugin =
CommandPlugin

View File

@@ -5,11 +5,10 @@ import type {
import {
ApplicationCommandType,
Client,
MessageType,
} from 'discord.js';
import type Wrapper from './structures/wrapper';
import { fromEvent, throwError } from 'rxjs';
import { fromEvent } from 'rxjs';
import { SernError } from './structures/errors';
import { onReady } from './events/readyEvent';
import { onMessageCreate } from './events/messageEvent';
@@ -31,8 +30,6 @@ function eventObserver(client: Client, events: DiscordEvent[] ) {
});
}
/**
* @enum { number };
*/
@@ -44,7 +41,6 @@ export enum CommandType {
Button = 0b0010000,
MenuSelect = 0b0100000,
Both = 0b0000011,
Auto = 0b1000000
}
export function cmdTypeToDjs(ty: CommandType) {