initial commit; add events system

master
Jane Petrovna 2 years ago
parent 2e7834b17e
commit fc1f05ae0c
  1. 112
      bot.js
  2. 94
      cmd/perm.js
  3. 52
      cmd/reg.js
  4. 7
      config.json
  5. 56
      logger.js
  6. 19
      package.json
  7. 133
      parser.js
  8. 41
      pnpm-lock.yaml
  9. 2
      start.sh
  10. 15
      utils.js
  11. 1
      whitelist.json

112
bot.js

@ -0,0 +1,112 @@
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');
if (!fs.existsSync('./whitelist.json')) {
fs.writeFileSync('./whitelist.json', '{}');
}
const whitelist = require('./whitelist.json');
const dir = dirname(import.meta.url);
const bot = new Eris(cfg.token);
global.ctx = {
bot: bot,
log_level: levels[cfg.log_level.toUpperCase()] || levels.WARN,
set_ctx: (key, value) => {
global.ctx[key] = value;
},
};
const log = new Logger(filename(import.meta.url), global.ctx.log_level);
const parse = new CommandParser(global.ctx, cfg.prefix || undefined);
const checkUser = (user) => {
if (cfg.user_whitelist.includes(user.id) || (whitelist.user && whitelist.user.includes(user.id))) {
return true;
}
log.info(`user not on whitelist: ${user.username}`);
return false;
};
const checkGuild = (guild) => {
if (cfg.whitelist.includes(guild.id) || (whitelist.guild && whitelist.guild.includes(guild.id))) {
return true;
}
log.info(`guild not on whitelist: ${guild.name}`);
return false;
};
const saveWhitelist = () => {
let data = JSON.stringify(whitelist);
fs.writeFileSync('./whitelist.json', data);
};
global.ctx.whitelist = {
guild: checkGuild,
user: checkUser,
save: saveWhitelist,
wl: whitelist,
};
const listeners = {}
bot.on('ready', () => {
log.info('ready recieved.');
bot.guilds.forEach((guild) => checkGuild(guild));
});
bot.on('messageCreate', (msg) => parse.parseMsg(msg, global.ctx));
bot.on('error', (err) => log.error(err.toString()));
bot.connect();
async function load_commands() {
for (let file of files) {
let p = path.join(cmd_dir, file);
log.debug('loading ' + p);
let obj;
try {
obj = await import('file:////' + p);
} catch (e) {
log.warn(`loading file ${file}, ran into issue: ${e.stack}`);
continue;
}
if (obj.default != undefined) {
if (obj.default.constructor.name == 'CommandInitializer') {
obj.default.initialize(global.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);
}
}
let events = obj.default.getEvents();
if (events != undefined) {
for (let event in events) {
if (!listeners[event]) {
listeners[event] = []
}
listeners[event].push(events[event])
}
}
}
} else {
log.warn('module ' + file + ' returned an undefined module.');
}
}
}
let cmd_dir = path.join(dir, 'cmd');
log.trace(dir);
let files = fs.readdirSync(cmd_dir);
load_commands();

@ -0,0 +1,94 @@
import { CommandInitializer, Command } from '../parser.js';
const initializer = new CommandInitializer();
class WhitelistUser extends Command {
name = 'wu';
whitelist = true;
func = async function (msg, args, ctx) {
let user = await ctx.bot.users.get(args[0].trim());
this.log.debug(msg.channel.guild.members);
this.log.debug(user);
if (!user) {
user = msg.channel.guild.members.get(args[0].trim());
this.log.debug(user);
if (!user) {
user = (await msg.channel.guild.fetchMembers({ userIDs: [args[0]] }))[0];
this.log.debug(user);
}
}
if (user.username) {
if (!ctx.whitelist.wl) {
ctx.whitelist.wl = {
user: [],
guild: [],
};
}
let list = ctx.whitelist.wl.user || [];
if (!list.includes(args[0])) {
list.push(args[0]);
ctx.whitelist.wl.user = list;
ctx.whitelist.save();
msg.channel.createMessage(`added user "${user.username}#${user.discriminator}" (${args[0]}) to whitelist`);
} else {
msg.channel.createMessage('user already whitelisted');
}
} else {
msg.channel.createMessage(`user with id ${args[0]} could not be found`);
}
};
}
initializer.addCommand(new WhitelistUser());
class WhitelistGuild extends Command {
name = 'wg';
whitelist = true;
func = async function (msg, args, ctx) {
let guild = await ctx.bot.guilds.get(args[0]);
if (guild && guild.name) {
if (!ctx.whitelist.wl) {
ctx.whitelist.wl = {
user: [],
guild: [],
};
}
let list = ctx.whitelist.wl.guild || [];
if (!list.includes(args[0])) {
list.push(args[0]);
ctx.whitelist.wl.guild = list;
ctx.whitelist.save();
msg.channel.createMessage(`added guild "${guild.name}" (${args[0]}) to whitelist`);
} else {
msg.channel.createMessage('guild already whitelisted');
}
} else {
msg.channel.createMessage(`guild with id ${args[0]} could not be found`);
}
};
}
initializer.addCommand(new WhitelistGuild());
class Purge extends Command {
name = 'purge';
whitelist = true;
func = async function (msg, args, ctx) {
let guilds = await ctx.bot.guilds;
let whitelist = ctx.whitelist.guild;
let purged = 0;
guilds.forEach((guild) => {
if (!whitelist(guild)) {
this.log.info(`purging guild ${guild.name} (${guild.id})`);
guild.leave();
purged++;
} else {
this.log.debug(`keeping guild ${guild.name} (${guild.id})`);
}
});
msg.channel.createMessage(`purged ${purged} guilds.`);
};
}
initializer.addCommand(new Purge());
export default initializer;

