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 { 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));

View File

@@ -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) =>

View File

@@ -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);
}

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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));
})

View File

@@ -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" });

View File

@@ -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');

View File

@@ -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];

View File

@@ -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: [],