harmony/src/commands/extension.ts

162 lines
4.9 KiB
TypeScript
Raw Normal View History

2020-12-02 12:29:52 +00:00
import { Collection } from '../utils/collection.ts'
import { Command } from './command.ts'
2021-04-04 05:42:15 +00:00
import { CommandClient } from './client.ts'
2021-04-04 09:29:56 +00:00
import type { ClientEvents } from '../gateway/handlers/mod.ts'
2020-11-11 09:04:49 +00:00
export type ExtensionEventCallback = (ext: Extension, ...args: any[]) => any
2020-12-03 03:19:39 +00:00
/** Extension Commands Manager */
2020-11-11 09:04:49 +00:00
export class ExtensionCommands {
extension: Extension
constructor(ext: Extension) {
this.extension = ext
}
/** Gets a list of Extension's Commands */
2020-11-11 09:04:49 +00:00
get list(): Collection<string, Command> {
2020-12-02 12:29:52 +00:00
return this.extension.client.commands.list.filter(
(c) => c.extension?.name === this.extension.name
)
2020-11-11 09:04:49 +00:00
}
/** Gets an Extension Command */
2020-11-11 09:04:49 +00:00
get(cmd: string): Command | undefined {
const find = this.extension.client.commands.find(cmd)
// linter sucks
if (find === undefined) return undefined
else if (find.extension === undefined) return undefined
else if (find.extension.name !== this.extension.name) return undefined
else return find
}
/** Adds an Extension Command */
2020-11-11 09:04:49 +00:00
add(Cmd: Command | typeof Command): boolean {
const cmd = Cmd instanceof Command ? Cmd : new Cmd()
cmd.extension = this.extension
return this.extension.client.commands.add(cmd)
}
/** Deletes an Extension Command */
2020-11-11 09:04:49 +00:00
delete(cmd: Command | string): boolean {
2020-12-02 12:29:52 +00:00
const find = this.extension.client.commands.find(
typeof cmd === 'string' ? cmd : cmd.name
)
2020-11-11 09:04:49 +00:00
if (find === undefined) return false
2020-12-02 12:29:52 +00:00
if (
find.extension !== undefined &&
find.extension.name !== this.extension.name
)
return false
2020-11-11 09:04:49 +00:00
else return this.extension.client.commands.delete(find)
}
/** Deletes all Commands of an Extension */
2020-11-11 09:04:49 +00:00
deleteAll(): void {
for (const [cmd] of this.list) {
this.delete(cmd)
}
}
}
2020-12-03 03:19:39 +00:00
/** Customizable, isolated and pluggable Extensions are a great way of writing certain Modules independent of others */
2020-11-11 09:04:49 +00:00
export class Extension {
client: CommandClient
2020-12-03 03:19:39 +00:00
/** Name of the Extension */
2020-11-11 09:04:49 +00:00
name: string = ''
2020-12-03 03:19:39 +00:00
/** Description of the Extension */
2020-11-11 09:04:49 +00:00
description?: string
2020-12-03 03:19:39 +00:00
/** Extensions's Commands Manager */
2020-11-11 09:04:49 +00:00
commands: ExtensionCommands = new ExtensionCommands(this)
2020-12-28 22:02:43 +00:00
/** Sub-Prefix to be used for ALL of Extension's Commands. */
2020-12-08 06:43:06 +00:00
subPrefix?: string
2020-12-03 03:19:39 +00:00
/** Events registered by this Extension */
2020-11-11 09:04:49 +00:00
events: { [name: string]: (...args: any[]) => {} } = {}
2020-11-11 09:04:49 +00:00
constructor(client: CommandClient) {
this.client = client
2021-04-23 05:48:59 +00:00
const self = this as any
if (self._decoratedCommands !== undefined) {
Object.entries(self._decoratedCommands).forEach((entry: any) => {
2020-12-08 06:43:06 +00:00
entry[1].extension = this
this.commands.add(entry[1])
})
2021-04-23 05:48:59 +00:00
self._decoratedCommands = undefined
}
if (
2021-04-23 05:48:59 +00:00
self._decoratedEvents !== undefined &&
Object.keys(self._decoratedEvents).length !== 0
) {
2021-04-23 05:48:59 +00:00
Object.entries(self._decoratedEvents).forEach((entry: any) => {
2021-01-24 18:36:19 +00:00
this.listen(entry[0] as keyof ClientEvents, entry[1].bind(this))
})
2021-04-23 05:48:59 +00:00
self._decoratedEvents = undefined
}
2020-11-11 09:04:49 +00:00
}
/** Listens for an Event through Extension. */
2021-01-20 10:05:15 +00:00
listen(event: keyof ClientEvents, cb: ExtensionEventCallback): boolean {
2020-11-11 09:04:49 +00:00
if (this.events[event] !== undefined) return false
else {
const fn = (...args: any[]): any => {
// eslint-disable-next-line standard/no-callback-literal
cb(this, ...args)
2020-12-02 12:29:52 +00:00
}
2020-11-11 09:04:49 +00:00
this.client.on(event, fn)
this.events[event] = fn
return true
}
}
2020-12-03 03:19:39 +00:00
/** Method called upon loading of an Extension */
2020-11-11 09:04:49 +00:00
load(): any {}
2020-12-03 03:19:39 +00:00
/** Method called upon unloading of an Extension */
2020-11-11 09:04:49 +00:00
unload(): any {}
}
2020-12-03 03:19:39 +00:00
/** Extensions Manager for CommandClient */
2020-11-11 09:04:49 +00:00
export class ExtensionsManager {
client: CommandClient
list: Collection<string, Extension> = new Collection()
constructor(client: CommandClient) {
this.client = client
}
/** Gets an Extension by name */
2020-11-11 09:04:49 +00:00
get(ext: string): Extension | undefined {
return this.list.get(ext)
}
/** Checks whether an Extension exists or not */
2020-11-11 09:04:49 +00:00
exists(ext: string): boolean {
return this.get(ext) !== undefined
}
/** Loads an Extension onto Command Client */
2020-11-11 09:04:49 +00:00
load(ext: Extension | typeof Extension): void {
// eslint-disable-next-line new-cap
if (!(ext instanceof Extension)) ext = new ext(this.client)
2020-12-02 12:29:52 +00:00
if (this.exists(ext.name))
throw new Error(`Extension with name '${ext.name}' already exists`)
2020-11-11 09:04:49 +00:00
this.list.set(ext.name, ext)
ext.load()
}
/** Unloads an Extension from Command Client */
2020-11-11 09:04:49 +00:00
unload(ext: Extension | string): boolean {
const name = typeof ext === 'string' ? ext : ext.name
const extension = this.get(name)
if (extension === undefined) return false
extension.commands.deleteAll()
for (const [k, v] of Object.entries(extension.events)) {
2021-01-20 10:05:15 +00:00
this.client.off(k as keyof ClientEvents, v)
2020-11-11 09:04:49 +00:00
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete extension.events[k]
}
extension.unload()
return this.list.delete(name)
}
2020-12-02 12:29:52 +00:00
}