From 6c7bbc23047365c1e588666db2d463369418b2a0 Mon Sep 17 00:00:00 2001 From: Jane Petrovna Date: Sat, 7 Nov 2020 22:29:13 -0500 Subject: [PATCH] light command --- bot.js | 95 +++++++++++----------- cmd/lights.js | 48 ++++++++---- cmd/reg.js | 18 +++-- lights/light_parser.js | 160 ++++++++++++++++++++++++++++--------- lights/request.js | 18 +++++ logger.js | 97 +++++++++++------------ parser.js | 174 +++++++++++++++++++++++------------------ 7 files changed, 378 insertions(+), 232 deletions(-) create mode 100644 lights/request.js diff --git a/bot.js b/bot.js index ae22e0b..07177cf 100644 --- a/bot.js +++ b/bot.js @@ -1,72 +1,73 @@ -import {createRequire} from "module"; +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"; +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 cfg = require('./config.json'); const dir = dirname(import.meta.url); const bot = new Eris(cfg.token); const ctx = { - bot: bot, - log_level: levels.DEBUG + bot: bot, + log_level: levels.DEBUG, + whitelist: cfg.user_whitelist || [] }; 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(); - } +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('ready', () => { + log.info('ready recieved.'); + bot.guilds.forEach((guild) => checkGuild(guild)); }); -bot.on("guildAvaliable", guild => checkGuild(guild)); +bot.on('guildAvaliable', (guild) => checkGuild(guild)); -bot.on("messageCreate", msg => parse.parseMsg(msg, ctx)); +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."); - } - } + 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"); +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 index 97555bc..d3a3d80 100644 --- a/cmd/lights.js +++ b/cmd/lights.js @@ -1,24 +1,40 @@ -import {CommandInitializer, Command} from "../parser.js"; -import parse, {instructions} from "../lights/light_parser.js"; +import { CommandInitializer, Command } from '../parser.js'; +import parse, { initialize, instructions } from '../lights/light_parser.js'; +import req from '../lights/request.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]); + init(ctx, log) { + this.log = log; + initialize(ctx); + } + name = 'lights'; + whitelist = true; + func(msg, args, ctx) { + if (!args.length) { + msg.channel.createMessage('no args found.'); + return; + } + 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}`); - } + this.log.debug(instructions); + let res = '```\n'; + instructions.forEach((instruction) => { + res += JSON.stringify(instruction) + '\n'; + }); + res += '```'; + msg.channel.createMessage(`parsed instructions:\n${res}`); + req( + instructions.filter((i) => i.valid), + (response) => { + msg.channel.createMessage(`${response.statusCode}`); + }, + (error) => { + msg.channel.createMessage(`error.`); + } + ); + } } initializer.addCommand(new LightsParser()); diff --git a/cmd/reg.js b/cmd/reg.js index bfd243c..dfa5480 100644 --- a/cmd/reg.js +++ b/cmd/reg.js @@ -1,14 +1,18 @@ -import {CommandInitializer, Command} from "../parser.js"; +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}`); - }); - } + 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()); diff --git a/lights/light_parser.js b/lights/light_parser.js index fade3e7..f0e94bd 100644 --- a/lights/light_parser.js +++ b/lights/light_parser.js @@ -1,49 +1,137 @@ +import Logger, { levels } from '../logger.js'; +import { filename } from '../utils.js'; + +const log = new Logger(filename(import.meta.url), levels.PANIC); + class Target { - constructor(channel) { - this.channel = channel; - } - channel; - value; + constructor(channel) { + this.channel = channel; + } + channel; + value; } const available_targets = { - r: new Target("r"), - g: new Target("g"), - b: new Target("b") + r: new Target('r'), + g: new Target('g'), + b: new Target('b'), + stack: new Target('stack'), }; 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); - }); - } + constructor(name, targets, 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.name = name; + this.targets = valid_targets; + this.args = args; + } + name; + targets; + args; } -class ConstantColor extends Instruction { - name = "CONSTANT"; - transform(index, time, channel_target) {} +export const instructions = [ + { n: 'CONSTANT', a: true }, + { n: 'ADD', a: true }, + { n: 'SUB', a: true }, + { n: 'RAND', a: false }, +]; + +export function initialize(ctx) { + log.s(ctx.log_level); +} + +function parseSingleInstruction(str = '') { + let item = { + valid: false, + instruction: undefined, + errors: undefined, + }; + let split = str.split(' '); + let cmd = split[0]; + let match = instructions.filter((i) => i.n == cmd.toUpperCase()); + split = split.slice(1); + if (match.length) { + let inst_targets = []; + let inst_args = []; + let parsed_args = []; + let join_index = -1; + let add = true; + for (let index in split) { + if (split[index].startsWith('[')) { + join_index = index; + add = false; + } + if (add) { + parsed_args.push(split[index]); + } + if (split[index].endsWith(']') && join_index != -1) { + let joined = split + .slice(join_index, index + 1) + .join(' ') + .replace(/[\[\]]/g, ''); + parsed_args.push(joined); + add = true; + join_index = -1; + } + } + inst_targets = parsed_args[0] + .split(',') + .map((s) => s.trim()) + .map((t) => new Target(t)); + + if (!inst_targets.length) { + item.errors = 'No valid targets.'; + } + inst_targets.forEach((t) => { + let match = Object.keys(available_targets).find((key) => available_targets[key].channel === t.channel); + if (!match) { + item.errors = `Invalid target: ${t.channel}`; + } + }); + if (match[0].a) { + if (parsed_args.length < 2) { + item.errors = 'Not enough arguments.'; + return item; + } + inst_args = parsed_args[1].split(',').map((s) => (s == 'stack' ? 'stack' : parseInt(s.trim()))); + if (!inst_args.length) { + item.errors = 'No valid args.'; + } + inst_args.forEach((arg) => { + if (!arg) { + item.errors = 'An argument is null or undefined.'; + } + }); + } + if (item.errors) { + return item; + } + + item.instruction = new Instruction(match[0].n, inst_targets, inst_args || []); + } else { + item.errors = 'No command matched.'; + return item; + } + item.valid = true; + return item; } -export const instructions = [ConstantColor]; export default function parse(str) { - return [{}]; + let parsed = []; + let split = str.split('\n'); + split.forEach((item) => { + let parsedItem = parseSingleInstruction(item); + parsed.push(parsedItem); + log.debug(item); + }); + return parsed; } diff --git a/lights/request.js b/lights/request.js new file mode 100644 index 0000000..d019727 --- /dev/null +++ b/lights/request.js @@ -0,0 +1,18 @@ +import * as https from 'https'; + +const options = { + hostname: '192.168.1.219', + port: '29999', + path: '/', + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, +}; + +export default function req(data, callback, errorCallback) { + const request = https.request(options, (res) => callback(res)); + request.on('error', (error) => errorCallback(error)); + request.write(JSON.stringify(data)); + request.end(); +} diff --git a/logger.js b/logger.js index 7a71e0c..595b224 100644 --- a/logger.js +++ b/logger.js @@ -1,54 +1,51 @@ -export const levels = { - DEBUG: 4, - INFO: 3, - WARN: 2, - ERROR: 1, - PANIC: 0 - } +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]; - } - } + 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}`); - } - } + 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 + 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); + } +} diff --git a/parser.js b/parser.js index d50a926..eaa4c59 100644 --- a/parser.js +++ b/parser.js @@ -1,95 +1,117 @@ -import Logger, {levels} from "./logger.js"; -import {filename} from "./utils.js"; +import Logger, { levels } from './logger.js'; +import { filename } from './utils.js'; export class Command { - init(ctx, log) { - this.log = log; - } - log; - name = "DEFAULT"; - func() {} + init(ctx, log) { + this.log = log; + } + log; + name = 'DEFAULT'; + whitelist = false; + func() {} } export class CommandInitializer { - commands = []; - uninitialized = []; + commands = []; + uninitialized = []; - initialize(ctx) { - for (let index in this.uninitialized) { - this.initCommand(this.uninitialized[index], ctx); - delete this.uninitialized[index]; - } - } + 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); - } + initCommand(cmd, ctx) { + cmd.init(ctx, new Logger(`cmd.${cmd.name}`, ctx.log_level)); + this.commands.push(cmd); + } - addCommand(cmd) { - this.uninitialized.push(cmd); - } + addCommand(cmd) { + this.uninitialized.push(cmd); + } - getCommands() { - return this.commands; - } + 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 = []; + 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); - } - } + 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); + hasCmd(str) { + let results = this.commands.filter((c) => c.name == str); - return results.length - ? results[0] - : undefined; - } + return results.length ? results[0] : undefined; + } - isCmd(cmd) { - return typeof cmd == "object" && cmd instanceof Command; - } + isCmd(cmd) { + return typeof cmd == 'object' && cmd instanceof Command; + } - getArgsList(args) { - return [args]; - } + getArgsList(split) { + let parsed_args = []; + let join_index = -1; + let add = true; + for (let index in split) { + if (split[index].startsWith('```')) { + join_index = index; + add = false; + } + if (add) { + parsed_args.push(split[index]); + } + if (split[index].endsWith('```') && join_index != -1) { + let joined = split + .slice(join_index, index + 1) + .join(' ') + .replace(/```/g, ''); + parsed_args.push(joined); + add = true; + join_index = -1; + } + } + return parsed_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); + 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)); + 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 + if (res != undefined) { + this.log.debug(`execute function ${res.name}`); + if (res.whitelist && ctx.whitelist.indexOf(msg.author.id) == -1) { + msg.channel.createMessage('not whitelisted'); + } else { + res.func(msg, args, ctx); + } + } + } + } +}