refactor, add cron types, reinstante module loader

This commit is contained in:
Jacob Nguyen
2024-05-14 12:01:18 -05:00
parent 0a05cbba3f
commit 880311f08c
17 changed files with 60 additions and 233 deletions

View File

@@ -1,4 +0,0 @@

View File

@@ -1,6 +1,5 @@
import type { Result } from 'ts-results-es'
export * from './operators';
export * from './functions';
export type _Module = {

View File

@@ -72,8 +72,9 @@ async function composeRoot(
//container should have no client or logger yet.
const hasLogger = conf.exclude?.has('@sern/logger');
if (!hasLogger) {
__add_container('@sern/logger', new __Services.DefaultLogging);
__add_container('@sern/logger', new __Services.DefaultLogging());
}
__add_container('@sern/errors', new __Services.DefaultErrorHandling());
//Build the container based on the callback provided by the user
conf.build(container as Container);
@@ -97,6 +98,7 @@ export async function makeDependencies (conf: ValidDependencyConfig) {
if(includeLogger) {
__add_container('@sern/logger', new __Services.DefaultLogging);
}
__add_container('@sern/errors', new __Services.DefaultErrorHandling());
await useContainerRaw().ready();
} else {
await composeRoot(useContainerRaw(), conf);

View File

@@ -1,7 +1,9 @@
import path from 'node:path';
import { existsSync } from 'fs';
import { readdir } from 'fs/promises';
import assert from 'node:assert';
import * as Id from './id'
import type { _Module } from './_internal';
export const parseCallsite = (site: string) => {
const pathobj = path.parse(site.replace(/file:\\?/, "")
@@ -27,7 +29,6 @@ export const shouldHandle = (pth: string, filenam: string) => {
* commonjs, javascript :
* ```js
* exports = commandModule({ })
*
* //or
* exports.default = commandModule({ })
* ```
@@ -37,16 +38,33 @@ export const shouldHandle = (pth: string, filenam: string) => {
export async function importModule<T>(absPath: string) {
let fileModule = await import(absPath);
let commandModule = fileModule.default;
let commandModule: _Module = fileModule.default;
assert(commandModule , `No export @ ${absPath}. Forgot to ignore with "!"? (!${path.basename(absPath)})?`);
if ('default' in commandModule) {
commandModule = commandModule.default;
commandModule = commandModule.default as _Module;
}
const p = path.parse(absPath)
commandModule.name ??= p.name; commandModule.description ??= "...";
commandModule.meta = {
//@ts-ignore
id: Id.create(commandModule.name, commandModule.type),
absPath,
};
return { module: commandModule } as T;
}
export async function* readRecursive(dir: string): AsyncGenerator<string> {
const files = await readdir(dir, { withFileTypes: true, recursive: true });
for (const file of files) {
const fullPath = path.join(file.path, file.name);
if(!file.name.startsWith('!') && !file.isDirectory()) {
yield fullPath;
}
}
}
export const fmtFileName = (fileName: string) => path.parse(fileName).name;
export const filename = (p: string) => fmtFileName(path.basename(p));

View File

@@ -7,29 +7,16 @@ import type {
} from '../types/core-modules';
import { type _Module, partitionPlugins } from './_internal';
import type { Awaitable } from '../types/utility';
import callsites, { type CallSite } from 'callsites';
import * as Files from './module-loading'
import * as Id from './id'
const get_callsite = (css: CallSite[]) => {
return css.map(cs => cs.getFileName()).filter(Boolean)
}
/**
* @since 1.0.0 The wrapper function to define command modules for sern
* @param mod
*/
export function commandModule(mod: InputCommand): _Module {
const [onEvent, plugins] = partitionPlugins(mod.plugins);
const initCallsite = get_callsite(callsites()).at(-2);
if(!initCallsite) throw Error("initCallsite is null");
const { name, absPath } = Files.parseCallsite(initCallsite);
mod.name ??= name; mod.description ??= '...'
//@ts-ignore
return {
...mod,
meta: {
id: Id.create(mod.name, mod.type),
absPath
},
onEvent,
plugins,
};
@@ -41,17 +28,10 @@ export function commandModule(mod: InputCommand): _Module {
*/
export function eventModule(mod: InputEvent): _Module {
const [onEvent, plugins] = partitionPlugins(mod.plugins);
const initCallsite = get_callsite(callsites()).at(-2);
if(!initCallsite) throw Error("initCallsite is null");
const { name, absPath } = Files.parseCallsite(initCallsite);
mod.name ??= name; mod.description ??= '...'
//@ts-ignore
return {
...mod,
meta: {
id: Id.create(mod.name, mod.type),
absPath
},
plugins,
onEvent,
};

View File

@@ -48,16 +48,17 @@ export enum EventType {
/**
* The EventType for handling discord events
*/
Discord = 1,
Discord,
/**
* The EventType for handling sern events
*/
Sern = 2,
Sern,
/**
* The EventType for handling external events.
* Could be for example, `process` events, database events
*/
External = 3,
External,
Cron
}
/**

View File

@@ -14,13 +14,8 @@ import {
pipe
} from 'rxjs';
import {
callPlugin,
everyPluginOk,
filterMapTo,
handleError,
type VoidResult,
resultPayload,
arrayifySource,
isAutocomplete,
treeSearch,
_Module,
@@ -39,6 +34,7 @@ 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';
function contextArgs(wrappable: Message | BaseInteraction, messageArgs?: string[]) {

View File

@@ -1,13 +1,12 @@
import type { Interaction } from 'discord.js';
import { mergeMap, merge, concatMap } from 'rxjs';
import { PayloadType } from '../core/structures/enums';
import { filterTap } from '../core/operators'
import { filterTap, sharedEventStream } from '../core/operators'
import {
isAutocomplete,
isCommand,
isMessageComponent,
isModal,
sharedEventStream,
resultPayload,
} from '../core/_internal';
import { createInteractionHandler, executeModule, makeModuleExecutor } from './event-utils';
@@ -19,7 +18,7 @@ export function interactionHandler([emitter, err, log, client]: DependencyList)
const handle = createInteractionHandler(interactionStream$, modules);
const interactionHandler$ = merge(handle(isMessageComponent),
handle(isAutocomplete),
handle(isAutocomplete),
handle(isCommand),
handle(isModal));
return interactionHandler$

View File

@@ -1,11 +1,11 @@
import { EMPTY, mergeMap, concatMap } from 'rxjs';
import type { Message } from 'discord.js';
import { sharedEventStream } from '../core/_internal';
import type { DependencyList } from '../types/ioc';
import { createMessageHandler, executeModule, makeModuleExecutor } from './event-utils';
import { PayloadType, SernError } from '../core/structures/enums'
import { resultPayload } from '../core/functions'
import { filterTap } from '../core/operators'
import { filterTap, sharedEventStream } from '../core/operators'
/**
* Ignores messages from any person / bot except itself
* @param prefix
@@ -16,7 +16,7 @@ function isNonBot(prefix: string) {
function hasPrefix(prefix: string, content: string) {
const prefixInContent = content.slice(0, prefix.length);
return (prefixInContent.localeCompare(prefix, undefined, { sensitivity: 'accent', }) === 0);
return (prefixInContent.localeCompare(prefix, undefined, { sensitivity: 'accent' }) === 0);
}
export function messageHandler(

View File

@@ -1,13 +1,13 @@
import { ObservableInput, concat, first, fromEvent, ignoreElements, pipe, tap } from 'rxjs';
import { concat, first, fromEvent, ignoreElements, pipe, tap } from 'rxjs';
import { _Module } from '../core/_internal';
import { Logging } from '../core/interfaces';
import type { DependencyList } from '../types/ioc';
import { callInitPlugins } from './event-utils';
const once = (log: Logging | undefined) => pipe(
tap(() => { log?.info({ message: "Waiting on discord client to be ready..." }) }),
first(),
ignoreElements())
const once = (log: Logging | undefined) =>
pipe(tap(() => { log?.info({ message: "Waiting on discord client to be ready..." }) }),
first(),
ignoreElements())
export function readyHandler(
[sEmitter, , log, client]: DependencyList,
@@ -15,7 +15,8 @@ export function readyHandler(
//Todo: add module manager on on ready
const ready$ = fromEvent(client!, 'ready').pipe(once(log));
return concat(ready$).pipe(callInitPlugins(sEmitter)).subscribe()
return concat(ready$).pipe(callInitPlugins(sEmitter)).subscribe();
// const validModuleType = module.type >= 0 && module.type <= 1 << 10;
// assert.ok(validModuleType,
// `Found ${module.name} at ${module.meta.fullPath}, which does not have a valid type`);

View File

@@ -27,8 +27,7 @@ interface Wrapper {
* })
* ```
*/
export function init(wrapper?: Wrapper) {
wrapper ??= { commands: "./dist/commands", events: "./dist/events" };
export function init(wrapper: Wrapper = { commands: "./dist/commands", events: "./dist/events" }) {
const startTime = performance.now();
const dependencies = Services('@sern/emitter',
'@sern/errors',
@@ -52,7 +51,7 @@ export function init(wrapper?: Wrapper) {
logger?.info({ message: `sern: registered in ${time} s`, });
if(presencePath.exists) {
const setPresence = async (p: any) => {
return (dependencies[4] as Client).user?.setPresence(p);
return (dependencies[3] as Client).user?.setPresence(p);
}
presenceHandler(presencePath.path, setPresence).subscribe();
}

View File

@@ -163,6 +163,8 @@ export interface EventModuleDefs {
[EventType.Sern]: SernEventCommand;
[EventType.Discord]: DiscordEventCommand;
[EventType.External]: ExternalEventCommand;
//TODO
[EventType.Cron]: ExternalEventCommand;
}
export interface SernAutocompleteData

View File

@@ -150,4 +150,8 @@ interface EventArgsMatrix {
[PluginType.Control]: unknown[];
[PluginType.Init]: [InitArgs<Processed<ExternalEventCommand>>];
};
[EventType.Cron]: {
[PluginType.Control]: unknown[];
[PluginType.Init]: [InitArgs<Processed<ExternalEventCommand>>];
};
}