From 5c9f2421c3c13a6161227d35ed35a401959d93ec Mon Sep 17 00:00:00 2001 From: Hri7566 Date: Wed, 7 Sep 2022 03:10:07 -0400 Subject: [PATCH] fix internal bot, log channel --- mpp.hri7566.info | 2 +- src/Channel.js | 89 ++++++++++++++++++++++++++++------ src/Client.js | 44 ++++++++++++++++- src/InternalBot/InternalBot.js | 30 ++++++++---- src/Logger.js | 30 ++++++++++-- 5 files changed, 163 insertions(+), 32 deletions(-) diff --git a/mpp.hri7566.info b/mpp.hri7566.info index 91ff834..b1dc90c 160000 --- a/mpp.hri7566.info +++ b/mpp.hri7566.info @@ -1 +1 @@ -Subproject commit 91ff8343d35176eb8bcfb4c51396871a7ddac5b6 +Subproject commit b1dc90c9b890b6c0d2446ebf5d6c419cb75336a6 diff --git a/src/Channel.js b/src/Channel.js index 89c00e0..b5fa347 100644 --- a/src/Channel.js +++ b/src/Channel.js @@ -10,8 +10,24 @@ const Color = require('./Color'); const { getTimeColor } = require('./ColorEncoder.js'); const { InternalBot } = require('./InternalBot'); +function ansiRegex({onlyFirst = false} = {}) { + const pattern = [ + '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)', + '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))' + ].join('|'); + + return new RegExp(pattern, onlyFirst ? undefined : 'g'); +} + +const LOGGER_PARTICIPANT = { + name: 'Logger', + color: '#72f1b8', + _id: 'logger', + id: 'logger' +} + class Channel extends EventEmitter { - constructor(server, _id, settings) { + constructor(server, _id, settings, cl) { super(); this.logger = new Logger(`Room - ${_id}`); this._id = _id; @@ -39,21 +55,53 @@ class Channel extends EventEmitter { this.logger.log('Created'); - Database.getRoomSettings(this._id, (err, set) => { - if (err) { - return; - } + if (this._id == 'supersecretsettings') { + if (cl.user.hasFlag('admin')) { + delete this.crown; - this.settings = RoomSettings.changeSettings(this.settings, true); - this.chatmsgs = set.chat; - this.connections.forEach(cl => { - cl.sendArray([{ - m: 'c', - c: this.chatmsgs.slice(-1 * 32) - }]); + Logger.buffer.forEach(str => { + this.chatmsgs.push({ + m: 'a', + p: LOGGER_PARTICIPANT, + a: str.replace(ansiRegex(), '') + }); + }); + + Logger.on('buffer update', (str) => { + this.chatmsgs.push({ + m: 'a', + p: LOGGER_PARTICIPANT, + a: str.replace(ansiRegex(), '') + }); + + this.sendChatArray(); + }); + + this.emit('update'); + let c = new Color(LOGGER_PARTICIPANT.color); + c.add(-0x40, -0x40, -0x40); + this.settings = RoomSettings.changeSettings({ + color: c.toHexa(), + chat: true, + crownsolo: true, + lobby: false, + owner_id: LOGGER_PARTICIPANT._id + }, true); + } else { + cl.setChannel('test/awkward'); + } + } else { + Database.getRoomSettings(this._id, (err, set) => { + if (err) { + return; + } + + this.settings = RoomSettings.changeSettings(this.settings, true); + this.chatmsgs = set.chat; + this.sendChatArray(); + this.setData(); }); - this.setData(); - }); + } if (this.isLobby(this._id)) { this.colorInterval = setInterval(() => { @@ -72,6 +120,15 @@ class Channel extends EventEmitter { this.setData(); } + sendChatArray() { + this.connections.forEach(cl => { + cl.sendArray([{ + m: 'c', + c: this.chatmsgs.slice(-1 * 32) + }]); + }); + } + setDefaultLobbyColorBasedOnDate() { let col = getTimeColor(); let col2 = new Color(col.r - 0x40, col.g - 0x40, col.b - 0x40); @@ -103,7 +160,7 @@ class Channel extends EventEmitter { cl.initParticipantQuotas(); // no users / already had crown? give crown - if (((this.connections.length == 0 && Array.from(this.ppl.values()).length == 0) && this.isLobby(this._id) == false) || this.crown && (this.crown.userId == cl.user._id)) { + if (((this.connections.length == 0 && Array.from(this.ppl.values()).length == 0) && this.isLobby(this._id) == false) || this.crown && (this.crown.userId == cl.user._id || this.settings['owner_id'] == cl.user._id)) { // user owns the room // we need to switch the crown to them //cl.quotas.a.setParams(Quota.PARAMS_A_CROWNED); @@ -278,7 +335,7 @@ class Channel extends EventEmitter { if (this._id == "lobby") return; this.destroyed = true; this._id; - console.log(`Deleted room ${this._id}`); + this.logger.log(`Deleted room ${this._id}`); this.settings = undefined; this.ppl; this.connnections; diff --git a/src/Client.js b/src/Client.js index 1ea9371..2d4fe47 100644 --- a/src/Client.js +++ b/src/Client.js @@ -7,6 +7,12 @@ const Database = require("./Database.js"); const { EventEmitter } = require('events'); class Client extends EventEmitter { + /** + * Server-side client representation + * @param {*} ws WebSocket object + * @param {*} req WebSocket request + * @param {*} server Server + */ constructor(ws, req, server) { super(); EventEmitter.call(this); @@ -35,14 +41,28 @@ class Client extends EventEmitter { }); } + /** + * Check if user is connected + * @returns boolean + */ isConnected() { return this.ws && this.ws.readyState === WebSocket.OPEN; } + /** + * Check if user is connecting + * @returns boolean + */ isConnecting() { return this.ws && this.ws.readyState === WebSocket.CONNECTING; } + /** + * Move user to channel + * @param {string} _id User ID + * @param {*} settings Settings object + * @returns undefined + */ setChannel(_id, settings) { if (this.channel && this.channel._id == _id) return; if (this.server.rooms.get(_id)) { @@ -74,7 +94,7 @@ class Client extends EventEmitter { this.channel = this.server.rooms.get(_id); this.channel.join(this); } else { - let room = new Channel(this.server, _id, settings); + let room = new Channel(this.server, _id, settings, this); this.server.rooms.set(_id, room); if (this.channel) this.channel.emit("bye", this); this.channel = this.server.rooms.get(_id); @@ -82,6 +102,10 @@ class Client extends EventEmitter { } } + /** + * Send data to client + * @param {any[]} arr Array of messages + */ sendArray(arr) { if (this.isConnected()) { //console.log(`SEND: `, JSON.colorStringify(arr)); @@ -89,6 +113,12 @@ class Client extends EventEmitter { } } + /** + * Set username in database + * @param {string} name Username + * @param {boolean} admin Is admin? + * @returns undefined + */ userset(name, admin) { if (name.length > 40 && !admin) return; if (!this.quotas.userset.attempt()) return; @@ -106,6 +136,9 @@ class Client extends EventEmitter { }); } + /** + * Set rate limits + */ initParticipantQuotas() { this.quotas = { //"chat": new Quota(Quota.PARAMS_A_NORMAL), @@ -125,6 +158,9 @@ class Client extends EventEmitter { } } + /** + * Stop the client + */ destroy() { this.user.stopFlagEvents(); this.ws.close(); @@ -140,6 +176,9 @@ class Client extends EventEmitter { this.destroied = true; } + /** + * Internal + */ bindEventListeners() { this.ws.on("message", (evt, admin) => { try { @@ -170,6 +209,9 @@ class Client extends EventEmitter { }); } + /** + * Send admin data bus message + */ sendAdminData() { let data = {}; data.m = "data"; diff --git a/src/InternalBot/InternalBot.js b/src/InternalBot/InternalBot.js index e0de30f..21f1290 100644 --- a/src/InternalBot/InternalBot.js +++ b/src/InternalBot/InternalBot.js @@ -1,5 +1,6 @@ const { EventEmitter } = require('events'); const { Command } = require('./Command'); +const Color = require('../Color'); class InternalBot { static on = EventEmitter.prototype.on; @@ -26,15 +27,18 @@ class InternalBot { } let args = msg.a.split(' '); - let cmd = args[0].toLowerCase(); + let cmd = args[0].toLowerCase().substring(this.prefix.length); let argcat = msg.a.substring(args[0].length).trim(); + let p = cl; + + if (!args[0].startsWith(this.prefix)) return; switch (cmd) { - case "!ping": - ch.adminChat("pong"); + case "ping": + ch.adminChat('pong'); break; - case "!setcolor": - case "!color": + case "setcolor": + case "color": if (!isAdmin) { ch.adminChat("You do not have permission to use this command."); return; @@ -65,10 +69,10 @@ class InternalBot { } ch.updateCh(); break; - case "!users": + case "users": ch.adminChat(`There are ${ch.server.connections.size} users online.`); break; - case "!chown": + case "chown": if (!isAdmin) return; let id = p.participantId; if (args[1]) { @@ -78,14 +82,22 @@ class InternalBot { ch.chown(id); } break; - case "!chlist": - case "!channellist": + case "chlist": + case "channellist": if (!isAdmin) return; ch.adminChat("Channels:"); for (let [_id] of ch.server.rooms) { ch.adminChat(`- ${_id}`); } break; + case "restart": + if (!isAdmin) return; + cl.server.restart(); + break; + case "eval": + if (!isAdmin) return; + cl.server.eval(argcat); + break; } }); } diff --git a/src/Logger.js b/src/Logger.js index 5962c1c..c8e88f2 100644 --- a/src/Logger.js +++ b/src/Logger.js @@ -1,28 +1,48 @@ const chalk = require('chalk'); +const { EventEmitter } = require('events'); class Logger { + static buffer = []; + + static on = EventEmitter.prototype.on; + static off = EventEmitter.prototype.off; + static once = EventEmitter.prototype.once; + static emit = EventEmitter.prototype.emit; + constructor (context) { this.context = context; } log(args) { - console.log(chalk.green(`[`) + chalk.green(`${this.context}`) + chalk.green(`]`), args); + let str = chalk.green(`[`) + chalk.green(`${this.context}`) + chalk.green(`]`) + ' ' + args + console.log(str); + this.buffer(str); } warn(args) { - console.warn(chalk.yellow(`[WARN] [`) + chalk.yellow(`${this.context}`) + chalk.yellow(`]`), args); + let str = chalk.yellow(`[WARN] [`) + chalk.yellow(`${this.context}`) + chalk.yellow(`]`) + ' ' + args; + console.warn(str); + this.buffer(str); } error(args) { - console.error(chalk.red(`[ERR] [`) + chalk.red(`${this.context}`) + chalk.red(`]`), args); + let str = chalk.red(`[ERR] [`) + chalk.red(`${this.context}`) + chalk.red(`]`) + ' ' + args; + console.error(str); + this.buffer(str); } debug(args) { if (process.env.DEBUG_ENABLED) { - console.log(chalk.blue(`[DEBUG] [`) + chalk.blue(`${this.context}`) + chalk.blue(`]`), args); + let str = chalk.blue(`[DEBUG] [`) + chalk.blue(`${this.context}`) + chalk.blue(`]`) + ' ' + args; + console.debug(str); + this.buffer(str); } } + + buffer(str) { + Logger.buffer.push(str); + Logger.emit('buffer update', str); + } } module.exports = Logger; -