mirror of
https://github.com/sern-handler/handler
synced 2026-06-06 01:16:55 +00:00
chore: change all file names to camel case
This commit is contained in:
@@ -29,6 +29,7 @@ export async function defaultModuleLoader<T extends Module>(absPath: string): Mo
|
||||
|
||||
function checkIsProcessed<T extends Module>(m: T): asserts m is Processed<T> {
|
||||
assert.ok(m.name !== undefined, `name is not defined for ${util.format(m)}`);
|
||||
assert.ok(m.description !== undefined, `description is not defined for ${util.format}`);
|
||||
}
|
||||
|
||||
export const fmtFileName = (n: string) => n.substring(0, n.length - 3);
|
||||
|
||||
@@ -7,7 +7,7 @@ import { EventEmitter } from 'node:events';
|
||||
import * as assert from 'node:assert';
|
||||
import { concatMap, from, fromEvent, map, OperatorFunction, pipe } from 'rxjs';
|
||||
import { arrayifySource, callPlugin } from '../../../core/operators';
|
||||
import { createResultResolver } from '../observableHandling';
|
||||
import { createResultResolver } from '../generic';
|
||||
|
||||
export function dispatchCommand(module: Processed<CommandModule>, createArgs: () => unknown[]) {
|
||||
const args = createArgs();
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export * from './dispatchers';
|
||||
export * from './provideArgs';
|
||||
export * from './provide-args';
|
||||
|
||||
@@ -5,13 +5,13 @@ import {
|
||||
InteractionType,
|
||||
Message,
|
||||
} from 'discord.js';
|
||||
import { Observable, filter, map } from 'rxjs';
|
||||
import { EMPTY, Observable, concatMap, filter, from, map, of, throwError, tap } from 'rxjs';
|
||||
import { CommandType, ModuleManager } from '../../core';
|
||||
import { SernError } from '../../core/structures/errors';
|
||||
import { filterMap } from '../../core/operators';
|
||||
import { callPlugin, everyPluginOk, filterMap, filterMapTo } from '../../core/operators';
|
||||
import { defaultModuleLoader } from '../../core/module-loading';
|
||||
import { Processed } from '../../types/core';
|
||||
import { BothCommand, CommandModule } from '../../types/module';
|
||||
import { ImportPayload, Processed } from '../../types/core';
|
||||
import { BothCommand, CommandModule, EventModule, Module } from '../../types/module';
|
||||
import { contextArgs, dispatchAutocomplete, dispatchCommand, interactionArg } from './dispatchers';
|
||||
import { isAutocomplete } from '../../core/predicates';
|
||||
import { ObservableInput, pipe, switchMap } from 'rxjs';
|
||||
@@ -23,6 +23,7 @@ import { AnyModule } from '../../types/module';
|
||||
import { Err, Result } from 'ts-results-es';
|
||||
import { Awaitable } from '../../types/handler';
|
||||
import { fmt } from './messages';
|
||||
import { ControlPlugin, VoidResult } from '../../types/plugin';
|
||||
|
||||
function createGenericHandler<Source, Narrowed extends Source, Output>(
|
||||
source: Observable<Source>,
|
||||
@@ -139,3 +140,112 @@ export function buildModules<T extends AnyModule>(
|
||||
map(module => ({ module, absPath: module[sernMeta].fullPath })),
|
||||
);
|
||||
}
|
||||
|
||||
function hasPrefix(prefix: string, content: string) {
|
||||
const prefixInContent = content.slice(0, prefix.length);
|
||||
return prefixInContent.localeCompare(prefix, undefined, { sensitivity: 'accent' }) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ignores messages from any person / bot except itself
|
||||
* @param prefix
|
||||
*/
|
||||
export function isNonBot(prefix: string) {
|
||||
return ({ author, content }: Message) => !author.bot && hasPrefix(prefix, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the task in a Result as a try / catch.
|
||||
* if the task is ok, an event is emitted and the stream becomes empty
|
||||
* if the task is an error, throw an error down the stream which will be handled by catchError
|
||||
* @param emitter reference to SernEmitter that will emit a successful execution of module
|
||||
* @param module the module that will be executed with task
|
||||
* @param task the deferred execution which will be called
|
||||
*/
|
||||
export function executeModule(
|
||||
emitter: SernEmitter,
|
||||
{
|
||||
module,
|
||||
task,
|
||||
}: {
|
||||
module: Processed<Module>;
|
||||
task: () => Awaitable<unknown>;
|
||||
},
|
||||
) {
|
||||
return of(module).pipe(
|
||||
//converting the task into a promise so rxjs can resolve the Awaitable properly
|
||||
concatMap(() => Result.wrapAsync(async () => task())),
|
||||
concatMap(result => {
|
||||
if (result.ok) {
|
||||
emitter.emit('module.activate', SernEmitter.success(module));
|
||||
return EMPTY;
|
||||
} else {
|
||||
return throwError(() => SernEmitter.failure(module, result.val));
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A higher order function that
|
||||
* - creates a stream of {@link VoidResult} { config.createStream }
|
||||
* - any failures results to { config.onFailure } being called
|
||||
* - if all results are ok, the stream is converted to { config.onSuccess }
|
||||
* emit config.onSuccess Observable
|
||||
* @param config
|
||||
* @returns receiver function for flattening a stream of data
|
||||
*/
|
||||
export function createResultResolver<
|
||||
T extends { execute: (...args: any[]) => any; onEvent: ControlPlugin[] },
|
||||
Args extends { module: T; [key: string]: unknown },
|
||||
Output,
|
||||
>(config: {
|
||||
onStop?: (module: T) => unknown;
|
||||
onNext: (args: Args) => Output;
|
||||
createStream: (args: Args) => Observable<VoidResult>;
|
||||
}) {
|
||||
return (args: Args) => {
|
||||
const task$ = config.createStream(args);
|
||||
return task$.pipe(
|
||||
tap(result => {
|
||||
result.err && config.onStop?.(args.module);
|
||||
}),
|
||||
everyPluginOk,
|
||||
filterMapTo(() => config.onNext(args)),
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a module's init plugins and checks for Err. If so, call { onStop } and
|
||||
* ignore the module
|
||||
*/
|
||||
export function callInitPlugins<
|
||||
T extends Processed<CommandModule | EventModule>,
|
||||
Args extends ImportPayload<T>,
|
||||
>(config: { onStop?: (module: T) => unknown; onNext: (module: Args) => T }) {
|
||||
return concatMap(
|
||||
createResultResolver({
|
||||
createStream: args => from(args.module.plugins).pipe(callPlugin(args)),
|
||||
...config,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an executable task ( execute the command ) if all control plugins are successful
|
||||
* @param onStop emits a failure response to the SernEmitter
|
||||
*/
|
||||
export function makeModuleExecutor<
|
||||
M extends Processed<Module>,
|
||||
Args extends { module: M; args: unknown[] },
|
||||
>(onStop: (m: M) => unknown) {
|
||||
const onNext = ({ args, module }: Args) => ({ task: () => module.execute(...args), module });
|
||||
return concatMap(
|
||||
createResultResolver({
|
||||
onStop,
|
||||
createStream: ({ args, module }) => from(module.onEvent).pipe(callPlugin(args)),
|
||||
onNext,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,23 +1,15 @@
|
||||
import { Interaction } from 'discord.js';
|
||||
import { catchError, concatMap, finalize, merge } from 'rxjs';
|
||||
import { SernError } from '../../core/structures/errors';
|
||||
import { executeModule, makeModuleExecutor } from './observableHandling';
|
||||
import { ErrorHandling, handleError } from '../../core/contracts/errorHandling';
|
||||
import { handleError } from '../../core/contracts/error-handling';
|
||||
import { SernEmitter } from '../../core';
|
||||
import { sharedObservable } from '../../core/operators';
|
||||
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 { createInteractionHandler } from './generic';
|
||||
import { createInteractionHandler, executeModule, makeModuleExecutor } from './generic';
|
||||
import { DependencyList } from '../../types/core';
|
||||
|
||||
export function makeInteractionCreate([s, err, log, modules, client]: [
|
||||
SernEmitter,
|
||||
ErrorHandling,
|
||||
Logging | undefined,
|
||||
ModuleManager,
|
||||
EventEmitter,
|
||||
]) {
|
||||
export function makeInteractionCreate([s, err, log, modules, client]: DependencyList ) {
|
||||
const interactionStream$ = sharedObservable<Interaction>(client, 'interactionCreate');
|
||||
const handle = createInteractionHandler<Interaction>(interactionStream$, modules);
|
||||
const interactionHandler$ = merge(
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { catchError, concatMap, EMPTY, finalize } from 'rxjs';
|
||||
import { SernError } from '../../core/structures/errors';
|
||||
import type { Message } from 'discord.js';
|
||||
import { executeModule, ignoreNonBot, makeModuleExecutor } from './observableHandling';
|
||||
import { ErrorHandling, handleError } from '../../core/contracts/errorHandling';
|
||||
import { ErrorHandling, handleError } from '../../core/contracts/error-handling';
|
||||
import type { Logging, ModuleManager } from '../../core/contracts';
|
||||
import type { EventEmitter } from 'node:events';
|
||||
import { SernEmitter, useContainerRaw } from '../../core';
|
||||
import { sharedObservable } from '../../core/operators';
|
||||
import { createMessageHandler } from './generic';
|
||||
import { createMessageHandler, executeModule, isNonBot, makeModuleExecutor } from './generic';
|
||||
import { DependencyList } from '../../types/core';
|
||||
|
||||
/**
|
||||
* Removes the first character(s) _[depending on prefix length]_ of the message
|
||||
@@ -24,13 +24,7 @@ export function fmt(msg: string, prefix: string): string[] {
|
||||
}
|
||||
|
||||
export function makeMessageCreate(
|
||||
[s, err, log, modules, client]: [
|
||||
SernEmitter,
|
||||
ErrorHandling,
|
||||
Logging | undefined,
|
||||
ModuleManager,
|
||||
EventEmitter,
|
||||
],
|
||||
[s, err, log, modules, client]: DependencyList,
|
||||
defaultPrefix: string | undefined,
|
||||
) {
|
||||
if (!defaultPrefix) {
|
||||
@@ -39,7 +33,7 @@ export function makeMessageCreate(
|
||||
}
|
||||
const messageStream$ = sharedObservable<Message>(client, 'messageCreate');
|
||||
const handler = createMessageHandler(messageStream$, defaultPrefix, modules);
|
||||
const messageHandler = handler(ignoreNonBot(defaultPrefix) as (m: Message) => m is Message);
|
||||
const messageHandler = handler(isNonBot(defaultPrefix) as (m: Message) => m is Message);
|
||||
return messageHandler.pipe(
|
||||
makeModuleExecutor(module => {
|
||||
s.emit('module.activate', SernEmitter.failure(module, SernError.PluginFailure));
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
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';
|
||||
import { callPlugin, everyPluginOk, filterMapTo } from '../../core/operators';
|
||||
import type { ImportPayload, Processed } from '../../types/core';
|
||||
import type { ControlPlugin, VoidResult } from '../../types/plugin';
|
||||
import { Awaitable } from '../../types/handler';
|
||||
import { Message } from 'discord.js';
|
||||
function hasPrefix(prefix: string, content: string) {
|
||||
const prefixInContent = content.slice(0, prefix.length);
|
||||
return prefixInContent.localeCompare(prefix, undefined, { sensitivity: 'accent' }) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ignores messages from any person / bot except itself
|
||||
* @param prefix
|
||||
*/
|
||||
export function ignoreNonBot(prefix: string) {
|
||||
return ({ author, content }: Message) => !author.bot && hasPrefix(prefix, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the task in a Result as a try / catch.
|
||||
* if the task is ok, an event is emitted and the stream becomes empty
|
||||
* if the task is an error, throw an error down the stream which will be handled by catchError
|
||||
* @param emitter reference to SernEmitter that will emit a successful execution of module
|
||||
* @param module the module that will be executed with task
|
||||
* @param task the deferred execution which will be called
|
||||
*/
|
||||
export function executeModule(
|
||||
emitter: SernEmitter,
|
||||
{
|
||||
module,
|
||||
task,
|
||||
}: {
|
||||
module: Processed<Module>;
|
||||
task: () => Awaitable<unknown>;
|
||||
},
|
||||
) {
|
||||
return of(module).pipe(
|
||||
//converting the task into a promise so rxjs can resolve the Awaitable properly
|
||||
concatMap(() => Result.wrapAsync(async () => task())),
|
||||
concatMap(result => {
|
||||
if (result.ok) {
|
||||
emitter.emit('module.activate', SernEmitter.success(module));
|
||||
return EMPTY;
|
||||
} else {
|
||||
return throwError(() => SernEmitter.failure(module, result.val));
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A higher order function that
|
||||
* - creates a stream of {@link VoidResult} { config.createStream }
|
||||
* - any failures results to { config.onFailure } being called
|
||||
* - if all results are ok, the stream is converted to { config.onSuccess }
|
||||
* emit config.onSuccess Observable
|
||||
* @param config
|
||||
* @returns receiver function for flattening a stream of data
|
||||
*/
|
||||
export function createResultResolver<
|
||||
T extends { execute: (...args: any[]) => any; onEvent: ControlPlugin[] },
|
||||
Args extends { module: T; [key: string]: unknown },
|
||||
Output,
|
||||
>(config: {
|
||||
onStop?: (module: T) => unknown;
|
||||
onNext: (args: Args) => Output;
|
||||
createStream: (args: Args) => Observable<VoidResult>;
|
||||
}) {
|
||||
return (args: Args) => {
|
||||
const task$ = config.createStream(args);
|
||||
return task$.pipe(
|
||||
tap(result => {
|
||||
result.err && config.onStop?.(args.module);
|
||||
}),
|
||||
everyPluginOk,
|
||||
filterMapTo(() => config.onNext(args)),
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a module's init plugins and checks for Err. If so, call { onStop } and
|
||||
* ignore the module
|
||||
*/
|
||||
export function callInitPlugins<
|
||||
T extends Processed<CommandModule | EventModule>,
|
||||
Args extends ImportPayload<T>,
|
||||
>(config: { onStop?: (module: T) => unknown; onNext: (module: Args) => T }) {
|
||||
return concatMap(
|
||||
createResultResolver({
|
||||
createStream: args => from(args.module.plugins).pipe(callPlugin(args)),
|
||||
...config,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an executable task ( execute the command ) if all control plugins are successful
|
||||
* @param onStop emits a failure response to the SernEmitter
|
||||
*/
|
||||
export function makeModuleExecutor<
|
||||
M extends Processed<Module>,
|
||||
Args extends { module: M; args: unknown[] },
|
||||
>(onStop: (m: M) => unknown) {
|
||||
const onNext = ({ args, module }: Args) => ({ task: () => module.execute(...args), module });
|
||||
return concatMap(
|
||||
createResultResolver({
|
||||
onStop,
|
||||
createStream: ({ args, module }) => from(module.onEvent).pipe(callPlugin(args)),
|
||||
onNext,
|
||||
}),
|
||||
);
|
||||
}
|
||||
@@ -1,20 +1,17 @@
|
||||
import { ObservableInput, fromEvent, take } from 'rxjs';
|
||||
import { callInitPlugins } from './observableHandling';
|
||||
import { CommandType } from '../../core/structures';
|
||||
import { SernError } from '../../core/structures/errors';
|
||||
import { Result } from 'ts-results-es';
|
||||
import { ModuleManager } from '../../core/contracts';
|
||||
import { SernEmitter, } from '../../core';
|
||||
import { sernMeta } from '../../commands';
|
||||
import { Processed, ServerlessDependencyList, WebsocketDependencyList } from '../../types/core';
|
||||
import { Processed, DependencyList } from '../../types/core';
|
||||
import { Module } from '../../types/module';
|
||||
import * as assert from 'node:assert';
|
||||
import { buildModules } from './generic';
|
||||
import { buildModules, callInitPlugins } from './generic';
|
||||
|
||||
export function startReadyEvent(
|
||||
[sEmitter, errorHandler, , moduleManager, client]:
|
||||
| ServerlessDependencyList
|
||||
| WebsocketDependencyList,
|
||||
[sEmitter, errorHandler, , moduleManager, client]: DependencyList,
|
||||
input: ObservableInput<string>,
|
||||
) {
|
||||
const ready$ = fromEvent(client!, 'ready').pipe(take(1));
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { catchError, finalize, map, mergeAll, of } from 'rxjs';
|
||||
import type { Dependencies, Processed, Wrapper } from '../../types/core';
|
||||
import { callInitPlugins } from './observableHandling';
|
||||
import type { CommandModule, EventModule } from '../../types/module';
|
||||
import type { EventEmitter } from 'node:events';
|
||||
import { SernEmitter } from '../../core';
|
||||
@@ -8,9 +7,9 @@ import type { ErrorHandling, Logging } from '../../core/contracts';
|
||||
import { EventType } from '../../core/structures';
|
||||
import { SernError } from '../../core/structures/errors';
|
||||
import { eventDispatcher } from './dispatchers';
|
||||
import { handleError } from '../../core/contracts/errorHandling';
|
||||
import { handleError } from '../../core/contracts/error-handling';
|
||||
import { useContainerRaw } from '../../core/dependencies';
|
||||
import { buildModules } from './generic';
|
||||
import { buildModules, callInitPlugins } from './generic';
|
||||
|
||||
export function makeEventsHandler(
|
||||
[s, err, log, client]: [SernEmitter, ErrorHandling, Logging | undefined, EventEmitter],
|
||||
@@ -1,4 +1,4 @@
|
||||
import { makeEventsHandler } from './events/userDefined';
|
||||
import { makeEventsHandler } from './events/user-defined';
|
||||
import { makeInteractionCreate } from './events/interactions';
|
||||
import { startReadyEvent } from './events/ready';
|
||||
import { makeMessageCreate } from './events/messages';
|
||||
|
||||
Reference in New Issue
Block a user