mirror of
https://github.com/sern-handler/handler
synced 2026-06-06 01:16:55 +00:00
fix circular dependency
This commit is contained in:
@@ -20,7 +20,7 @@
|
||||
"lint": "eslint src/**/*.ts",
|
||||
"format": "eslint src/**/*.ts --fix",
|
||||
"build:dev": "tsup --metafile",
|
||||
"build:prod": "tsup ",
|
||||
"build:prod": "tsc",
|
||||
"prepare": "tsc",
|
||||
"pretty": "prettier --write .",
|
||||
"tdd": "npx --yes vitest",
|
||||
|
||||
@@ -1,84 +1 @@
|
||||
import { EventEmitter } from 'node:events';
|
||||
import * as assert from 'node:assert';
|
||||
import { concatMap, from, fromEvent, map, OperatorFunction, pipe } from 'rxjs';
|
||||
import {
|
||||
arrayifySource,
|
||||
callPlugin,
|
||||
isAutocomplete,
|
||||
treeSearch,
|
||||
SernError,
|
||||
} from '../core/_internal';
|
||||
import { createResultResolver } from './event-utils';
|
||||
import { BaseInteraction, Message } from 'discord.js';
|
||||
import { CommandType, Context } from '../core/structures';
|
||||
import type { Args } from '../types/utility';
|
||||
import { inspect } from 'node:util'
|
||||
import type { CommandModule, Module, Processed } from '../types/core-modules';
|
||||
|
||||
//TODO: refactor dispatchers so that it implements a strategy for each different type of payload?
|
||||
export function dispatchMessage(module: Processed<CommandModule>, args: [Context, Args]) {
|
||||
return { module, args };
|
||||
}
|
||||
|
||||
export function contextArgs(wrappable: Message | BaseInteraction, messageArgs?: string[]) {
|
||||
const ctx = Context.wrap(wrappable);
|
||||
const args = ctx.isMessage() ? ['text', messageArgs!] : ['slash', ctx.options];
|
||||
return [ctx, args] as [Context, Args];
|
||||
}
|
||||
|
||||
|
||||
function intoPayload(module: Processed<Module>, ) {
|
||||
return pipe(
|
||||
arrayifySource,
|
||||
map(args => ({ module, args, })));
|
||||
}
|
||||
|
||||
const createResult = createResultResolver<
|
||||
Processed<Module>,
|
||||
{ module: Processed<Module>; args: unknown[] },
|
||||
unknown[]
|
||||
>({
|
||||
createStream: ({ module, args }) => from(module.onEvent).pipe(callPlugin(args)),
|
||||
onNext: ({ args }) => args,
|
||||
});
|
||||
/**
|
||||
* Creates an observable from { source }
|
||||
* @param module
|
||||
* @param source
|
||||
*/
|
||||
export function eventDispatcher(module: Processed<Module>, source: unknown) {
|
||||
assert.ok(source instanceof EventEmitter, `${source} is not an EventEmitter`);
|
||||
|
||||
const execute: OperatorFunction<unknown[], unknown> =
|
||||
concatMap(async args => module.execute(...args));
|
||||
return fromEvent(source, module.name)
|
||||
.pipe(intoPayload(module),
|
||||
concatMap(createResult),
|
||||
execute);
|
||||
}
|
||||
|
||||
export function createDispatcher(payload: {
|
||||
module: Processed<CommandModule>;
|
||||
event: BaseInteraction;
|
||||
}) {
|
||||
assert.ok(CommandType.Text !== payload.module.type,
|
||||
SernError.MismatchEvent + 'Found text command in interaction stream');
|
||||
switch (payload.module.type) {
|
||||
case CommandType.Slash:
|
||||
case CommandType.Both: {
|
||||
if (isAutocomplete(payload.event)) {
|
||||
const option = treeSearch(payload.event, payload.module.options);
|
||||
assert.ok(option, SernError.NotSupportedInteraction + ` There is no autocomplete tag for ` + inspect(payload.module));
|
||||
const { command } = option;
|
||||
|
||||
return {
|
||||
...payload,
|
||||
module: command as Processed<Module>, //autocomplete is not a true "module" warning cast!
|
||||
args: [payload.event],
|
||||
};
|
||||
}
|
||||
return { module: payload.module, args: contextArgs(payload.event) };
|
||||
}
|
||||
default: return { module: payload.module, args: [payload.event] };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Interaction, Message } from 'discord.js';
|
||||
import type { Interaction, Message, BaseInteraction } from 'discord.js';
|
||||
import {
|
||||
EMPTY,
|
||||
Observable,
|
||||
@@ -8,30 +8,100 @@ import {
|
||||
of,
|
||||
throwError,
|
||||
tap,
|
||||
fromEvent, map, OperatorFunction,
|
||||
catchError,
|
||||
finalize,
|
||||
pipe
|
||||
} from 'rxjs';
|
||||
import {
|
||||
Files,
|
||||
Id,
|
||||
callPlugin,
|
||||
everyPluginOk,
|
||||
filterMapTo,
|
||||
handleError,
|
||||
SernError,
|
||||
VoidResult,
|
||||
type VoidResult,
|
||||
resultPayload,
|
||||
arrayifySource,
|
||||
isAutocomplete,
|
||||
treeSearch,
|
||||
} from '../core/_internal';
|
||||
import { Emitter, ErrorHandling, Logging } from '../core/interfaces';
|
||||
import type { Emitter, ErrorHandling, Logging } from '../core/interfaces';
|
||||
import { PayloadType } from '../core/structures/enums'
|
||||
import { contextArgs, createDispatcher } from './dispatchers';
|
||||
import { ObservableInput, pipe } from 'rxjs';
|
||||
import { Err, Ok, Result } from 'ts-results-es';
|
||||
import type { Awaitable } from '../types/utility';
|
||||
import type { ControlPlugin } from '../types/core-plugin';
|
||||
import type { AnyModule, CommandMeta, CommandModule, Module, Processed } from '../types/core-modules';
|
||||
import { EventEmitter } from 'node:events';
|
||||
import * as assert from 'node:assert';
|
||||
import { CommandType, Context } from '../core/structures';
|
||||
import type { Args } from '../types/utility';
|
||||
import { inspect } from 'node:util'
|
||||
import { disposeAll } from '../core/ioc/base';
|
||||
|
||||
|
||||
function contextArgs(wrappable: Message | BaseInteraction, messageArgs?: string[]) {
|
||||
const ctx = Context.wrap(wrappable);
|
||||
const args = ctx.isMessage() ? ['text', messageArgs!] : ['slash', ctx.options];
|
||||
return [ctx, args] as [Context, Args];
|
||||
}
|
||||
|
||||
|
||||
function intoPayload(module: Processed<Module>, ) {
|
||||
return pipe(
|
||||
arrayifySource,
|
||||
map(args => ({ module, args, })));
|
||||
}
|
||||
|
||||
const createResult = createResultResolver<
|
||||
Processed<Module>,
|
||||
{ module: Processed<Module>; args: unknown[] },
|
||||
unknown[]
|
||||
>({
|
||||
createStream: ({ module, args }) => from(module.onEvent).pipe(callPlugin(args)),
|
||||
onNext: ({ args }) => args,
|
||||
});
|
||||
/**
|
||||
* Creates an observable from { source }
|
||||
* @param module
|
||||
* @param source
|
||||
*/
|
||||
export function eventDispatcher(module: Processed<Module>, source: unknown) {
|
||||
assert.ok(source instanceof EventEmitter, `${source} is not an EventEmitter`);
|
||||
|
||||
const execute: OperatorFunction<unknown[], unknown> =
|
||||
concatMap(async args => module.execute(...args));
|
||||
return fromEvent(source, module.name)
|
||||
.pipe(intoPayload(module),
|
||||
concatMap(createResult),
|
||||
execute);
|
||||
}
|
||||
|
||||
export function createDispatcher(payload: {
|
||||
module: Processed<CommandModule>;
|
||||
event: BaseInteraction;
|
||||
}) {
|
||||
assert.ok(CommandType.Text !== payload.module.type,
|
||||
SernError.MismatchEvent + 'Found text command in interaction stream');
|
||||
switch (payload.module.type) {
|
||||
case CommandType.Slash:
|
||||
case CommandType.Both: {
|
||||
if (isAutocomplete(payload.event)) {
|
||||
const option = treeSearch(payload.event, payload.module.options);
|
||||
assert.ok(option, SernError.NotSupportedInteraction + ` There is no autocomplete tag for ` + inspect(payload.module));
|
||||
const { command } = option;
|
||||
|
||||
return {
|
||||
...payload,
|
||||
module: command as Processed<Module>, //autocomplete is not a true "module" warning cast!
|
||||
args: [payload.event],
|
||||
};
|
||||
}
|
||||
return { module: payload.module, args: contextArgs(payload.event) };
|
||||
}
|
||||
default: return { module: payload.module, args: [payload.event] };
|
||||
}
|
||||
}
|
||||
function createGenericHandler<Source, Narrowed extends Source, Output>(
|
||||
source: Observable<Source>,
|
||||
makeModule: (event: Narrowed) => Promise<Output>,
|
||||
@@ -138,7 +208,7 @@ export function executeModule(
|
||||
|
||||
}),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
@@ -169,7 +239,7 @@ export function createResultResolver<
|
||||
filterMapTo(() => config.onNext(args)),
|
||||
);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Calls a module's init plugins and checks for Err. If so, call { onStop } and
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
import { Interaction } from 'discord.js';
|
||||
import { mergeMap, merge, concatMap } from 'rxjs';
|
||||
import { PayloadType } from '../core/structures/enums';
|
||||
import {
|
||||
isAutocomplete,
|
||||
isCommand,
|
||||
isMessageComponent,
|
||||
isModal,
|
||||
sharedEventStream,
|
||||
SernError,
|
||||
filterTap,
|
||||
resultPayload,
|
||||
} from '../core/_internal';
|
||||
import { createInteractionHandler, executeModule, makeModuleExecutor } from './event-utils';
|
||||
import type { DependencyList } from '../types/ioc';
|
||||
|
||||
export function interactionHandler([emitter, err, log, modules, client]: DependencyList) {
|
||||
const interactionStream$ = sharedEventStream<Interaction>(client, 'interactionCreate');
|
||||
const handle = createInteractionHandler(interactionStream$, modules);
|
||||
|
||||
const interactionHandler$ = merge(
|
||||
handle(isMessageComponent),
|
||||
handle(isAutocomplete),
|
||||
handle(isCommand),
|
||||
handle(isModal),
|
||||
);
|
||||
return interactionHandler$
|
||||
.pipe(
|
||||
filterTap(e => emitter.emit('warning', resultPayload(PayloadType.Warning, undefined, e))),
|
||||
concatMap(makeModuleExecutor(module =>
|
||||
emitter.emit('module.activate', resultPayload(PayloadType.Failure, module, SernError.PluginFailure)))),
|
||||
mergeMap(payload => executeModule(emitter, log, err, payload)));
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
import { ObservableInput, map, mergeAll } from 'rxjs';
|
||||
import { ObservableInput } from 'rxjs';
|
||||
import { EventType } from '../core/structures';
|
||||
import { SernError } from '../core/_internal';
|
||||
import { callInitPlugins, handleCrash } from './event-utils';
|
||||
import { eventDispatcher } from './dispatchers'
|
||||
import { eventDispatcher } from './event-utils'
|
||||
import { Service } from '../core/ioc';
|
||||
import type { DependencyList } from '../types/ioc';
|
||||
import type { EventModule, Processed } from '../types/core-modules';
|
||||
|
||||
Reference in New Issue
Block a user