@ -0,0 +1,52 @@
import { CommandInitializer, Command } from '../parser.js';
import Logger, { levels } from '../logger.js';
import { filename } from '../utils.js';
const initializer = new CommandInitializer();
const log = new Logger(filename(import.meta.url), global.ctx.log_level);
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());
class RestartCommand extends Command {
name = 'restart';
func(msg, args, ctx) {
msg.channel.createMessage('restarting.').then(() => {
process.exit();
});
}
}
initializer.addCommand(new RestartCommand());
class EvalCommand extends Command {
name = 'eval';
whitelist = true;
func(msg, args, ctx) {
log.debug('evaluating ' + args[0]);
let result = eval(args[0]);
log.debug('result is: \n' + result);
if (result.length <= 1999) {
msg.channel.createMessage(result);
}
else {
msg.channel.createMessage("result too long, see logs");
}
}
}
initializer.addCommand(new EvalCommand());
export default initializer;

@ -0,0 +1,7 @@
{
"token": "MjY3Mzg2MTUyMzIxOTQxNTA1.WHFMwg.KgEUojOa43UL43yqUy9-TKz05tY",
"log_level": "DEBUG",
"prefix": "p.",
"whitelist": ["656579275008245830"],
"user_whitelist": ["123601647258697730"]
}

@ -0,0 +1,56 @@
export const levels = {
TRACE: 5,
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}`);
}
}
trace(msg) {
this.lo(levels.TRACE, msg);
}
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);
}
}

@ -0,0 +1,19 @@
{
"type": "module",
"name": "pinbot",
"version": "1.0.0",
"description": "a bot to manage pins (and also other stuff!)",
"main": "bot.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git@ssh.gitdab.com:jane/pinbot.git"
},
"author": "jane petrovna (jane@j4.pm)",
"license": "SEE LICENSE IN LICENSE",
"dependencies": {
"eris": "^0.15.0"
}
}

@ -0,0 +1,133 @@
import Logger, { levels } from './logger.js';
import { filename } from './utils.js';
export class Command {
init(ctx, log) {
this.log = log;
}
log;
name = 'DEFAULT';
whitelist = false;
func() {}
}
export class CommandInitializer {
commands = [];
uninitialized = [];
events = {};
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);
}
addEvent(event, func) {
if (!events[event]) {
events[event] = [];
}
events[event].push(func);
}
getCommands() {
return this.commands;
}
getEvents() {
return this.events;
}
}
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.trace(`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(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;
}
if (msg.channel.guild && !ctx.whitelist.guild(msg.channel.guild)) {
msg.channel.createMessage('guild not whitelisted');
return;
}
this.log.trace(msg.content);
this.log.trace(msg.content.startsWith(this.prefix));
this.log.trace(msg.content[0]);
this.log.trace(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.trace(snip);
this.log.trace(res);
this.log.trace(args);
if (res != undefined) {
this.log.debug(`execute function ${res.name}`);
if (res.whitelist && !ctx.whitelist.user(msg.author)) {
msg.channel.createMessage('not whitelisted');
} else {
res.func(msg, args, ctx);
}
}
}
}
}

@ -0,0 +1,41 @@
dependencies:
eris: 0.15.0
lockfileVersion: 5.2
packages:
/eris/0.15.0:
dependencies:
ws: 7.4.4
dev: false
engines:
node: '>=10.4.0'
optionalDependencies:
opusscript: 0.0.8
tweetnacl: 1.0.3
resolution:
integrity: sha512-muBdi5XyMXdxFQ8xUG6yofq40/Z02CHlqJP7zIdHhpdDiHvFM/mybGiFAHuoSYcsVTTvEfbUaAJ+SDEmMjARYw==
/opusscript/0.0.8:
dev: false
optional: true
resolution:
integrity: sha512-VSTi1aWFuCkRCVq+tx/BQ5q9fMnQ9pVZ3JU4UHKqTkf0ED3fKEPdr+gKAAl3IA2hj9rrP6iyq3hlcJq3HELtNQ==
/tweetnacl/1.0.3:
dev: false
optional: true
resolution:
integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==
/ws/7.4.4:
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-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==
specifiers:
eris: ^0.15.0

@ -0,0 +1,2 @@
git pull
pnpm start

@ -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;
}

@ -0,0 +1 @@
{"guild":["656579275008245830","823796249832194088"],"user":["123601647258697730"]}
Loading…
Cancel
Save