mirror of
https://github.com/sern-handler/handler
synced 2026-06-06 01:16:55 +00:00
ksdjkldsfld
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import type { DependencyConfiguration } from '../../types/ioc';
|
||||
import { Container } from './container';
|
||||
import * as __Services from '../structures/default-services';
|
||||
import { UnpackedDependencies } from '../../types/utility';
|
||||
import type { Logging } from '../interfaces';
|
||||
import { __add_container, __init_container, __swap_container, useContainerRaw } from './global';
|
||||
import { EventEmitter } from 'node:events';
|
||||
@@ -14,7 +13,7 @@ export function disposeAll(logger: Logging|undefined) {
|
||||
|
||||
|
||||
type Insertable =
|
||||
| ((container: UnpackedDependencies) => object)
|
||||
| ((container: Dependencies) => object)
|
||||
| object
|
||||
const dependencyBuilder = (container: Container, excluded: string[] ) => {
|
||||
return {
|
||||
@@ -26,7 +25,8 @@ const dependencyBuilder = (container: Container, excluded: string[] ) => {
|
||||
if(typeof v !== 'function') {
|
||||
container.addSingleton(key, v)
|
||||
} else {
|
||||
container.addWiredSingleton(key, (cntr) => v(cntr as UnpackedDependencies))
|
||||
//@ts-ignore
|
||||
container.addWiredSingleton(key, (cntr) => v(cntr))
|
||||
}
|
||||
},
|
||||
/**
|
||||
@@ -53,7 +53,6 @@ const dependencyBuilder = (container: Container, excluded: string[] ) => {
|
||||
type ValidDependencyConfig =
|
||||
| ((c: ReturnType<typeof dependencyBuilder>) => any)
|
||||
| DependencyConfiguration;
|
||||
|
||||
|
||||
/**
|
||||
* Given the user's conf, check for any excluded/included dependency keys.
|
||||
@@ -79,13 +78,14 @@ async function composeRoot(
|
||||
|
||||
if (!hasLogger) {
|
||||
container.get<Logging>('@sern/logger')
|
||||
?.info({ message: 'All dependencies loaded successfully.' });
|
||||
?.info({ message: 'All dependencies loaded successfully.' });
|
||||
}
|
||||
container.ready();
|
||||
await container.ready();
|
||||
}
|
||||
|
||||
export async function makeDependencies (conf: ValidDependencyConfig) {
|
||||
await __init_container({ autowire: false });
|
||||
|
||||
if(typeof conf === 'function') {
|
||||
const excluded: string[] = [];
|
||||
conf(dependencyBuilder(useContainerRaw(), excluded));
|
||||
|
||||
@@ -35,14 +35,12 @@ interface PluginExecutable {
|
||||
* Calls any plugin with {args}.
|
||||
* @param args if an array, its spread and plugin called.
|
||||
*/
|
||||
export function callPlugin(args: unknown): OperatorFunction<PluginExecutable, VoidResult>
|
||||
export function callPlugin(plugin: PluginExecutable, args: unknown)
|
||||
{
|
||||
return concatMap(async plugin => {
|
||||
if (Array.isArray(args)) {
|
||||
return plugin.execute(...args);
|
||||
}
|
||||
return plugin.execute(args);
|
||||
});
|
||||
if (Array.isArray(args)) {
|
||||
return plugin.execute(...args);
|
||||
}
|
||||
return plugin.execute(args);
|
||||
}
|
||||
|
||||
export const arrayifySource = <T>(src: T) =>
|
||||
@@ -52,7 +50,7 @@ export const arrayifySource = <T>(src: T) =>
|
||||
* Checks if the stream of results is all ok.
|
||||
*/
|
||||
export const everyPluginOk: OperatorFunction<VoidResult, boolean> =
|
||||
pipe(every(result => result.isOk()),
|
||||
pipe(every(result => result.isOk()), //this shortcircuits
|
||||
defaultIfEmpty(true));
|
||||
|
||||
export const sharedEventStream = <T>(e: Emitter, eventName: string) =>
|
||||
|
||||
@@ -61,7 +61,7 @@ export class Cron extends EventEmitter {
|
||||
|
||||
//@ts-ignore
|
||||
if(!cron.validate(module.pattern)) {
|
||||
throw Error("Invalid cron expression while adding")
|
||||
throw Error("Invalid cron expression while adding " + module.name)
|
||||
}
|
||||
this.modules.set(module.name!, module as CronEventCommand);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import { Err, Ok, Result } from 'ts-results-es';
|
||||
import type { Awaitable, UnpackedDependencies, VoidResult } from '../types/utility';
|
||||
import type { ControlPlugin } from '../types/core-plugin';
|
||||
import type { CommandModule, Module, Processed } from '../types/core-modules';
|
||||
import { EventEmitter } from 'node:events';
|
||||
import * as assert from 'node:assert';
|
||||
import { Context } from '../core/structures/context';
|
||||
import { CommandType } from '../core/structures/enums'
|
||||
@@ -28,7 +27,6 @@ import type { Args } from '../types/utility';
|
||||
import { inspect } from 'node:util'
|
||||
import { disposeAll } from '../core/ioc/base';
|
||||
import { arrayifySource, callPlugin, everyPluginOk, filterMapTo, handleError } from '../core/operators';
|
||||
|
||||
import { resultPayload, isAutocomplete, treeSearch } from '../core/functions'
|
||||
|
||||
function contextArgs(wrappable: Message | BaseInteraction, messageArgs?: string[]) {
|
||||
@@ -41,13 +39,17 @@ function intoPayload(module: Module) {
|
||||
return pipe(map(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)),
|
||||
createStream: async function* ({ module, args }) {
|
||||
for(const plugin of module.onEvent) {
|
||||
|
||||
}
|
||||
//from(module.onEvent).pipe(callPlugin(args))
|
||||
},
|
||||
onNext: ({ args }) => args,
|
||||
});
|
||||
/**
|
||||
@@ -56,10 +58,10 @@ const createResult = createResultResolver<
|
||||
* @param source
|
||||
*/
|
||||
export function eventDispatcher(module: Module, source: unknown) {
|
||||
assert.ok(source instanceof EventEmitter, `${source} is not an EventEmitter`);
|
||||
|
||||
assert.ok(source && typeof source === 'object', `${source} cannot be constructed into an event listener`);
|
||||
const execute: OperatorFunction<unknown[], unknown> =
|
||||
concatMap(async args => module.execute(...args));
|
||||
//@ts-ignore
|
||||
return fromEvent(source, module.name!)
|
||||
//@ts-ignore
|
||||
.pipe(intoPayload(module),
|
||||
@@ -67,25 +69,24 @@ export function eventDispatcher(module: Module, source: unknown) {
|
||||
execute);
|
||||
}
|
||||
|
||||
export function createDispatcher(payload: { module: Processed<CommandModule>; event: BaseInteraction; }) {
|
||||
assert.ok(CommandType.Text !== payload.module.type,
|
||||
export function createDispatcher({ module, event }: { module: Processed<CommandModule>; event: BaseInteraction; }) {
|
||||
assert.ok(CommandType.Text !== module.type,
|
||||
SernError.MismatchEvent + 'Found text command in interaction stream');
|
||||
switch (payload.module.type) {
|
||||
if(isAutocomplete(event)) {
|
||||
assert.ok(module.type === CommandType.Slash
|
||||
|| module.type === CommandType.Both);
|
||||
const option = treeSearch(event, module.options);
|
||||
assert.ok(option, SernError.NotSupportedInteraction + ` There is no autocomplete tag for ` + inspect(module));
|
||||
const { command } = option;
|
||||
return { module: command as Processed<Module>, //autocomplete is not a true "module" warning cast!
|
||||
args: [event] };
|
||||
}
|
||||
switch (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 {
|
||||
module: command as Processed<Module>, //autocomplete is not a true "module" warning cast!
|
||||
args: [payload.event],
|
||||
};
|
||||
}
|
||||
return { module: payload.module, args: contextArgs(payload.event) };
|
||||
return { module, args: contextArgs(event) };
|
||||
}
|
||||
default: return { module: payload.module, args: [payload.event] };
|
||||
default: return { module, args: [event] };
|
||||
}
|
||||
}
|
||||
function createGenericHandler<Source, Narrowed extends Source, Output>(
|
||||
@@ -94,8 +95,8 @@ function createGenericHandler<Source, Narrowed extends Source, Output>(
|
||||
) {
|
||||
return (pred: (i: Source) => i is Narrowed) =>
|
||||
source.pipe(
|
||||
filter(pred),
|
||||
concatMap(makeModule));
|
||||
filter(pred), // only handle this stream if it passes pred
|
||||
concatMap(makeModule)); // create a payload, preparing to execute
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,7 +122,7 @@ export function fmt(msg: string, prefix: string): string[] {
|
||||
*/
|
||||
export function createInteractionHandler<T extends Interaction>(
|
||||
source: Observable<Interaction>,
|
||||
mg: Map<string, Module>, //TODO
|
||||
mg: Map<string, Module>,
|
||||
) {
|
||||
return createGenericHandler<Interaction, T, Result<ReturnType<typeof createDispatcher>, void>>(
|
||||
source,
|
||||
@@ -135,7 +136,6 @@ export function createInteractionHandler<T extends Interaction>(
|
||||
return Err.EMPTY;
|
||||
}
|
||||
const [ path ] = fullPaths;
|
||||
//@ts-ignore TODO fixme
|
||||
return Ok(createDispatcher({ module: path as Processed<CommandModule>, event }));
|
||||
});
|
||||
}
|
||||
@@ -147,12 +147,9 @@ export function createMessageHandler(
|
||||
) {
|
||||
return createGenericHandler(source, async event => {
|
||||
const [prefix, ...rest] = fmt(event.content, defaultPrefix);
|
||||
let fullPath = mg.get(`${prefix}_T`);
|
||||
let fullPath = mg.get(`${prefix}_T`) ?? mg.get(`${prefix}_B`);
|
||||
if(!fullPath) {
|
||||
fullPath = mg.get(`${prefix}_B`);
|
||||
if(!fullPath) {
|
||||
return Err('Possibly undefined behavior: could not find a static id to resolve');
|
||||
}
|
||||
return Err('Possibly undefined behavior: could not find a static id to resolve');
|
||||
}
|
||||
return Ok({ args: contextArgs(event, rest), module: fullPath as Processed<CommandModule> })
|
||||
});
|
||||
@@ -173,12 +170,13 @@ interface ExecutePayload {
|
||||
* @param module the module that will be executed with task
|
||||
* @param task the deferred execution which will be called
|
||||
*/
|
||||
export function executeModule(
|
||||
export async function executeModule(
|
||||
emitter: Emitter,
|
||||
logger: Logging|undefined,
|
||||
errHandler: ErrorHandling,
|
||||
{ module, task, args }: ExecutePayload,
|
||||
) {
|
||||
const wrappedTask = await Result.wrapAsync(async () => task());
|
||||
return of(module).pipe(
|
||||
//converting the task into a promise so rxjs can resolve the Awaitable properly
|
||||
concatMap(() => Result.wrapAsync(async () => task())),
|
||||
@@ -208,11 +206,11 @@ export function createResultResolver<
|
||||
>(config: {
|
||||
onStop?: (module: T) => unknown;
|
||||
onNext: (args: Args) => Output;
|
||||
createStream: (args: Args) => Observable<VoidResult>;
|
||||
createStream: (args: Args) => AsyncGenerator<VoidResult>;
|
||||
}) {
|
||||
return (args: Args) => {
|
||||
const task$ = config.createStream(args);
|
||||
return task$.pipe(
|
||||
const task = config.createStream(args);
|
||||
return from(task).pipe(
|
||||
tap(result => {
|
||||
result.isErr() && config.onStop?.(args.module);
|
||||
}),
|
||||
@@ -225,9 +223,7 @@ export function createResultResolver<
|
||||
* 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[]; }>
|
||||
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),
|
||||
@@ -235,10 +231,17 @@ export function makeModuleExecutor<
|
||||
args
|
||||
});
|
||||
return createResultResolver({
|
||||
onStop,
|
||||
createStream: ({ args, module }) => from(module.onEvent).pipe(callPlugin(args)),
|
||||
onNext,
|
||||
})
|
||||
onStop,
|
||||
createStream: async function* ({ args, module }) {
|
||||
for(const plugin of module.onEvent) {
|
||||
const result = await callPlugin(plugin, args);
|
||||
if(result.isErr()) {
|
||||
return result.error
|
||||
}
|
||||
}
|
||||
},
|
||||
onNext,
|
||||
})
|
||||
}
|
||||
|
||||
export const handleCrash = ({ "@sern/errors": err,
|
||||
|
||||
@@ -20,7 +20,8 @@ function hasPrefix(prefix: string, content: string) {
|
||||
return (prefixInContent.localeCompare(prefix, undefined, { sensitivity: 'accent' }) === 0);
|
||||
}
|
||||
|
||||
export default function message({"@sern/emitter": emitter, '@sern/errors':err,
|
||||
export default function message(
|
||||
{"@sern/emitter": emitter, '@sern/errors':err,
|
||||
'@sern/logger': log, '@sern/client': client,
|
||||
'@sern/modules': commands}: UnpackedDependencies,
|
||||
defaultPrefix: string | undefined) {
|
||||
|
||||
@@ -14,9 +14,8 @@ const parseConfig = async (conf: Promise<PresenceResult>) => {
|
||||
const src$ = typeof repeat === 'number'
|
||||
? interval(repeat)
|
||||
: fromEvent(...repeat);
|
||||
return src$
|
||||
.pipe(scan(onRepeat, s),
|
||||
startWith(s));
|
||||
return src$.pipe(scan(onRepeat, s),
|
||||
startWith(s));
|
||||
}
|
||||
return of(s).pipe(take(1));
|
||||
})
|
||||
|
||||
@@ -7,10 +7,10 @@ import { Module } from '../types/core-modules';
|
||||
import { UnpackedDependencies } from '../types/utility';
|
||||
|
||||
export default async function(dir: string, deps : UnpackedDependencies) {
|
||||
const { "@sern/client": client,
|
||||
const { '@sern/client': client,
|
||||
'@sern/logger': log,
|
||||
'@sern/emitter': sEmitter,
|
||||
'@sern/modules': commands} = deps;
|
||||
'@sern/modules': commands } = deps;
|
||||
log?.info({ message: "Waiting on discord client to be ready..." })
|
||||
await once(client, "ready");
|
||||
log?.info({ message: "Client signaled ready, registering modules" });
|
||||
|
||||
@@ -19,7 +19,7 @@ const intoDispatcher = (deps: UnpackedDependencies) =>
|
||||
//@ts-ignore
|
||||
const cron = deps['@sern/cron'];
|
||||
cron.addCronModule(module);
|
||||
return eventDispatcher(module, cron)
|
||||
return eventDispatcher(module, cron);
|
||||
}
|
||||
default:
|
||||
throw Error(SernError.InvalidModuleType + ' while creating event handler');
|
||||
|
||||
@@ -6,11 +6,11 @@ import { Module } from './core-modules';
|
||||
|
||||
|
||||
export interface CoreDependencies {
|
||||
'@sern/client': () => Client;
|
||||
'@sern/emitter': () => Contracts.Emitter;
|
||||
'@sern/errors': () => Contracts.ErrorHandling;
|
||||
'@sern/logger'?: () => Contracts.Logging;
|
||||
'@sern/modules': () => Map<string, Module>
|
||||
'@sern/client': Client;
|
||||
'@sern/emitter': Contracts.Emitter;
|
||||
'@sern/errors': Contracts.ErrorHandling;
|
||||
'@sern/logger'?: Contracts.Logging;
|
||||
'@sern/modules': Map<string, Module>;
|
||||
}
|
||||
|
||||
export type DependencyFromKey<T extends keyof Dependencies> = Dependencies[T];
|
||||
|
||||
@@ -12,6 +12,7 @@ function createRandomModule(): Processed<Module> {
|
||||
min: CommandType.Text,
|
||||
max: CommandType.ChannelSelect,
|
||||
}),
|
||||
meta: { id:"", absPath: faker.system.directoryPath() },
|
||||
description: faker.string.alpha(),
|
||||
name: faker.string.alpha(),
|
||||
onEvent: [],
|
||||
|
||||
Reference in New Issue
Block a user