Fix memory issues and insert unhinged comments
This commit is contained in:
parent
8ab74266e2
commit
828443cb93
|
@ -7,6 +7,11 @@ import { ChannelList } from "./ChannelList";
|
|||
|
||||
const logger = new Logger("Channel Forceloader");
|
||||
|
||||
/**
|
||||
* Forceloads a channel
|
||||
* @param id The channel ID
|
||||
* @returns Whether the channel was loaded
|
||||
*/
|
||||
export function forceloadChannel(id: string) {
|
||||
try {
|
||||
logger.info("Forceloading", id);
|
||||
|
@ -17,6 +22,11 @@ export function forceloadChannel(id: string) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unforceloads a channel
|
||||
* @param id The channel ID
|
||||
* @returns Whether the channel was unloaded
|
||||
*/
|
||||
export function unforceloadChannel(id: string) {
|
||||
const ch = ChannelList.getList().find(ch => ch.getID() == id);
|
||||
if (!ch) return false;
|
||||
|
@ -27,6 +37,10 @@ export function unforceloadChannel(id: string) {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forceloads all forceload-configured channels
|
||||
* This is meant to be called on startup
|
||||
**/
|
||||
export function loadForcedStartupChannels() {
|
||||
let hasFullChannel = false;
|
||||
|
||||
|
|
32
src/index.ts
32
src/index.ts
|
@ -4,15 +4,47 @@
|
|||
* by Hri7566
|
||||
*/
|
||||
|
||||
// There are a lot of unhinged bs comments in this repo
|
||||
// Pay no attention to the ones that cuss you out
|
||||
|
||||
// If you don't load the server first, bun will literally segfault
|
||||
import "./ws/server";
|
||||
import { loadForcedStartupChannels } from "./channel/forceLoad";
|
||||
import { Logger } from "./util/Logger";
|
||||
|
||||
// Let's construct an entire object just for one thing to be printed
|
||||
// and then keep it in memory for the entirety of runtime
|
||||
const logger = new Logger("Main");
|
||||
logger.info("Forceloading startup channels...");
|
||||
loadForcedStartupChannels();
|
||||
|
||||
// This literally breaks editors and they stick all the imports here instead of at the top
|
||||
import "./util/readline";
|
||||
import { Socket, socketsBySocketID } from "./ws/Socket";
|
||||
import { createSocketID } from "./util/id";
|
||||
|
||||
// Nevermind we use it twice
|
||||
logger.info("Ready");
|
||||
|
||||
// Connect 5 sockets
|
||||
const sockets = [];
|
||||
|
||||
for (let i = 0; i < 5; i++) {
|
||||
setTimeout(() => {
|
||||
const socket = new Socket(undefined, createSocketID());
|
||||
|
||||
socket.on("ready", () => {
|
||||
logger.info(`Socket ${i} is ready`);
|
||||
});
|
||||
|
||||
socket.setChannel("lobby");
|
||||
|
||||
sockets.push(socket);
|
||||
|
||||
if (socket.socketID == undefined) {
|
||||
socket.socketID = createSocketID();
|
||||
}
|
||||
|
||||
socketsBySocketID.set(socket.socketID, socket);
|
||||
}, i * 5000);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
import { padNum, unimportant } from "./helpers";
|
||||
|
||||
/**
|
||||
* A logger that doesn't fuck with the readline prompt
|
||||
* timestamps are likely wrong because of js timezones
|
||||
**/
|
||||
export class Logger {
|
||||
private static log(method: string, ...args: any[]) {
|
||||
// Clear current line
|
||||
// Un-fuck the readline prompt
|
||||
process.stdout.write("\x1b[2K\r");
|
||||
|
||||
// Log our stuff
|
||||
// Log
|
||||
(console as unknown as Record<string, (..._args: any[]) => any>)[
|
||||
method
|
||||
](
|
||||
|
@ -14,7 +18,7 @@ export class Logger {
|
|||
...args
|
||||
);
|
||||
|
||||
// Fix the readline prompt (spooky cringe code)
|
||||
// Re-print the readline prompt (spooky cringe global variable)
|
||||
if ((globalThis as unknown as any).rl)
|
||||
(globalThis as unknown as any).rl.prompt();
|
||||
}
|
||||
|
@ -38,7 +42,7 @@ export class Logger {
|
|||
return new Date().toISOString().split("T")[0];
|
||||
}
|
||||
|
||||
constructor(public id: string) {}
|
||||
constructor(public id: string) { }
|
||||
|
||||
public info(...args: any[]) {
|
||||
Logger.log("log", `[${this.id}]`, `\x1b[34m[info]\x1b[0m`, ...args);
|
||||
|
|
|
@ -1,9 +1,20 @@
|
|||
// Gray console text
|
||||
/**
|
||||
* Gray console text maker
|
||||
* @param str String to gray
|
||||
* @returns Gray string to put in console
|
||||
**/
|
||||
export function unimportant(str: string) {
|
||||
return `\x1b[90m${str}\x1b[0m`;
|
||||
}
|
||||
|
||||
// Pad time strings
|
||||
/**
|
||||
* Pad time strings
|
||||
* @param num Number to pad
|
||||
* @param padAmount Amount of padding
|
||||
* @param padChar Character to pad with
|
||||
* @param left Whether to pad left or right
|
||||
* @returns Padded string
|
||||
**/
|
||||
export function padNum(
|
||||
num: number,
|
||||
padAmount: number,
|
||||
|
@ -21,6 +32,9 @@ export const encoder = new TextEncoder();
|
|||
|
||||
/**
|
||||
* Check if an object has a property
|
||||
* @param obj Object to check
|
||||
* @param property Property to check
|
||||
* @returns Whether the object has the property
|
||||
**/
|
||||
export function hasOwn(obj: any, property: string | number | Symbol) {
|
||||
return (Object as unknown as any).hasOwn(obj, property);
|
||||
|
@ -47,7 +61,15 @@ export function darken(color: string, amount = 0x40) {
|
|||
|
||||
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
|
||||
}
|
||||
// Brandon made this literally eons ago and it's fucking hilarious
|
||||
|
||||
// spooky.jsaurus
|
||||
// NOT the same as poop_text
|
||||
|
||||
/**
|
||||
* Make text spoopy
|
||||
* @param message Message to spoop
|
||||
* @returns Spooped message
|
||||
**/
|
||||
export function spoop_text(message: string) {
|
||||
var old = message;
|
||||
message = "";
|
||||
|
@ -64,6 +86,11 @@ export function spoop_text(message: string) {
|
|||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix two objects
|
||||
* @param obj1 Object to mix into
|
||||
* @param obj2 Object to mix
|
||||
**/
|
||||
export function mixin(obj1: any, obj2: any) {
|
||||
for (const key of Object.keys(obj2)) {
|
||||
obj1[key] = obj2[key];
|
||||
|
|
|
@ -75,3 +75,49 @@ Command.addCommand(
|
|||
}
|
||||
})
|
||||
);
|
||||
|
||||
Command.addCommand(
|
||||
new Command(["js", "eval"], "js <code>", async msg => {
|
||||
function roughSizeOfObject(object: any) {
|
||||
const objectList: any[] = [];
|
||||
const stack = [object];
|
||||
let bytes = 0;
|
||||
|
||||
while (stack.length) {
|
||||
const value = stack.pop();
|
||||
|
||||
switch (typeof value) {
|
||||
case 'boolean':
|
||||
bytes += 4;
|
||||
break;
|
||||
case 'string':
|
||||
bytes += value.length * 2;
|
||||
break;
|
||||
case 'number':
|
||||
bytes += 8;
|
||||
break;
|
||||
case 'object':
|
||||
if (!objectList.includes(value)) {
|
||||
objectList.push(value);
|
||||
for (const prop in value) {
|
||||
if (value.hasOwnProperty(prop)) {
|
||||
stack.push(value[prop]);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
if (msg.args.length > 1) {
|
||||
try {
|
||||
const output = eval(msg.args[1]);
|
||||
return output;
|
||||
} catch (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
|
|
@ -36,6 +36,11 @@ const logger = new Logger("Sockets");
|
|||
|
||||
type CursorValue = string | number;
|
||||
|
||||
/**
|
||||
* Extended websocket thing
|
||||
* Most poeple call this "Client" but it's not on the client...
|
||||
* This is likely the source of my memory leaks
|
||||
**/
|
||||
export class Socket extends EventEmitter {
|
||||
private id: string;
|
||||
private _id: string;
|
||||
|
@ -65,6 +70,7 @@ export class Socket extends EventEmitter {
|
|||
) {
|
||||
super();
|
||||
|
||||
// real user?
|
||||
if (ws) {
|
||||
// Real user
|
||||
this.ip = ws.data.ip;
|
||||
|
@ -82,13 +88,18 @@ export class Socket extends EventEmitter {
|
|||
let foundSocket;
|
||||
let count = 0;
|
||||
|
||||
// big boi loop
|
||||
for (const socket of socketsBySocketID.values()) {
|
||||
// Skip us
|
||||
if (socket.socketID == this.socketID) continue;
|
||||
|
||||
// Are they real?
|
||||
if (socket.ws) {
|
||||
// Are they connected?
|
||||
if (socket.ws.readyState !== 1) continue;
|
||||
}
|
||||
|
||||
// Same user ID?
|
||||
if (socket.getUserID() == this.getUserID()) {
|
||||
foundSocket = socket;
|
||||
count++;
|
||||
|
@ -96,11 +107,14 @@ export class Socket extends EventEmitter {
|
|||
}
|
||||
|
||||
if (count >= 4) {
|
||||
// Too many go away
|
||||
this.destroy();
|
||||
}
|
||||
|
||||
// logger.debug("Found socket?", foundSocket);
|
||||
|
||||
// If there is another socket, use their ID for some reason I forgot
|
||||
// otherwise, make a new one
|
||||
if (!foundSocket) {
|
||||
// Use new session ID
|
||||
this.id = createID();
|
||||
|
@ -109,18 +123,24 @@ export class Socket extends EventEmitter {
|
|||
this.id = foundSocket.id;
|
||||
|
||||
// Break us off
|
||||
// didn't work nvm
|
||||
//this.id = "broken";
|
||||
//this.destroy();
|
||||
}
|
||||
|
||||
// Load stuff
|
||||
(async () => {
|
||||
// Load our user data
|
||||
await this.loadUser();
|
||||
|
||||
// Set our rate limits
|
||||
this.resetRateLimits();
|
||||
this.setNoteQuota(NoteQuota.PARAMS_RIDICULOUS);
|
||||
|
||||
// Bind a bunch of our event listeners so we do stuff when told to
|
||||
this.bindEventListeners();
|
||||
|
||||
// Send a challenge to the browser for MPP.net frontends
|
||||
if (config.browserChallenge == "basic") {
|
||||
this.sendArray([{
|
||||
m: "b",
|
||||
|
@ -131,6 +151,7 @@ export class Socket extends EventEmitter {
|
|||
}
|
||||
})();
|
||||
|
||||
// all done
|
||||
this.emit("ready");
|
||||
}
|
||||
|
||||
|
@ -143,7 +164,7 @@ export class Socket extends EventEmitter {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the user ID of this socket
|
||||
* Get the user ID (_id) of this socket
|
||||
* @returns User ID
|
||||
**/
|
||||
public getUserID() {
|
||||
|
@ -151,7 +172,7 @@ export class Socket extends EventEmitter {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the participant ID of this socket
|
||||
* Get the participant ID (id) of this socket
|
||||
* @returns Participant ID
|
||||
**/
|
||||
public getParticipantID() {
|
||||
|
@ -744,6 +765,9 @@ export class Socket extends EventEmitter {
|
|||
|
||||
/**
|
||||
* Ban this socket's user for doing bad things
|
||||
* this doesn't actually ban the user, it just sends a notification right now FIXME
|
||||
* @param duration Duration of the ban in milliseconds
|
||||
* @param reason Reason for the ban
|
||||
**/
|
||||
public ban(duration: number, reason: string) {
|
||||
// TODO cleaner ban system
|
||||
|
@ -763,13 +787,26 @@ export class Socket extends EventEmitter {
|
|||
}
|
||||
|
||||
export const socketsBySocketID = new Map<string, Socket>();
|
||||
(globalThis as any).socketsBySocketID = socketsBySocketID;
|
||||
|
||||
/**
|
||||
* Find a socket by their participant ID
|
||||
* bad don't use for unique sockets
|
||||
* @param id Participant ID to find
|
||||
* @returns Socket object
|
||||
**/
|
||||
export function findSocketByPartID(id: string) {
|
||||
for (const socket of socketsBySocketID.values()) {
|
||||
if (socket.getParticipantID() == id) return socket;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all sockets by their user ID
|
||||
* also not unique
|
||||
* @param _id User ID to find
|
||||
* @returns Socket objects
|
||||
**/
|
||||
export function findSocketsByUserID(_id: string) {
|
||||
const sockets = [];
|
||||
|
||||
|
@ -781,6 +818,12 @@ export function findSocketsByUserID(_id: string) {
|
|||
return sockets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a socket by their IP
|
||||
* probably not unique if they're on different tabs
|
||||
* @param ip IP to find
|
||||
* @returns Socket object
|
||||
**/
|
||||
export function findSocketByIP(ip: string) {
|
||||
for (const socket of socketsBySocketID.values()) {
|
||||
if (socket.getIP() == ip) {
|
||||
|
|
|
@ -22,18 +22,18 @@ export const adminLimits: RateLimitConstructorList = {
|
|||
chains: {
|
||||
userset: () =>
|
||||
new RateLimitChain(
|
||||
config.admin.chains.userset.interval,
|
||||
config.admin.chains.userset.num
|
||||
config.admin.chains.userset.num,
|
||||
config.admin.chains.userset.interval
|
||||
),
|
||||
chset: () =>
|
||||
new RateLimitChain(
|
||||
config.admin.chains.chset.interval,
|
||||
config.admin.chains.userset.num
|
||||
config.admin.chains.chset.num,
|
||||
config.admin.chains.userset.interval
|
||||
),
|
||||
n: () =>
|
||||
new RateLimitChain(
|
||||
config.admin.chains.n.interval,
|
||||
config.admin.chains.userset.num
|
||||
config.admin.chains.n.num,
|
||||
config.admin.chains.userset.interval
|
||||
)
|
||||
}
|
||||
};
|
||||
|
|
|
@ -22,18 +22,18 @@ export const crownLimits: RateLimitConstructorList = {
|
|||
chains: {
|
||||
userset: () =>
|
||||
new RateLimitChain(
|
||||
config.crown.chains.userset.interval,
|
||||
config.crown.chains.userset.num
|
||||
config.crown.chains.userset.num,
|
||||
config.crown.chains.userset.interval
|
||||
),
|
||||
chset: () =>
|
||||
new RateLimitChain(
|
||||
config.crown.chains.chset.interval,
|
||||
config.crown.chains.userset.num
|
||||
config.crown.chains.chset.num,
|
||||
config.crown.chains.userset.interval
|
||||
),
|
||||
n: () =>
|
||||
new RateLimitChain(
|
||||
config.crown.chains.n.interval,
|
||||
config.crown.chains.userset.num
|
||||
config.crown.chains.n.num,
|
||||
config.crown.chains.userset.interval
|
||||
)
|
||||
}
|
||||
};
|
||||
|
|
|
@ -22,18 +22,18 @@ export const userLimits: RateLimitConstructorList = {
|
|||
chains: {
|
||||
userset: () =>
|
||||
new RateLimitChain(
|
||||
config.user.chains.userset.interval,
|
||||
config.user.chains.userset.num
|
||||
config.user.chains.userset.num,
|
||||
config.user.chains.userset.interval
|
||||
),
|
||||
chset: () =>
|
||||
new RateLimitChain(
|
||||
config.user.chains.chset.interval,
|
||||
config.user.chains.userset.num
|
||||
config.user.chains.chset.num,
|
||||
config.user.chains.userset.interval
|
||||
),
|
||||
n: () =>
|
||||
new RateLimitChain(
|
||||
config.user.chains.n.interval,
|
||||
config.user.chains.userset.num
|
||||
config.user.chains.n.num,
|
||||
config.user.chains.userset.interval
|
||||
)
|
||||
}
|
||||
};
|
||||
|
|
|
@ -19,6 +19,8 @@ async function getIndex() {
|
|||
// nobody realistically uses templates in 2024 and documents
|
||||
// it well enough to say what library they used
|
||||
|
||||
// I totally forget if this even works
|
||||
|
||||
const index = Bun.file("./public/index.html");
|
||||
|
||||
const rendered = nunjucks.renderString(await index.text(), {
|
||||
|
@ -91,11 +93,15 @@ export const app = Bun.serve<{ ip: string }>({
|
|||
// logger.debug("Connection at " + socket.getIP());
|
||||
|
||||
// Let's put it in the dinner bucket.
|
||||
socketsBySocketID.set((socket.socketID as any), socket);
|
||||
if (socket.socketID == undefined) {
|
||||
socket.socketID = createSocketID();
|
||||
}
|
||||
|
||||
socketsBySocketID.set(socket.socketID, socket);
|
||||
},
|
||||
|
||||
message: (ws, message) => {
|
||||
// "Let's make it binary" said all websocket developers for some reason
|
||||
// Fucking string
|
||||
const msg = message.toString();
|
||||
|
||||
// Let's find out wtf they even sent
|
||||
|
@ -103,8 +109,6 @@ export const app = Bun.serve<{ ip: string }>({
|
|||
},
|
||||
|
||||
close: (ws, code, message) => {
|
||||
// logger.debug("Close called");
|
||||
|
||||
// This usually gets called when someone leaves,
|
||||
// but it's also used internally just in case
|
||||
// some dickhead can't close their tab like a
|
||||
|
|
Loading…
Reference in New Issue