first commit

This commit is contained in:
jacoobes
2022-01-24 20:48:18 -06:00
commit 8b428f7ff1
10 changed files with 757 additions and 0 deletions

115
src/handler/sern/sern.ts Normal file
View File

@@ -0,0 +1,115 @@
import { CommandType, delegate, MessagePackage, Visibility } from "../../types/handler/handler";
import { Files } from "../utils/readFile"
import type { Awaitable, Client, Message } from "discord.js";
import type { possibleOutput } from "../../types/handler/handler"
import {Err, Ok, Result } from "ts-results";
export namespace Sern {
type Error = string;
export class Handler {
private wrapper: Sern.Wrapper;
private msgHandler : MsgHandler = new MsgHandler();
constructor(
wrapper : Sern.Wrapper,
) {
this.wrapper = wrapper;
this.wrapper.client
.on("ready", async () => {
if (this.wrapper.init !== undefined) this.wrapper.init();
await Files.registerModules(this.wrapper.commands);
})
.on("messageCreate", async message => {
let tryFmt = this.msgHandler.listen({message, prefix: this.prefix}).fmt();
if (tryFmt === undefined) return;
const commandName = this.msgHandler.fmtMsg!.shift()!;
const module = Files.Commands.get(commandName) ?? Files.Alias.get(commandName)
let cmdResult = (await this.commandResult(module, message))
if (cmdResult === undefined) return;
message.channel.send(cmdResult)
})
}
async commandResult(module: Sern.Module<unknown> | undefined, message: Message) : Promise<possibleOutput| undefined> {
if (module === undefined) return "Unknown Command";
if (module.visibility === "private" && message.guildId !== this.privateServerId) {
return "This command is not availible in this guild!"
}
if (module.type === CommandType.SLASH) return `This may be a slash command and not a legacy command`
let args = this.msgHandler.fmtMsg.slice(1).join(" ");
let parsedArgs = module.parse === undefined ? Ok("") : module.parse(args);
if(parsedArgs.err) return parsedArgs.val;
let fn = await module.delegate(message, parsedArgs)
return fn instanceof Object ? fn.val : undefined
}
get prefix() {
return this.wrapper.prefix;
}
private get privateServerId() {
return this.wrapper.privateServerId;
}
}
export interface Wrapper {
client : Client<boolean>,
prefix: string,
commands : string
init? : () => void,
privateServerId : string
}
export interface Module<Args> {
alias: string[],
desc : string,
visibility : Visibility,
type: CommandType,
delegate : (message: Message, args: Ok<Args> ) => Awaitable<Result<possibleOutput, string > | void>
parse? : (args: string) => Result<Args, Error>
}
}
class MsgHandler {
private msg : MessagePackage | null = null;
private resMsg : string[] | null = null;
listen (msg : MessagePackage): MsgHandler {
this.msg = msg
return this;
}
isCommand() : boolean {
const msg = this.msg!.message.content.trim()
return this.message.author.bot || msg.slice(0, this.prefix.length).toLowerCase() !== this.prefix;
}
fmt() : void | undefined {
if (this.isCommand()) return undefined;
this.resMsg = this.message.content.slice(this.prefix.length).trim().split(/\s+/g);
}
get fmtMsg() {
return this.resMsg!;
}
get messagePack() {
return this.msg;
}
get message() {
return this.msg!.message
}
get prefix() {
return this.msg!.prefix
}
}

View File

@@ -0,0 +1,50 @@
import { readdirSync, statSync } from "fs";
import { basename, join } from "path";
import type { Sern } from "../sern/sern";
export namespace Files {
export const Commands = new Map<string, Sern.Module<unknown> >()
export const Alias = new Map<string, Sern.Module<unknown>>()
//courtesy of Townsy#0001 on Discord
async function readPath(dir: string, arrayOfFiles: string[] = []): Promise<string[]> {
try {
const files = readdirSync(dir);
for (const file of files) {
if (statSync(dir + "/" + file).isDirectory()) {
await readPath(dir + "/" + file, arrayOfFiles)
} else {
arrayOfFiles.push(join(dir, "/", file));
}
}
} catch(err) {
throw err;
}
return arrayOfFiles;
}
export async function registerModules(dir: string) : Promise<void> {
Promise.all((await getCommands(dir)).map(async absPath => {
return { name : basename(absPath), mod: ( await import(absPath)).default as Sern.Module<unknown> }
})).then( modArr => {
for ( const { name, mod } of modArr) {
Commands.set(name.substring(0, name.length-3), mod)
if(mod.alias.length > 0) {
for( const alias of mod.alias) {
Alias.set(alias, mod)
}
}
}
})
}
export async function getCommands(dir: string) : Promise<string[]> {
return readPath(join(process.cwd(), dir ))
}
}

0
src/index.ts Normal file
View File

19
src/types/handler/handler.d.ts vendored Normal file
View File

@@ -0,0 +1,19 @@
import type { Ok, Result } from 'ts-results';
import type { Awaitable, Client, Message, MessagePayload} from 'discord.js';
import type { MessageOptions } from 'child_process';
export type Visibility = "private" | "public"
export type possibleOutput = string | MessagePayload & MessageOptions
export type MessagePackage = {
message : Message,
prefix : string
}
export type delegate = Sern.Module<unknown>["delegate"]
export enum CommandType {
TEXT = 0b00000001 << 0b00000001,
SLASH = 0b00000001 << 0b00000010,
}
declare class MsgHandler {}