Implement basic tag system
This commit is contained in:
parent
828443cb93
commit
9b48d41bd8
18
README.md
18
README.md
|
@ -20,10 +20,12 @@ Brandon's server originally used MongoDB for storing user data, but there are to
|
|||
|
||||
- Chat
|
||||
- Original chat filter by chacha and Brandon Lockaby
|
||||
- Commands for debugging or administrative purposes
|
||||
- Piano Notes
|
||||
- Uses the same `NoteQuota` implementation from the client
|
||||
- Usernames/colors
|
||||
- Allowing color changing can be toggled in the config
|
||||
- Allowing color changing can be toggled in the config, similar to MPP.com
|
||||
- Default user parameters can be set
|
||||
- Channels
|
||||
- Channel list
|
||||
- Channel settings
|
||||
|
@ -37,20 +39,32 @@ Brandon's server originally used MongoDB for storing user data, but there are to
|
|||
- Chat muting
|
||||
- Rate limit bypasses
|
||||
- Channel/User-targeted notifications
|
||||
- Server-wide/channel-specific/user-specific notifications
|
||||
- New admin messages
|
||||
- Restart message
|
||||
- Triggers notification on every connected socket, then shuts down after 20 seconds
|
||||
- Server must be setup as a pm2/docker/systemd process
|
||||
- Server must be setup as a pm2/docker/systemd process for automatic restarting
|
||||
- Ability to change tags
|
||||
|
||||
## TODO
|
||||
|
||||
- Fully implement and test tags
|
||||
- Tags are sent to clients now
|
||||
- Check if tags are sent to everyone
|
||||
- Permission groups and permissions
|
||||
- Probable permission groups: owner, admin, mod, trialmod, default
|
||||
- Setup tags for each permission group
|
||||
- Full server-wide event bus
|
||||
- Channel events
|
||||
- Socket events
|
||||
- User data events
|
||||
- Permission-related events
|
||||
- Redo all of the validations with Zod
|
||||
- This probably means making Zod schemas for every single message type
|
||||
- Also user and channel data
|
||||
- Test every frontend
|
||||
- Test fishing bot
|
||||
- Remote console
|
||||
|
||||
## Backlog/Notes
|
||||
|
||||
|
|
|
@ -7,13 +7,17 @@ defaultFlags:
|
|||
|
||||
# Whether or not to allow users to change their color.
|
||||
# Brandon's server has this set to false, but multiple users have reported it to be on before 2016.
|
||||
enableColorChanging: false
|
||||
enableColorChanging: true
|
||||
|
||||
# Allows custom data inside note messages.
|
||||
# This was in the original server, but not in MPP.net's server.
|
||||
# This only exists for backwards compatibility with scripts like nagalun's drarwing script.
|
||||
enableCustomNoteData: true
|
||||
|
||||
# Whether or not to enable tags that are sent publicly.
|
||||
# This won't prevent admins from changing tags internally, but it will not be sent to clients.
|
||||
enableTags: true
|
||||
|
||||
# This is the user data that the server will use to send admin chat messages with.
|
||||
adminParticipant:
|
||||
_id: "0"
|
||||
|
@ -27,11 +31,11 @@ enableAdminEval: true
|
|||
|
||||
# The token validation scheme. Valid values are "none", "jwt" and "uuid".
|
||||
# This server will still validate existing tokens generated with other schemes if not set to "none".
|
||||
tokenAuth: none
|
||||
tokenAuth: jwt
|
||||
|
||||
# The browser challenge scheme. Valid values are "none", "obf" and "basic".
|
||||
# This is to change what is sent in the "b" message.
|
||||
# "none" will disable the browser challenge,
|
||||
# "obf" will sent an obfuscated function to the client,
|
||||
# and "basic" will just send a simple function that expects a boolean.
|
||||
browserChallenge: none
|
||||
browserChallenge: basic
|
||||
|
|
|
@ -88,7 +88,7 @@ export class Channel extends EventEmitter {
|
|||
(typeof set.color2 == "undefined" ||
|
||||
set.color2 === this.settings.color2)
|
||||
) {
|
||||
this.logger.debug("color 2 darken triggered");
|
||||
//this.logger.debug("color 2 darken triggered");
|
||||
set.color2 = darken(set.color);
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,7 @@ export class Channel extends EventEmitter {
|
|||
|
||||
// Set the verified settings
|
||||
for (const key of Object.keys(validatedSet)) {
|
||||
this.logger.debug(`${key}: ${(validatedSet as any)[key]}`);
|
||||
//this.logger.debug(`${key}: ${(validatedSet as any)[key]}`);
|
||||
if ((validatedSet as any)[key] === false) continue;
|
||||
(this.settings as any)[key] = (set as any)[key];
|
||||
}
|
||||
|
@ -480,7 +480,7 @@ export class Channel extends EventEmitter {
|
|||
if (this.isTrueLobby()) {
|
||||
// Get the next lobby number
|
||||
const nextID = this.getNextLobbyID();
|
||||
this.logger.debug("New ID:", nextID);
|
||||
//this.logger.debug("New ID:", nextID);
|
||||
// Move them to the next lobby
|
||||
return socket.setChannel(nextID);
|
||||
}
|
||||
|
@ -691,7 +691,7 @@ export class Channel extends EventEmitter {
|
|||
name: p.name,
|
||||
color: p.color,
|
||||
id: p.id,
|
||||
tag: config.sendTags ? p.tag : undefined
|
||||
tag: usersConfig.enableTags ? p.tag : undefined
|
||||
});
|
||||
}
|
||||
|
||||
|
|
25
src/index.ts
25
src/index.ts
|
@ -20,31 +20,6 @@ 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,10 +1,19 @@
|
|||
import EventEmitter from "events";
|
||||
import { padNum, unimportant } from "./helpers";
|
||||
|
||||
export const logEvents = new EventEmitter();
|
||||
|
||||
/**
|
||||
* A logger that doesn't fuck with the readline prompt
|
||||
* timestamps are likely wrong because of js timezones
|
||||
**/
|
||||
export class Logger {
|
||||
/**
|
||||
* Log a message
|
||||
* This does weird prompt things
|
||||
* @param method The method from `console` to use
|
||||
* @param args The data to print
|
||||
**/
|
||||
private static log(method: string, ...args: any[]) {
|
||||
// Un-fuck the readline prompt
|
||||
process.stdout.write("\x1b[2K\r");
|
||||
|
@ -21,8 +30,15 @@ export class Logger {
|
|||
// Re-print the readline prompt (spooky cringe global variable)
|
||||
if ((globalThis as unknown as any).rl)
|
||||
(globalThis as unknown as any).rl.prompt();
|
||||
|
||||
// Emit the log event for remote consoles
|
||||
logEvents.emit("log", method, unimportant(this.getDate()), unimportant(this.getHHMMSSMS()), args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current time in HH:MM:SS.MS format
|
||||
* @returns The current time in HH:MM:SS.MS format
|
||||
**/
|
||||
public static getHHMMSSMS() {
|
||||
const ms = Date.now();
|
||||
|
||||
|
@ -38,24 +54,44 @@ export class Logger {
|
|||
return `${hh}:${mm}:${ss}.${ll}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current date in ISO format
|
||||
* @returns The current date in ISO format
|
||||
**/
|
||||
public static getDate() {
|
||||
return new Date().toISOString().split("T")[0];
|
||||
}
|
||||
|
||||
constructor(public id: string) { }
|
||||
|
||||
/**
|
||||
* Print an info message
|
||||
* @param args The data to print
|
||||
**/
|
||||
public info(...args: any[]) {
|
||||
Logger.log("log", `[${this.id}]`, `\x1b[34m[info]\x1b[0m`, ...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print an error message
|
||||
* @param args The data to print
|
||||
**/
|
||||
public error(...args: any[]) {
|
||||
Logger.log("error", `[${this.id}]`, `\x1b[31m[error]\x1b[0m`, ...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a warning message
|
||||
* @param args The data to print
|
||||
**/
|
||||
public warn(...args: any[]) {
|
||||
Logger.log("warn", `[${this.id}]`, `\x1b[33m[warn]\x1b[0m`, ...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a debug message
|
||||
* @param args The data to print
|
||||
**/
|
||||
public debug(...args: any[]) {
|
||||
Logger.log("debug", `[${this.id}]`, `\x1b[32m[debug]\x1b[0m`, ...args);
|
||||
}
|
||||
|
|
|
@ -14,7 +14,8 @@ import {
|
|||
ServerEvents,
|
||||
UserFlags,
|
||||
Vector2,
|
||||
Notification
|
||||
Notification,
|
||||
Tag
|
||||
} from "../util/types";
|
||||
import type { User } from "@prisma/client";
|
||||
import { createUser, readUser, updateUser } from "../data/user";
|
||||
|
@ -355,11 +356,20 @@ export class Socket extends EventEmitter {
|
|||
}
|
||||
}
|
||||
|
||||
let tag: Tag | undefined;
|
||||
|
||||
try {
|
||||
tag = JSON.parse(this.user.tag) as Tag;
|
||||
} catch (err) {
|
||||
logger.warn("Unable to parse tag:", err);
|
||||
}
|
||||
|
||||
return {
|
||||
_id: facadeID,
|
||||
name: this.user.name,
|
||||
color: this.user.color,
|
||||
id: this.getParticipantID()
|
||||
id: this.getParticipantID(),
|
||||
tag: config.enableTags ? tag : undefined
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
|
@ -744,6 +754,7 @@ export class Socket extends EventEmitter {
|
|||
* @param color Color of the tag
|
||||
**/
|
||||
public setTag(text: string, color: string) {
|
||||
//logger.debug("Setting tag:", text, color);
|
||||
const user = this.getUser();
|
||||
if (!user) return;
|
||||
user.tag = JSON.stringify({ text, color });
|
||||
|
|
|
@ -11,6 +11,7 @@ import { name } from "./handlers/name";
|
|||
import { notification } from "./handlers/notification";
|
||||
import { rename_channel } from "./handlers/rename_channel";
|
||||
import { restart } from "./handlers/restart";
|
||||
import { tag } from "./handlers/tag";
|
||||
import { user_flag } from "./handlers/user_flag";
|
||||
|
||||
// EVENT_GROUP_ADMIN.add(color);
|
||||
|
@ -27,7 +28,8 @@ EVENT_GROUP_ADMIN.addMany(
|
|||
move,
|
||||
rename_channel,
|
||||
admin_chat,
|
||||
eval_msg
|
||||
eval_msg,
|
||||
tag
|
||||
);
|
||||
|
||||
eventGroups.push(EVENT_GROUP_ADMIN);
|
||||
|
|
|
@ -65,10 +65,13 @@ export const hi: ServerEventListener<"hi"> = {
|
|||
_id: socket.getUserID(),
|
||||
name: "Anonymous",
|
||||
color: "#777",
|
||||
id: ""
|
||||
id: "",
|
||||
tag: undefined
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug("Tag:", part.tag);
|
||||
|
||||
socket.sendArray([{
|
||||
m: "hi",
|
||||
accountInfo: undefined,
|
||||
|
@ -77,7 +80,8 @@ export const hi: ServerEventListener<"hi"> = {
|
|||
u: {
|
||||
_id: part._id,
|
||||
color: part.color,
|
||||
name: part.name
|
||||
name: part.name,
|
||||
tag: part.tag
|
||||
},
|
||||
motd: getMOTD(),
|
||||
token
|
||||
|
|
|
@ -6,6 +6,7 @@ export interface UsersConfig {
|
|||
defaultFlags: UserFlags;
|
||||
enableColorChanging: boolean;
|
||||
enableCustomNoteData: boolean;
|
||||
enableTags: boolean;
|
||||
adminParticipant: Participant;
|
||||
enableAdminEval: boolean;
|
||||
tokenAuth: "jwt" | "uuid" | "none";
|
||||
|
@ -21,6 +22,7 @@ export const defaultUsersConfig: UsersConfig = {
|
|||
},
|
||||
enableColorChanging: false,
|
||||
enableCustomNoteData: true,
|
||||
enableTags: false,
|
||||
adminParticipant: {
|
||||
_id: "0",
|
||||
name: "mpp",
|
||||
|
|
Loading…
Reference in New Issue