This commit is contained in:
2025-06-07 11:04:30 +08:00
commit 7e7774d4f4
26 changed files with 3943 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
output/
logs/
node_modules/
.env
+67
View File
@@ -0,0 +1,67 @@
"use strict";
// from crepesr
// logger
Object.defineProperty(exports, "__esModule", { value: true });
exports.VerboseLevel = void 0;
require("colorts/lib/string");
var VerboseLevel;
(function (VerboseLevel) {
VerboseLevel[VerboseLevel["NONE"] = 0] = "NONE";
VerboseLevel[VerboseLevel["WARNS"] = 1] = "WARNS";
VerboseLevel[VerboseLevel["ALL"] = 2] = "ALL";
VerboseLevel[VerboseLevel["VERBL"] = 3] = "VERBL";
VerboseLevel[VerboseLevel["VERBH"] = 4] = "VERBH";
})(VerboseLevel || (exports.VerboseLevel = VerboseLevel = {}));
class Logger {
constructor(name = 'CLIENT', color = 'blue') {
this.name = name;
this.color = color;
this.name = name;
this.color = color;
}
getDate() {
return new Date().toLocaleTimeString();
}
raw(...args) {
// @ts-ignore - Element implicitly has an 'any' type because index expression is not of type 'number'
console.log(`[${this.getDate().white.bold}] <${this.name[this.color].bold}>`, ...args);
}
log(...args) {
this.raw(...args);
}
trail(...args) {
console.log(`\t${args.join(' ').gray}`);
}
error(e, stack = true) {
if (typeof e === 'string')
e = new Error(e);
console.log(`[${this.getDate().white.bold}] ${`ERROR<${this.name}>`.bgRed.bold}`, e.message);
if (e.stack && stack)
this.trail(e.stack);
}
warn(...args) {
if (Logger.VERBOSE_LEVEL < VerboseLevel.WARNS)
return;
console.log(`[${this.getDate().white.bold}] ${`WARN<${this.name}>`.bgYellow.bold}`, ...args);
}
debug(...args) {
if (Logger.VERBOSE_LEVEL < VerboseLevel.ALL)
return;
console.log(`[${this.getDate().white.bold}] ${`DEBUG<${this.name}>`.bgBlue.bold}`, ...args);
this.trail(new Error().stack.split('\n').slice(2).join('\n'));
}
verbL(...args) {
if (Logger.VERBOSE_LEVEL < VerboseLevel.VERBL)
return;
console.log(`[${this.getDate().white.bold}] ${`VERBL<${this.name}>`.bgCyan.bold}`, ...args);
this.trail(new Error().stack.split('\n').slice(2).join('\n'));
}
verbH(...args) {
if (Logger.VERBOSE_LEVEL < VerboseLevel.VERBH)
return;
console.log(`[${this.getDate().white.bold}] ${`VERBH<${this.name}>`.bgCyan.bold}`, ...args);
this.trail(new Error().stack.split('\n').slice(2).join('\n'));
}
}
Logger.VERBOSE_LEVEL = 1;
exports.default = Logger;
+16
View File
@@ -0,0 +1,16 @@
async function Token() {
const { MatrixAuth } = require('matrix-bot-sdk')
// This will be the URL where clients can reach your homeserver. Note that this might be different
// from where the web/chat interface is hosted. The server must support password registration without
// captcha or terms of service (public servers typically won't work).
const homeserverUrl = "https://chat.sob.moe";
const auth = new MatrixAuth(homeserverUrl);
// sobu: mk_sob_relEKA1axmA
// sob: mk_sob_relA3cDmA3
const client = await auth.passwordLogin("sobu", "mk_sob_relEKA1axmA");
console.log("\n\n")
console.log("Copy this access token to your bot's config: ", client.accessToken);
};Token()
+2844
View File
File diff suppressed because it is too large Load Diff
+23
View File
@@ -0,0 +1,23 @@
{
"name": "matrix-sob",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"clean": "rimraf output/",
"test": "echo \"Error: no test specified\" && exit 1",
"quick": "npm run clean && tsc && node ./output/src/index.js"
},
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"colorts": "^0.1.63",
"dotenv": "^16.5.0",
"matrix-bot-sdk": "^0.7.1",
"node-pager": "^0.3.6",
"rimraf": "^6.0.1",
"tree-kill": "^1.2.2",
"typescript": "^5.8.3",
"winston": "^3.17.0"
}
}
+7
View File
@@ -0,0 +1,7 @@
{
"syncToken": "s20307_514091_162_46420_7870_32_844_11065_0_7",
"filter": null,
"appserviceUsers": {},
"appserviceTransactions": {},
"kvStore": {}
}
+54
View File
@@ -0,0 +1,54 @@
import { AutojoinRoomsMixin, MatrixClient, SimpleFsStorageProvider } from "matrix-bot-sdk";
import Logger from "./util/Logger";
import { StrawberryFilling } from "./types/Cheesecake";
const csc = new Logger("Strawberry Cheesecake", 'red')
import { cd, commands, handleCommand } from ".";
require('dotenv').config()
var homeServer = process.env.homeserver
var accessToken: any = process.env.token
var storage: SimpleFsStorageProvider
var client: MatrixClient = null;
export function BakeStrawberryCheesecake(): StrawberryFilling {
client = null;
csc.log('Baking strawberry cheesecake...')
storage = new SimpleFsStorageProvider('session.json')
cd.quiet('Started Matrix Client.')
client = new MatrixClient(homeServer, accessToken, storage);
client.start()
csc.log(`Baked strawberry cheesecake. Serving cake.`)
AutojoinRoomsMixin.setupOnClient(client);
client.on("room.message", handleCommand);
return GetStrawberryCheesecake()
}
export function GetStrawberryCheesecake(): StrawberryFilling {
return {
accessToken: accessToken,
stomach: storage,
cake: client
}
}
export async function RebakeStrawberryCheesecake() {
csc.log('Eating strawberry cheesecake!')
await client.stop();
client = null;
setTimeout(async () => {
BakeStrawberryCheesecake();
AutojoinRoomsMixin.setupOnClient(client);
await client.start()
csc.log(`Cinnamon reports a command amount of ${commands.length}`)
csc.log('Connection reset! Cake is served once more with an ID of ' + await client.getUserId())
client.on("room.message", handleCommand);
}, 7000)
}
export function EatStrawberryCheesecake() {
client.stop()
client = null
csc.log('Ate strawberry cheesecake.')
}
+58
View File
@@ -0,0 +1,58 @@
import { MatrixClient } from "matrix-bot-sdk";
import { CommandData } from "./types/Command";
import Logger from "./util/Logger";
const c = new Logger("Cinnamon")
import fs from 'fs';
require('dotenv').config()
var commands: string[] = []
// Grab all the command files from the commands directory you created earlier
export function CinnamonInit(): string[] {
const commandFiles = fs
.readdirSync(process.cwd() + "/output/src/commands")
.filter((file: any) => file.endsWith('.js'))
for (let file = 0; file < commandFiles.length; file++) {
const cmd = commandFiles[file];
commands.push(cmd)
c.log(`Cinnamon found: ${cmd}`)
}
return commands
}
export async function Cinnamon(client: MatrixClient, roomId: string, event: any, userInput: any) {
try {
var CommandMatched = false
var CommandFile = ""
if (userInput.startsWith('sob!')) {
c.quiet("Cinnamon was called.")
c.quiet(`Cinnamon input: ${userInput}`)
for (let cmd = 0; cmd < commands.length; cmd++) {
const command: string = commands[cmd];
if (userInput.trim().split(" ")[0] === `sob!${command.replace('.js', '')}`) {
CommandMatched = true
CommandFile = command
}
}
c.quiet(`Match? ${CommandMatched}`)
if (CommandMatched && CommandFile) {
c.quiet(`${process.cwd()}/output/src/commands/${CommandFile}`)
c.quiet(`File exists? ${fs.existsSync(`${process.cwd()}/output/src/commands/${CommandFile}`)}`)
const TheCommandItself: CommandData = require(`${process.cwd()}/output/src/commands/${CommandFile}`).default
if (TheCommandItself) {
await client.sendMessage(roomId, {
msgtype: "m.text",
body: (await TheCommandItself.execute(client, roomId, event, userInput)).toString()
});
c.quiet(`Cinnamon executed ${TheCommandItself.name}.`)
}
}
}
} catch (err) {
c.error(`Cinnamon caught an error: ${err}`)
}
}
+129
View File
@@ -0,0 +1,129 @@
import { MatrixClient } from "matrix-bot-sdk";
import { CommandData } from "../types/Command";
import { commands, StrawberryCheesecake } from "..";
import Logger from "../util/Logger";
import { cd } from "..";
import { EatStrawberryCheesecake, RebakeStrawberryCheesecake } from "../Cheesecake";
import { run } from "../console_commands/update";
export var dbg = {
sessionIsForDebugging: true,
targetEvent: 'none',
roomId: 'none'
};
export const Command: CommandData = {
name: 'dbg',
description: 'Debug command.',
usage: false,
execute: async (client: MatrixClient, roomId: string, event: any, userInput: any) => {
userInput = userInput.replace('sob!dbg ', '')
cd.quiet(`Tt ${userInput}`)
var args: string[] = userInput.split(' ')
if (args[0] && event.sender === "@maki:chat.sob.moe") {
switch (args[0].toLowerCase()) {
case 'cinnamon':
var out = `Cinnamon found:\n\n`
for (let i = 0; i < commands.length; i++) {
const cmdName = commands[i];
cd.quiet('Cinnamon found ' + cmdName)
out = `${out}${cmdName},\n`
}
return `${out}`
case 'strawberrycheesecake':
if (args[1] && typeof (args[1]) === 'string') {
switch (args[1].toLowerCase()) {
case 'rebake':
RebakeStrawberryCheesecake();
return "Rebaked strawberry cheesecake!"
case 'eat':
client.sendMessage(roomId, {
msgtype: "m.text",
body: 'Eating strawberry cheesecake.'
})
EatStrawberryCheesecake();
return 'Ate strawberry cheesecake.'
case 'updaterecipe':
client.sendMessage(roomId, {
msgtype: "m.text",
body: 'Updating recipe...'
})
StrawberryCheesecake.cake.stop()
setTimeout(() => run('npm run quick'), 7000)
default:
return 'What do I do with the strawberry cheesecake?'
}
} else return 'Invalid arguments.'
case 'eval':
if (args[0].toLowerCase() === "eval") {
args.splice(0, 1)
var result = args.join(' ')
const showRawOutput = result.includes(";;;raw")
result = result.replace(';;;raw', '')
try {
let evaled = eval(result)
cd.quiet(`Evaled ${evaled}`)
if (!showRawOutput) {
result = result.replaceAll(process.env.token, "\"[token\"").replaceAll('client.token', '\"[token]\"').replaceAll('process.env.token', '\"[token]\"');
//Convert evaled into a JSON String if it is an Object
if (typeof evaled === "object") evaled = JSON.stringify(evaled);
//Do this if evaled is anything else other than a number, text, or true/false
if (typeof evaled !== "number" && typeof evaled !== "string" && typeof evaled !== "boolean") evaled = `Output could not be converted to text (output was of type: ${typeof evaled}).`;
evaled = evaled.toString().replaceAll(process.env.token.toString(), "[token]")
result = result.toString().replaceAll(process.env.token, "[token]").replaceAll('client.token', '[token]').replaceAll('process.env.token', '[token]');
}
return `${showRawOutput ? "Raw e" : "E"}valuation result:\n${evaled}`
} catch (err) {
return `${showRawOutput ? "Raw e" : "E"}valuation result:\n${err}`
}
}
default:
if (!args[0]) {
dbg.sessionIsForDebugging = true;
dbg.targetEvent = event.event_id
dbg.roomId = roomId
return 'Debugging event where sob!dbg was used.'
} else {
switch (args[0]) {
case 'target':
if (args[1] && dbg.targetEvent === "none")
dbg.targetEvent = args[1]
break;
case 'room':
if (args[1] && dbg.roomId === "none")
dbg.roomId = args[1]
break;
case 'reset':
dbg.roomId = 'none'
dbg.sessionIsForDebugging = false
dbg.targetEvent = 'none'
return 'Reset.'
}
switch (args[2]) {
case 'target':
if (args[3] && dbg.targetEvent === "none")
dbg.targetEvent = args[3]
break;
case 'room':
if (args[3] && dbg.roomId === "none")
dbg.roomId = args[3]
break;
}
if (dbg.roomId === 'none')
dbg.roomId = roomId
if (dbg.targetEvent === 'none')
dbg.targetEvent = event.event_id
dbg.sessionIsForDebugging = true
return `Set ${dbg.targetEvent} as the target event and ${dbg.roomId} as the room id. Now debugging.`
}
}
} else if (event.sender !== "@maki:chat.sob.moe") {
return 'No permission to do this!'
} else
return 'No arguments provided!'
}
}
export default Command
+62
View File
@@ -0,0 +1,62 @@
import { MatrixClient, RoomEvent } from "matrix-bot-sdk";
import { CommandData } from "../types/Command";
export const Command: CommandData = {
name: 'delete',
description: 'Deletes/redacts a set amount of messages.',
usage: false,
execute: async (client: MatrixClient, roomId: string, event: any, userInput: any) => {
//await client.replyNotice(roomId, event, "😭");
userInput = userInput.replace(`sob!${Command.name} `, '')
var args = userInput.split(' ')
try {
if (args[0]) {
var reason = ""
if (args[1])
reason = args[1]
var times = parseInt(args[0])
var RecentFew = await getRecentMessages(client, roomId, times)
if (RecentFew.length > 1) {
for (let i = 0; i < times; i++) {
console.log(`Cleared ${i} times total of ${times}`)
const event: RoomEvent = RecentFew[i];
console.log(`This: ${event.eventId}`)
await client.redactEvent(roomId, event.eventId, reason)
}
}
return `Tried redacting ${times} time(s).`
}
return `Invalid usage of command. ${userInput}`
} catch (err) {
return `${err}`
}
}
}
async function getRecentMessages(client: MatrixClient, roomId: string, count: number) {
const messages = [];
let fromToken = (await client.doRequest("GET", "/_matrix/client/v3/sync?timeout=0")).next_batch;
while (messages.length < count) {
const res = await client.doRequest("GET", `/_matrix/client/v3/rooms/${encodeURIComponent(roomId)}/messages`, {
dir: "b",
from: fromToken,
limit: 50, // Can adjust this
filter: JSON.stringify({ types: ["m.room.message"] }),
});
// @ts-ignore
const filtered = res.chunk.filter(e => e.type === "m.room.message");
for (const msg of filtered) {
messages.push(msg);
if (messages.length === count) return messages; // ✅ Return immediately
}
if (!res.end || res.chunk.length === 0) break; // No more messages to paginate
fromToken = res.end;
}
return messages; // May contain fewer than `count` if not enough messages
}
export default Command
+35
View File
@@ -0,0 +1,35 @@
import { MatrixClient } from "matrix-bot-sdk";
import { CommandData } from "../types/Command";
import Logger from "../util/Logger";
import { cd } from "..";
export const Command: CommandData = {
name: 'repeat',
description: 'w...',
usage: false,
execute: async (client: MatrixClient, roomId: string, event: any, userInput: any) => {
//await client.replyNotice(roomId, event, "😭");
userInput = userInput.replace('sob!repeat ', '')
var initial: string[] = userInput.split(';;;') // initial[0]: text to spam
try {
if (initial[1] === "@") {
var times = parseInt(initial[2])
cd.quiet(`Times: ${times.toString()}`)
for (let i = 0; i < times; i++) {
if (i != (times - 1))
await client.sendMessage(roomId, {
msgtype: "m.text",
body: initial[0],
})
}
return initial[0]
}
return initial[0]
} catch (err) {
return err.toString()
}
}
}
export default Command
+14
View File
@@ -0,0 +1,14 @@
import { MatrixClient } from "matrix-bot-sdk";
import { CommandData } from "../types/Command";
export const Command: CommandData = {
name: 'sob',
description: 'sob...',
usage: false,
execute: async (client: MatrixClient, roomId: string, event: any, userInput: any) => {
//await client.replyNotice(roomId, event, "😭");
return "😭"
}
}
export default Command
+10
View File
@@ -0,0 +1,10 @@
export const metadata = {
name: 'clear',
description: "Clears the console.",
usage: false,
aliases: ["cls"]
}
export function Main(args: Array<string>) {
return '$clear'
}
+30
View File
@@ -0,0 +1,30 @@
import { cd, StrawberryCheesecake } from ".."
import { BakeStrawberryCheesecake, RebakeStrawberryCheesecake } from "../Cheesecake"
export const metadata = {
name: 'debug',
description: "Debug commands.",
usage: false,
aliases: ["dbg"]
}
export async function Main(args: Array<string>) {
if (!args[0]) {
cd.log(`No arguments supplied.`)
return ``
} else {
switch (args[0]) {
case 'bake':
BakeStrawberryCheesecake();
return 0;
case 'reset':
RebakeStrawberryCheesecake();
return 0
case 'eat':
StrawberryCheesecake.cake.stop();
return 'Ate strawberry cheesecake. Client shouldn\'t be active anymore.'
default:
return 'Unknown argument supplied.'
}
}
}
+14
View File
@@ -0,0 +1,14 @@
import Logger from "../util/Logger";
const c = new Logger("CLIENT/echo.js")
import 'colorts/lib/string'
export const metadata = {
name: "echo",
description: "Repeats text.",
usage: `echo ${"<input text>"["bold"]}`,
aliases: false
}
export function Main(args: Array<string>) {
return args.join(' ')
}
+32
View File
@@ -0,0 +1,32 @@
import { cd } from "..";
import { ConsoleCommandData } from "../types/Command";
export const metadata: ConsoleCommandData = {
name: "eval",
description: "Evaluates JavaScript code.",
usage: `eval ${'<code>'['bold']}`,
aliases: ["do"]
}
export function Main(args: string[]) {
let result = ""
result = args.join(" ")
const showRawOutput = result.includes("--raw") || result.includes("-r")
result = result.replace('--raw', '').replace('-r', '')
let evaled = eval(result)
if (!showRawOutput) {
result = result.replaceAll(process.env.token, "\"[token\"").replaceAll('client.token', '\"[token]\"').replaceAll('process.env.token', '\"[token]\"');
//Convert evaled into a JSON String if it is an Object
if (typeof evaled === "object") evaled = JSON.stringify(evaled);
//Do this if evaled is anything else other than a number, text, or true/false
if (typeof evaled !== "number" && typeof evaled !== "string" && typeof evaled !== "boolean") evaled = `Output could not be converted to text (output was of type: ${typeof evaled}).`;
evaled = evaled.toString().replaceAll(process.env.token.toString(), "[token]")
result = result.toString().replaceAll(process.env.token, "[token]").replaceAll('client.token', '[token]').replaceAll('process.env.token', '[token]');
}
cd.log(`Evaled ${evaled}`)
return `${showRawOutput ? "Raw e" : "E"}valuation result:\n${evaled}`
}
+21
View File
@@ -0,0 +1,21 @@
import Logger from "../util/Logger"
var c = new Logger("CLIENT/exit.js")
import 'colorts/lib/string'
import treeKill from "tree-kill"
export const metadata = {
name: "exit",
description: "Ends this process.",
usage: `exit ${"<exitcode>"["italic"]}`,
aliases: [ "stop" ]
}
export function Main(args: Array<string>) {
var code: number | boolean = Number.parseInt(args[0]) || false // the default is set to 1 for rebuild processes
c.log(code ? `Exiting process with exitcode ${code}.` : `Killing this process tree (${process.pid}).`)
if (!code)
treeKill(process.pid)
else
process.exit(parseInt(code.toString()))
return 'Have a nice day!'
}
+62
View File
@@ -0,0 +1,62 @@
import Logger from "../util/Logger";
const cm = new Logger("CLIENT/help.js")
import fs from 'fs'
import 'colorts/lib/string'
import { ConsoleCommandData } from "../types/Command";
export const metadata = {
name: "help",
description: "Returns a list of usable commands / usage of a command.",
usage: `help ${"<command name>"["italic"]}`,
aliases: false
}
export function Main(args: Array<string>) {
const cmdname = args[0]
const cwd = process.cwd();
try {
if (cmdname) {
const metadata: ConsoleCommandData = require(cwd + `/output/src/console_commands/${cmdname.replace('ts', 'js')}`).metadata
cm.log('Command name: ' + cmdname)
cm.log(`Description: ${metadata.description}`)
cm.log(`Usage: ${metadata.usage ? metadata.usage : 'No particular arguments.'}`)
if (Array.isArray(metadata.aliases) && metadata.aliases.length)
cm.log(`Aliases: ${metadata.aliases.join(', ')}`)
return 0
}
} catch {
cm.log(`The command ${cmdname} was not found.`)
return 0
}
if (!cmdname)
try {
//var commands = "\n"
const commandList = fs.readdirSync(cwd + '/output/src/console_commands')
//var processed_commands: number = 0
cm.log(`${"Italic text"["italic"]} represent optional arguments, while ${"bold"["bold"]} text represent mandatory arguments.`)
cm.log(`Command usage: ${this.metadata.usage}\n`)
cm.log("The following commands are available:")
for (let i = 0; i < commandList.length; i++) {
const commandFile = commandList[i];
if (commandFile.includes('.map'))
""
else {
//processed_commands++
const commandMetadata = require(cwd + `/output/src/console_commands/${commandFile.replace('ts', 'js')}`).metadata
const usage = commandMetadata.usage ? commandMetadata.usage : commandFile
cm.log(`${commandFile.replace('.js', '')}\t${commandMetadata.description}`)
//cm.log(`description: ${commandMetadata.description}`)
//cm.log(`usage: ${usage}`)
}
}
return 1;
} catch (err) {
cm.error("An error occured while running this command: " + err)
return 0
}
}
+42
View File
@@ -0,0 +1,42 @@
import Logger, { defaultLogName } from "../util/Logger"
const c = new Logger("CLIENT/log.js")
import fs from 'fs'
const pager = require('node-pager')
import 'colorts/lib/string'
export const metadata = {
name: "log",
description: "Views the log files.",
usage: `log ${'<clear>'["italic"]}`,
aliases: false
}
export function Main(args: Array<string>) {
c.log(`Using the log file at ${defaultLogName}.`)
if (!args[0])
fs.readFile(defaultLogName, (err, data) => {
if (err) {
c.error('Error reading file:\n' + err);
return '...';
}
pager(data.toString('utf8')).then(() => {
return 'Done.'
});
});
else if (args[0].toLowerCase() === "clear") {
c.clear()
return "Cleared."
} else if (args[0].toLowerCase() === "debug") { // means a log file was supplied
fs.readFile('./logs/' + require('../index').cd.logger.transports[0].filename, (err, data) => {
if (err) {
c.error('Error reading file:\n' + err);
return '...';
}
pager(data.toString('utf8')).then(() => {
return 'Done.'
});
});
}
return 'Done.'
}
+28
View File
@@ -0,0 +1,28 @@
import Logger from "../util/Logger"
var c = new Logger("CLIENT/update.js")
import proc, { exec, execSync } from 'child_process'
import { ConsoleCommandData } from '../types/Command'
import { StrawberryCheesecake } from ".."
export const metadata: ConsoleCommandData = {
name: "update",
description: "Rebuilds the application from within this process.",
usage: false,
aliases: [ "reload", "restart", 're' ]
}
export function run(command: string) {
try {
execSync(command, { stdio: 'inherit' })
} catch (err) {
//c.error(`Caught exception while rebuilding the project. E:\n${err}`)
process.exit(0) // probably a sigint?
}
}
export const Main = async (args: Array<string>) => {
c.log(`Rebuilding project.`)
StrawberryCheesecake.cake.stop()
// assuming you have and use npm already
run('npm run quick')
}
+47
View File
@@ -0,0 +1,47 @@
export var dateAsOfInitialization = new Date()
import Logger, { defaultLogName } from "./util/Logger";
import dotenv from 'dotenv'
import { Prompt } from "./util/Prompt";
import { Cinnamon, CinnamonInit } from "./Cinnamon";
import { BakeStrawberryCheesecake } from "./Cheesecake";
import { StrawberryFilling } from "./types/Cheesecake";
dotenv.config()
export const cd = new Logger("DEBUGGER", 'cyan', `${new Date().toLocaleDateString('en-us').replaceAll('/', '-')}-DEBUG`)
const cm = new Logger("CLIENT/index.ts")
export var commands: string[] = []
console.clear();
cm.quiet('\n\nNEW CLIENT!')
cm.log("Hi!")
export const StrawberryCheesecake: StrawberryFilling = BakeStrawberryCheesecake()
// Now that everything is set up, start the bot. This will start the sync loop and run until killed.
StrawberryCheesecake.cake.start().then(async () => {
cm.log("Cheesecake is to be served! Cake ID is " + await StrawberryCheesecake.cake.getUserId())
cm.log(`Logs will be printed at ${defaultLogName}.`)
cm.log(`-----------------------------------------------------`)
commands = CinnamonInit()
cm.log(`Cinnamon reports a command amount of ${commands.length}`)
cm.log(`-----------------------------------------------------`)
cm.log("Enter \"help\" for a list of console commands.")
process.stdout.write(`\x1b]0;MTRXC as ${await StrawberryCheesecake.cake.getUserId()}\x07`);
Prompt()
});
// This is the command handler we registered a few lines up
export async function handleCommand(roomId: string, event: any) {
// Don't handle unhelpful events (ones that aren't text messages, are redacted, or sent by us)
if (event['content']?.['msgtype'] !== 'm.text') return;
if (event['sender'] === await StrawberryCheesecake.cake.getUserId()) return;
// Check to ensure that the `!hello` command is being run
const UserInput = event['content']['body'];
//cm.log("Handle Command")
if (UserInput)
await Cinnamon(StrawberryCheesecake.cake, roomId, event, UserInput)
}
+7
View File
@@ -0,0 +1,7 @@
import { MatrixClient, SimpleFsStorageProvider } from "matrix-bot-sdk";
export interface StrawberryFilling {
accessToken: string,
stomach: SimpleFsStorageProvider,
cake: MatrixClient
}
+16
View File
@@ -0,0 +1,16 @@
import { MatrixClient } from "matrix-bot-sdk"
export interface ConsoleCommandData {
name: string,
description: string,
usage: string | boolean,
aliases?: string[] // should be boolean but makes issues
}
export interface CommandData {
name: string,
description: string,
usage: string | boolean,
aliases?: string[], // should be boolean but makes issues
execute?: (client: MatrixClient, roomId: string, event: any, userInput: any) => Promise<string>; // the string is its final output!
}
+156
View File
@@ -0,0 +1,156 @@
// from crepesr
// logger
import 'colorts/lib/string';
import fs from 'fs'
export enum VerboseLevel {
NONE = 0, // No logging except for errors
WARNS = 1, // Log warns
ALL = 2, // Warns and (useless) debug
VERBL = 3, // Warns, debug and verbose
VERBH = 4, // Warns, debug, verbose and very verbose (thanks copilot this is so funny)
}
type Color = 'red' | 'green' | 'yellow' | 'blue' | 'magenta' | 'cyan' | 'white' | 'gray' | 'black' | 'italic' | 'bold' | 'underline' | 'strikethrough' | 'inverse' | 'bgRed' | 'bgGreen' | 'bgYellow' | 'bgBlue' | 'bgMagenta' | 'bgCyan' | 'bgWhite' | 'bgBlack' | 'bgGray' | 'bgItalic';
import { createLogger, transports, format } from 'winston';
import { dateAsOfInitialization } from '../index.js';
export var defaultLogName = `./logs/${new Date().getFullYear()}-${new Date().getMonth() + 1}-${new Date().getDay() + 1}.log`
export default class Logger {
public static VERBOSE_LEVEL: VerboseLevel = 3;
private constructorLogFile = ''
public logger = createLogger({
format: format.combine(
format.timestamp(),
format.printf(({ }) => ``)
),
transports: [
new transports.File({ filename: defaultLogName })
]
});
constructor(public name: string = 'CLIENT', public color: Color = 'blue', public logName: string = `default`) {
this.name = name;
this.color = color;
if (logName === "default") {
this.logName = defaultLogName
this.constructorLogFile = defaultLogName
} else {
this.logName = logName
this.constructorLogFile = logName
this.logger.destroy()
this.logger = createLogger({
format: format.combine(
format.timestamp(),
format.printf(({ }) => ``)
),
transports: [
new transports.File({ filename: `./logs/${this.constructorLogFile}` })
]
});
this.raw(`New ctm logger logging at ${(this.logger.transports as any)[0].filename}`)
}
}
public getDate(): string {
return new Date().toLocaleTimeString();
}
// clears log file, not stdout!!
public clear() {
fs.truncateSync(defaultLogName, 0)
}
private raw(...args: string[]) {
// @ts-ignore - Element implicitly has an 'any' type because index expression is not of type 'number'
console.log(`[${this.getDate().white.bold}] <${this.name[this.color].bold}>`, ...args);
}
public quiet(...args: string[]) {
this.logger.format = format.printf(({ message }) => {
return `[${this.getDate()}] <${this.name}> ${message}`;
});
this.logger.info(...args as [string, ...string[]])
}
public plain(...args: string[]) {
this.logger.format = format.printf(({ message }) => {
return `${message}`;
});
this.logger.info(...args as [string, ...string[]])
console.log(...args)
}
public log(...args: string[]) {
this.logger.format = format.printf(({ message }) => {
return `[${this.getDate()}] <${this.name}> ${message}`;
});
this.logger.info(...args as [string, ...string[]])
this.raw(...args);
}
public trail(...args: any[]) {
var returnValue = `\t↳ ${args.join(' ').gray}`
console.log(returnValue);
this.logger.format = format.printf(({ message }) => {
//@ts-ignore
return returnValue;
});
this.logger.info(...args as [string, ...string[]])
}
public error(e: Error | string, stack: boolean = true) {
if (typeof e === 'string') e = new Error(e);
this.logger.format = format.printf(({ message }) => {
return `[${this.getDate()}] ERROR<${this.name}> ${message}`;
});
this.logger.error(e)
console.log(`[${this.getDate().white.bold}] ${`ERROR<${this.name}>`.bgRed.bold}`, e.message);
if (e.stack && stack) this.trail(e.stack);
}
public warn(...args: string[]) {
if (Logger.VERBOSE_LEVEL < VerboseLevel.WARNS) return;
this.logger.format = format.printf(({ message }) => {
return `[${this.getDate()}] <${this.name}> ${message}`;
});
this.logger.warn(...args as [string, ...string[]])
console.log(`[${this.getDate().white.bold}] ${`WARN<${this.name}>`.bgYellow.bold}`, ...args);
}
public debug(...args: any) {
if (Logger.VERBOSE_LEVEL < VerboseLevel.ALL) return;
this.logger.format = format.printf(({ message }) => {
return `[${this.getDate()}] ${`DEBUG<${this.name}>`} ${message}`;
});
this.logger.debug(...args as [string, ...string[]])
console.log(`[${this.getDate().white.bold}] ${`DEBUG<${this.name}>`.bgBlue.bold}`, ...args);
this.trail(new Error().stack!.split('\n').slice(2).join('\n'));
}
public verbL(...args: any) {
if (Logger.VERBOSE_LEVEL < VerboseLevel.VERBL) return;
this.logger.format = format.printf(({ message }) => {
return `[${this.getDate()}] ${`VERBL<${this.name}>`} ${message}`;
});
this.logger.info(...args as [string, ...string[]])
console.log(`[${this.getDate().white.bold}] ${`VERBL<${this.name}>`.bgCyan.bold}`, ...args);
this.trail(new Error().stack!.split('\n').slice(2).join('\n'));
}
public verbH(...args: any) {
if (Logger.VERBOSE_LEVEL < VerboseLevel.VERBH) return;
this.logger.format = format.printf(({ message }) => {
return `[${this.getDate()}] ${`VERBH<${this.name}>`} ${message}`;
});
this.logger.info(...args as [string, ...string[]])
console.log(`[${this.getDate().white.bold}] ${`VERBH<${this.name}>`.bgCyan.bold}`, ...args);
this.trail(new Error().stack!.split('\n').slice(2).join('\n'));
}
}
+145
View File
@@ -0,0 +1,145 @@
// import from jtw 🤤
// all log comments here r for debug dont remove
import readline from 'readline'
import Logger from './Logger'
import { ConsoleCommandData } from '../types/Command'
import fs from 'fs'
var c = new Logger("COMMAND", "yellow")
const rl = readline.createInterface({
input: process.stdin as unknown as NodeJS.ReadableStream,
output: process.stdout as unknown as NodeJS.WritableStream
})
const originalWrite = process.stdout.write.bind(process.stdout)
let inWritePatch = false
process.stdout.write = (chunk: any, encoding?: any, cb?: any) => {
if (inWritePatch) {
// Don't recurse
return originalWrite(chunk, encoding, cb)
}
inWritePatch = true
try {
readline.clearLine(process.stdout as unknown as NodeJS.WritableStream, 0)
readline.cursorTo(process.stdout as unknown as NodeJS.WritableStream, 0)
const result = originalWrite(chunk, encoding, cb)
rl.prompt(true)
return result
} finally {
inWritePatch = false
}
}
// helper
export function splitStr(q: string): Array<string> {
return q.split(" ")
}
// clears last printed line
// right now this just prints another line...
export function removeLine() {
readline.moveCursor(process.stdout as unknown as NodeJS.WritableStream, 0, -1)
readline.clearLine(process.stdout as unknown as NodeJS.WritableStream, 1)
}
// repeat
export function Prompt() {
rl.prompt()
rl.once("line", async (cmd) => {
if (!cmd.trim()) {
Prompt()
} else {
await HandlePrompt(splitStr(cmd.trim()))
Prompt()
}
})
}
export const Clear: string = "$clear"
export var CommandAliases: ConsoleCommandData[] = []
export var CommandFiles: string[] = []
export var AllFilesProcessed: boolean = false
export var AllAliasesProcessed: boolean = false
export async function HandlePrompt(args: Array<string>) {
let inputName = args[0].toLowerCase()
let cmdArgs: Array<string> = args.slice(1)
let error = false
c.log(`${process.cwd()}`)
try {
let cs = new Logger(`CLIENT/${inputName}.js+resp`)
c.log(`${inputName} ${cmdArgs.join(' ')}`)
const directoryPath = process.cwd() + '/output/src/console_commands'; // Replace with your directory path
try {
const files = fs.readdirSync(directoryPath, 'utf-8');
//c.log(`HI ${files[0]}`)
if (!AllFilesProcessed)
for (let i = 0; i < files.length; i++) {
var file = files[i]
let check = true
for (var file2 in CommandFiles)
if (file2.includes(file))
check = false
if (!file.includes('.map') && check) {
//c.log(file)
CommandFiles.push(file.replace(".ts", ".js"))
//c.log(`${file}`)
}
}
AllFilesProcessed = true
//c.log(CommandFiles.length.toString() + " CommandFile")
} catch (err) {
console.error('Error reading directory:', err);
}
if (!AllAliasesProcessed)
for (let i = 0; i < CommandFiles.length; i++) {
var CommandFile = CommandFiles[i]
const file: ConsoleCommandData = require(`${process.cwd()}/output/src/console_commands/${CommandFile}`).metadata
//c.log(file.name)
if (file.aliases)
CommandAliases.push(file)
AllAliasesProcessed = true
}
for (let i = 0; i < CommandAliases.length; i++) {
const cmd = CommandAliases[i];
if (cmd.aliases) {
//c.log('checked aaa')
for (let i = 0; i < cmd.aliases.length; i++) {
var alias = cmd.aliases[i]
//c.log(alias)
if (alias.includes(inputName))
inputName = cmd.name
}
}
}
//c.log(CommandAliases.length.toString() + " Alias")
let response = await require(`${process.cwd()}/output/src/console_commands/${inputName}.js`).Main(cmdArgs)
if (response === Clear)
console.clear()
else if (response == 0 || response == 1)
"" // do nothing, an error occured.
else
cs.log(response)
} catch (err) {
//@ts-ignore
if (err.toString().includes("Cannot find module"))
c.log(`Command ${inputName} not found.`)
else
c.error(`${err}`)
}
}
+20
View File
@@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "esnext",
"module": "NodeNext",
"sourceMap": true,
"experimentalDecorators": true,
"rootDir": "./",
"outDir": "output",
"strict": true,
"moduleResolution":"nodenext",
"noImplicitAny": true,
"esModuleInterop": true,
"noImplicitThis": false,
"resolveJsonModule":true,
"strictNullChecks":false,
"noImplicitReturns":false,
"skipLibCheck": true
},
"exclude": ["node_modules"]
}