Skip to content

Commit

Permalink
ksdjkldsfld
Browse files Browse the repository at this point in the history
  • Loading branch information
jacoobes committed May 16, 2024
1 parent 203e8c8 commit 44c072f
Show file tree
Hide file tree
Showing 10 changed files with 70 additions and 68 deletions.
12 changes: 6 additions & 6 deletions src/core/ioc/base.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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 {
Expand All @@ -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))
}
},
/**
Expand All @@ -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.
Expand All @@ -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));
Expand Down
14 changes: 6 additions & 8 deletions src/core/operators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) =>
Expand All @@ -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) =>
Expand Down
2 changes: 1 addition & 1 deletion src/core/structures/default-services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
85 changes: 44 additions & 41 deletions src/handlers/event-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,13 @@ 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'
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[]) {
Expand All @@ -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,
});
/**
Expand All @@ -56,36 +58,35 @@ 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),
concatMap(createResult),
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>(
Expand All @@ -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
}

/**
Expand All @@ -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,
Expand All @@ -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 }));
});
}
Expand All @@ -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> })
});
Expand All @@ -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())),
Expand Down Expand Up @@ -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);
}),
Expand All @@ -225,20 +223,25 @@ 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),
module,
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,
Expand Down
3 changes: 2 additions & 1 deletion src/handlers/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
5 changes: 2 additions & 3 deletions src/handlers/presence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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));
})
Expand Down
4 changes: 2 additions & 2 deletions src/handlers/ready.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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" });
Expand Down
2 changes: 1 addition & 1 deletion src/handlers/user-defined-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
10 changes: 5 additions & 5 deletions src/types/ioc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
1 change: 1 addition & 0 deletions test/handlers/dispatchers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: [],
Expand Down

0 comments on commit 44c072f

Please sign in to comment.