feat : partitioning command stores for better event mapping, more

refactoring
This commit is contained in:
Jacob Nguyen
2022-04-29 14:11:10 -05:00
parent 5b82d5f282
commit 9e05090214
6 changed files with 76 additions and 41 deletions

View File

@@ -1,19 +1,23 @@
import type { Interaction } from 'discord.js';
import { fromEvent, Observable, of, concatMap } from 'rxjs';
import { fromEvent, Observable, of, concatMap, map, tap } from 'rxjs';
import { CommandType } from '../sern';
import Context from '../structures/context';
import type Wrapper from '../structures/wrapper';
import * as Files from '../utilities/readFile';
import { filterTap } from './observableHandling';
export const onInteractionCreate = ( wrapper : Wrapper ) => {
const { client } = wrapper;
(<Observable<Interaction>> fromEvent(client, 'interactionCreate'))
.pipe(
concatMap (async interaction => {
interaction.type
const interactionEvent = (<Observable<Interaction>> fromEvent(client, 'interactionCreate'))
interactionEvent.pipe(
tap(console.log)
).subscribe()
/** concatMap (async interaction => {
if (interaction.isChatInputCommand()) {
return of(Files.Commands.get(interaction.commandName))
.pipe(
@@ -56,6 +60,7 @@ export const onInteractionCreate = ( wrapper : Wrapper ) => {
);
}
else return of();
})
).subscribe({
error(e){
@@ -66,5 +71,6 @@ export const onInteractionCreate = ( wrapper : Wrapper ) => {
//console.log(command);
},
});
**/
};

View File

@@ -1,5 +1,5 @@
import type { Message } from 'discord.js';
import { fromEvent, Observable, of, concatMap, map, from, every, concatAll, tap, switchMap } from 'rxjs';
import { fromEvent, Observable, of, concatMap, map, from, every, concatAll, tap } from 'rxjs';
import { Err, Ok } from 'ts-results';
import type { Args } from '../..';
import { CommandType } from '../sern';
@@ -13,12 +13,13 @@ import { isEventPlugin } from './readyEvent';
export const onMessageCreate = (wrapper : Wrapper) => {
const { client, defaultPrefix } = wrapper;
if (defaultPrefix === undefined) return;
const messageEvent$ = (<Observable<Message>> fromEvent( client, 'messageCreate'));
const processMessage$ = messageEvent$.pipe(
ignoreNonBot(defaultPrefix),
map(message => {
const [prefix, ...rest] = fmt(message, defaultPrefix);
console.log(prefix, rest)
return {
ctx : Context.wrap(message),
args : <Args>['text', rest],
@@ -47,6 +48,7 @@ export const onMessageCreate = (wrapper : Wrapper) => {
}));
return from(res).pipe(map(res => ({ plugged, ctx, args, res })))
}));
processEventPlugins$.subscribe( ( { plugged, ctx, args, res } ) => {
if(res.every( pl => pl.ok)) {
Promise.resolve(plugged.mod.execute(ctx, args)).then(() =>

View File

@@ -1,4 +1,4 @@
import type { Awaitable, Message } from 'discord.js';
import type { Awaitable, InteractionType, Message } from 'discord.js';
import { Observable, throwError } from 'rxjs';
import type { ModuleDefs } from '../structures/modules/commands/moduleHandler';
import { SernError } from '../structures/errors';
@@ -33,7 +33,8 @@ export function filterCorrectModule<T extends keyof ModuleDefs>(cmdType : T) {
});
}
export function filterTap<T extends keyof ModuleDefs>(
/** export function filterTap<T extends keyof ModuleDefs>(
cmdType : T,
tap: (mod : ModuleDefs[T], plugins : EventPlugin[]) => Awaitable<void>
) {
@@ -57,7 +58,7 @@ export function filterTap<T extends keyof ModuleDefs>(
});
});
}
**/
export function ignoreNonBot(prefix : string) {
return (src : Observable<Message>) =>
new Observable<Message>(subscriber => {
@@ -82,6 +83,7 @@ export function ignoreNonBot(prefix : string) {
});
});
}
export function partition<T,U extends T>(
condition : (el : T) => el is U,
array : T[]

View File

@@ -2,13 +2,15 @@ import {concatMap, from, fromEvent, map, take,concat, skip, Observable, of,
import { basename } from 'path';
import * as Files from '../utilities/readFile';
import type Wrapper from '../structures/wrapper';
import type { HandlerCallback, ModuleHandlers, ModuleStates, ModuleType } from '../structures/modules/commands/moduleHandler';
import type { ApplicationModules, HandlerCallback, MessageCompModules, ModDefs, ModuleCbs, ModuleHandlers, ModuleStates, ModuleType, StateMachine, TextCommandModules, ModuleHandler } from '../structures/modules/commands/moduleHandler';
import { CommandType } from '../sern';
import { CommandPlugin, EventPlugin, PluginType, SernPlugin } from '../plugins/plugin';
import { partition } from './observableHandling';
import { match, partition } from './observableHandling';
import { Err, Ok, Result } from 'ts-results';
import type { PluggedModule } from '../structures/modules/module';
import type { Awaitable } from 'discord.js';
import { SernError } from '../structures/errors';
import type { ContextMenuMsg, ContextMenuUser, Module, SlashCommand } from '../structures/modules/commands/module';
export const onReady = ( wrapper : Wrapper ) => {
@@ -56,54 +58,60 @@ export const onReady = ( wrapper : Wrapper ) => {
)
),
)
.subscribe(({ plugged : { mod, plugins }, cmdPluginsRes }) => {
registerModule(mod.name!, mod, plugins)
.subscribe(({ plugged, cmdPluginsRes }) => {
const loadedPluginsCorrectly = cmdPluginsRes.every(res => res.execute.ok);
const { mod, plugins } = plugged;
if(loadedPluginsCorrectly) {
registerModule(mod.name!, mod, plugins);
}
else {
console.log(`Failed to load command ${mod.name!}`)
console.log(mod)
}
})
}
// Refactor : ? Possibly repetitive and verbose.
const handler = ( name : string ) =>
({
function handler( name : string ) : ModuleHandlers {
return {
[CommandType.Text] : (mod, plugins) => {
mod.alias.forEach ( a => Files.Alias.set(a,{ mod, plugins}));
Files.Commands.set( name, { mod, plugins } );
Files.ApplicationCommandStore[1].set( name, { mod, plugins } );
},
[CommandType.Slash]: (mod, plugins) => {
Files.Commands.set( name , { mod, plugins });
Files.ApplicationCommandStore[1].set( name , { mod, plugins });
},
[CommandType.Both] :( mod, plugins )=> {
Files.Commands.set ( name,{ mod, plugins});
Files.ApplicationCommandStore[1].set ( name,{ mod, plugins});
mod.alias.forEach (a => Files.Alias.set(a, {mod,plugins}));
},
[CommandType.MenuUser] : (mod, plugins) => {
Files.ContextMenuUser.set ( name, {mod, plugins} );
Files.ApplicationCommandStore[2].set ( name, {mod, plugins} );
},
[CommandType.MenuMsg] : (mod,plugins) => {
Files.ContextMenuMsg.set (name, {mod, plugins} );
Files.ApplicationCommandStore[3].set (name, {mod, plugins} );
},
[CommandType.Button] : (mod,plugins) => {
Files.Buttons.set(name, {mod, plugins});
Files.MessageCompCommandStore[2].set(name, {mod, plugins});
},
[CommandType.MenuSelect] : ( mod, plugins ) => {
Files.SelectMenus.set(name, { mod, plugins });
Files.MessageCompCommandStore[2].set(name, { mod, plugins });
},
} as ModuleHandlers);
}
function registerModule <T extends ModuleType> (
name : string,
mod : ModuleStates[T],
plugins : SernPlugin[]
) {
return (<HandlerCallback<T>> handler(name)[mod.type])(mod, plugins);
}
function isCmdPlugin (p : SernPlugin) : p is CommandPlugin {
return (p.type & PluginType.Command) !== 0;
}
export function isEventPlugin( p : SernPlugin) : p is EventPlugin {
return (p.type & PluginType.Event) !== 0;
}
function registerModule <T extends ModuleType> (
name : string,
mod : ModuleStates[T],
plugins : SernPlugin[]
) {
return (<HandlerCallback<T>> handler(name)[mod.type])(mod, plugins);
}

View File

@@ -1,4 +1,4 @@
import type { EventPlugin, SernPlugin } from '../../../plugins/plugin';
import type { SernPlugin } from '../../../plugins/plugin';
import { CommandType } from '../../../sern';
import type {
TextCommand,
@@ -21,11 +21,13 @@ export type ModuleDefs = {
[CommandType.MenuSelect] : SelectMenuCommand;
}
//Keys of ModuleDefs
export type ModuleType = keyof ModuleDefs;
// The keys mapped to a constructed union with its type
export type ModuleStates = {
[ K in ModuleType ] : { type : K } & ModuleDefs[K] };
[ K in ModuleType ] : { type : K } & ModuleDefs[K]
};
// A handler callback that is called on each ModuleDef
export type HandlerCallback<K extends ModuleType> =
( mod: ModuleStates[K], plugins : SernPlugin[] ) => unknown;

View File

@@ -1,14 +1,29 @@
import { ApplicationCommandType, ComponentType, InteractionType, MessageComponentInteraction, MessageComponentType } from 'discord.js';
import { readdirSync, statSync } from 'fs';
import { join } from 'path';
import { from, Observable } from 'rxjs';
import { SernError } from '../structures/errors';
import type { PluggedModule } from '../structures/modules/module';
//We can look into lazily loading modules once everything is set
// A little ambigious, but ChatInput map stores text commands also.
export const ApplicationCommandStore = {
[ApplicationCommandType.User] : new Map<string, PluggedModule>(),
[ApplicationCommandType.Message] : new Map<string, PluggedModule>(),
[ApplicationCommandType.ChatInput] : new Map<string, PluggedModule>(),
} as {[K in ApplicationCommandType] : Map<string, PluggedModule> }
export const MessageCompCommandStore = {
[ComponentType.Button] : new Map<string, PluggedModule>(),
[ComponentType.SelectMenu] : new Map<string, PluggedModule>()
}
export const TextCommandStore = {
[420] : new Map<string, PluggedModule>() // Aliases
}
export const Alias = new Map<string, PluggedModule>();
export const ContextMenuUser = new Map<string, PluggedModule>();
export const ContextMenuMsg = new Map<string, PluggedModule>();
export const Commands = new Map<string, PluggedModule>();
export const Alias = new Map<string, PluggedModule>();
export const Buttons = new Map<string, PluggedModule>();
export const SelectMenus = new Map<string, PluggedModule>();