ksdjkldsfld

This commit is contained in:
Jacob Nguyen
2024-05-16 00:21:29 -05:00
parent 203e8c8ecf
commit 44c072f401
10 changed files with 70 additions and 68 deletions

View File

@@ -1,7 +1,6 @@
import type { DependencyConfiguration } from '../../types/ioc'; import type { DependencyConfiguration } from '../../types/ioc';
import { Container } from './container'; import { Container } from './container';
import * as __Services from '../structures/default-services'; import * as __Services from '../structures/default-services';
import { UnpackedDependencies } from '../../types/utility';
import type { Logging } from '../interfaces'; import type { Logging } from '../interfaces';
import { __add_container, __init_container, __swap_container, useContainerRaw } from './global'; import { __add_container, __init_container, __swap_container, useContainerRaw } from './global';
import { EventEmitter } from 'node:events'; import { EventEmitter } from 'node:events';
@@ -14,7 +13,7 @@ export function disposeAll(logger: Logging|undefined) {
type Insertable = type Insertable =
| ((container: UnpackedDependencies) => object) | ((container: Dependencies) => object)
| object | object
const dependencyBuilder = (container: Container, excluded: string[] ) => { const dependencyBuilder = (container: Container, excluded: string[] ) => {
return { return {
@@ -26,7 +25,8 @@ const dependencyBuilder = (container: Container, excluded: string[] ) => {
if(typeof v !== 'function') { if(typeof v !== 'function') {
container.addSingleton(key, v) container.addSingleton(key, v)
} else { } 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 = type ValidDependencyConfig =
| ((c: ReturnType<typeof dependencyBuilder>) => any) | ((c: ReturnType<typeof dependencyBuilder>) => any)
| DependencyConfiguration; | DependencyConfiguration;
/** /**
* Given the user's conf, check for any excluded/included dependency keys. * Given the user's conf, check for any excluded/included dependency keys.
@@ -79,13 +78,14 @@ async function composeRoot(
if (!hasLogger) { if (!hasLogger) {
container.get<Logging>('@sern/logger') 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) { export async function makeDependencies (conf: ValidDependencyConfig) {
await __init_container({ autowire: false }); await __init_container({ autowire: false });
if(typeof conf === 'function') { if(typeof conf === 'function') {
const excluded: string[] = []; const excluded: string[] = [];
conf(dependencyBuilder(useContainerRaw(), excluded)); conf(dependencyBuilder(useContainerRaw(), excluded));

View File

@@ -35,14 +35,12 @@ interface PluginExecutable {
* Calls any plugin with {args}. * Calls any plugin with {args}.
* @param args if an array, its spread and plugin called. * @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)) {
if (Array.isArray(args)) { return plugin.execute(...args);
return plugin.execute(...args); }
} return plugin.execute(args);
return plugin.execute(args);
});
} }
export const arrayifySource = <T>(src: T) => 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. * Checks if the stream of results is all ok.
*/ */
export const everyPluginOk: OperatorFunction<VoidResult, boolean> = export const everyPluginOk: OperatorFunction<VoidResult, boolean> =
pipe(every(result => result.isOk()), pipe(every(result => result.isOk()), //this shortcircuits
defaultIfEmpty(true)); defaultIfEmpty(true));
export const sharedEventStream = <T>(e: Emitter, eventName: string) => export const sharedEventStream = <T>(e: Emitter, eventName: string) =>

View File

@@ -61,7 +61,7 @@ export class Cron extends EventEmitter {
//@ts-ignore //@ts-ignore
if(!cron.validate(module.pattern)) { 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); this.modules.set(module.name!, module as CronEventCommand);
} }

View File

@@ -20,7 +20,6 @@ import { Err, Ok, Result } from 'ts-results-es';
import type { Awaitable, UnpackedDependencies, VoidResult } from '../types/utility'; import type { Awaitable, UnpackedDependencies, VoidResult } from '../types/utility';
import type { ControlPlugin } from '../types/core-plugin'; import type { ControlPlugin } from '../types/core-plugin';
import type { CommandModule, Module, Processed } from '../types/core-modules'; import type { CommandModule, Module, Processed } from '../types/core-modules';
import { EventEmitter } from 'node:events';
import * as assert from 'node:assert'; import * as assert from 'node:assert';
import { Context } from '../core/structures/context'; import { Context } from '../core/structures/context';
import { CommandType } from '../core/structures/enums' import { CommandType } from '../core/structures/enums'
@@ -28,7 +27,6 @@ import type { Args } from '../types/utility';
import { inspect } from 'node:util' import { inspect } from 'node:util'
import { disposeAll } from '../core/ioc/base'; import { disposeAll } from '../core/ioc/base';
import { arrayifySource, callPlugin, everyPluginOk, filterMapTo, handleError } from '../core/operators'; import { arrayifySource, callPlugin, everyPluginOk, filterMapTo, handleError } from '../core/operators';
import { resultPayload, isAutocomplete, treeSearch } from '../core/functions' import { resultPayload, isAutocomplete, treeSearch } from '../core/functions'
function contextArgs(wrappable: Message | BaseInteraction, messageArgs?: string[]) { function contextArgs(wrappable: Message | BaseInteraction, messageArgs?: string[]) {
@@ -41,13 +39,17 @@ function intoPayload(module: Module) {
return pipe(map(arrayifySource), return pipe(map(arrayifySource),
map(args => ({ module, args }))); map(args => ({ module, args })));
} }
const createResult = createResultResolver< const createResult = createResultResolver<
Processed<Module>, Processed<Module>,
{ module: Processed<Module>; args: unknown[] }, { module: Processed<Module>; args: unknown[] },
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, onNext: ({ args }) => args,
}); });
/** /**
@@ -56,10 +58,10 @@ const createResult = createResultResolver<
* @param source * @param source
*/ */
export function eventDispatcher(module: Module, source: unknown) { 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> = const execute: OperatorFunction<unknown[], unknown> =
concatMap(async args => module.execute(...args)); concatMap(async args => module.execute(...args));
//@ts-ignore
return fromEvent(source, module.name!) return fromEvent(source, module.name!)
//@ts-ignore //@ts-ignore
.pipe(intoPayload(module), .pipe(intoPayload(module),
@@ -67,25 +69,24 @@ export function eventDispatcher(module: Module, source: unknown) {
execute); execute);
} }
export function createDispatcher(payload: { module: Processed<CommandModule>; event: BaseInteraction; }) { export function createDispatcher({ module, event }: { module: Processed<CommandModule>; event: BaseInteraction; }) {
assert.ok(CommandType.Text !== payload.module.type, assert.ok(CommandType.Text !== module.type,
SernError.MismatchEvent + 'Found text command in interaction stream'); 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.Slash:
case CommandType.Both: { case CommandType.Both: {
if (isAutocomplete(payload.event)) { return { module, args: contextArgs(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) };
} }
default: return { module: payload.module, args: [payload.event] }; default: return { module, args: [event] };
} }
} }
function createGenericHandler<Source, Narrowed extends Source, Output>( 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) => return (pred: (i: Source) => i is Narrowed) =>
source.pipe( source.pipe(
filter(pred), filter(pred), // only handle this stream if it passes pred
concatMap(makeModule)); 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>( export function createInteractionHandler<T extends Interaction>(
source: Observable<Interaction>, source: Observable<Interaction>,
mg: Map<string, Module>, //TODO mg: Map<string, Module>,
) { ) {
return createGenericHandler<Interaction, T, Result<ReturnType<typeof createDispatcher>, void>>( return createGenericHandler<Interaction, T, Result<ReturnType<typeof createDispatcher>, void>>(
source, source,
@@ -135,7 +136,6 @@ export function createInteractionHandler<T extends Interaction>(
return Err.EMPTY; return Err.EMPTY;
} }
const [ path ] = fullPaths; const [ path ] = fullPaths;
//@ts-ignore TODO fixme
return Ok(createDispatcher({ module: path as Processed<CommandModule>, event })); return Ok(createDispatcher({ module: path as Processed<CommandModule>, event }));
}); });
} }
@@ -147,12 +147,9 @@ export function createMessageHandler(
) { ) {
return createGenericHandler(source, async event => { return createGenericHandler(source, async event => {
const [prefix, ...rest] = fmt(event.content, defaultPrefix); 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) { if(!fullPath) {
fullPath = mg.get(`${prefix}_B`); return Err('Possibly undefined behavior: could not find a static id to resolve');
if(!fullPath) {
return Err('Possibly undefined behavior: could not find a static id to resolve');
}
} }
return Ok({ args: contextArgs(event, rest), module: fullPath as Processed<CommandModule> }) 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 module the module that will be executed with task
* @param task the deferred execution which will be called * @param task the deferred execution which will be called
*/ */
export function executeModule( export async function executeModule(
emitter: Emitter, emitter: Emitter,
logger: Logging|undefined, logger: Logging|undefined,
errHandler: ErrorHandling, errHandler: ErrorHandling,
{ module, task, args }: ExecutePayload, { module, task, args }: ExecutePayload,
) { ) {
const wrappedTask = await Result.wrapAsync(async () => task());
return of(module).pipe( return of(module).pipe(
//converting the task into a promise so rxjs can resolve the Awaitable properly //converting the task into a promise so rxjs can resolve the Awaitable properly
concatMap(() => Result.wrapAsync(async () => task())), concatMap(() => Result.wrapAsync(async () => task())),
@@ -208,11 +206,11 @@ export function createResultResolver<
>(config: { >(config: {
onStop?: (module: T) => unknown; onStop?: (module: T) => unknown;
onNext: (args: Args) => Output; onNext: (args: Args) => Output;
createStream: (args: Args) => Observable<VoidResult>; createStream: (args: Args) => AsyncGenerator<VoidResult>;
}) { }) {
return (args: Args) => { return (args: Args) => {
const task$ = config.createStream(args); const task = config.createStream(args);
return task$.pipe( return from(task).pipe(
tap(result => { tap(result => {
result.isErr() && config.onStop?.(args.module); 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 * Creates an executable task ( execute the command ) if all control plugins are successful
* @param onStop emits a failure response to the SernEmitter * @param onStop emits a failure response to the SernEmitter
*/ */
export function makeModuleExecutor< export function makeModuleExecutor< M extends Processed<Module>, Args extends { module: M; args: unknown[]; }>
M extends Processed<Module>,
Args extends { module: M; args: unknown[]; }>
(onStop: (m: M) => unknown) { (onStop: (m: M) => unknown) {
const onNext = ({ args, module }: Args) => ({ const onNext = ({ args, module }: Args) => ({
task: () => module.execute(...args), task: () => module.execute(...args),
@@ -235,10 +231,17 @@ export function makeModuleExecutor<
args args
}); });
return createResultResolver({ return createResultResolver({
onStop, onStop,
createStream: ({ args, module }) => from(module.onEvent).pipe(callPlugin(args)), createStream: async function* ({ args, module }) {
onNext, 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, export const handleCrash = ({ "@sern/errors": err,

View File

@@ -20,7 +20,8 @@ function hasPrefix(prefix: string, content: string) {
return (prefixInContent.localeCompare(prefix, undefined, { sensitivity: 'accent' }) === 0); 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/logger': log, '@sern/client': client,
'@sern/modules': commands}: UnpackedDependencies, '@sern/modules': commands}: UnpackedDependencies,
defaultPrefix: string | undefined) { defaultPrefix: string | undefined) {

View File

@@ -14,9 +14,8 @@ const parseConfig = async (conf: Promise<PresenceResult>) => {
const src$ = typeof repeat === 'number' const src$ = typeof repeat === 'number'
? interval(repeat) ? interval(repeat)
: fromEvent(...repeat); : fromEvent(...repeat);
return src$ return src$.pipe(scan(onRepeat, s),
.pipe(scan(onRepeat, s), startWith(s));
startWith(s));
} }
return of(s).pipe(take(1)); return of(s).pipe(take(1));
}) })

View File

@@ -7,10 +7,10 @@ import { Module } from '../types/core-modules';
import { UnpackedDependencies } from '../types/utility'; import { UnpackedDependencies } from '../types/utility';
export default async function(dir: string, deps : UnpackedDependencies) { export default async function(dir: string, deps : UnpackedDependencies) {
const { "@sern/client": client, const { '@sern/client': client,
'@sern/logger': log, '@sern/logger': log,
'@sern/emitter': sEmitter, '@sern/emitter': sEmitter,
'@sern/modules': commands} = deps; '@sern/modules': commands } = deps;
log?.info({ message: "Waiting on discord client to be ready..." }) log?.info({ message: "Waiting on discord client to be ready..." })
await once(client, "ready"); await once(client, "ready");
log?.info({ message: "Client signaled ready, registering modules" }); log?.info({ message: "Client signaled ready, registering modules" });

View File

@@ -19,7 +19,7 @@ const intoDispatcher = (deps: UnpackedDependencies) =>
//@ts-ignore //@ts-ignore
const cron = deps['@sern/cron']; const cron = deps['@sern/cron'];
cron.addCronModule(module); cron.addCronModule(module);
return eventDispatcher(module, cron) return eventDispatcher(module, cron);
} }
default: default:
throw Error(SernError.InvalidModuleType + ' while creating event handler'); throw Error(SernError.InvalidModuleType + ' while creating event handler');

View File

@@ -6,11 +6,11 @@ import { Module } from './core-modules';
export interface CoreDependencies { export interface CoreDependencies {
'@sern/client': () => Client; '@sern/client': Client;
'@sern/emitter': () => Contracts.Emitter; '@sern/emitter': Contracts.Emitter;
'@sern/errors': () => Contracts.ErrorHandling; '@sern/errors': Contracts.ErrorHandling;
'@sern/logger'?: () => Contracts.Logging; '@sern/logger'?: Contracts.Logging;
'@sern/modules': () => Map<string, Module> '@sern/modules': Map<string, Module>;
} }
export type DependencyFromKey<T extends keyof Dependencies> = Dependencies[T]; export type DependencyFromKey<T extends keyof Dependencies> = Dependencies[T];

View File

@@ -12,6 +12,7 @@ function createRandomModule(): Processed<Module> {
min: CommandType.Text, min: CommandType.Text,
max: CommandType.ChannelSelect, max: CommandType.ChannelSelect,
}), }),
meta: { id:"", absPath: faker.system.directoryPath() },
description: faker.string.alpha(), description: faker.string.alpha(),
name: faker.string.alpha(), name: faker.string.alpha(),
onEvent: [], onEvent: [],