Fix channel settings validation, attempt to implement channel list and admin messages
This commit is contained in:
parent
ffb8044734
commit
8a8ce405fd
|
@ -13,6 +13,7 @@ import { Socket } from "../ws/Socket";
|
||||||
import { validateChannelSettings } from "./settings";
|
import { validateChannelSettings } from "./settings";
|
||||||
import { findSocketByPartID, socketsBySocketID } from "../ws/Socket";
|
import { findSocketByPartID, socketsBySocketID } from "../ws/Socket";
|
||||||
import Crown from "./Crown";
|
import Crown from "./Crown";
|
||||||
|
import { ChannelList } from "./ChannelList";
|
||||||
|
|
||||||
interface ChannelConfig {
|
interface ChannelConfig {
|
||||||
forceLoad: string[];
|
forceLoad: string[];
|
||||||
|
@ -40,14 +41,11 @@ export const config = loadConfig<ChannelConfig>("config/channels.yml", {
|
||||||
color2: "#001014",
|
color2: "#001014",
|
||||||
visible: true
|
visible: true
|
||||||
},
|
},
|
||||||
// TODO Test this regex
|
lobbyRegexes: ["^lobby[0-9][0-9]$", "^lobby[1-9]$", "^test/.+$"],
|
||||||
lobbyRegexes: ["^lobby[1-9]?[1-9]?$", "^test/.+$"],
|
|
||||||
lobbyBackdoor: "lolwutsecretlobbybackdoor",
|
lobbyBackdoor: "lolwutsecretlobbybackdoor",
|
||||||
fullChannel: "test/awkward"
|
fullChannel: "test/awkward"
|
||||||
});
|
});
|
||||||
|
|
||||||
export const channelList = new Array<Channel>();
|
|
||||||
|
|
||||||
export class Channel extends EventEmitter {
|
export class Channel extends EventEmitter {
|
||||||
private settings: Partial<IChannelSettings> = config.defaultSettings;
|
private settings: Partial<IChannelSettings> = config.defaultSettings;
|
||||||
private ppl = new Array<Participant>();
|
private ppl = new Array<Participant>();
|
||||||
|
@ -75,9 +73,8 @@ export class Channel extends EventEmitter {
|
||||||
if (set) {
|
if (set) {
|
||||||
const validatedSet = validateChannelSettings(set);
|
const validatedSet = validateChannelSettings(set);
|
||||||
|
|
||||||
for (const key in Object.keys(validatedSet)) {
|
for (const key of Object.keys(set)) {
|
||||||
if (!(validatedSet as any)[key]) continue;
|
if ((validatedSet as any)[key] === false) continue;
|
||||||
|
|
||||||
(this.settings as any)[key] = (set as any)[key];
|
(this.settings as any)[key] = (set as any)[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,10 +82,10 @@ export class Channel extends EventEmitter {
|
||||||
this.crown = new Crown();
|
this.crown = new Crown();
|
||||||
|
|
||||||
if (creator) {
|
if (creator) {
|
||||||
if (this.crown.canBeSetBy(creator)) {
|
// if (this.crown.canBeSetBy(creator)) {
|
||||||
const part = creator.getParticipant();
|
const part = creator.getParticipant();
|
||||||
if (part) this.giveCrown(part);
|
if (part) this.giveCrown(part);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,8 +95,10 @@ export class Channel extends EventEmitter {
|
||||||
|
|
||||||
this.bindEventListeners();
|
this.bindEventListeners();
|
||||||
|
|
||||||
channelList.push(this);
|
ChannelList.add(this);
|
||||||
// TODO channel closing
|
// TODO channel closing
|
||||||
|
|
||||||
|
this.logger.info("Created");
|
||||||
}
|
}
|
||||||
|
|
||||||
private alreadyBound = false;
|
private alreadyBound = false;
|
||||||
|
@ -264,7 +263,7 @@ export class Channel extends EventEmitter {
|
||||||
|
|
||||||
if (hasChangedChannel) {
|
if (hasChangedChannel) {
|
||||||
if (socket.currentChannelID) {
|
if (socket.currentChannelID) {
|
||||||
const ch = channelList.find(
|
const ch = ChannelList.getList().find(
|
||||||
ch => ch._id == socket.currentChannelID
|
ch => ch._id == socket.currentChannelID
|
||||||
);
|
);
|
||||||
if (ch) {
|
if (ch) {
|
||||||
|
@ -475,7 +474,8 @@ export class Channel extends EventEmitter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
channelList.splice(channelList.indexOf(this), 1);
|
ChannelList.remove(this);
|
||||||
|
this.logger.info("Destroyed");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -567,5 +567,5 @@ for (const id of config.forceLoad) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasFullChannel) {
|
if (!hasFullChannel) {
|
||||||
channelList.push(new Channel(config.fullChannel));
|
new Channel(config.fullChannel);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
import { findSocketByPartID } from "../ws/Socket";
|
||||||
|
import type Channel from "./Channel";
|
||||||
|
|
||||||
|
const onChannelUpdate = (channel: Channel) => {
|
||||||
|
const info = channel.getInfo();
|
||||||
|
const ppl = channel.getParticipantList();
|
||||||
|
|
||||||
|
for (const partId of ChannelList.subscribers) {
|
||||||
|
const socket = findSocketByPartID(partId);
|
||||||
|
|
||||||
|
if (typeof socket == "undefined") {
|
||||||
|
ChannelList.subscribers.splice(
|
||||||
|
ChannelList.subscribers.indexOf(partId),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.sendChannelUpdate(info, ppl);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export class ChannelList {
|
||||||
|
private static list = new Array<Channel>();
|
||||||
|
public static subscribers = new Array<string>();
|
||||||
|
|
||||||
|
public static add(channel: Channel) {
|
||||||
|
this.list.push(channel);
|
||||||
|
channel.on("update", () => {
|
||||||
|
onChannelUpdate(channel);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static remove(channel: Channel) {
|
||||||
|
this.list.splice(this.list.indexOf(channel), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getList() {
|
||||||
|
return this.list;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,9 @@
|
||||||
import { ChannelSettings } from "../util/types";
|
import { Logger } from "../util/Logger";
|
||||||
|
import { IChannelSettings } from "../util/types";
|
||||||
|
|
||||||
type Validator = "boolean" | "string" | "number" | ((val: any) => boolean);
|
type Validator = "boolean" | "string" | "number" | ((val: unknown) => boolean);
|
||||||
|
|
||||||
const validationRecord: Record<keyof ChannelSettings, Validator> = {
|
const validationRecord: Record<keyof IChannelSettings, Validator> = {
|
||||||
// Brandon
|
// Brandon
|
||||||
lobby: "boolean",
|
lobby: "boolean",
|
||||||
visible: "boolean",
|
visible: "boolean",
|
||||||
|
@ -25,13 +26,12 @@ const validationRecord: Record<keyof ChannelSettings, Validator> = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check the validity of channel settings
|
* Check the validity of channel settings
|
||||||
* @param set Unknown data
|
* @param set Dirty settings
|
||||||
* @returns Record of which settings are correct
|
* @returns Record of which settings are correct
|
||||||
*/
|
*/
|
||||||
export function validateChannelSettings(set: Partial<ChannelSettings>) {
|
export function validateChannelSettings(set: Partial<IChannelSettings>) {
|
||||||
// Create record
|
// Create record
|
||||||
let keys = Object.keys(validationRecord);
|
let record: Partial<Record<keyof IChannelSettings, boolean>> = {};
|
||||||
let record: Partial<Record<keyof ChannelSettings, boolean>> = {};
|
|
||||||
|
|
||||||
for (const key of Object.keys(set)) {
|
for (const key of Object.keys(set)) {
|
||||||
let val = (set as Record<string, any>)[key];
|
let val = (set as Record<string, any>)[key];
|
||||||
|
@ -46,7 +46,7 @@ export function validateChannelSettings(set: Partial<ChannelSettings>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set valid status
|
// Set valid status
|
||||||
record[key as keyof ChannelSettings] = validate(val, validator);
|
record[key as keyof IChannelSettings] = validate(val, validator);
|
||||||
}
|
}
|
||||||
|
|
||||||
return record;
|
return record;
|
||||||
|
|
|
@ -12,3 +12,5 @@ import "./ws/server";
|
||||||
import { Logger } from "./util/Logger";
|
import { Logger } from "./util/Logger";
|
||||||
|
|
||||||
const logger = new Logger("Main");
|
const logger = new Logger("Main");
|
||||||
|
|
||||||
|
import "./util/readline";
|
||||||
|
|
|
@ -2,6 +2,10 @@ import { padNum, unimportant } from "./helpers";
|
||||||
|
|
||||||
export class Logger {
|
export class Logger {
|
||||||
private static log(method: string, ...args: any[]) {
|
private static log(method: string, ...args: any[]) {
|
||||||
|
// Clear current line
|
||||||
|
process.stdout.write("\x1b[2K\r");
|
||||||
|
|
||||||
|
// Log our stuff
|
||||||
(console as unknown as Record<string, (..._args: any[]) => any>)[
|
(console as unknown as Record<string, (..._args: any[]) => any>)[
|
||||||
method
|
method
|
||||||
](
|
](
|
||||||
|
@ -9,6 +13,10 @@ export class Logger {
|
||||||
unimportant(this.getHHMMSSMS()),
|
unimportant(this.getHHMMSSMS()),
|
||||||
...args
|
...args
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Fix the readline prompt (spooky code)
|
||||||
|
if ((globalThis as unknown as any).rl)
|
||||||
|
(globalThis as unknown as any).rl.prompt();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getHHMMSSMS() {
|
public static getHHMMSSMS() {
|
||||||
|
|
|
@ -1,19 +1,35 @@
|
||||||
import readline from "readline";
|
import readline from "readline";
|
||||||
|
import { Logger } from "./Logger";
|
||||||
|
|
||||||
export const rl = readline.createInterface({
|
export const rl = readline.createInterface({
|
||||||
input: process.stdin,
|
input: process.stdin,
|
||||||
output: process.stdout
|
output: process.stdout
|
||||||
});
|
});
|
||||||
|
|
||||||
rl.setPrompt("mpps> ");
|
const logger = new Logger("CLI");
|
||||||
|
|
||||||
|
rl.setPrompt("mpps> ");
|
||||||
rl.prompt();
|
rl.prompt();
|
||||||
|
|
||||||
rl.on("line", msg => {
|
rl.on("line", msg => {
|
||||||
// TODO readline commands
|
// TODO readline commands
|
||||||
|
|
||||||
|
if (msg == "mem" || msg == "memory") {
|
||||||
|
const mem = process.memoryUsage();
|
||||||
|
logger.info(
|
||||||
|
`Memory: ${(mem.heapUsed / 1000 / 1000).toFixed(2)} MB used / ${(
|
||||||
|
mem.heapTotal /
|
||||||
|
1000 /
|
||||||
|
1000
|
||||||
|
).toFixed(2)} MB total`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
rl.prompt();
|
rl.prompt();
|
||||||
});
|
});
|
||||||
|
|
||||||
rl.on("SIGINT", () => {
|
rl.on("SIGINT", () => {
|
||||||
process.exit();
|
process.exit();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
(globalThis as unknown as any).rl = rl;
|
||||||
|
|
|
@ -91,15 +91,6 @@ declare interface Crown {
|
||||||
endPos: Vector2;
|
endPos: Vector2;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare interface ChannelInfo {
|
|
||||||
banned?: boolean;
|
|
||||||
count: number;
|
|
||||||
id: string;
|
|
||||||
_id: string;
|
|
||||||
crown?: Crown;
|
|
||||||
settings: Partial<IChannelSettings>;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Events copied from Hri7566/mppclone-client typedefs
|
// Events copied from Hri7566/mppclone-client typedefs
|
||||||
declare interface ServerEvents {
|
declare interface ServerEvents {
|
||||||
a: {
|
a: {
|
||||||
|
@ -200,6 +191,12 @@ declare interface ServerEvents {
|
||||||
set: { name?: string; color?: string };
|
set: { name?: string; color?: string };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
"admin message": {
|
||||||
|
m: "admin message";
|
||||||
|
password: string;
|
||||||
|
msg: ServerEvents<keyof ServerEvents>;
|
||||||
|
};
|
||||||
|
|
||||||
// Admin
|
// Admin
|
||||||
|
|
||||||
color: {
|
color: {
|
||||||
|
@ -243,7 +240,7 @@ declare interface ClientEvents {
|
||||||
ch: {
|
ch: {
|
||||||
m: "ch";
|
m: "ch";
|
||||||
p: string;
|
p: string;
|
||||||
ch: ChannelInfo;
|
ch: IChannelInfo;
|
||||||
ppl: Participant[];
|
ppl: Participant[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -342,6 +339,7 @@ declare interface ICrown {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare interface IChannelInfo {
|
declare interface IChannelInfo {
|
||||||
|
banned?: boolean;
|
||||||
_id: string;
|
_id: string;
|
||||||
id: string;
|
id: string;
|
||||||
count: number;
|
count: number;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
import { createColor, createID, createUserID } from "../util/id";
|
import { createColor, createID, createUserID } from "../util/id";
|
||||||
import EventEmitter from "events";
|
import EventEmitter from "events";
|
||||||
import {
|
import {
|
||||||
ChannelInfo,
|
IChannelInfo,
|
||||||
IChannelSettings,
|
IChannelSettings,
|
||||||
ClientEvents,
|
ClientEvents,
|
||||||
Participant,
|
Participant,
|
||||||
|
@ -19,7 +19,8 @@ import { User } from "@prisma/client";
|
||||||
import { createUser, readUser, updateUser } from "../data/user";
|
import { createUser, readUser, updateUser } from "../data/user";
|
||||||
import { eventGroups } from "./events";
|
import { eventGroups } from "./events";
|
||||||
import { Gateway } from "./Gateway";
|
import { Gateway } from "./Gateway";
|
||||||
import { channelList, Channel } from "../channel/Channel";
|
import { Channel } from "../channel/Channel";
|
||||||
|
import { ChannelList } from "../channel/ChannelList";
|
||||||
import { ServerWebSocket } from "bun";
|
import { ServerWebSocket } from "bun";
|
||||||
import { Logger } from "../util/Logger";
|
import { Logger } from "../util/Logger";
|
||||||
import { RateLimitConstructorList, RateLimitList } from "./ratelimit/config";
|
import { RateLimitConstructorList, RateLimitList } from "./ratelimit/config";
|
||||||
|
@ -114,7 +115,7 @@ export class Socket extends EventEmitter {
|
||||||
this.desiredChannel.set = set;
|
this.desiredChannel.set = set;
|
||||||
|
|
||||||
let channel;
|
let channel;
|
||||||
for (const ch of channelList) {
|
for (const ch of ChannelList.getList()) {
|
||||||
if (ch.getID() == _id) {
|
if (ch.getID() == _id) {
|
||||||
channel = ch;
|
channel = ch;
|
||||||
}
|
}
|
||||||
|
@ -138,21 +139,25 @@ export class Socket extends EventEmitter {
|
||||||
);
|
);
|
||||||
|
|
||||||
channel.join(this);
|
channel.join(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO Give the crown upon joining
|
public admin = new EventEmitter();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bindEventListeners() {
|
private bindEventListeners() {
|
||||||
for (const group of eventGroups) {
|
for (const group of eventGroups) {
|
||||||
|
if (group.id == "admin") {
|
||||||
|
for (const event of group.eventList) {
|
||||||
|
this.admin.on(event.id, event.callback);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
// TODO Check event group permissions
|
// TODO Check event group permissions
|
||||||
if (group.id == "admin") continue;
|
|
||||||
|
|
||||||
for (const event of group.eventList) {
|
for (const event of group.eventList) {
|
||||||
this.on(event.id, event.callback);
|
this.on(event.id, event.callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public sendArray<EventID extends keyof ClientEvents>(
|
public sendArray<EventID extends keyof ClientEvents>(
|
||||||
arr: ClientEvents[EventID][]
|
arr: ClientEvents[EventID][]
|
||||||
|
@ -198,6 +203,23 @@ export class Socket extends EventEmitter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async setUserFlag(key: keyof UserFlags, value: unknown) {
|
||||||
|
if (this.user) {
|
||||||
|
try {
|
||||||
|
const flags = JSON.parse(this.user.flags) as Partial<UserFlags>;
|
||||||
|
if (!flags) return false;
|
||||||
|
(flags as unknown as Record<string, unknown>)[key] = value;
|
||||||
|
this.user.flags = JSON.stringify(flags);
|
||||||
|
await updateUser(this.user.id, this.user);
|
||||||
|
return true;
|
||||||
|
} catch (err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public getParticipant() {
|
public getParticipant() {
|
||||||
if (this.user) {
|
if (this.user) {
|
||||||
const flags = this.getUserFlags();
|
const flags = this.getUserFlags();
|
||||||
|
@ -226,7 +248,7 @@ export class Socket extends EventEmitter {
|
||||||
// Socket was closed or should be closed, clear data
|
// Socket was closed or should be closed, clear data
|
||||||
// logger.debug("Destroying UID:", this._id);
|
// logger.debug("Destroying UID:", this._id);
|
||||||
|
|
||||||
const foundCh = channelList.find(
|
const foundCh = ChannelList.getList().find(
|
||||||
ch => ch.getID() === this.currentChannelID
|
ch => ch.getID() === this.currentChannelID
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -290,10 +312,12 @@ export class Socket extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCurrentChannel() {
|
public getCurrentChannel() {
|
||||||
return channelList.find(ch => ch.getID() == this.currentChannelID);
|
return ChannelList.getList().find(
|
||||||
|
ch => ch.getID() == this.currentChannelID
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public sendChannelUpdate(ch: ChannelInfo, ppl: Participant[]) {
|
public sendChannelUpdate(ch: IChannelInfo, ppl: Participant[]) {
|
||||||
this.sendArray([
|
this.sendArray([
|
||||||
{
|
{
|
||||||
m: "ch",
|
m: "ch",
|
||||||
|
@ -370,6 +394,8 @@ export class Socket extends EventEmitter {
|
||||||
if (!ch) return;
|
if (!ch) return;
|
||||||
ch.playNotes(msg, this);
|
ch.playNotes(msg, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public subscribeToChannelList() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const socketsBySocketID = new Map<string, Socket>();
|
export const socketsBySocketID = new Map<string, Socket>();
|
||||||
|
@ -380,11 +406,15 @@ export function findSocketByPartID(id: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function findSocketByUserID(_id: string) {
|
export function findSocketsByUserID(_id: string) {
|
||||||
|
const sockets = [];
|
||||||
|
|
||||||
for (const socket of socketsBySocketID.values()) {
|
for (const socket of socketsBySocketID.values()) {
|
||||||
// logger.debug("User ID:", socket.getUserID());
|
// logger.debug("User ID:", socket.getUserID());
|
||||||
if (socket.getUserID() == _id) return socket;
|
if (socket.getUserID() == _id) sockets.push(socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return sockets;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function findSocketByIP(ip: string) {
|
export function findSocketByIP(ip: string) {
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
import { readUser, updateUser } from "../../../../data/user";
|
||||||
|
import { ServerEventListener } from "../../../../util/types";
|
||||||
|
import { findSocketsByUserID } from "../../../Socket";
|
||||||
|
|
||||||
|
export const user_flag: ServerEventListener<"user_flag"> = {
|
||||||
|
id: "user_flag",
|
||||||
|
callback: async (msg, socket) => {
|
||||||
|
if (typeof msg._id !== "string") return;
|
||||||
|
if (typeof msg.key !== "string") return;
|
||||||
|
if (typeof msg.value == "undefined") return;
|
||||||
|
|
||||||
|
socket.getCurrentChannel()?.logger.debug(msg);
|
||||||
|
|
||||||
|
// Find the user data we're modifying
|
||||||
|
const user = await readUser(msg._id);
|
||||||
|
if (!user) return;
|
||||||
|
|
||||||
|
// Set the flag
|
||||||
|
const flags = JSON.parse(user.flags);
|
||||||
|
flags[msg.key] = msg.value;
|
||||||
|
user.flags = JSON.stringify(flags);
|
||||||
|
|
||||||
|
// Save the user data
|
||||||
|
await updateUser(user.id, user);
|
||||||
|
|
||||||
|
// Update this data for loaded users as well
|
||||||
|
const socks = findSocketsByUserID(user.id);
|
||||||
|
socks.forEach(sock => {
|
||||||
|
sock.setUserFlag(msg.key, msg.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.getCurrentChannel()?.logger.debug("socks:", socks);
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,9 +1,11 @@
|
||||||
import { EventGroup, eventGroups } from "../../events";
|
import { EventGroup, eventGroups } from "../../events";
|
||||||
|
|
||||||
export const EVENT_GROUP_ADMIN = new EventGroup("user");
|
export const EVENT_GROUP_ADMIN = new EventGroup("admin");
|
||||||
|
|
||||||
import { color } from "./handlers/color";
|
import { color } from "./handlers/color";
|
||||||
|
import { user_flag } from "./handlers/user_flag";
|
||||||
|
|
||||||
EVENT_GROUP_ADMIN.add(color);
|
EVENT_GROUP_ADMIN.add(color);
|
||||||
|
EVENT_GROUP_ADMIN.add(user_flag);
|
||||||
|
|
||||||
eventGroups.push(EVENT_GROUP_ADMIN);
|
eventGroups.push(EVENT_GROUP_ADMIN);
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { ServerEventListener } from "../../../../util/types";
|
||||||
|
|
||||||
|
export const plus_ls: ServerEventListener<"+ls"> = {
|
||||||
|
id: "+ls",
|
||||||
|
callback: (msg, socket) => {
|
||||||
|
socket.subscribeToChannelList();
|
||||||
|
}
|
||||||
|
};
|
|
@ -4,6 +4,10 @@ export const a: ServerEventListener<"a"> = {
|
||||||
id: "a",
|
id: "a",
|
||||||
callback: (msg, socket) => {
|
callback: (msg, socket) => {
|
||||||
// Chat message
|
// Chat message
|
||||||
|
const flags = socket.getUserFlags();
|
||||||
|
if (!flags) return;
|
||||||
|
|
||||||
|
if (!flags["no chat rate limit"] || flags["no chat rate limit"] == 0)
|
||||||
if (!socket.rateLimits?.normal.a.attempt()) return;
|
if (!socket.rateLimits?.normal.a.attempt()) return;
|
||||||
const ch = socket.getCurrentChannel();
|
const ch = socket.getCurrentChannel();
|
||||||
if (!ch) return;
|
if (!ch) return;
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
import env from "../../../../util/env";
|
||||||
|
import { ServerEventListener } from "../../../../util/types";
|
||||||
|
import { config } from "../../../usersConfig";
|
||||||
|
|
||||||
|
export const admin_message: ServerEventListener<"admin message"> = {
|
||||||
|
id: "admin message",
|
||||||
|
callback: (msg, socket) => {
|
||||||
|
if (typeof msg.password !== "string") return;
|
||||||
|
if (msg.password !== env.ADMIN_PASS) return;
|
||||||
|
socket.admin.emit(msg.msg.m, msg.msg, socket, true);
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue