From 9e050902143d526211daaa9684878c0172359e45 Mon Sep 17 00:00:00 2001 From: Jacob Nguyen <76754747+jacoobes@users.noreply.github.com> Date: Fri, 29 Apr 2022 14:11:10 -0500 Subject: [PATCH] feat : partitioning command stores for better event mapping, more refactoring --- src/handler/events/interactionCreate.ts | 18 ++++-- src/handler/events/messageEvent.ts | 6 +- src/handler/events/observableHandling.ts | 8 ++- src/handler/events/readyEvent.ts | 56 +++++++++++-------- .../modules/commands/moduleHandler.ts | 6 +- src/handler/utilities/readFile.ts | 23 ++++++-- 6 files changed, 76 insertions(+), 41 deletions(-) diff --git a/src/handler/events/interactionCreate.ts b/src/handler/events/interactionCreate.ts index a8b8a93..d2d7a0a 100644 --- a/src/handler/events/interactionCreate.ts +++ b/src/handler/events/interactionCreate.ts @@ -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; - (> fromEvent(client, 'interactionCreate')) - .pipe( - concatMap (async interaction => { - interaction.type + const interactionEvent = (> 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); }, }); + **/ }; diff --git a/src/handler/events/messageEvent.ts b/src/handler/events/messageEvent.ts index 0b9d073..6b4de1f 100644 --- a/src/handler/events/messageEvent.ts +++ b/src/handler/events/messageEvent.ts @@ -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$ = (> 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 : ['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(() => diff --git a/src/handler/events/observableHandling.ts b/src/handler/events/observableHandling.ts index aad785c..9204fd3 100644 --- a/src/handler/events/observableHandling.ts +++ b/src/handler/events/observableHandling.ts @@ -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(cmdType : T) { }); } -export function filterTap( + +/** export function filterTap( cmdType : T, tap: (mod : ModuleDefs[T], plugins : EventPlugin[]) => Awaitable ) { @@ -57,7 +58,7 @@ export function filterTap( }); }); } - +**/ export function ignoreNonBot(prefix : string) { return (src : Observable) => new Observable(subscriber => { @@ -82,6 +83,7 @@ export function ignoreNonBot(prefix : string) { }); }); } + export function partition( condition : (el : T) => el is U, array : T[] diff --git a/src/handler/events/readyEvent.ts b/src/handler/events/readyEvent.ts index b603dfd..c987d2a 100644 --- a/src/handler/events/readyEvent.ts +++ b/src/handler/events/readyEvent.ts @@ -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 ( - name : string, - mod : ModuleStates[T], - plugins : SernPlugin[] -) { - return (> 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 ( + name : string, + mod : ModuleStates[T], + plugins : SernPlugin[] +) { + return (> handler(name)[mod.type])(mod, plugins); +} diff --git a/src/handler/structures/modules/commands/moduleHandler.ts b/src/handler/structures/modules/commands/moduleHandler.ts index 837de72..9a85a2c 100644 --- a/src/handler/structures/modules/commands/moduleHandler.ts +++ b/src/handler/structures/modules/commands/moduleHandler.ts @@ -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 = ( mod: ModuleStates[K], plugins : SernPlugin[] ) => unknown; diff --git a/src/handler/utilities/readFile.ts b/src/handler/utilities/readFile.ts index 234bfc7..abc0365 100644 --- a/src/handler/utilities/readFile.ts +++ b/src/handler/utilities/readFile.ts @@ -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(), + [ApplicationCommandType.Message] : new Map(), + [ApplicationCommandType.ChatInput] : new Map(), +} as {[K in ApplicationCommandType] : Map } + +export const MessageCompCommandStore = { + [ComponentType.Button] : new Map(), + [ComponentType.SelectMenu] : new Map() +} +export const TextCommandStore = { + [420] : new Map() // Aliases +} + +export const Alias = new Map(); + export const ContextMenuUser = new Map(); export const ContextMenuMsg = new Map(); -export const Commands = new Map(); -export const Alias = new Map(); export const Buttons = new Map(); export const SelectMenus = new Map();