Skip to content

Instantly share code, notes, and snippets.

@dannycreations
Created December 26, 2022 08:42
Show Gist options
  • Save dannycreations/893b7cf41fa11293d33dea390cc44abe to your computer and use it in GitHub Desktop.
Save dannycreations/893b7cf41fa11293d33dea390cc44abe to your computer and use it in GitHub Desktop.
import { join } from 'node:path'
import { existsSync, opendirSync } from 'node:fs'
export class TaskLoader {
public async loadAll(dir: string): Promise<void> {
if (!existsSync(dir)) return
const filePaths = await this.loadPath(dir)
for (const filePath of filePaths) {
const mod = require(filePath) as Function
delete require.cache[require.resolve(filePath)]
new (Object.values(mod)[0])()
}
}
private async loadPath(dir: string): Promise<string[]> {
const pieces: string[] = []
await (async function walk(path) {
const dir = opendirSync(path)
for await (const item of dir) {
const filePath = join(path, item.name)
if (item.isDirectory()) walk(filePath)
else if (item.isFile()) pieces.push(filePath)
}
})(dir)
return pieces
}
}
import { randomUUID } from 'crypto'
export abstract class TaskStore {
private readonly name: string
private readonly stores: Map<string, ITaskStore> = new Map()
public constructor(options: TaskOptions) {
this.name = (options.name || randomUUID()).toLowerCase()
this.setTaskInit(options)
}
public taskInit?(): unknown
public abstract taskRun(): unknown
private async setTaskInit(options: TaskOptions): Promise<void> {
const maxDelay = 2147483647
if (options.delay > maxDelay) options.delay = maxDelay
this.taskInit ??= () => true
await this.clearTask()
const [delay, taskRun] = [options.delay, this.taskRun.bind(this)]
this.stores.set(this.name, { delay, taskRun })
await this.taskInit()
this.runner()
}
public getTask(key: string = this.name): ITaskStore | undefined {
return this.stores.get(key)
}
public setTaskDelay(delay: number, key?: string): Promise<boolean> {
return this.operations(key, (job, resolve) => {
job.delay = delay
resolve(true)
})
}
public setTaskRun(taskRun: () => void, key?: string): Promise<boolean> {
return this.operations(key, (job, resolve) => {
job.taskRun = taskRun
resolve(true)
})
}
public startTask(key?: string): Promise<boolean> {
return this.operations(key, (job, resolve) => {
if (!job.pause || job.running) return resolve(false)
job.pause = false
this.runner(key)
resolve(true)
})
}
public pauseTask(key?: string): Promise<boolean> {
return this.operations(key, async (job, resolve) => {
job.pause = true
await this.sleepUntil(() => !this.getTask(key)?.running)
resolve(true)
})
}
public clearTask(key?: string): Promise<boolean> {
return this.operations(key, async (job, resolve) => {
job.clear = true
await this.sleepUntil(() => !this.getTask(key))
resolve(true)
})
}
public async clearAllTask(): Promise<void> {
await Promise.all([...this.stores.keys()].map(this.clearTask))
}
public sleepUntil(f: () => boolean, sleep: number = 20): Promise<boolean> {
return new Promise((resolve) => {
const wait = setInterval(() => {
if (f()) {
clearInterval(wait)
resolve(true)
}
}, sleep)
})
}
private runner(key?: string): Promise<boolean> {
return this.operations(key, async (job) => {
if (job.running) return
clearTimeout(job.timeout)
if (job.pause) return
if (job.clear) return this.delete(key!)
job.timeout = setTimeout(async () => {
job.running = true
await job.taskRun()
job.running = false
this.runner(key)
}, job.delay)
})
}
private delete(key: string): boolean {
return this.stores.delete(key)
}
private operations(key: string = this.name, cb: (job: ITaskStore, resolve: (value: boolean) => void) => void): Promise<boolean> {
return new Promise((resolve) => {
const job = this.getTask(key)
if (job) return cb(job, resolve)
resolve(false)
})
}
}
export interface TaskOptions {
delay: number
name?: string
}
export interface ITaskStore {
delay: number
taskRun(): unknown
clear?: boolean
pause?: boolean
running?: boolean
timeout?: NodeJS.Timeout
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment