From aef1e208a44397ab77c308c85bc75974ee150d7e Mon Sep 17 00:00:00 2001 From: Hri7566 Date: Fri, 27 Oct 2023 14:53:14 -0400 Subject: [PATCH] Cursor user data commands logger update --- src/commands/CommandHandler.ts | 54 ++++++- src/commands/commands/general/about.ts | 4 +- src/commands/commands/general/help.ts | 39 ++++- src/commands/commands/utility/id.ts | 14 ++ src/commands/commands/utility/math.ts | 2 +- src/commands/commands/utility/memory.ts | 17 ++ src/commands/commands/utility/msg.ts | 14 ++ src/commands/index.ts | 12 +- src/data/inventory.ts | 26 ++++ src/data/prisma.ts | 3 + src/data/user.ts | 18 +++ src/services/ServiceAgent.ts | 2 +- src/services/index.ts | 49 +++++- src/services/mpp/Cursor.ts | 196 ++++++++++++++++++++++++ src/services/mpp/index.ts | 115 ++++++++++---- src/services/switchchat/index.ts | 24 ++- src/util/Logger.ts | 65 ++++++++ 17 files changed, 598 insertions(+), 56 deletions(-) create mode 100644 src/commands/commands/utility/id.ts create mode 100644 src/commands/commands/utility/msg.ts create mode 100644 src/data/inventory.ts create mode 100644 src/data/prisma.ts create mode 100644 src/data/user.ts create mode 100644 src/services/mpp/Cursor.ts create mode 100644 src/util/Logger.ts diff --git a/src/commands/CommandHandler.ts b/src/commands/CommandHandler.ts index 5d05ced..fa39e22 100644 --- a/src/commands/CommandHandler.ts +++ b/src/commands/CommandHandler.ts @@ -1,16 +1,32 @@ +import { Inventory, User } from "@prisma/client"; +import { createUser, readUser } from "../data/user"; import { ServiceAgent } from "../services/ServiceAgent"; import { Command } from "./Command"; import { CommandGroup } from "./CommandGroup"; import { Prefix } from "./Prefix"; +import { createInventory, readInventory } from "../data/inventory"; export interface CommandMessage { m: "command"; a: string; argv: string[]; argc: number; + p: { + _id: string; + platformId: string; + name: string; + color: string; + }; originalMessage: T; + user: NonNullable; + inventory: NonNullable; } +export type BaseCommandMessage = Omit< + CommandMessage, + "user" | "inventory" +>; + export class CommandHandler { public static commandGroups = new Array(); public static prefixes = new Array( @@ -29,9 +45,39 @@ export class CommandHandler { } public static async handleCommand( - msg: CommandMessage, + msg: Omit, agent: ServiceAgent ) { + // Get user data + let user = await readUser(msg.p._id); + + if (!user) { + await createUser({ + id: msg.p._id, + platform: agent.platform, + platformId: msg.p.platformId, + name: msg.p.name + }); + + user = await readUser(msg.p._id); + if (!user) + return "Somehow, something has gone terribly wrong and I can't create user data for you. I can't run your command now."; + } + + // Get inventory data + let inventory = await readInventory(msg.p._id); + + if (!inventory) { + await createInventory({ + userId: msg.p._id, + items: [] + }); + + inventory = await readInventory(msg.p._id); + if (!inventory) + return "You have no inventory and I have been told I can't give you one. Sorry, your command won't work without it."; + } + let usedPrefix: Prefix | undefined; for (const prefix of this.prefixes) { @@ -40,6 +86,7 @@ export class CommandHandler { if (prefix.spaced) { msg.argv.splice(0, 1); + msg.argc--; } break; @@ -67,8 +114,11 @@ export class CommandHandler { if (!usedCommand) return; + (msg as CommandMessage).user = user; + (msg as CommandMessage).inventory = inventory; + try { - const out = usedCommand.callback(msg, agent); + const out = usedCommand.callback(msg as CommandMessage, agent); if (out) return out; } catch (err) { console.error(err); diff --git a/src/commands/commands/general/about.ts b/src/commands/commands/general/about.ts index 6e9a93f..f24be00 100644 --- a/src/commands/commands/general/about.ts +++ b/src/commands/commands/general/about.ts @@ -1,10 +1,10 @@ import { Command } from "../../Command"; -export const help = new Command( +export const about = new Command( "about", ["about", "info"], "get about bozo", - "{prefix}about", + "about", (msg, agent) => { return `This is a dumb chat bot`; } diff --git a/src/commands/commands/general/help.ts b/src/commands/commands/general/help.ts index 0202d82..4a69bc2 100644 --- a/src/commands/commands/general/help.ts +++ b/src/commands/commands/general/help.ts @@ -1,11 +1,46 @@ import { Command } from "../../Command"; +import { CommandHandler } from "../../CommandHandler"; export const help = new Command( "help", ["help", "h", "commands", "cmds"], "get help bozo", - "{prefix}help", + "help [command]", (msg, agent) => { - return "test"; + if (msg.argv[1]) { + // Get command usage + let command: Command | undefined; + + commandGroupLoop: for (const commandGroup of CommandHandler.commandGroups) { + commandLoop: for (const cmd of commandGroup.commands) { + if (cmd.aliases.includes(msg.argv[1])) { + command = cmd; + break commandGroupLoop; + } + } + } + if (!command) return `Command "${msg.argv[1]}" not found.`; + + return `🌟 Description: ${command.description} | πŸ›  Usage: ${command.usage}`; + } else { + // Just list commands + const list = CommandHandler.commandGroups.map(commandGroup => { + return ( + commandGroup.displayName + + ": " + + commandGroup.commands + .map(command => { + if (!command.visible) return; + return command.aliases[0]; + }) + .filter(val => { + return typeof val !== "undefined"; + }) + .join(" | ") + ); + }); + + return list.join("\n"); + } } ); diff --git a/src/commands/commands/utility/id.ts b/src/commands/commands/utility/id.ts new file mode 100644 index 0000000..1a2a087 --- /dev/null +++ b/src/commands/commands/utility/id.ts @@ -0,0 +1,14 @@ +import { MPPAgent } from "../../../services/mpp"; +import { Command } from "../../Command"; + +export const id = new Command( + "id", + ["id"], + "get your id bozo", + "id", + (msg, agent) => { + if (!(agent as MPPAgent).client.isConnected) return; + return `ID: \`${(msg.originalMessage as any).p._id}\``; + }, + false +); diff --git a/src/commands/commands/utility/math.ts b/src/commands/commands/utility/math.ts index 4f44ab8..f0d7ff5 100644 --- a/src/commands/commands/utility/math.ts +++ b/src/commands/commands/utility/math.ts @@ -6,7 +6,7 @@ export const math = new Command( "math", ["math"], "math bozo", - "{prefix}math", + "math ", (msg, agent) => { try { const argcat = msg.argv.slice(1, msg.argv.length).join(" "); diff --git a/src/commands/commands/utility/memory.ts b/src/commands/commands/utility/memory.ts index e69de29..94a09b9 100644 --- a/src/commands/commands/utility/memory.ts +++ b/src/commands/commands/utility/memory.ts @@ -0,0 +1,17 @@ +import { MPPAgent } from "../../../services/mpp"; +import { Command } from "../../Command"; + +export const memory = new Command( + "memory", + ["memory", "mem"], + "get the memory bozo", + "memory", + (msg, agent) => { + return `${(process.memoryUsage().heapUsed / 1000 / 1000).toFixed( + 2 + )} MB / ${(process.memoryUsage().heapTotal / 1000 / 1000).toFixed( + 2 + )} MB`; + }, + false +); diff --git a/src/commands/commands/utility/msg.ts b/src/commands/commands/utility/msg.ts new file mode 100644 index 0000000..0eaecca --- /dev/null +++ b/src/commands/commands/utility/msg.ts @@ -0,0 +1,14 @@ +import { MPPAgent } from "../../../services/mpp"; +import { Command } from "../../Command"; + +export const msg = new Command( + "msg", + ["msg"], + "get your msg bozo", + "msg", + (msg, agent) => { + if (!(agent as MPPAgent).client.isConnected) return; + return `${JSON.stringify(msg)}`; + }, + false +); diff --git a/src/commands/index.ts b/src/commands/index.ts index 902d0fc..9c2b671 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -1,14 +1,18 @@ import { CommandGroup } from "./CommandGroup"; import { CommandHandler } from "./CommandHandler"; +import { about } from "./commands/general/about"; import { help } from "./commands/general/help"; +import { id } from "./commands/utility/id"; +import { msg } from "./commands/utility/msg"; import { math } from "./commands/utility/math"; +import { memory } from "./commands/utility/memory"; export function loadCommands() { - const general = new CommandGroup("general", "General"); - general.addCommands([help]); + const general = new CommandGroup("general", "⭐ General"); + general.addCommands([help, about]); CommandHandler.addCommandGroup(general); - const utility = new CommandGroup("utility", "Utility"); - utility.addCommands([math]); + const utility = new CommandGroup("utility", "πŸ”¨ Utility"); + utility.addCommands([math, memory, id, msg]); CommandHandler.addCommandGroup(utility); } diff --git a/src/data/inventory.ts b/src/data/inventory.ts new file mode 100644 index 0000000..0996388 --- /dev/null +++ b/src/data/inventory.ts @@ -0,0 +1,26 @@ +import { Inventory, Prisma, User } from "@prisma/client"; +import { prisma } from "./prisma"; + +export async function createInventory(data: Omit) { + await prisma.inventory.create({ + data: { + userId: data.userId, + items: data.items as any[] + } + }); +} + +export async function readInventory(userId: Inventory["userId"]) { + return await prisma.inventory.findUnique({ where: { userId: userId } }); +} + +export async function updateInventory(data: Omit) { + return await prisma.inventory.update({ + where: { userId: data.userId }, + data: {} + }); +} + +export async function deleteInventory(userId: Inventory["userId"]) { + return await prisma.inventory.delete({ where: { userId } }); +} diff --git a/src/data/prisma.ts b/src/data/prisma.ts new file mode 100644 index 0000000..901f3a0 --- /dev/null +++ b/src/data/prisma.ts @@ -0,0 +1,3 @@ +import { PrismaClient } from "@prisma/client"; + +export const prisma = new PrismaClient(); diff --git a/src/data/user.ts b/src/data/user.ts new file mode 100644 index 0000000..959ee30 --- /dev/null +++ b/src/data/user.ts @@ -0,0 +1,18 @@ +import { Prisma, User } from "@prisma/client"; +import { prisma } from "./prisma"; + +export async function createUser(data: User) { + await prisma.user.create({ data }); +} + +export async function readUser(id: User["id"]) { + return await prisma.user.findUnique({ where: { id } }); +} + +export async function updateUser(data: User) { + return await prisma.user.update({ where: { id: data.id }, data }); +} + +export async function deleteUser(id: User["id"]) { + return await prisma.user.delete({ where: { id } }); +} diff --git a/src/services/ServiceAgent.ts b/src/services/ServiceAgent.ts index ba816ea..fe7c014 100644 --- a/src/services/ServiceAgent.ts +++ b/src/services/ServiceAgent.ts @@ -1,7 +1,7 @@ import EventEmitter from "events"; export abstract class ServiceAgent extends EventEmitter { - constructor(public client: T) { + constructor(public platform: string, public client: T) { super(); this.bindEventListeners(); } diff --git a/src/services/index.ts b/src/services/index.ts index 04a5430..9efcc49 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -17,6 +17,31 @@ const config = loadConfig("config/services.yml", { enableSwitchChat: false }); +interface MPPNetConfig { + desiredUser: { + name: string; + color: string; + }; + agents: Record< + string, + { id: string; overrideToken?: string; overrideName?: string }[] + >; +} + +const mppConfig = loadConfig("config/mpp_net_channels.yml", { + desiredUser: { + name: "πŸŸ‡ π™Žπ™ͺπ™₯π™šπ™§ Cosmic (*help)", + color: "#1d0054" + }, + agents: { + "wss://mppclone.com": [ + { + id: "βœ§π““π“”π“₯ π“‘π“Έπ“Έπ“Άβœ§" + } + ] + } +}); + export class ServiceLoader { public static agents = new Array>(); @@ -26,14 +51,24 @@ export class ServiceLoader { public static loadServices() { if (config.enableMPP) { - // TODO Implement URI and channel configuration - const testAgent = new MPPAgent( - "wss://mppclone.com:8443", - env.MPPNET_TOKEN - ); + for (const uri of Object.keys(mppConfig.agents)) { + for (const channel of mppConfig.agents[uri]) { + const mppAgent = new MPPAgent( + uri, + channel.id, + channel.overrideName + ? { + name: channel.overrideName, + color: mppConfig.desiredUser.color + } + : mppConfig.desiredUser, + env.MPPNET_TOKEN + ); - testAgent.start(); - this.addAgent(testAgent); + mppAgent.start(); + this.addAgent(mppAgent); + } + } } if (config.enableSwitchChat) { diff --git a/src/services/mpp/Cursor.ts b/src/services/mpp/Cursor.ts new file mode 100644 index 0000000..33a82d9 --- /dev/null +++ b/src/services/mpp/Cursor.ts @@ -0,0 +1,196 @@ +import { MPPAgent } from "."; + +interface Vector2 { + x: number; + y: number; +} + +interface CursorProps { + currentAnimation: string; + position: Vector2; + oldPosition: Vector2; + velocity: Vector2; + acceleration: Vector2; + t: number; + ot: number; + dt: number; + gravity: number; + angles: number[]; + following: string; +} + +export class Cursor { + public visible: boolean = true; + public displayInterval: NodeJS.Timeout; + public updateInterval: NodeJS.Timeout; + + public props: CursorProps = { + currentAnimation: "lemniscate", + position: { + x: 50, + y: 50 + }, + oldPosition: { + x: 0, + y: 0 + }, + velocity: { + x: 0, + y: 0 + }, + acceleration: { + x: 0, + y: 0 + }, + t: Date.now(), + ot: Date.now(), + dt: 0, + gravity: 98, + angles: [], + following: "" + }; + + constructor(public agent: MPPAgent) { + this.displayInterval = setInterval(() => { + if ( + this.props.oldPosition.x !== this.props.position.x || + this.props.oldPosition.y !== this.props.position.y + ) { + this.agent.client.sendArray([ + { + m: "m", + x: this.props.position.x.toFixed(2).toString(), + y: this.props.position.y.toFixed(2).toString() + } + ]); + } + }, 1000 / 20); + + this.updateInterval = setInterval(() => { + switch (this.props.currentAnimation) { + case "bounce": + this.props.oldPosition.x = this.props.position.x; + this.props.oldPosition.y = this.props.position.y; + this.props.t = Date.now(); + this.props.dt = (this.props.t - this.props.ot) / 1000; + + this.props.acceleration.x = Math.random() * 100 - 50; + + if (this.props.position.y < 75) { + this.props.acceleration.y = + Math.random() * 100 - 50 + this.props.gravity; + } else { + this.props.acceleration.y = -(Math.random() * 50); + } + + this.props.velocity.x += + this.props.acceleration.x * this.props.dt; + this.props.velocity.y += + this.props.acceleration.y * this.props.dt; + + this.props.position.x += + this.props.velocity.x * this.props.dt; + this.props.position.y += + this.props.velocity.y * this.props.dt; + + if ( + this.props.position.x >= 100 || + this.props.position.x <= 0 + ) { + this.props.velocity.x = -this.props.velocity.x; + } + + if ( + this.props.position.y >= 100 || + this.props.position.y <= 0 + ) { + this.props.velocity.y = -this.props.velocity.y; + } + + if ( + this.props.position.x <= -5 || + this.props.position.x >= 105 + ) { + this.props.position.x = 50; + } + + if ( + this.props.position.y <= -5 || + this.props.position.y >= 105 + ) { + this.props.position.y = 50; + } + + this.props.ot = Date.now(); + break; + case "constrained": + this.props.oldPosition.x = this.props.position.x; + this.props.oldPosition.y = this.props.position.y; + this.props.t = Date.now(); + this.props.dt = (this.props.t - this.props.ot) / 1000; + + this.props.acceleration.x = Math.random() * 100 - 50; + + this.props.velocity.x += + this.props.acceleration.x * this.props.dt; + + this.props.position.x += + this.props.velocity.x * this.props.dt; + + if ( + this.props.position.x >= 100 || + this.props.position.x <= 0 + ) { + this.props.velocity.x = -this.props.velocity.x; + } + + if ( + this.props.position.y >= 100 || + this.props.position.y <= 0 + ) { + this.props.velocity.y = -this.props.velocity.y; + } + + if ( + this.props.position.x <= -5 || + this.props.position.x >= 105 + ) { + this.props.position.x = 50; + } + + if ( + this.props.position.y <= -5 || + this.props.position.y >= 105 + ) { + this.props.position.y = 50; + } + + this.props.ot = Date.now(); + break; + case "lemniscate": + if (!this.props.angles[0]) this.props.angles[0] = 0; + + this.props.angles[0] += 1; + if (this.props.angles[0] > 360) this.props.angles[0] = 0; + + this.props.position.x = + Math.cos(this.props.angles[0] * (Math.PI / 180)) * 10 + + 50; + this.props.position.y = + Math.sin(this.props.angles[0] * (Math.PI / 180) * 3) * + 10 + + 50; + + break; + } + }, 1000 / 60); + } + + public show() { + this.visible = true; + } + + public hide() { + this.visible = false; + } +} diff --git a/src/services/mpp/index.ts b/src/services/mpp/index.ts index 1bda9fb..bb44b5b 100644 --- a/src/services/mpp/index.ts +++ b/src/services/mpp/index.ts @@ -1,20 +1,21 @@ import Client from "mpp-client-net"; import { ServiceAgent } from "../ServiceAgent"; -import { ptr } from "bun:ffi"; - -let p; +import { CommandHandler } from "../../commands/CommandHandler"; +import { Cursor } from "./Cursor"; export class MPPAgent extends ServiceAgent { - public desiredUser = { - name: "πŸŸ‡ π™Žπ™ͺπ™₯π™šπ™§ Cosmic (no commands yet)", - color: "#1d0054" - }; + public cursor: Cursor; - public desiredChannel = "nothing"; - - constructor(uri: string, token: string) { + constructor( + uri: string, + public desiredChannel: string, + public desiredUser: { name: string; color: string }, + token: string + ) { const cl = new Client(uri, token); - super(cl); + super("mpp", cl); + this.emit("log", desiredChannel); + this.cursor = new Cursor(this); } public start() { @@ -31,31 +32,85 @@ export class MPPAgent extends ServiceAgent { this.client.on("hi", msg => { this.emit("log", msg.u); this.client.setChannel(this.desiredChannel); + this.fixUser(); + }); - console.log( - msg.u.name !== this.desiredUser.name || - msg.u.color !== this.desiredUser.color + this.client.on("t", msg => { + this.fixUser(); + }); + + this.client.on("a", async msg => { + console.log(`${msg.p.name}: ${msg.a}`); + let args = msg.a.split(" "); + + const str = await CommandHandler.handleCommand( + { + m: "command", + a: msg.a, + argc: args.length, + argv: args, + p: { + _id: "MPP_" + this.client.uri + "_" + msg.p._id, + name: msg.p.name, + color: msg.p.color, + platformId: msg.p._id + }, + originalMessage: msg + }, + this ); - if ( - msg.u.name !== this.desiredUser.name || - msg.u.color !== this.desiredUser.color - ) { - // setTimeout(() => { - this.client.sendArray([ - { - m: "userset", - set: this.desiredUser + if (str) { + if (str.includes("\n")) { + let sp = str.split("\n"); + + for (const s of sp) { + this.client.sendArray([ + { + m: "a", + message: `\u034f${s}` + } + ]); } - ]); - // }, 1000); + } else { + this.client.sendArray([ + { + m: "a", + message: `\u034f${str}` + } + ]); + } } }); + } - this.client.on("a", msg => { - p = ptr(new TextEncoder().encode(msg.a).buffer); - // handleCommand(p); - console.log(`${msg.p.name}: ${msg.a}`); - }); + public fixUser() { + if (!this.client.user) return; + + if ( + this.client.user.name !== this.desiredUser.name || + this.client.user.color !== this.desiredUser.color + ) { + this.client.sendArray([ + { + m: "userset", + set: this.desiredUser + } + ]); + } + } + + public getParticipant(fuzzy: string) { + for (const p of Object.values(this.client.ppl)) { + if (!p._id.includes(fuzzy) && !p.name.includes(fuzzy)) return; + return p as unknown as { + name: string; + _id: string; + id: string; + color: string; + x: number; + y: number; + }; + } } } diff --git a/src/services/switchchat/index.ts b/src/services/switchchat/index.ts index 4340625..f6a27a9 100644 --- a/src/services/switchchat/index.ts +++ b/src/services/switchchat/index.ts @@ -1,4 +1,8 @@ -import { CommandHandler, CommandMessage } from "../../commands/CommandHandler"; +import { + BaseCommandMessage, + CommandHandler, + CommandMessage +} from "../../commands/CommandHandler"; import { loadConfig } from "../../util/config"; import { ServiceAgent } from "../ServiceAgent"; import { Client } from "switchchat"; @@ -15,7 +19,7 @@ export class SwitchChatAgent extends ServiceAgent { constructor(token: string) { const cl = new Client(token); - super(cl); + super("mc", cl); this.client.defaultName = this.desiredUser.name; this.client.defaultFormattingMode = "markdown"; @@ -41,12 +45,18 @@ export class SwitchChatAgent extends ServiceAgent { } ${cmd.args.join(" ")}` ); - const message: CommandMessage = { + const message: BaseCommandMessage = { m: "command", a: `${cmd.command} ${cmd.args.join(" ")}`, argc: cmd.args.length + 1, argv: [cmd.command, ...cmd.args], - originalMessage: cmd + originalMessage: cmd, + p: { + _id: "MC_" + cmd.user.uuid, + name: cmd.user.displayName, + color: "#000000", + platformId: cmd.user.uuid + } }; const out = await CommandHandler.handleCommand(message, this); @@ -54,8 +64,8 @@ export class SwitchChatAgent extends ServiceAgent { if (out) await this.client.tell(cmd.user.name, out); }); - this.client.on("rawraw", data => { - console.log(data); - }); + // this.client.on("rawraw", data => { + // console.log(data); + // }); } } diff --git a/src/util/Logger.ts b/src/util/Logger.ts new file mode 100644 index 0000000..cb8f698 --- /dev/null +++ b/src/util/Logger.ts @@ -0,0 +1,65 @@ +// Gray console text +export function unimportant(str: string) { + return `\x1b[90m${str}\x1b[0m`; +} + +// Pad time strings +export function padNum( + num: number, + padAmount: number, + padChar: string, + left: boolean = true +) { + return left + ? num.toString().padStart(padAmount, padChar) + : num.toString().padEnd(padAmount, padChar); +} + +export class Logger { + private static log(method: string, ...args: any[]) { + (console as unknown as Record any>)[ + method + ]( + unimportant(this.getDate()), + unimportant(this.getHHMMSSMS()), + ...args + ); + } + + public static getHHMMSSMS() { + const ms = Date.now(); + + const s = ms / 1000; + const m = s / 60; + const h = m / 60; + + const ss = padNum(Math.floor(s) % 60, 2, "0"); + const mm = padNum(Math.floor(m) % 60, 2, "0"); + const hh = padNum(Math.floor(h) % 24, 2, "0"); + const ll = padNum(ms % 1000, 3, "0"); + + return `${hh}:${mm}:${ss}.${ll}`; + } + + public static getDate() { + return new Date().toISOString().split("T")[0]; + } + + constructor(public id: string) {} + + public info(...args: any[]) { + Logger.log("log", `[${this.id}]`, `\x1b[34m[info]\x1b[0m`, ...args); + } + + public error(...args: any[]) { + Logger.log("error", `[${this.id}]`, `\x1b[31m[error]\x1b[0m`, ...args); + } + + public warn(...args: any[]) { + Logger.log("warn", `[${this.id}]`, `\x1b[33m[warn]\x1b[0m`, ...args); + } + + public debug(...args: any[]) { + Logger.log("debug", `[${this.id}]`, `\x1b[32m[debug]\x1b[0m`, ...args); + } +}