mirror of
https://github.com/sern-handler/handler
synced 2026-06-06 01:16:55 +00:00
refactor: add createGenericHandler
This commit is contained in:
@@ -1,21 +1,35 @@
|
||||
import { BaseInteraction, ChatInputCommandInteraction, Interaction, InteractionType } from "discord.js";
|
||||
import { BaseInteraction, ChatInputCommandInteraction, Interaction, InteractionType, Message } from "discord.js";
|
||||
import { Observable, filter, map } from "rxjs";
|
||||
import { CommandType, ModuleManager } from "../../core";
|
||||
import { SernError } from '../../core/structures/errors'
|
||||
import { filterMap } from '../../core/operators';
|
||||
import { defaultModuleLoader } from "../../core/module-loading";
|
||||
import { Processed } from "../../types/core";
|
||||
import { BothCommand, CommandModule } from "../../types/module";
|
||||
import { BothCommand, CommandModule, Module } from "../../types/module";
|
||||
import { contextArgs, dispatchAutocomplete, dispatchCommand, interactionArg } from "./dispatchers";
|
||||
import { isAutocomplete } from "../../core/predicates";
|
||||
import { err } from "../../core/functions";
|
||||
import { ObservableInput, pipe, switchMap} from "rxjs";
|
||||
import { SernEmitter } from "../../core";
|
||||
import { errTap } from '../../core/operators';
|
||||
import * as Files from '../../core/module-loading';
|
||||
import { sernMeta } from "../../commands";
|
||||
import { AnyModule } from "../../types/module";
|
||||
import { Err, Result } from "ts-results-es";
|
||||
import { Awaitable } from "../../types/handler";
|
||||
import { fmt } from "./messages";
|
||||
|
||||
|
||||
|
||||
function createGenericHandler<Source, Narrowed extends Source, Output>(
|
||||
source: Observable<Source>,
|
||||
makeModule: (event: Narrowed) => Awaitable<Result<Output, unknown>>
|
||||
) {
|
||||
return (pred: (i: Source) => i is Narrowed) =>
|
||||
source.pipe(
|
||||
filter(pred),
|
||||
filterMap(makeModule)
|
||||
)
|
||||
}
|
||||
/**
|
||||
*
|
||||
* Creates an RxJS observable that filters and maps incoming interactions to their respective modules.
|
||||
@@ -23,21 +37,45 @@ import { AnyModule } from "../../types/module";
|
||||
* @param mg The module manager instance used to retrieve the module path for each interaction.
|
||||
* @returns A handler to create a RxJS observable of dispatchers that take incoming interactions and execute their corresponding modules.
|
||||
*/
|
||||
export function createHandler<T extends BaseInteraction>(
|
||||
i: Observable<Interaction>,
|
||||
export function createInteractionHandler<T extends Interaction>(
|
||||
source: Observable<Interaction>,
|
||||
mg: ModuleManager,
|
||||
) {
|
||||
return (pred: (i: BaseInteraction) => i is T) =>
|
||||
i.pipe(
|
||||
filter(pred),
|
||||
filterMap(event => {
|
||||
const fullPath = mg.get(createId(event as unknown as Interaction))
|
||||
if(!fullPath) return err();
|
||||
return defaultModuleLoader<CommandModule>(fullPath)
|
||||
.then(res => res.map(module => ({ module, event }) ))
|
||||
}),
|
||||
map(createDispatcher)
|
||||
)
|
||||
return createGenericHandler<Interaction, T, ReturnType<typeof createDispatcher>>(
|
||||
source,
|
||||
( event ) => {
|
||||
const fullPath = mg.get(createId(event as unknown as Interaction))
|
||||
if(!fullPath) return Err(SernError.UndefinedModule + " No full path found in module store");
|
||||
return defaultModuleLoader<CommandModule>(fullPath)
|
||||
.then(res =>
|
||||
res.map(module => createDispatcher({ module, event }))
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export function createMessageHandler(
|
||||
source: Observable<Message>,
|
||||
defaultPrefix: string,
|
||||
mg: ModuleManager
|
||||
) {
|
||||
return createGenericHandler(
|
||||
source,
|
||||
( event ) => {
|
||||
const [prefix, ...rest] = fmt(event.content, defaultPrefix);
|
||||
const fullPath = mg.get(`${prefix}__A0`);
|
||||
if (fullPath === undefined) {
|
||||
return Err(SernError.UndefinedModule + " No full path found in module store");
|
||||
}
|
||||
return defaultModuleLoader<CommandModule>(fullPath).then(
|
||||
result => {
|
||||
const args = contextArgs(event, rest);
|
||||
return result.map(module => dispatchCommand(module, args))
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Creates a unique ID for a given interaction object.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Interaction } from 'discord.js';
|
||||
import { BaseInteraction, Interaction } from 'discord.js';
|
||||
import {
|
||||
catchError,
|
||||
concatMap,
|
||||
@@ -14,7 +14,7 @@ import { useContainerRaw } from '../../core/dependencies';
|
||||
import type { Logging, ModuleManager } from '../../core/contracts';
|
||||
import type { EventEmitter } from 'node:events';
|
||||
import { isAutocomplete, isCommand, isMessageComponent, isModal } from '../../core/predicates';
|
||||
import { createHandler } from './generic';
|
||||
import { createInteractionHandler } from './generic';
|
||||
|
||||
|
||||
export function makeInteractionCreate([s, err, log, modules, client]: [
|
||||
@@ -27,7 +27,7 @@ export function makeInteractionCreate([s, err, log, modules, client]: [
|
||||
platform: WebsocketStrategy
|
||||
) {
|
||||
const interactionStream$ = sharedObservable<Interaction>(client, platform.eventNames[0]);
|
||||
const handle = createHandler(interactionStream$, modules);
|
||||
const handle = createInteractionHandler<Interaction>(interactionStream$, modules);
|
||||
const interactionHandler$ = merge(
|
||||
handle(isMessageComponent),
|
||||
handle(isAutocomplete),
|
||||
|
||||
@@ -13,6 +13,7 @@ import { WebsocketStrategy, SernEmitter } from '../../core';
|
||||
import { err } from '../../core/functions';
|
||||
import { defaultModuleLoader } from '../../core/module-loading';
|
||||
import { sharedObservable, filterMap } from '../../core/operators';
|
||||
import { createMessageHandler } from './generic';
|
||||
|
||||
/**
|
||||
* Removes the first character(s) _[depending on prefix length]_ of the message
|
||||
@@ -28,32 +29,6 @@ export function fmt(msg: string, prefix: string): string[] {
|
||||
return msg.slice(prefix.length).trim().split(/\s+/g);
|
||||
}
|
||||
|
||||
/**
|
||||
* An operator function that processes a message to fetch a command module and prepares context payload.
|
||||
* @param defaultPrefix
|
||||
* @param get
|
||||
*/
|
||||
const createMessageProcessor = (
|
||||
defaultPrefix: string,
|
||||
moduleManager: ModuleManager
|
||||
) =>
|
||||
pipe(
|
||||
ignoreNonBot(defaultPrefix),
|
||||
filterMap(message => {
|
||||
const [prefix, ...rest] = fmt(message.content, defaultPrefix);
|
||||
const fullPath = moduleManager.get(`${prefix}__A0`);
|
||||
if (fullPath === undefined) {
|
||||
return err();
|
||||
}
|
||||
return defaultModuleLoader<CommandModule>(fullPath).then(
|
||||
result => {
|
||||
const args = contextArgs(message, rest);
|
||||
return result.map(module => ({ module, args }))
|
||||
})
|
||||
}),
|
||||
map(({ args, module }) => dispatchCommand(module as Processed<CommandModule>, args)),
|
||||
);
|
||||
|
||||
export function makeMessageCreate(
|
||||
[s, err, log, modules, client]: [
|
||||
SernEmitter,
|
||||
@@ -68,10 +43,12 @@ export function makeMessageCreate(
|
||||
return EMPTY.subscribe()
|
||||
}
|
||||
const messageStream$ = sharedObservable<Message>(client, platform.eventNames[1]);
|
||||
const messageProcessor = createMessageProcessor(platform.defaultPrefix, modules);
|
||||
return messageStream$
|
||||
const handler = createMessageHandler(messageStream$, platform.defaultPrefix, modules);
|
||||
const messageHandler = handler(
|
||||
ignoreNonBot(platform.defaultPrefix) as (m: Message) => m is Message
|
||||
)
|
||||
return messageHandler
|
||||
.pipe(
|
||||
messageProcessor,
|
||||
makeModuleExecutor(module => {
|
||||
s.emit('module.activate', SernEmitter.failure(module, SernError.PluginFailure));
|
||||
}),
|
||||
@@ -84,5 +61,4 @@ export function makeMessageCreate(
|
||||
.then(() => log?.info({ message: 'Cleaning container and crashing' }));
|
||||
}),
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { concatMap, EMPTY, filter, from, Observable, of, tap, throwError } from 'rxjs';
|
||||
import { concatMap, EMPTY, from, Observable, of, tap, throwError } from 'rxjs';
|
||||
import { Result } from 'ts-results-es';
|
||||
import type { CommandModule, EventModule, Module } from '../../types/module';
|
||||
import { SernEmitter } from '../../core';
|
||||
@@ -18,9 +18,8 @@ function hasPrefix(prefix: string, content: string) {
|
||||
* @param prefix
|
||||
*/
|
||||
export function ignoreNonBot(prefix: string) {
|
||||
const messageFromHumanAndHasPrefix = ({ author, content }: Message) =>
|
||||
return ({ author, content }: Message) =>
|
||||
!author.bot && hasPrefix(prefix, content);
|
||||
return filter(messageFromHumanAndHasPrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user