From 9eda4abcf7c88f802956daf3fd0bcfa496ac4772 Mon Sep 17 00:00:00 2001 From: janeptrv Date: Sat, 7 Nov 2020 18:12:27 -0500 Subject: [PATCH] initial bot commit --- .gitignore | 119 +++++++++++++++++++++++++++++++++++++++++ bot.js | 72 +++++++++++++++++++++++++ cmd/lights.js | 25 +++++++++ cmd/reg.js | 16 ++++++ lights/light_parser.js | 49 +++++++++++++++++ logger.js | 54 +++++++++++++++++++ package.json | 17 ++++++ parser.js | 95 ++++++++++++++++++++++++++++++++ pnpm-lock.yaml | 41 ++++++++++++++ utils.js | 15 ++++++ 10 files changed, 503 insertions(+) create mode 100644 .gitignore create mode 100644 bot.js create mode 100644 cmd/lights.js create mode 100644 cmd/reg.js create mode 100644 lights/light_parser.js create mode 100644 logger.js create mode 100644 package.json create mode 100644 parser.js create mode 100644 pnpm-lock.yaml create mode 100644 utils.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..612cc10 --- /dev/null +++ b/.gitignore @@ -0,0 +1,119 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# config file +config.json \ No newline at end of file diff --git a/bot.js b/bot.js new file mode 100644 index 0000000..ae22e0b --- /dev/null +++ b/bot.js @@ -0,0 +1,72 @@ +import {createRequire} from "module"; +const require = createRequire(import.meta.url); + +import Eris from "eris"; +import Logger, {levels} from "./logger.js"; +import CommandParser, {Command} from "./parser.js"; +import {filename, dirname} from "./utils.js"; +import path from "path"; +import fs from "fs"; + +const cfg = require("./config.json"); +const dir = dirname(import.meta.url); + +const bot = new Eris(cfg.token); +const ctx = { + bot: bot, + log_level: levels.DEBUG +}; +const log = new Logger(filename(import.meta.url), ctx.log_level); +const parse = new CommandParser(ctx); + +const checkGuild = guild => { + if (!cfg.whitelist.includes(guild.id)) { + log.info(`Leaving guild not on whitelist: ${guild.name}`); + guild.leave(); + } +}; + +bot.on("ready", () => { + log.info("ready recieved."); + bot.guilds.forEach(guild => checkGuild(guild)); +}); + +bot.on("guildAvaliable", guild => checkGuild(guild)); + +bot.on("messageCreate", msg => parse.parseMsg(msg, ctx)); + +bot.connect(); + +async function load_commands() { + for (let file of files) { + let p = path.join(cmd_dir, file); + log.debug(p); + let obj; + try { + obj = await import ("file:////" + p); + } catch (e) { + log.warn(`loading file ${file}, ran into issue: ${e.message}`); + continue; + } + if (obj.default != undefined) { + if (obj.default.constructor.name == "CommandInitializer") { + obj.default.initialize(ctx); + let cmds = obj.default.getCommands(); + if (parse.isCmd(cmds)) { + parse.addCommand(cmds); + } else if (cmds.constructor.name == "Array") { + for (let cmd of cmds) { + parse.addCommand(cmd); + } + } + } + } else { + log.warn("module " + file + " returned an undefined module."); + } + } +} + +let cmd_dir = path.join(dir, "cmd"); +log.debug(dir); +let files = fs.readdirSync(cmd_dir); +load_commands(); diff --git a/cmd/lights.js b/cmd/lights.js new file mode 100644 index 0000000..97555bc --- /dev/null +++ b/cmd/lights.js @@ -0,0 +1,25 @@ +import {CommandInitializer, Command} from "../parser.js"; +import parse, {instructions} from "../lights/light_parser.js"; + +const initializer = new CommandInitializer(); + +class LightsParser extends Command { + init(ctx, log) { + this.log = log; + } + name = "lights"; + func(msg, args, ctx) { + let instructions = parse(args[0]); + + this.log.debug(instructions); + let res = "```\n"; + instructions.forEach(instruction => { + res += JSON.stringify(instruction) + "\n"; + }); + res += "```"; + msg.channel.createMessage(`parsed instructions:\n${res}`); + } +} +initializer.addCommand(new LightsParser()); + +export default initializer; diff --git a/cmd/reg.js b/cmd/reg.js new file mode 100644 index 0000000..bfd243c --- /dev/null +++ b/cmd/reg.js @@ -0,0 +1,16 @@ +import {CommandInitializer, Command} from "../parser.js"; + +const initializer = new CommandInitializer(); + +class PingCommand extends Command { + name = "ping"; + func(msg, args, ctx) { + msg.channel.createMessage("p").then(m => { + m.edit(`rtt: ${Math.floor(m.timestamp - msg.timestamp)}, gateway: ${ctx.bot.shards.get(ctx.bot.guildShardMap[ctx.bot.channelGuildMap[msg.channel.id]] || 0).latency}`); + }); + } +} + +initializer.addCommand(new PingCommand()); + +export default initializer; diff --git a/lights/light_parser.js b/lights/light_parser.js new file mode 100644 index 0000000..fade3e7 --- /dev/null +++ b/lights/light_parser.js @@ -0,0 +1,49 @@ +class Target { + constructor(channel) { + this.channel = channel; + } + channel; + value; +} + +const available_targets = { + r: new Target("r"), + g: new Target("g"), + b: new Target("b") +}; + +class Instruction { + constructor(t1ets, args) { + let valid_targets = []; + targets.forEach(t => { + if (t instanceof Target) { + let match = Object.keys(available_targets).find(key => available_targets[key].channel === t.channel); + if (match) { + valid_targets.push(t); + } + } + }); + this.targets = valid_targets; + this.args = args; + } + name; + targets; + args; + transform(index, time, channel_target, channel_in) {} + transformAll(index, time) { + let new_targets = []; + this.targets.forEach(target => { + this.transform(index, time, target, this.args); + }); + } +} + +class ConstantColor extends Instruction { + name = "CONSTANT"; + transform(index, time, channel_target) {} +} +export const instructions = [ConstantColor]; + +export default function parse(str) { + return [{}]; +} diff --git a/logger.js b/logger.js new file mode 100644 index 0000000..7a71e0c --- /dev/null +++ b/logger.js @@ -0,0 +1,54 @@ +export const levels = { + DEBUG: 4, + INFO: 3, + WARN: 2, + ERROR: 1, + PANIC: 0 + } + +export default class Logger { + constructor(name, level) { + console.log(`created new logger for ${name} with level ${level}`) + this.sn(name); + this.s(level); + } + n = "DEFAULT"; + l = 0; + sn(n) { + this.n = n; + } + s(l) { + if(l && l.constructor === Number) { + this.l = l + } + else { + this.l = levels[l]; + } + } + + lo(l, m) { + if (l <= this.l) { + let level = Object.keys(levels).find(key => levels[key] === l); + let ms = typeof m == "object" + ? JSON.stringify(m) + : m; + console.log(`${level} [${this.n}]: ${ms}`); + } + } + + debug(msg) { + this.lo(levels.DEBUG, msg); + } + info(msg) { + this.lo(levels.INFO, msg); + } + warn(msg) { + this.lo(levels.WARN, msg); + } + error(msg) { + this.lo(levels.ERROR, msg); + } + panic(msg) { + this.lo(levels.PANIC, msg); + } +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..d0147c7 --- /dev/null +++ b/package.json @@ -0,0 +1,17 @@ +{ + "type": "module", + "dependencies": { + "eris": "^0.14.0" + }, + "name": "lights", + "version": "1.0.0", + "main": "bot.js", + "devDependencies": {}, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node bot.js" + }, + "author": "", + "license": "ISC", + "description": "" +} diff --git a/parser.js b/parser.js new file mode 100644 index 0000000..d50a926 --- /dev/null +++ b/parser.js @@ -0,0 +1,95 @@ +import Logger, {levels} from "./logger.js"; +import {filename} from "./utils.js"; + +export class Command { + init(ctx, log) { + this.log = log; + } + log; + name = "DEFAULT"; + func() {} +} + +export class CommandInitializer { + commands = []; + uninitialized = []; + + initialize(ctx) { + for (let index in this.uninitialized) { + this.initCommand(this.uninitialized[index], ctx); + delete this.uninitialized[index]; + } + } + + initCommand(cmd, ctx) { + cmd.init(ctx, new Logger(`cmd.${cmd.name}`, ctx.log_level)); + this.commands.push(cmd); + } + + addCommand(cmd) { + this.uninitialized.push(cmd); + } + + getCommands() { + return this.commands; + } +} + +export default class CommandParser { + constructor(ctx, prefix = ";") { + this.log = new Logger(filename(import.meta.url), ctx.log_level); + this.prefix = prefix + ? prefix + : this.prefix; + } + log; + prefix; + commands = []; + + addCommand(cmd) { + this.log.debug(`cmd to add: ${JSON.stringify(cmd)}`); + if (this.isCmd(cmd)) { + this.commands.push(cmd); + } + } + + hasCmd(str) { + let results = this.commands.filter(c => c.name == str); + + return results.length + ? results[0] + : undefined; + } + + isCmd(cmd) { + return typeof cmd == "object" && cmd instanceof Command; + } + + getArgsList(args) { + return [args]; + } + + parseMsg(msg, ctx) { + if (msg.author.bot) { + return; + } + this.log.debug(msg.content); + this.log.debug(msg.content.startsWith(this.prefix)); + this.log.debug(msg.content[0]); + this.log.debug(this.prefix); + if (msg.content.startsWith(this.prefix)) { + let snip = msg.content.slice(this.prefix.length); + let unsep = snip.split(" "); + let res = this.hasCmd(unsep[0]); + let args = this.getArgsList(unsep.slice(1).join(" ")); + this.log.debug(snip); + this.log.debug(res); + this.log.debug(args); + + if (res != undefined) { + this.log.debug(`execute function ${res.name}`); + res.func(msg, args, ctx); + } + } + } +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..d21f2f0 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,41 @@ +dependencies: + eris: 0.14.0 +lockfileVersion: 5.1 +packages: + /eris/0.14.0: + dependencies: + ws: 7.3.1 + dev: false + engines: + node: '>=8.0.0' + optionalDependencies: + opusscript: 0.0.7 + tweetnacl: 1.0.3 + resolution: + integrity: sha512-/W6X0SFR2swtA9oc4ga5Wh1TQcZtPgbUaDDdwYc67fvFUAtwC+V1xzWUZq2yDeJnTfB8Uot9SJWA8Lthe2sDtQ== + /opusscript/0.0.7: + dev: false + optional: true + resolution: + integrity: sha512-DcBadTdYTUuH9zQtepsLjQn4Ll6rs3dmeFvN+SD0ThPnxRBRm/WC1zXWPg+wgAJimB784gdZvUMA57gDP7FdVg== + /tweetnacl/1.0.3: + dev: false + optional: true + resolution: + integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== + /ws/7.3.1: + dev: false + engines: + node: '>=8.3.0' + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + resolution: + integrity: sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA== +specifiers: + eris: ^0.14.0 diff --git a/utils.js b/utils.js new file mode 100644 index 0000000..24fad97 --- /dev/null +++ b/utils.js @@ -0,0 +1,15 @@ +import path from "path"; +import {platform} from "process"; + +export function filename(url) { + let __filename = new URL(url).pathname; + return path.basename(__filename, ".js"); +} + +export function dirname(url) { + let __filename = new URL(url).pathname; + let __dirname = path.dirname(__filename); + return platform == "win32" + ? __dirname.slice(1) + : __dirname; +} \ No newline at end of file