forked from Hri7566/mpp-server-dev2
Update everything
This commit is contained in:
parent
8644f3787e
commit
275ad3823f
|
@ -16,3 +16,8 @@ model User {
|
|||
color String @default("#ffffff")
|
||||
flags String @default("{}") // JSON flags object
|
||||
}
|
||||
|
||||
model ChatHistory {
|
||||
id String @id @unique @map("_id")
|
||||
messages String @default("[]") // JSON messages
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import {
|
|||
ServerEvents,
|
||||
IChannelInfo
|
||||
} from "../util/types";
|
||||
import { Socket } from "../ws/Socket";
|
||||
import type { Socket } from "../ws/Socket";
|
||||
import { validateChannelSettings } from "./settings";
|
||||
import { findSocketByPartID, socketsBySocketID } from "../ws/Socket";
|
||||
import Crown from "./Crown";
|
||||
|
@ -185,8 +185,6 @@ export class Channel extends EventEmitter {
|
|||
(typeof set.color2 == "undefined" ||
|
||||
set.color2 === this.settings.color2)
|
||||
) {
|
||||
this.logger.debug("Setting color 2 from first color:", set.color);
|
||||
this.logger.debug("Red:", parseInt(set.color.substring(1, 2), 16));
|
||||
const r = Math.max(
|
||||
0,
|
||||
parseInt(set.color.substring(1, 3), 16) - 0x40
|
||||
|
@ -201,7 +199,6 @@ export class Channel extends EventEmitter {
|
|||
);
|
||||
|
||||
set.color2 = `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
|
||||
this.logger.debug("Color 2 is now:", set.color2);
|
||||
}
|
||||
|
||||
if (this.isLobby() && !admin) return;
|
||||
|
|
|
@ -2,6 +2,7 @@ import { type Socket, findSocketByPartID } from "../ws/Socket";
|
|||
import type Channel from "./Channel";
|
||||
|
||||
const onChannelUpdate = (channel: Channel) => {
|
||||
// If this shit ever manages to handle over 10 people I'd be impressed
|
||||
const info = channel.getInfo();
|
||||
// const ppl = channel.getParticipantList();
|
||||
if (info.settings.visible !== true) return;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Participant, Vector2 } from "../util/types";
|
||||
import { Socket } from "../ws/Socket";
|
||||
|
||||
// shiny hat
|
||||
export class Crown {
|
||||
public userId: string | undefined;
|
||||
public participantId: string | undefined;
|
||||
|
|
|
@ -27,6 +27,7 @@ export const config = loadConfig<ChannelConfig>("config/channels.yml", {
|
|||
color2: "#001014",
|
||||
visible: true
|
||||
},
|
||||
// Here's a terrifying fact: Brandon used parseInt to check lobby names in the OG server code
|
||||
lobbyRegexes: ["^lobby[0-9][0-9]$", "^lobby[1-9]$", "^test/.+$"],
|
||||
lobbyBackdoor: "lolwutsecretlobbybackdoor",
|
||||
fullChannel: "test/awkward"
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { Channel } from "./Channel";
|
||||
import { config } from "./config";
|
||||
|
||||
// This shit was moved here to try to fix the unit tests segfaulting but it didn't work
|
||||
|
||||
// Channel forceloader (cringe)
|
||||
let hasFullChannel = false;
|
||||
|
||||
|
|
|
@ -4,4 +4,6 @@ import validateChannelSettings, {
|
|||
validate as validateChannelSetting
|
||||
} from "./settings";
|
||||
|
||||
// I don't even know if I bothered to use this file
|
||||
|
||||
export { Channel, Crown, validateChannelSettings, validateChannelSetting };
|
||||
|
|
|
@ -3,6 +3,8 @@ import { IChannelSettings } from "../util/types";
|
|||
|
||||
type Validator = "boolean" | "string" | "number" | ((val: unknown) => boolean);
|
||||
|
||||
// This record contains the exact data Brandon used to check channel settings, down to the regex.
|
||||
// It also contains things that might be useful to other people in the future (things that make me vomit)
|
||||
const validationRecord: Record<keyof IChannelSettings, Validator> = {
|
||||
// Brandon
|
||||
lobby: "boolean",
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* by Hri7566
|
||||
*/
|
||||
|
||||
// If you don't load the server first, bun will literally segfault
|
||||
import "./ws/server";
|
||||
import "./channel/forceLoad";
|
||||
import { Logger } from "./util/Logger";
|
||||
|
@ -12,4 +13,5 @@ const logger = new Logger("Main");
|
|||
|
||||
import "./util/readline";
|
||||
|
||||
// Does this really even need to be here?
|
||||
logger.info("Ready");
|
||||
|
|
|
@ -14,7 +14,7 @@ export class Logger {
|
|||
...args
|
||||
);
|
||||
|
||||
// Fix the readline prompt (spooky code)
|
||||
// Fix the readline prompt (spooky cringe code)
|
||||
if ((globalThis as unknown as any).rl)
|
||||
(globalThis as unknown as any).rl.prompt();
|
||||
}
|
||||
|
|
|
@ -2,6 +2,16 @@ import { existsSync, readFileSync, writeFileSync } from "fs";
|
|||
import { parse, stringify } from "yaml";
|
||||
import { z } from "zod";
|
||||
|
||||
/**
|
||||
* This file uses the synchronous functions from the fs
|
||||
* module because these functions should only be used
|
||||
* to load configs at the beginning of runtime
|
||||
*
|
||||
* Hint: This means you shouldn't load configs in the
|
||||
* middle of doing other shit, only when you start the
|
||||
* program.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Load a YAML config file and set default values if config path is nonexistent
|
||||
*
|
||||
|
@ -64,6 +74,7 @@ export function loadConfig<T>(configPath: string, defaultConfig: T): T {
|
|||
* @param config
|
||||
*/
|
||||
export function writeConfig<T>(configPath: string, config: T) {
|
||||
// Write config to disk unconditionally
|
||||
writeFileSync(
|
||||
configPath,
|
||||
stringify(config, {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { createEnv } from "@t3-oss/env-core";
|
||||
import { z } from "zod";
|
||||
|
||||
// Best way to do env ever
|
||||
export const env = createEnv({
|
||||
server: {
|
||||
PORT: z.coerce.number(),
|
||||
|
@ -9,6 +10,7 @@ export const env = createEnv({
|
|||
ADMIN_PASS: z.string()
|
||||
},
|
||||
isServer: true,
|
||||
// Bun loads process.env automatically so we don't have to use modules
|
||||
runtimeEnv: process.env
|
||||
});
|
||||
|
||||
|
|
|
@ -40,3 +40,20 @@ export function darken(hex: string) {
|
|||
.padStart(2, "0")}${newB.toString(16).padStart(2, "0")}`;
|
||||
} catch (err) {}
|
||||
}
|
||||
|
||||
// Brandon made this literally eons ago and it's fucking hilarious
|
||||
export function spoop_text(message: string) {
|
||||
var old = message;
|
||||
message = "";
|
||||
for (var i = 0; i < old.length; i++) {
|
||||
if (Math.random() < 0.9) {
|
||||
message += String.fromCharCode(
|
||||
old.charCodeAt(i) + Math.floor(Math.random() * 20 - 10)
|
||||
);
|
||||
//message[i] = String.fromCharCode(Math.floor(Math.random() * 255));
|
||||
} else {
|
||||
message += old[i];
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,24 @@
|
|||
import { createHash, randomBytes } from "crypto";
|
||||
import env from "./env";
|
||||
import { spoop_text } from "./helpers";
|
||||
|
||||
export function createID() {
|
||||
return randomBytes(12).toString("hex");
|
||||
// Maybe I could make this funnier than it needs to be...
|
||||
// return randomBytes(12).toString("hex");
|
||||
|
||||
let weirdness = "";
|
||||
while (weirdness.length < 24) {
|
||||
const time = new Date().toString();
|
||||
const randomShit = spoop_text(time); // looks like this: We]%Cau&:,\u0018403*"32>8,B15&GP[2)='7\u0019-@etyhlw\u0017QqXqiime&Khhe-
|
||||
|
||||
let index1 = Math.floor(Math.random() * randomShit.length);
|
||||
let index2 = Math.floor(Math.random() * randomShit.length);
|
||||
|
||||
weirdness += randomShit.substring(index1, index2);
|
||||
}
|
||||
|
||||
// Get 12 bytes
|
||||
return Buffer.from(weirdness.substring(0, 12)).toString("hex");
|
||||
}
|
||||
|
||||
export function createUserID(ip: string) {
|
||||
|
@ -25,6 +41,6 @@ export function createColor(ip: string) {
|
|||
.update(env.SALT)
|
||||
.update("color")
|
||||
.digest("hex")
|
||||
.substring(0, 6)
|
||||
.substring(0, 24 + 6)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// bruh
|
||||
export function getMOTD() {
|
||||
return "This site makes a lot of sound! You may want to adjust the volume before continuing.";
|
||||
}
|
||||
|
|
|
@ -21,4 +21,5 @@ rl.on("SIGINT", () => {
|
|||
process.exit();
|
||||
});
|
||||
|
||||
// Fucking cringe but it works
|
||||
(globalThis as unknown as any).rl = rl;
|
||||
|
|
|
@ -1,5 +1,18 @@
|
|||
/**
|
||||
* Typedefs
|
||||
*/
|
||||
|
||||
import { Socket } from "../ws/Socket";
|
||||
|
||||
/**
|
||||
* Halfway through this file, the same types have appeared again
|
||||
*
|
||||
* I am not a decent enough person to go looking down there, so
|
||||
* good luck when you get there. Somehow I forgot what is even
|
||||
* in this file, so don't come and ask me why something isn't
|
||||
* defined correctly here.
|
||||
*/
|
||||
|
||||
declare type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
||||
|
||||
declare type UserFlags = Partial<{
|
||||
|
|
|
@ -1,3 +1,16 @@
|
|||
/**
|
||||
* I made this thing to keep track of what sockets
|
||||
* have and haven't done yet so we know if they
|
||||
* should be doing certain things.
|
||||
*
|
||||
* For instance, being logged in in the first place,
|
||||
* or if they're on shitty McDonalds WiFi and they
|
||||
* lost connection for over a minute, or if they
|
||||
* decided that they're going to put their browser
|
||||
* in a chokehold and force it to load weird shit...
|
||||
* or, you know, maybe I could log their user agent
|
||||
* and IP address instead sometime in the future.
|
||||
*/
|
||||
export class Gateway {
|
||||
public hasProcessedHi: boolean = false;
|
||||
public hasSentDevices: boolean = false;
|
||||
|
|
|
@ -15,7 +15,7 @@ import {
|
|||
UserFlags,
|
||||
Vector2
|
||||
} from "../util/types";
|
||||
import { User } from "@prisma/client";
|
||||
import type { User } from "@prisma/client";
|
||||
import { createUser, readUser, updateUser } from "../data/user";
|
||||
import { eventGroups } from "./events";
|
||||
import { Gateway } from "./Gateway";
|
||||
|
@ -55,10 +55,7 @@ export class Socket extends EventEmitter {
|
|||
public currentChannelID: string | undefined;
|
||||
private cursorPos: Vector2<CursorValue> = { x: 200, y: 100 };
|
||||
|
||||
constructor(
|
||||
private ws: ServerWebSocket<unknown>,
|
||||
public socketID: string
|
||||
) {
|
||||
constructor(private ws: ServerWebSocket<unknown>, public socketID: string) {
|
||||
super();
|
||||
this.ip = ws.remoteAddress; // Participant ID
|
||||
|
||||
|
@ -432,6 +429,22 @@ export class Socket extends EventEmitter {
|
|||
}
|
||||
]);
|
||||
}
|
||||
|
||||
public isOwner() {
|
||||
const channel = this.getCurrentChannel();
|
||||
const part = this.getParticipant();
|
||||
|
||||
// this looks cool
|
||||
if (!channel) return false;
|
||||
if (!channel.crown) return false;
|
||||
if (!channel.crown.userId) return false;
|
||||
if (!channel.crown.participantId) return false;
|
||||
if (!part) return;
|
||||
if (!part.id) return;
|
||||
if (channel.crown.participantId !== part.id) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export const socketsBySocketID = new Map<string, Socket>();
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
// Bun hoists import so we are kinda forced to use require here...
|
||||
// Maybe bun should have a setting for that :/
|
||||
|
||||
// This feels really dirty and months have passed... guess who's fixing it?
|
||||
// Nobody is. It's going to stay like this.
|
||||
|
||||
require("./events/user");
|
||||
require("./events/admin");
|
||||
|
|
|
@ -8,6 +8,10 @@ export class EventGroup {
|
|||
this.eventList.push(listener);
|
||||
}
|
||||
|
||||
public addMany(...listeners: ServerEventListener<any>[]) {
|
||||
listeners.forEach(l => this.add(l));
|
||||
}
|
||||
|
||||
public remove(listener: ServerEventListener<any>) {
|
||||
this.eventList.splice(this.eventList.indexOf(listener), 1);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import { findSocketsByUserID } from "../../../Socket";
|
|||
export const color: ServerEventListener<"color"> = {
|
||||
id: "color",
|
||||
callback: async (msg, socket) => {
|
||||
// TODO color
|
||||
// I'm not allowed to use this feature on MPP.net for a really stupid reason
|
||||
const id = msg._id;
|
||||
const color = msg.color;
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import { findSocketsByUserID } from "../../../Socket";
|
|||
export const name: ServerEventListener<"name"> = {
|
||||
id: "name",
|
||||
callback: async (msg, socket) => {
|
||||
// Change someone else's name but it's an annoying admin feature
|
||||
const id = msg._id;
|
||||
const name = msg.name;
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import { findSocketsByUserID } from "../../../Socket";
|
|||
export const user_flag: ServerEventListener<"user_flag"> = {
|
||||
id: "user_flag",
|
||||
callback: async (msg, socket) => {
|
||||
// User flag modification (changing some real specific shit)
|
||||
if (typeof msg._id !== "string") return;
|
||||
if (typeof msg.key !== "string") return;
|
||||
if (typeof msg.value == "undefined") return;
|
||||
|
|
|
@ -6,8 +6,10 @@ import { color } from "./handlers/color";
|
|||
import { name } from "./handlers/name";
|
||||
import { user_flag } from "./handlers/user_flag";
|
||||
|
||||
EVENT_GROUP_ADMIN.add(color);
|
||||
EVENT_GROUP_ADMIN.add(name);
|
||||
EVENT_GROUP_ADMIN.add(user_flag);
|
||||
// EVENT_GROUP_ADMIN.add(color);
|
||||
// EVENT_GROUP_ADMIN.add(name);
|
||||
// EVENT_GROUP_ADMIN.add(user_flag);
|
||||
|
||||
EVENT_GROUP_ADMIN.addMany(color, name, user_flag);
|
||||
|
||||
eventGroups.push(EVENT_GROUP_ADMIN);
|
||||
|
|
|
@ -3,6 +3,15 @@ import { ServerEventListener } from "../../../../util/types";
|
|||
export const plus_ls: ServerEventListener<"+ls"> = {
|
||||
id: "+ls",
|
||||
callback: (msg, socket) => {
|
||||
// Give us the latest news on literally everything
|
||||
// that's happening in the server. In fact, I want
|
||||
// to know when someone clicks a button instantly,
|
||||
// so I can stalk other users by watching the room
|
||||
// count go up somewhere else when I watch someone
|
||||
// leave the channel I'm reading their messages in
|
||||
// and when I see their cursor disappear I'll know
|
||||
// precisely where they went to follow them and to
|
||||
// annoy them in chat when I see them again.
|
||||
socket.subscribeToChannelList();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -3,6 +3,7 @@ import { ServerEventListener } from "../../../../util/types";
|
|||
export const minus_ls: ServerEventListener<"-ls"> = {
|
||||
id: "-ls",
|
||||
callback: (msg, socket) => {
|
||||
// Stop giving us the latest server forecast
|
||||
socket.unsubscribeFromChannelList();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -7,11 +7,15 @@ export const a: ServerEventListener<"a"> = {
|
|||
const flags = socket.getUserFlags();
|
||||
if (!flags) return;
|
||||
|
||||
// Why did I write this statement so weird
|
||||
if (!flags["no chat rate limit"] || flags["no chat rate limit"] == 0)
|
||||
if (!socket.rateLimits?.normal.a.attempt()) return;
|
||||
const ch = socket.getCurrentChannel();
|
||||
if (!ch) return;
|
||||
|
||||
// msg.m
|
||||
// Permission denied: msg.m
|
||||
// sudo msg.m
|
||||
ch.emit("message", msg, socket);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -11,6 +11,8 @@ export const admin_message: ServerEventListener<"admin message"> = {
|
|||
if (typeof msg.password !== "string") return;
|
||||
if (msg.password !== env.ADMIN_PASS) return;
|
||||
|
||||
// Probably shouldn't be using password auth in 2024
|
||||
// Maybe I'll setup a dashboard instead some day
|
||||
socket.admin.emit(msg.msg.m, msg.msg, socket, true);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -5,6 +5,8 @@ export const ch: ServerEventListener<"ch"> = {
|
|||
callback: (msg, socket) => {
|
||||
// Switch channel
|
||||
if (!msg._id) return;
|
||||
|
||||
// So technical and convoluted...
|
||||
socket.setChannel(msg._id, msg.set);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -5,8 +5,11 @@ export const chset: ServerEventListener<"chset"> = {
|
|||
callback: (msg, socket) => {
|
||||
// Change channel settings
|
||||
if (typeof msg.set == "undefined") return;
|
||||
|
||||
const ch = socket.getCurrentChannel();
|
||||
if (!ch) return;
|
||||
|
||||
// Edit room now
|
||||
ch.changeSettings(msg.set, false);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@ import { ServerEventListener } from "../../../../util/types";
|
|||
export const devices: ServerEventListener<"devices"> = {
|
||||
id: "devices",
|
||||
callback: (msg, socket) => {
|
||||
// List of MIDI Devices
|
||||
// List of MIDI Devices (or software ports, because nobody can tell the difference)
|
||||
if (socket.gateway.hasSentDevices) return;
|
||||
socket.gateway.hasSentDevices = true;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,9 @@ export const hi: ServerEventListener<"hi"> = {
|
|||
callback: (msg, socket) => {
|
||||
// Handshake message
|
||||
// TODO Hi message tokens
|
||||
// I'm not actually sure if I'm up for doing tokens,
|
||||
// but if someone wants to submit a pull request, I
|
||||
// look forward to watching you do all the work
|
||||
if (socket.gateway.hasProcessedHi) return;
|
||||
let part = socket.getParticipant();
|
||||
|
||||
|
|
|
@ -4,15 +4,18 @@ export const m: ServerEventListener<"m"> = {
|
|||
id: "m",
|
||||
callback: (msg, socket) => {
|
||||
// Cursor movement
|
||||
if (!socket.rateLimits?.normal.m.attempt()) return;
|
||||
if (!socket.rateLimits) return;
|
||||
if (!socket.rateLimits.normal.m.attempt()) return;
|
||||
if (!msg.x || !msg.y) return;
|
||||
|
||||
let x = msg.x;
|
||||
let y = msg.y;
|
||||
|
||||
// Make it numbers
|
||||
if (typeof msg.x == "string") x = parseFloat(msg.x);
|
||||
if (typeof msg.y == "string") y = parseFloat(msg.y);
|
||||
|
||||
// Move the laggy piece of shit
|
||||
socket.setCursorPos(x, y);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -8,6 +8,10 @@ export const n: ServerEventListener<"n"> = {
|
|||
if (!Array.isArray(msg.n)) return;
|
||||
if (typeof msg.t !== "number") return;
|
||||
|
||||
// This should've been here months ago
|
||||
const channel = socket.getCurrentChannel();
|
||||
if (!channel) return;
|
||||
|
||||
// Check note properties
|
||||
for (const n of msg.n) {
|
||||
if (typeof n.n != "string") return;
|
||||
|
@ -29,9 +33,15 @@ export const n: ServerEventListener<"n"> = {
|
|||
|
||||
let amount = msg.n.length;
|
||||
|
||||
// TODO Check crownsolo
|
||||
const crownsolo = channel.getSetting("crownsolo");
|
||||
|
||||
if ((crownsolo && socket.isOwner()) || !crownsolo) {
|
||||
// Shiny hat exists and we have shiny hat
|
||||
// or there is no shiny hat
|
||||
if (socket.noteQuota.spend(amount)) {
|
||||
// make noise
|
||||
socket.playNotes(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -8,6 +8,7 @@ export const t: ServerEventListener<"t"> = {
|
|||
if (typeof msg.e !== "number") return;
|
||||
}
|
||||
|
||||
// Pong!
|
||||
socket.sendArray([
|
||||
{
|
||||
m: "t",
|
||||
|
|
|
@ -5,6 +5,15 @@ export const userset: ServerEventListener<"userset"> = {
|
|||
callback: (msg, socket) => {
|
||||
// Change username/color
|
||||
if (!socket.rateLimits?.chains.userset.attempt()) return;
|
||||
// You can disable color in the config because
|
||||
// Brandon's/jacored's server doesn't allow color changes,
|
||||
// and that's the OG server, but folks over at MPP.net
|
||||
// said otherwise because they're dumb roleplayers
|
||||
// or something and don't understand the unique value
|
||||
// of the fishing bot and how it allows you to change colors
|
||||
// without much control, giving it the feeling of value...
|
||||
// Kinda reminds me of crypto.
|
||||
// Also, Brandon's server had color changing on before.
|
||||
if (!msg.set.name && !msg.set.color) return;
|
||||
socket.userset(msg.set.name, msg.set.color);
|
||||
}
|
||||
|
|
|
@ -14,16 +14,33 @@ import { minus_ls } from "./handlers/-ls";
|
|||
import { admin_message } from "./handlers/admin_message";
|
||||
import { chset } from "./handlers/chset";
|
||||
|
||||
EVENTGROUP_USER.add(hi);
|
||||
EVENTGROUP_USER.add(devices);
|
||||
EVENTGROUP_USER.add(ch);
|
||||
EVENTGROUP_USER.add(m);
|
||||
EVENTGROUP_USER.add(a);
|
||||
EVENTGROUP_USER.add(userset);
|
||||
EVENTGROUP_USER.add(n);
|
||||
EVENTGROUP_USER.add(plus_ls);
|
||||
EVENTGROUP_USER.add(minus_ls);
|
||||
EVENTGROUP_USER.add(admin_message);
|
||||
EVENTGROUP_USER.add(chset);
|
||||
// Imagine not having an "addMany" function...
|
||||
|
||||
// EVENTGROUP_USER.add(hi);
|
||||
// EVENTGROUP_USER.add(devices);
|
||||
// EVENTGROUP_USER.add(ch);
|
||||
// EVENTGROUP_USER.add(m);
|
||||
// EVENTGROUP_USER.add(a);
|
||||
// EVENTGROUP_USER.add(userset);
|
||||
// EVENTGROUP_USER.add(n);
|
||||
// EVENTGROUP_USER.add(plus_ls);
|
||||
// EVENTGROUP_USER.add(minus_ls);
|
||||
// EVENTGROUP_USER.add(admin_message);
|
||||
// EVENTGROUP_USER.add(chset);
|
||||
|
||||
// Imagine it looks exactly the same and calls the same function underneath
|
||||
EVENTGROUP_USER.addMany(
|
||||
hi,
|
||||
devices,
|
||||
ch,
|
||||
m,
|
||||
a,
|
||||
userset,
|
||||
n,
|
||||
plus_ls,
|
||||
minus_ls,
|
||||
admin_message,
|
||||
chset
|
||||
);
|
||||
|
||||
eventGroups.push(EVENTGROUP_USER);
|
||||
|
|
|
@ -2,7 +2,9 @@ import { Logger } from "../util/Logger";
|
|||
import { Socket } from "./Socket";
|
||||
import { hasOwn } from "../util/helpers";
|
||||
|
||||
const logger = new Logger("Message Handler");
|
||||
// const logger = new Logger("Message Handler");
|
||||
// this one sounds cooler
|
||||
const logger = new Logger("The Messenger");
|
||||
|
||||
export function handleMessage(socket: Socket, text: string) {
|
||||
try {
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// This is some convoluted dark magic I copied from some old mpp server I wrote
|
||||
// No fucking clue where it came from or how it works internally, but I typedefized it
|
||||
// It's just a bunch of rate limits in a chain... like a RateLimitChain...... hmmmm.......
|
||||
export class NoteQuota {
|
||||
public allowance = 8000;
|
||||
public max = 24000;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// Thank you Brandon for this thing
|
||||
export class RateLimit {
|
||||
public after: number = 0;
|
||||
constructor(private interval_ms: number = 0) {}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { RateLimit } from "./RateLimit";
|
||||
|
||||
// Thank you Brandon for this other thing
|
||||
export class RateLimitChain {
|
||||
public chain: RateLimit[] = [];
|
||||
|
||||
|
|
|
@ -47,7 +47,8 @@ export const config = loadConfig<RateLimitsConfig>("config/ratelimits.yml", {
|
|||
crown: {
|
||||
normal: {
|
||||
a: 6000 / 10,
|
||||
m: 1000 / 20
|
||||
m: 1000 / 20,
|
||||
ch: 1000 / 1
|
||||
},
|
||||
chains: {
|
||||
userset: {
|
||||
|
@ -59,7 +60,8 @@ export const config = loadConfig<RateLimitsConfig>("config/ratelimits.yml", {
|
|||
admin: {
|
||||
normal: {
|
||||
a: 6000 / 50,
|
||||
m: 1000 / 60
|
||||
m: 1000 / 60,
|
||||
ch: 1000 / 10
|
||||
},
|
||||
chains: {
|
||||
userset: {
|
||||
|
|
|
@ -5,7 +5,8 @@ import { RateLimitConstructorList, config } from "../config";
|
|||
export const adminLimits: RateLimitConstructorList = {
|
||||
normal: {
|
||||
a: () => new RateLimit(config.admin.normal.a),
|
||||
m: () => new RateLimit(config.admin.normal.m)
|
||||
m: () => new RateLimit(config.admin.normal.m),
|
||||
ch: () => new RateLimit(config.admin.normal.ch)
|
||||
},
|
||||
chains: {
|
||||
userset: () =>
|
||||
|
|
|
@ -5,7 +5,8 @@ import { RateLimitConstructorList, config } from "../config";
|
|||
export const crownLimits: RateLimitConstructorList = {
|
||||
normal: {
|
||||
a: () => new RateLimit(config.crown.normal.a),
|
||||
m: () => new RateLimit(config.crown.normal.m)
|
||||
m: () => new RateLimit(config.crown.normal.m),
|
||||
ch: () => new RateLimit(config.crown.normal.ch)
|
||||
},
|
||||
chains: {
|
||||
userset: () =>
|
||||
|
|
|
@ -2,6 +2,9 @@ import { RateLimit } from "../RateLimit";
|
|||
import { RateLimitChain } from "../RateLimitChain";
|
||||
import { RateLimitConstructorList, config } from "../config";
|
||||
|
||||
// I have no idea why these things exist but I made it apparently
|
||||
// All it does it construct the rate limits from the config instead
|
||||
// of using random numbers I found on the internet
|
||||
export const userLimits: RateLimitConstructorList = {
|
||||
normal: {
|
||||
a: () => new RateLimit(config.user.normal.a),
|
||||
|
|
|
@ -10,7 +10,15 @@ import nunjucks from "nunjucks";
|
|||
|
||||
const logger = new Logger("WebSocket Server");
|
||||
|
||||
/**
|
||||
* Get a rendered version of the index file
|
||||
* @returns Response with html in it
|
||||
*/
|
||||
async function getIndex() {
|
||||
// This tiny function took like an hour to write because
|
||||
// nobody realistically uses templates in 2024 and documents
|
||||
// it well enough to say what library they used
|
||||
|
||||
const index = Bun.file("./public/index.html");
|
||||
|
||||
const rendered = nunjucks.renderString(await index.text(), {
|
||||
|
@ -19,6 +27,7 @@ async function getIndex() {
|
|||
|
||||
const response = new Response(rendered);
|
||||
response.headers.set("Content-Type", "text/html");
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
@ -30,11 +39,21 @@ export const app = Bun.serve({
|
|||
return;
|
||||
} else {
|
||||
const url = new URL(req.url).pathname;
|
||||
|
||||
// lol
|
||||
// const ip = decoder.decode(res.getRemoteAddressAsText());
|
||||
// logger.debug(`${req.getMethod()} ${url} ${ip}`);
|
||||
// res.writeStatus(`200 OK`).end("HI!");
|
||||
|
||||
// I have no clue if this is even safe...
|
||||
// wtf do I do when the user types "/../.env" in the URL?
|
||||
// From my testing, nothing out of the ordinary happens...
|
||||
// but just in case, if you find something wrong with URLs,
|
||||
// this is the most likely culprit
|
||||
|
||||
const file = path.join("./public/", url);
|
||||
|
||||
// Time for unreadable blocks of confusion
|
||||
try {
|
||||
if (fs.lstatSync(file).isFile()) {
|
||||
const data = Bun.file(file);
|
||||
|
@ -54,20 +73,33 @@ export const app = Bun.serve({
|
|||
},
|
||||
websocket: {
|
||||
open: ws => {
|
||||
// We got one!
|
||||
const socket = new Socket(ws, createSocketID());
|
||||
|
||||
// Reel 'em in...
|
||||
(ws as unknown as any).socket = socket;
|
||||
// logger.debug("Connection at " + socket.getIP());
|
||||
|
||||
// Let's put it in the dinner bucket.
|
||||
socketsBySocketID.set(socket.socketID, socket);
|
||||
},
|
||||
|
||||
message: (ws, message) => {
|
||||
// "Let's make it binary" said all websocket developers for some reason
|
||||
const msg = message.toString();
|
||||
|
||||
// Let's find out wtf they even sent
|
||||
handleMessage((ws as unknown as any).socket, msg);
|
||||
},
|
||||
|
||||
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
|
||||
// normal person.
|
||||
|
||||
const socket = (ws as unknown as any).socket as Socket;
|
||||
if (socket) {
|
||||
socket.destroy();
|
||||
|
|
|
@ -20,6 +20,12 @@ export const defaultUsersConfig = {
|
|||
};
|
||||
|
||||
// Importing this elsewhere causes bun to segfault
|
||||
|
||||
// Now that I look back at this, using this elsewhere
|
||||
// before calling other things tends to make bun segfault?
|
||||
// Not dealing with it. The code somehow runs, and I'm not
|
||||
// going to fuck with the order of loading things until bun
|
||||
// pushes an update and fucks all this stuff up.
|
||||
export const config = loadConfig<UsersConfig>(
|
||||
usersConfigPath,
|
||||
defaultUsersConfig
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
import { test, expect } from "bun:test";
|
||||
import { Channel } from "../../src/channel/Channel";
|
||||
|
||||
test("Channel is created correctly", () => {
|
||||
const channel = new Channel("my room");
|
||||
expect(channel.getID()).toBe("my room");
|
||||
|
||||
const info = channel.getInfo();
|
||||
expect(info.id).toBe("my room");
|
||||
expect(info._id).toBe("my room");
|
||||
expect(info.count).toBe(0);
|
||||
|
||||
const ppl = channel.getParticipantList();
|
||||
expect(ppl).toBeEmpty();
|
||||
});
|
|
@ -1 +0,0 @@
|
|||
export class FakeSocket {}
|
Loading…
Reference in New Issue