diff --git a/src/core/module-loading/readFile.ts b/src/core/module-loading/readFile.ts deleted file mode 100644 index 80e89bc..0000000 --- a/src/core/module-loading/readFile.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { readdirSync, statSync } from 'fs'; -import { join } from 'path'; -import { type Observable, from, mergeMap } from 'rxjs'; -import { SernError } from '../structures/errors'; -import { type Result, Err, Ok } from 'ts-results-es'; -import { ImportPayload } from '../../types/handler'; -import { pathToFileURL } from 'node:url'; - -// Courtesy @Townsy45 -function readPath(dir: string, arrayOfFiles: string[] = []): string[] { - try { - const files = readdirSync(dir); - for (const file of files) { - if (statSync(dir + '/' + file).isDirectory()) readPath(dir + '/' + file, arrayOfFiles); - else arrayOfFiles.push(join(dir, '/', file)); - } - } catch (err) { - throw err; - } - - return arrayOfFiles; -} -export const fmtFileName = (n: string) => n.substring(0, n.length - 3); -// export const isLazy = (n: string) => n.indexOf(".lazy.", n.length-9) !== -1; - -export async function defaultModuleLoader( - absPath: string, -): Promise, SernError>> { - // prettier-ignore - let module: T | undefined - /// #if MODE === 'esm' - = (await import(pathToFileURL(absPath).toString())).default - /// #elif MODE === 'cjs' - = require(absPath).default; // eslint-disable-line - /// #endif - if (module === undefined) { - return Err(SernError.UndefinedModule); - } - try { - module = new (module as unknown as new () => T)(); - } catch {} - return Ok({ module, absPath }); -} - -/** - * a directory string is converted into a stream of modules. - * starts the stream of modules that sern needs to process on init - * @returns {Observable<{ mod: Module; absPath: string; }[]>} data from command files - * @param commandDir - */ -export function buildModuleStream( - commandDir: string, -): Observable, SernError>> { - const commands = getCommands(commandDir); - return from(commands).pipe(mergeMap(defaultModuleLoader)); -} - -export function fullPathFrom(dir: string) { - return join(process.cwd(), dir); -} - -export function getCommands(dir: string): string[] { - return readPath(fullPathFrom(dir)); -} diff --git a/src/handler/events/dispatchers/dispatchers.ts b/src/handler/events/dispatchers/dispatchers.ts index 2c0bbee..d443225 100644 --- a/src/handler/events/dispatchers/dispatchers.ts +++ b/src/handler/events/dispatchers/dispatchers.ts @@ -1,12 +1,12 @@ import type { Processed } from '../../../types/handler'; import type { AutocompleteInteraction } from 'discord.js'; import { SernError } from '../../../core/structures'; -import treeSearch from '../../../core/utilities/treeSearch'; -import type { BothCommand, CommandModule, Module, SlashCommand } from '../../../types/module'; +import { treeSearch } from '../../../core/functions'; +import type { CommandModule, Module } from '../../../types/module'; import { EventEmitter } from 'events'; import * as assert from 'assert'; import { concatMap, from, fromEvent, map, OperatorFunction, pipe } from 'rxjs'; -import { arrayifySource, callPlugin } from '../operators'; +import { arrayifySource, callPlugin } from '../../../core/operators'; import { createResultResolver } from '../observableHandling'; export function dispatchCommand(module: Processed, createArgs: () => unknown[]) { @@ -51,7 +51,7 @@ export function eventDispatcher(module: Processed, source: unknown) { } export function dispatchAutocomplete( - module: Processed, + module: Processed, interaction: AutocompleteInteraction, ) { const option = treeSearch(interaction, module.options); diff --git a/src/handler/events/dispatchers/provideArgs.ts b/src/handler/events/dispatchers/provideArgs.ts index 33aa91e..f112235 100644 --- a/src/handler/events/dispatchers/provideArgs.ts +++ b/src/handler/events/dispatchers/provideArgs.ts @@ -1,23 +1,38 @@ -import type { ChatInputCommandInteraction, Interaction, Message } from 'discord.js'; -import { Context } from '../../structures'; +import type { Message, ChatInputCommandInteraction } from 'discord.js'; +import { CoreContext } from '../../../core/structures' import type { Args, SlashOptions } from '../../../types/handler'; +import Context from '../../../classic/context'; -/** - * function overloads to create an arguments list for Context - * @param wrap - * @param messageArgs +/* + * @overload */ export function contextArgs( wrap: Message, messageArgs?: string[], ): () => [Context, ['text', string[]]]; -export function contextArgs(wrap: Interaction): () => [Context, ['slash', SlashOptions]]; -export function contextArgs(wrap: Interaction | Message, messageArgs?: string[]) { - const ctx = Context.wrap(wrap as ChatInputCommandInteraction | Message); - const args = ctx.isMessage() ? ['text', messageArgs!] : ['slash', ctx.interaction.options]; +/* + * @overload + */ +export function contextArgs(wrappable: ChatInputCommandInteraction): () => [Context, ['slash', SlashOptions]]; +/** + * function overloads to create an arguments list for Context + * @param wrap + * @param messageArgs + */ +export function contextArgs(wrappable: Message | ChatInputCommandInteraction, messageArgs?: string[]) { + const ctx = Context.wrap(wrappable); + const args = ctx.isMessage() ? ['text', messageArgs!] : ['slash', ctx.options]; return () => [ctx, args] as [Context, Args]; } -export function interactionArg(interaction: T) { +export function interactionArg(interaction: T) { return () => [interaction] as [T]; } + + +export function multiplatformArgs< + M, + I, + Ctx extends typeof CoreContext +>(c: Ctx) { +} diff --git a/src/handler/events/interactionHandler.ts b/src/handler/events/interactions.ts similarity index 68% rename from src/handler/events/interactionHandler.ts rename to src/handler/events/interactions.ts index a2c9bf2..c357cda 100644 --- a/src/handler/events/interactionHandler.ts +++ b/src/handler/events/interactions.ts @@ -1,4 +1,4 @@ -import { Interaction } from 'discord.js'; +import { ChatInputCommandInteraction, Interaction, InteractionType } from 'discord.js'; import { catchError, concatMap, @@ -12,25 +12,63 @@ import { OperatorFunction, pipe, } from 'rxjs'; -import { CommandType, type ModuleStore, SernError } from '../../core/structures'; +import { CommandType,SernError } from '../../core/structures'; import { contextArgs, dispatchAutocomplete, dispatchCommand, interactionArg } from './dispatchers'; import { executeModule, makeModuleExecutor } from './observableHandling'; import type { CommandModule } from '../../types/module'; import { ErrorHandling, handleError } from '../../core/contracts/errorHandling'; -import { SernEmitter } from '../../core'; +import { SernEmitter, WebsocketStrategy } from '../../core'; import type { Processed } from '../../types/handler'; import { useContainerRaw } from '../../core/dependencies'; import type { Logging, ModuleManager } from '../../core/contracts'; import type { EventEmitter } from 'node:events'; +import { ModuleGetter, createModuleGetter } from '../../core/contracts/moduleManager'; + +function handleMessageComponents(i: Observable, mg: ModuleGetter) { + return i.pipe( + filter(e => e.isMessageComponent()), + map(event => ({ module: mg('' as any), event }) ) + ) +} + +function handleAutocomplete(i: Observable, mg: ModuleGetter) { + return i.pipe( + filter(e => e.isAutocomplete()), + map(event => ({ module: mg('' as any), event }) ) + ) +} + +function handleApplicationCommands(i: Observable, mg: ModuleGetter) { + return i.pipe( + filter(e => e.isCommand()), + map(event => ({ module: mg('' as any), event }) ) + ) +} + +function handleModal(i: Observable, mg: ModuleGetter) { + return i.pipe( + filter(e => e.isModalSubmit()), + map(event => ({ module: mg('' as any), event }) ) + ) +} function makeInteractionProcessor( modules: ModuleManager, ): OperatorFunction; event: Interaction }> { - const get = (cb: (ms: ModuleStore) => Processed | undefined) => { - return modules.get(cb); - }; + const get = createModuleGetter(modules); return pipe( concatMap(event => { + switch(event.type) { + case InteractionType.MessageComponent: + case InteractionType.ModalSubmit: { + const id = `${event.customId}__M${event.componentType}` + } break; + case InteractionType.ApplicationCommand: + case InteractionType.ApplicationCommandAutocomplete: { + + } + + } if (event.isMessageComponent()) { const customId = event.customId; const module = get(ms => { @@ -58,15 +96,17 @@ function makeInteractionProcessor( ) as OperatorFunction; event: Interaction }>; } -export function makeInteractionCreate([s, client, err, log, modules]: [ +export function makeInteractionCreate([s, err, log, modules, client]: [ SernEmitter, - EventEmitter, ErrorHandling, Logging | undefined, ModuleManager, -]) { + EventEmitter +], + platform: WebsocketStrategy +) { //map. If nothing again,this means a slash command - const interactionStream$ = fromEvent(client, 'interactionCreate') as Observable; + const interactionStream$ = fromEvent(client, platform.eventNames[0]) as Observable; const interactionProcessor = makeInteractionProcessor(modules); return interactionStream$ .pipe( @@ -109,7 +149,7 @@ function createDispatcher({ */ return dispatchAutocomplete(module, event); } else { - return dispatchCommand(module, contextArgs(event)); + return dispatchCommand(module, contextArgs(event as ChatInputCommandInteraction)); } } default: diff --git a/src/handler/events/messageHandler.ts b/src/handler/events/messages.ts similarity index 75% rename from src/handler/events/messageHandler.ts rename to src/handler/events/messages.ts index b76e070..8311d26 100644 --- a/src/handler/events/messageHandler.ts +++ b/src/handler/events/messages.ts @@ -1,15 +1,17 @@ import { catchError, concatMap, EMPTY, finalize, fromEvent, map, Observable, of, pipe } from 'rxjs'; -import { type ModuleStore, SernError } from '../structures'; +import { type ModuleStore, SernError } from '../../core/structures'; import type { Message } from 'discord.js'; import { executeModule, ignoreNonBot, makeModuleExecutor } from './observableHandling'; -import type { CommandModule, TextCommand } from '../../types/module'; -import { ErrorHandling, handleError } from '../contracts/errorHandling'; +import type { CommandModule } from '../../types/module'; +import { ErrorHandling, handleError } from '../../core/contracts/errorHandling'; import { contextArgs, dispatchCommand } from './dispatchers'; -import SernEmitter from '../sernEmitter'; +import SernEmitter from '../../core/sernEmitter'; import type { Processed } from '../../types/handler'; -import { useContainerRaw } from '../dependencies'; -import type { Logging, ModuleManager } from '../contracts'; +import { useContainerRaw } from '../../core/dependencies'; +import type { Logging, ModuleManager } from '../../core/contracts'; import type { EventEmitter } from 'node:events'; +import { WebsocketStrategy } from '../../core'; +import { createModuleGetter } from '../../core/contracts/moduleManager'; /** * Removes the first character(s) _[depending on prefix length]_ of the message @@ -52,27 +54,25 @@ const createMessageProcessor = ( }; return of(payload); }), - map(({ args, module }) => dispatchCommand(module as Processed, args)), + map(({ args, module }) => dispatchCommand(module as Processed, args)), ); export function makeMessageCreate( - [s, client, err, log, modules]: [ + [s, err, log, modules, client]: [ SernEmitter, - EventEmitter, ErrorHandling, Logging | undefined, ModuleManager, + EventEmitter, ], - defaultPrefix?: string, + platform: WebsocketStrategy ) { - if (!defaultPrefix) { - return EMPTY.subscribe(); + if(!platform.defaultPrefix) { + return EMPTY.subscribe() } - const get = (cb: (ms: ModuleStore) => Processed | undefined) => { - return modules.get(cb); - }; - const messageStream$ = fromEvent(client, 'messageCreate') as Observable; - const messageProcessor = createMessageProcessor(defaultPrefix, get); + const get = createModuleGetter(modules); + const messageStream$ = fromEvent(client, platform.eventNames[1]) as Observable; + const messageProcessor = createMessageProcessor(platform.defaultPrefix, get); return messageStream$ .pipe( messageProcessor, diff --git a/src/handler/events/observableHandling.ts b/src/handler/events/observableHandling.ts index 84da392..281d3da 100644 --- a/src/handler/events/observableHandling.ts +++ b/src/handler/events/observableHandling.ts @@ -77,9 +77,7 @@ export function createResultResolver< const task$ = config.createStream(args); return task$.pipe( tap(result => { - if (result.err) { - config.onStop?.(args.module); - } + result.err && config.onStop?.(args.module); }), everyPluginOk, filterMapTo(() => config.onNext(args)), diff --git a/src/handler/events/readyHandler.ts b/src/handler/events/ready.ts similarity index 79% rename from src/handler/events/readyHandler.ts rename to src/handler/events/ready.ts index 86d9738..eac4c92 100644 --- a/src/handler/events/readyHandler.ts +++ b/src/handler/events/ready.ts @@ -1,5 +1,5 @@ -import { fromEvent, map, pipe, switchMap, take } from 'rxjs'; -import * as Files from '../../core/module-loading/readFile'; +import { Subscription, fromEvent, map, of, pipe, switchMap, take } from 'rxjs'; +import * as Files from '../../core/module-loading'; import { callInitPlugins } from './observableHandling'; import { CommandType, type ModuleStore, SernError } from '../../core/structures'; import { Result } from 'ts-results-es'; @@ -7,10 +7,11 @@ import { ApplicationCommandType, ComponentType } from 'discord.js'; import type { CommandModule } from '../../types/module'; import type { Processed } from '../../types/handler'; import type { ErrorHandling, Logging, ModuleManager } from '../../core/contracts'; -import { err, ok } from '../../core/utilities/functions'; +import { err, ok } from '../../core/functions'; import { errTap, fillDefaults } from '../../core/operators'; import SernEmitter from '../../core/sernEmitter'; import type { EventEmitter } from 'node:events'; +import { DispatchType, PlatformStrategy, ServerlessStrategy, WebsocketStrategy } from '../../core'; function buildCommandModules(commandDir: string, sernEmitter: SernEmitter) { return pipe( @@ -21,18 +22,49 @@ function buildCommandModules(commandDir: string, sernEmitter: SernEmitter) { map(fillDefaults), ); } + +/** + * @overload + */ export function makeReadyEvent( - [sEmitter, client, errorHandler, , moduleManager]: [ + dependencies: [ SernEmitter, - EventEmitter, ErrorHandling, Logging | undefined, ModuleManager, ], commandDir: string, + platform: ServerlessStrategy + +): Subscription +export function makeReadyEvent( + dependencies: [ + SernEmitter, + ErrorHandling, + Logging | undefined, + ModuleManager, + EventEmitter + ], + commandDir: string, + platform: WebsocketStrategy + +): Subscription + +export function makeReadyEvent( + [sEmitter, errorHandler, , moduleManager, client]: [ + SernEmitter, + ErrorHandling, + Logging | undefined, + ModuleManager, + EventEmitter? + ], + commandDir: string, + platform: PlatformStrategy ) { - const readyOnce$ = fromEvent(client, 'ready').pipe(take(1)); - return readyOnce$ + const ready$ = platform.type === DispatchType.Serverless + ? of(null) + : fromEvent(client!, platform.eventNames[2]).pipe(take(1)); + return ready$ .pipe( buildCommandModules(commandDir, sEmitter), callInitPlugins({ diff --git a/src/handler/events/userDefinedEventsHandling.ts b/src/handler/events/userDefined.ts similarity index 89% rename from src/handler/events/userDefinedEventsHandling.ts rename to src/handler/events/userDefined.ts index c145216..cb94eec 100644 --- a/src/handler/events/userDefinedEventsHandling.ts +++ b/src/handler/events/userDefined.ts @@ -1,21 +1,22 @@ import { catchError, finalize, map, mergeAll } from 'rxjs'; -import * as Files from '../../core/module-loading/readFile'; +import * as Files from '../../core/module-loading'; import type { Processed, WebsocketDependencies } from '../../types/handler'; import { callInitPlugins } from './observableHandling'; import type { CommandModule, EventModule } from '../../types/module'; import type { EventEmitter } from 'events'; import SernEmitter from '../../core/sernEmitter'; import type { ErrorHandling, Logging } from '../../core/contracts'; -import { SernError, EventType, type Wrapper } from '../../core/structures'; +import { SernError, EventType } from '../../core/structures'; import { eventDispatcher } from './dispatchers'; import { handleError } from '../../core/contracts/errorHandling'; import { errTap, fillDefaults } from '../../core/operators'; import { useContainerRaw } from '../../core/dependencies'; +import { AnyWrapper } from '../../core/structures/wrapper'; export function makeEventsHandler( - [s, client, err, log]: [SernEmitter, EventEmitter, ErrorHandling, Logging | undefined], + [s, err, log, client]: [SernEmitter, ErrorHandling, Logging | undefined, EventEmitter], eventsPath: string, - containerGetter: Wrapper['containerConfig'], + containerGetter: AnyWrapper['containerConfig'], ) { const lazy = (k: string) => containerGetter.get(k as keyof WebsocketDependencies)[0]; const eventStream$ = eventObservable(eventsPath, s);