diff --git a/src/core/functions.ts b/src/core/functions.ts index dfbb2d83..46e204c6 100644 --- a/src/core/functions.ts +++ b/src/core/functions.ts @@ -14,8 +14,8 @@ import { PayloadType, PluginType } from './structures/enums'; import assert from 'assert'; import type { Payload } from '../types/utility'; -export const ok = () => Ok.EMPTY; -export const err = () => Err.EMPTY; +export const ok = (val: unknown) => Ok(val); +export const err = (val: string) => Err(val); export function partitionPlugins (arr: Array<{ type: PluginType }> = []): [T[], V[]] { diff --git a/src/core/ioc/base.ts b/src/core/ioc/base.ts index 3b1c1ab5..3ac05c3e 100644 --- a/src/core/ioc/base.ts +++ b/src/core/ioc/base.ts @@ -2,7 +2,7 @@ import type { DependencyConfiguration } from '../../types/ioc'; import { Container } from './container'; import * as __Services from '../structures/default-services'; import type { Logging } from '../interfaces'; -import { __add_container, __init_container, __swap_container, useContainerRaw } from './global'; +import { __add_container, __add_wiredcontainer, __init_container, __swap_container, useContainerRaw } from './global'; import { EventEmitter } from 'node:events'; export function disposeAll(logger: Logging|undefined) { @@ -70,9 +70,9 @@ async function composeRoot( __add_container('@sern/logger', new __Services.DefaultLogging()); } __add_container('@sern/errors', new __Services.DefaultErrorHandling()); - __add_container('@sern/cron', new __Services.Cron()) __add_container('@sern/modules', new Map()) __add_container('@sern/emitter', new EventEmitter()) + __add_wiredcontainer('@sern/cron', deps => new __Services.Cron(deps)) //Build the container based on the callback provided by the user conf.build(container as Container); @@ -84,26 +84,25 @@ async function composeRoot( } export async function makeDependencies (conf: ValidDependencyConfig) { - await __init_container({ autowire: false }); - + const container = await __init_container({ autowire: false }); if(typeof conf === 'function') { const excluded: string[] = []; - conf(dependencyBuilder(useContainerRaw(), excluded)); + conf(dependencyBuilder(container, excluded)); //We only include logger if it does not exist const includeLogger = !excluded.includes('@sern/logger') - && !useContainerRaw().hasKey('@sern/logger'); + && !container.hasKey('@sern/logger'); if(includeLogger) { __add_container('@sern/logger', new __Services.DefaultLogging); } __add_container('@sern/errors', new __Services.DefaultErrorHandling()); - __add_container('@sern/cron', new __Services.Cron()) __add_container('@sern/modules', new Map()) __add_container('@sern/emitter', new EventEmitter()) - await useContainerRaw().ready(); + __add_wiredcontainer('@sern/cron', deps => new __Services.Cron(deps)) + await container.ready(); } else { - await composeRoot(useContainerRaw(), conf); + await composeRoot(container, conf); } } diff --git a/src/core/ioc/global.ts b/src/core/ioc/global.ts index 42ff98c9..766b8c5e 100644 --- a/src/core/ioc/global.ts +++ b/src/core/ioc/global.ts @@ -1,3 +1,4 @@ +import { UnpackedDependencies } from '../../types/utility'; import { Container } from './container'; //SIDE EFFECT: GLOBAL DI @@ -22,6 +23,14 @@ export function __add_container(key: string, v: object) { containerSubject.addSingleton(key, v); } +/** + * Don't use this unless you know what you're doing. Destroys old containerSubject if it exists and disposes everything + * then it will swap + */ +export function __add_wiredcontainer(key: string, depfn : (deps: UnpackedDependencies) => object) { + //@ts-ignore + containerSubject.addWiredSingleton(key, depfn); +} /** * Initiates the global api. * Once this is finished, the Service api and the other global api is available @@ -32,6 +41,7 @@ export async function __init_container(options: { }) { containerSubject = new Container(options); await containerSubject.ready() + return containerSubject } /** diff --git a/src/core/structures/default-services.ts b/src/core/structures/default-services.ts index 933579e7..95e2b47c 100644 --- a/src/core/structures/default-services.ts +++ b/src/core/structures/default-services.ts @@ -1,5 +1,5 @@ -import type { LogPayload, Logging, ErrorHandling } from '../interfaces'; -import { AnyFunction } from '../../types/utility'; +import type { LogPayload, Logging, ErrorHandling, Emitter } from '../interfaces'; +import { AnyFunction, UnpackedDependencies } from '../../types/utility'; import cron from 'node-cron' import { EventEmitter } from 'events'; import type { CronEventCommand, Module } from '../../types/core-modules' @@ -13,12 +13,8 @@ export class DefaultErrorHandling implements ErrorHandling { crash(err: Error): never { throw err; } - keepAlive = 1; updateAlive(err: Error) { - this.keepAlive--; - if (this.keepAlive === 0) { - throw err; - } + throw err; } } @@ -47,41 +43,51 @@ export class DefaultLogging implements Logging { } } -export class Cron extends EventEmitter { +export class Cron implements Emitter { tasks: string[] = []; modules: Map = new Map(); + constructor(private deps: UnpackedDependencies) {} private sanityCheck(eventName: string | symbol) : asserts eventName is string { if(typeof eventName === 'symbol') throw Error("Cron cannot add symbol based listener") - } addCronModule(module: Module) { if(module.type !== EventType.Cron) { throw Error("Can only add cron modules"); } - //@ts-ignore if(!cron.validate(module.pattern)) { throw Error("Invalid cron expression while adding " + module.name) } + (module as CronEventCommand) this.modules.set(module.name!, module as CronEventCommand); } addListener(eventName: string | symbol, listener: AnyFunction): this { this.sanityCheck(eventName); const retrievedModule = this.modules.get(eventName); if(!retrievedModule) throw Error("Adding task: module " +eventName +"was not found"); - cron.schedule(retrievedModule.pattern, listener, { - name: retrievedModule?.name! - }); + + cron.schedule(retrievedModule.pattern, + (date) => listener({ date, deps: this.deps }), + { name: retrievedModule?.name!, + runOnInit: retrievedModule.runOnInit, + timezone: retrievedModule.timezone, + }); return this; } removeListener(eventName: string | symbol, listener: AnyFunction) { this.sanityCheck(eventName); const retrievedModule = this.modules.get(eventName); if(!retrievedModule) throw Error("Removing cron: module " +eventName +"was not found"); - const task= cron.getTasks().get(retrievedModule.name!) + const task = cron.getTasks().get(retrievedModule.name!) if(!task) throw Error("Finding cron task with"+ retrievedModule.name + " not found"); task.stop(); - super.removeListener(eventName, listener); return this; } + emit(eventName: string | symbol, ...payload: any[]): boolean { + this.sanityCheck(eventName); + const retrievedModule = this.modules.get(eventName); + if(!retrievedModule) throw Error("Removing cron: module " +eventName +"was not found"); + const task= cron.getTasks().get(retrievedModule.name!) + return task?.emit(eventName, payload) ?? false; + } } diff --git a/src/types/core-modules.ts b/src/types/core-modules.ts index 58684ac1..c0f35565 100644 --- a/src/types/core-modules.ts +++ b/src/types/core-modules.ts @@ -53,6 +53,8 @@ export interface CronEventCommand extends Module { type: EventType.Cron; name?: string; pattern: string; + runOnInit?: boolean + timezone?: string; execute(...args: unknown[]): Awaitable; }