Add IPData, Windows support, bugfixes (#2)
* Add IPData, Windows support, bugfixes Changes: - Added IPData: mutes and votes are now tracked per-IP instead of per-user. - Windows support: QMP over TCP can now be enabled in the config. - Vote cooldown can now be specified in the config. - Fixed bugs: "Username is already taken" message appearing when it shouldn't * Remove vote from closed connections --------- Co-authored-by: Elijah R <62162399+elijahr2411@users.noreply.github.com>
This commit is contained in:
@@ -11,6 +11,10 @@ proxyAllowedIps = ["127.0.0.1"]
|
|||||||
qemuArgs = "qemu-system-x86_64"
|
qemuArgs = "qemu-system-x86_64"
|
||||||
vncPort = 5900
|
vncPort = 5900
|
||||||
snapshots = true
|
snapshots = true
|
||||||
|
# Uncomment qmpHost and qmpPort if you're using Windows.
|
||||||
|
#qmpHost = "127.0.0.1"
|
||||||
|
#qmpPort = "5800"
|
||||||
|
# Comment out qmpSockDir if you're using Windows.
|
||||||
qmpSockDir = "/tmp/"
|
qmpSockDir = "/tmp/"
|
||||||
|
|
||||||
[collabvm]
|
[collabvm]
|
||||||
@@ -31,6 +35,8 @@ tempMuteTime = 30
|
|||||||
turnTime = 20
|
turnTime = 20
|
||||||
# How long a reset vote lasts, in seconds
|
# How long a reset vote lasts, in seconds
|
||||||
voteTime = 100
|
voteTime = 100
|
||||||
|
# How long until another vote can be started, in seconds
|
||||||
|
voteCooldown = 180
|
||||||
# SHA256 sum of the admin and mod passwords. This can be generated with the following command:
|
# SHA256 sum of the admin and mod passwords. This can be generated with the following command:
|
||||||
# printf "<password>" | sha256sum -
|
# printf "<password>" | sha256sum -
|
||||||
# Example hash is hunter2 and hunter3
|
# Example hash is hunter2 and hunter3
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ export default interface IConfig {
|
|||||||
qemuArgs : string;
|
qemuArgs : string;
|
||||||
vncPort : number;
|
vncPort : number;
|
||||||
snapshots : boolean;
|
snapshots : boolean;
|
||||||
qmpSockDir : string;
|
qmpHost : string | null;
|
||||||
|
qmpPort : number | null;
|
||||||
|
qmpSockDir : string | null;
|
||||||
};
|
};
|
||||||
collabvm : {
|
collabvm : {
|
||||||
node : string;
|
node : string;
|
||||||
@@ -27,6 +29,7 @@ export default interface IConfig {
|
|||||||
tempMuteTime : number;
|
tempMuteTime : number;
|
||||||
turnTime : number;
|
turnTime : number;
|
||||||
voteTime : number;
|
voteTime : number;
|
||||||
|
voteCooldown: number;
|
||||||
adminpass : string;
|
adminpass : string;
|
||||||
modpass : string;
|
modpass : string;
|
||||||
moderatorPermissions : Permissions;
|
moderatorPermissions : Permissions;
|
||||||
|
|||||||
12
src/IPData.ts
Normal file
12
src/IPData.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
export class IPData {
|
||||||
|
tempMuteExpireTimeout? : NodeJS.Timer;
|
||||||
|
muted: Boolean;
|
||||||
|
vote: boolean | null;
|
||||||
|
address: string;
|
||||||
|
|
||||||
|
constructor(address: string) {
|
||||||
|
this.address = address;
|
||||||
|
this.muted = false;
|
||||||
|
this.vote = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ export default class QEMUVM extends EventEmitter {
|
|||||||
framebuffer : Canvas;
|
framebuffer : Canvas;
|
||||||
framebufferCtx : CanvasRenderingContext2D;
|
framebufferCtx : CanvasRenderingContext2D;
|
||||||
qmpSock : string;
|
qmpSock : string;
|
||||||
|
qmpType: string;
|
||||||
qmpClient : QMPClient;
|
qmpClient : QMPClient;
|
||||||
qemuCmd : string;
|
qemuCmd : string;
|
||||||
qemuProcess? : ExecaChildProcess;
|
qemuProcess? : ExecaChildProcess;
|
||||||
@@ -36,9 +37,14 @@ export default class QEMUVM extends EventEmitter {
|
|||||||
console.error("[FATAL] VNC Port must be 5900 or higher");
|
console.error("[FATAL] VNC Port must be 5900 or higher");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
this.qmpSock = `${Config.vm.qmpSockDir}collab-vm-qmp-${Config.collabvm.node}.sock`;
|
Config.vm.qmpSockDir == null ? this.qmpType = "tcp:" : this.qmpType = "unix:";
|
||||||
|
if(this.qmpType == "tcp:") {
|
||||||
|
this.qmpSock = `${Config.vm.qmpHost}:${Config.vm.qmpPort}`;
|
||||||
|
}else{
|
||||||
|
this.qmpSock = `${Config.vm.qmpSockDir}collab-vm-qmp-${Config.collabvm.node}.sock`;
|
||||||
|
}
|
||||||
this.vncPort = Config.vm.vncPort;
|
this.vncPort = Config.vm.vncPort;
|
||||||
this.qemuCmd = `${Config.vm.qemuArgs} -snapshot -no-shutdown -vnc 127.0.0.1:${this.vncPort - 5900} -qmp unix:${this.qmpSock},server`;
|
this.qemuCmd = `${Config.vm.qemuArgs} -snapshot -no-shutdown -vnc 127.0.0.1:${this.vncPort - 5900} -qmp ${this.qmpType}${this.qmpSock},server`;
|
||||||
this.qmpErrorLevel = 0;
|
this.qmpErrorLevel = 0;
|
||||||
this.vncErrorLevel = 0;
|
this.vncErrorLevel = 0;
|
||||||
this.vncOpen = true;
|
this.vncOpen = true;
|
||||||
@@ -48,7 +54,7 @@ export default class QEMUVM extends EventEmitter {
|
|||||||
this.framebufferCtx = this.framebuffer.getContext("2d");
|
this.framebufferCtx = this.framebuffer.getContext("2d");
|
||||||
this.processRestartErrorLevel = 0;
|
this.processRestartErrorLevel = 0;
|
||||||
this.expectedExit = false;
|
this.expectedExit = false;
|
||||||
this.qmpClient = new QMPClient(this.qmpSock);
|
this.qmpClient = new QMPClient(this.qmpSock, this.qmpType);
|
||||||
this.qmpClient.on('connected', () => this.qmpConnected());
|
this.qmpClient.on('connected', () => this.qmpConnected());
|
||||||
this.qmpClient.on('close', () => this.qmpClosed());
|
this.qmpClient.on('close', () => this.qmpClosed());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,14 @@ import { Mutex } from "async-mutex";
|
|||||||
|
|
||||||
export default class QMPClient extends EventEmitter {
|
export default class QMPClient extends EventEmitter {
|
||||||
socketfile : string;
|
socketfile : string;
|
||||||
|
sockettype: string;
|
||||||
socket : Socket;
|
socket : Socket;
|
||||||
connected : boolean;
|
connected : boolean;
|
||||||
sentConnected : boolean;
|
sentConnected : boolean;
|
||||||
cmdMutex : Mutex; // So command outputs don't get mixed up
|
cmdMutex : Mutex; // So command outputs don't get mixed up
|
||||||
constructor(socketfile : string) {
|
constructor(socketfile : string, sockettype: string) {
|
||||||
super();
|
super();
|
||||||
|
this.sockettype = sockettype;
|
||||||
this.socketfile = socketfile;
|
this.socketfile = socketfile;
|
||||||
this.socket = new Socket();
|
this.socket = new Socket();
|
||||||
this.connected = false;
|
this.connected = false;
|
||||||
@@ -20,7 +22,12 @@ export default class QMPClient extends EventEmitter {
|
|||||||
return new Promise((res, rej) => {
|
return new Promise((res, rej) => {
|
||||||
if (this.connected) {res(); return;}
|
if (this.connected) {res(); return;}
|
||||||
try {
|
try {
|
||||||
this.socket.connect(this.socketfile);
|
if(this.sockettype == "tcp:") {
|
||||||
|
let _sock = this.socketfile.split(':');
|
||||||
|
this.socket.connect(parseInt(_sock[1]), _sock[0]);
|
||||||
|
}else{
|
||||||
|
this.socket.connect(this.socketfile);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.onClose();
|
this.onClose();
|
||||||
}
|
}
|
||||||
|
|||||||
22
src/User.ts
22
src/User.ts
@@ -1,6 +1,7 @@
|
|||||||
import * as Utilities from './Utilities.js';
|
import * as Utilities from './Utilities.js';
|
||||||
import * as guacutils from './guacutils.js';
|
import * as guacutils from './guacutils.js';
|
||||||
import {WebSocket} from 'ws';
|
import {WebSocket} from 'ws';
|
||||||
|
import {IPData} from './IPData.js';
|
||||||
import IConfig from './IConfig.js';
|
import IConfig from './IConfig.js';
|
||||||
import RateLimiter from './RateLimiter.js';
|
import RateLimiter from './RateLimiter.js';
|
||||||
import { execaCommand } from 'execa';
|
import { execaCommand } from 'execa';
|
||||||
@@ -12,25 +13,20 @@ export class User {
|
|||||||
username? : string;
|
username? : string;
|
||||||
connectedToNode : boolean;
|
connectedToNode : boolean;
|
||||||
rank : Rank;
|
rank : Rank;
|
||||||
muted : Boolean;
|
|
||||||
tempMuteExpireTimeout? : NodeJS.Timer;
|
|
||||||
msgsSent : number;
|
msgsSent : number;
|
||||||
Config : IConfig;
|
Config : IConfig;
|
||||||
IP : string;
|
IP : IPData;
|
||||||
vote : boolean | null;
|
|
||||||
// Rate limiters
|
// Rate limiters
|
||||||
ChatRateLimit : RateLimiter;
|
ChatRateLimit : RateLimiter;
|
||||||
LoginRateLimit : RateLimiter;
|
LoginRateLimit : RateLimiter;
|
||||||
RenameRateLimit : RateLimiter;
|
RenameRateLimit : RateLimiter;
|
||||||
TurnRateLimit : RateLimiter;
|
TurnRateLimit : RateLimiter;
|
||||||
constructor(ws : WebSocket, ip : string, config : IConfig, username? : string, node? : string) {
|
constructor(ws : WebSocket, ip : IPData, config : IConfig, username? : string, node? : string) {
|
||||||
this.IP = ip;
|
this.IP = ip;
|
||||||
this.connectedToNode = false;
|
this.connectedToNode = false;
|
||||||
this.Config = config;
|
this.Config = config;
|
||||||
this.socket = ws;
|
this.socket = ws;
|
||||||
this.muted = false;
|
|
||||||
this.msgsSent = 0;
|
this.msgsSent = 0;
|
||||||
this.vote = null;
|
|
||||||
this.socket.on('close', () => {
|
this.socket.on('close', () => {
|
||||||
clearInterval(this.nopSendInterval);
|
clearInterval(this.nopSendInterval);
|
||||||
});
|
});
|
||||||
@@ -86,22 +82,22 @@ export class User {
|
|||||||
this.ChatRateLimit.request();
|
this.ChatRateLimit.request();
|
||||||
}
|
}
|
||||||
mute(permanent : boolean) {
|
mute(permanent : boolean) {
|
||||||
this.muted = true;
|
this.IP.muted = true;
|
||||||
this.sendMsg(guacutils.encode("chat", "", `You have been muted${permanent ? "" : ` for ${this.Config.collabvm.tempMuteTime} seconds`}.`));
|
this.sendMsg(guacutils.encode("chat", "", `You have been muted${permanent ? "" : ` for ${this.Config.collabvm.tempMuteTime} seconds`}.`));
|
||||||
if (!permanent) {
|
if (!permanent) {
|
||||||
clearTimeout(this.tempMuteExpireTimeout);
|
clearTimeout(this.IP.tempMuteExpireTimeout);
|
||||||
this.tempMuteExpireTimeout = setTimeout(() => this.unmute(), this.Config.collabvm.tempMuteTime * 1000);
|
this.IP.tempMuteExpireTimeout = setTimeout(() => this.unmute(), this.Config.collabvm.tempMuteTime * 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unmute() {
|
unmute() {
|
||||||
clearTimeout(this.tempMuteExpireTimeout);
|
clearTimeout(this.IP.tempMuteExpireTimeout);
|
||||||
this.muted = false;
|
this.IP.muted = false;
|
||||||
this.sendMsg(guacutils.encode("chat", "", "You are no longer muted."));
|
this.sendMsg(guacutils.encode("chat", "", "You are no longer muted."));
|
||||||
}
|
}
|
||||||
|
|
||||||
async ban() {
|
async ban() {
|
||||||
// Prevent the user from taking turns or chatting, in case the ban command takes a while
|
// Prevent the user from taking turns or chatting, in case the ban command takes a while
|
||||||
this.muted = true;
|
this.IP.muted = true;
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
var cmd = this.Config.collabvm.bancmd.replace(/\$IP/g, this.IP).replace(/\$NAME/g, this.username);
|
var cmd = this.Config.collabvm.bancmd.replace(/\$IP/g, this.IP).replace(/\$NAME/g, this.username);
|
||||||
await execaCommand(cmd);
|
await execaCommand(cmd);
|
||||||
|
|||||||
@@ -12,12 +12,14 @@ import { createHash } from 'crypto';
|
|||||||
import { isIP } from 'net';
|
import { isIP } from 'net';
|
||||||
import QEMUVM from './QEMUVM.js';
|
import QEMUVM from './QEMUVM.js';
|
||||||
import { Canvas, createCanvas, CanvasRenderingContext2D } from 'canvas';
|
import { Canvas, createCanvas, CanvasRenderingContext2D } from 'canvas';
|
||||||
|
import { IPData } from './IPData.js';
|
||||||
|
|
||||||
export default class WSServer {
|
export default class WSServer {
|
||||||
private Config : IConfig;
|
private Config : IConfig;
|
||||||
private server : http.Server;
|
private server : http.Server;
|
||||||
private socket : WebSocketServer;
|
private socket : WebSocketServer;
|
||||||
private clients : User[];
|
private clients : User[];
|
||||||
|
private ips : IPData[];
|
||||||
private ChatHistory : CircularBuffer<{user:string,msg:string}>
|
private ChatHistory : CircularBuffer<{user:string,msg:string}>
|
||||||
private TurnQueue : Queue<User>;
|
private TurnQueue : Queue<User>;
|
||||||
// Time remaining on the current turn
|
// Time remaining on the current turn
|
||||||
@@ -33,9 +35,9 @@ export default class WSServer {
|
|||||||
// How much time is left on the vote
|
// How much time is left on the vote
|
||||||
private voteTime : number;
|
private voteTime : number;
|
||||||
// How much time until another reset vote can be cast
|
// How much time until another reset vote can be cast
|
||||||
private voteTimeout : number;
|
private voteCooldown : number;
|
||||||
// Interval to keep track
|
// Interval to keep track
|
||||||
private voteTimeoutInterval? : NodeJS.Timer;
|
private voteCooldownInterval? : NodeJS.Timer;
|
||||||
// Completely disable turns
|
// Completely disable turns
|
||||||
private turnsAllowed : boolean;
|
private turnsAllowed : boolean;
|
||||||
// Indefinite turn
|
// Indefinite turn
|
||||||
@@ -48,10 +50,11 @@ export default class WSServer {
|
|||||||
this.TurnTime = 0;
|
this.TurnTime = 0;
|
||||||
this.TurnIntervalRunning = false;
|
this.TurnIntervalRunning = false;
|
||||||
this.clients = [];
|
this.clients = [];
|
||||||
|
this.ips = [];
|
||||||
this.Config = config;
|
this.Config = config;
|
||||||
this.voteInProgress = false;
|
this.voteInProgress = false;
|
||||||
this.voteTime = 0;
|
this.voteTime = 0;
|
||||||
this.voteTimeout = 0;
|
this.voteCooldown = 0;
|
||||||
this.turnsAllowed = true;
|
this.turnsAllowed = true;
|
||||||
this.indefiniteTurn = null;
|
this.indefiniteTurn = null;
|
||||||
this.ModPerms = Utilities.MakeModPerms(this.Config.collabvm.moderatorPermissions);
|
this.ModPerms = Utilities.MakeModPerms(this.Config.collabvm.moderatorPermissions);
|
||||||
@@ -120,7 +123,7 @@ export default class WSServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private onConnection(ws : WebSocket, req : http.IncomingMessage) {
|
private onConnection(ws : WebSocket, req : http.IncomingMessage) {
|
||||||
var ip;
|
var ip: string;
|
||||||
if (this.Config.http.proxying) {
|
if (this.Config.http.proxying) {
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
if (!req.proxiedIP) return;
|
if (!req.proxiedIP) return;
|
||||||
@@ -130,7 +133,17 @@ export default class WSServer {
|
|||||||
if (!req.socket.remoteAddress) return;
|
if (!req.socket.remoteAddress) return;
|
||||||
ip = req.socket.remoteAddress;
|
ip = req.socket.remoteAddress;
|
||||||
}
|
}
|
||||||
var user = new User(ws, ip, this.Config);
|
|
||||||
|
var _ipdata = this.ips.filter(data => data.address == ip);
|
||||||
|
var ipdata;
|
||||||
|
if(_ipdata.length > 0) {
|
||||||
|
ipdata = _ipdata[0];
|
||||||
|
}else{
|
||||||
|
ipdata = new IPData(ip);
|
||||||
|
this.ips.push(ipdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
var user = new User(ws, ipdata, this.Config);
|
||||||
this.clients.push(user);
|
this.clients.push(user);
|
||||||
ws.on('close', () => this.connectionClosed(user));
|
ws.on('close', () => this.connectionClosed(user));
|
||||||
ws.on('message', (e) => {
|
ws.on('message', (e) => {
|
||||||
@@ -144,12 +157,13 @@ export default class WSServer {
|
|||||||
this.onMessage(user, msg);
|
this.onMessage(user, msg);
|
||||||
});
|
});
|
||||||
user.sendMsg(this.getAdduserMsg());
|
user.sendMsg(this.getAdduserMsg());
|
||||||
console.log(`[Connect] From ${user.IP}`);
|
console.log(`[Connect] From ${user.IP.address}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
private connectionClosed(user : User) {
|
private connectionClosed(user : User) {
|
||||||
|
if(user.IP.vote != null) user.IP.vote = null;
|
||||||
this.clients.splice(this.clients.indexOf(user), 1);
|
this.clients.splice(this.clients.indexOf(user), 1);
|
||||||
console.log(`[DISCONNECT] From ${user.IP}${user.username ? ` with username ${user.username}` : ""}`);
|
console.log(`[DISCONNECT] From ${user.IP.address}${user.username ? ` with username ${user.username}` : ""}`);
|
||||||
if (!user.username) return;
|
if (!user.username) return;
|
||||||
if (this.TurnQueue.toArray().indexOf(user) !== -1) {
|
if (this.TurnQueue.toArray().indexOf(user) !== -1) {
|
||||||
var hadturn = (this.TurnQueue.peek() === user);
|
var hadturn = (this.TurnQueue.peek() === user);
|
||||||
@@ -189,7 +203,7 @@ export default class WSServer {
|
|||||||
break;
|
break;
|
||||||
case "chat":
|
case "chat":
|
||||||
if (!client.username) return;
|
if (!client.username) return;
|
||||||
if (client.muted) return;
|
if (client.IP.muted) return;
|
||||||
if (msgArr.length !== 2) return;
|
if (msgArr.length !== 2) return;
|
||||||
var msg = Utilities.HTMLSanitize(msgArr[1]);
|
var msg = Utilities.HTMLSanitize(msgArr[1]);
|
||||||
// One of the things I hated most about the old server is it completely discarded your message if it was too long
|
// One of the things I hated most about the old server is it completely discarded your message if it was too long
|
||||||
@@ -226,7 +240,7 @@ export default class WSServer {
|
|||||||
if (this.TurnQueue.toArray().indexOf(client) !== -1) return;
|
if (this.TurnQueue.toArray().indexOf(client) !== -1) return;
|
||||||
// If they're muted, also fuck them off.
|
// If they're muted, also fuck them off.
|
||||||
// Send them the turn queue to prevent client glitches
|
// Send them the turn queue to prevent client glitches
|
||||||
if (client.muted) return;
|
if (client.IP.muted) return;
|
||||||
this.TurnQueue.enqueue(client);
|
this.TurnQueue.enqueue(client);
|
||||||
if (this.TurnQueue.size === 1) this.nextTurn();
|
if (this.TurnQueue.size === 1) this.nextTurn();
|
||||||
} else {
|
} else {
|
||||||
@@ -261,22 +275,22 @@ export default class WSServer {
|
|||||||
switch (msgArr[1]) {
|
switch (msgArr[1]) {
|
||||||
case "1":
|
case "1":
|
||||||
if (!this.voteInProgress) {
|
if (!this.voteInProgress) {
|
||||||
if (this.voteTimeout !== 0) {
|
if (this.voteCooldown !== 0) {
|
||||||
client.sendMsg(guacutils.encode("vote", "3", this.voteTimeout.toString()));
|
client.sendMsg(guacutils.encode("vote", "3", this.voteCooldown.toString()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.startVote();
|
this.startVote();
|
||||||
this.clients.forEach(c => c.sendMsg(guacutils.encode("chat", "", `${client.username} has started a vote to reset the VM.`)));
|
this.clients.forEach(c => c.sendMsg(guacutils.encode("chat", "", `${client.username} has started a vote to reset the VM.`)));
|
||||||
}
|
}
|
||||||
else if (client.vote !== true)
|
else if (client.IP.vote !== true)
|
||||||
this.clients.forEach(c => c.sendMsg(guacutils.encode("chat", "", `${client.username} has voted yes.`)));
|
this.clients.forEach(c => c.sendMsg(guacutils.encode("chat", "", `${client.username} has voted yes.`)));
|
||||||
client.vote = true;
|
client.IP.vote = true;
|
||||||
break;
|
break;
|
||||||
case "0":
|
case "0":
|
||||||
if (!this.voteInProgress) return;
|
if (!this.voteInProgress) return;
|
||||||
if (client.vote !== false)
|
if (client.IP.vote !== false)
|
||||||
this.clients.forEach(c => c.sendMsg(guacutils.encode("chat", "", `${client.username} has voted no.`)));
|
this.clients.forEach(c => c.sendMsg(guacutils.encode("chat", "", `${client.username} has voted no.`)));
|
||||||
client.vote = false;
|
client.IP.vote = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
this.sendVoteUpdate();
|
this.sendVoteUpdate();
|
||||||
@@ -397,7 +411,7 @@ export default class WSServer {
|
|||||||
if (msgArr.length !== 3) return;
|
if (msgArr.length !== 3) return;
|
||||||
var user = this.clients.find(c => c.username === msgArr[2]);
|
var user = this.clients.find(c => c.username === msgArr[2]);
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
client.sendMsg(guacutils.encode("admin", "19", msgArr[2], user.IP));
|
client.sendMsg(guacutils.encode("admin", "19", msgArr[2], user.IP.address));
|
||||||
break;
|
break;
|
||||||
case "20":
|
case "20":
|
||||||
// Steal turn
|
// Steal turn
|
||||||
@@ -473,7 +487,9 @@ export default class WSServer {
|
|||||||
}
|
}
|
||||||
if (this.getUsernameList().indexOf(newName) !== -1) {
|
if (this.getUsernameList().indexOf(newName) !== -1) {
|
||||||
client.assignGuestName(this.getUsernameList());
|
client.assignGuestName(this.getUsernameList());
|
||||||
status = "1";
|
if(client.connectedToNode) {
|
||||||
|
status = "1";
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
if (!/^[a-zA-Z0-9\ \-\_\.]+$/.test(newName) || newName.length > 20 || newName.length < 3) {
|
if (!/^[a-zA-Z0-9\ \-\_\.]+$/.test(newName) || newName.length > 20 || newName.length < 3) {
|
||||||
client.assignGuestName(this.getUsernameList());
|
client.assignGuestName(this.getUsernameList());
|
||||||
@@ -487,12 +503,12 @@ export default class WSServer {
|
|||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
client.sendMsg(guacutils.encode("rename", "0", status, client.username));
|
client.sendMsg(guacutils.encode("rename", "0", status, client.username));
|
||||||
if (hadName) {
|
if (hadName) {
|
||||||
console.log(`[RENAME] ${client.IP} from ${oldname} to ${client.username}`);
|
console.log(`[RENAME] ${client.IP.address} from ${oldname} to ${client.username}`);
|
||||||
this.clients.filter(c => c.username !== client.username).forEach((c) =>
|
this.clients.filter(c => c.username !== client.username).forEach((c) =>
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
c.sendMsg(guacutils.encode("rename", "1", oldname, client.username)));
|
c.sendMsg(guacutils.encode("rename", "1", oldname, client.username)));
|
||||||
} else {
|
} else {
|
||||||
console.log(`[RENAME] ${client.IP} to ${client.username}`);
|
console.log(`[RENAME] ${client.IP.address} to ${client.username}`);
|
||||||
this.clients.forEach((c) =>
|
this.clients.forEach((c) =>
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
c.sendMsg(guacutils.encode("adduser", "1", client.username, client.rank)));
|
c.sendMsg(guacutils.encode("adduser", "1", client.username, client.rank)));
|
||||||
@@ -624,12 +640,14 @@ export default class WSServer {
|
|||||||
} else {
|
} else {
|
||||||
this.clients.forEach(c => c.sendMsg(guacutils.encode("chat", "", "The vote to reset the VM has lost.")));
|
this.clients.forEach(c => c.sendMsg(guacutils.encode("chat", "", "The vote to reset the VM has lost.")));
|
||||||
}
|
}
|
||||||
this.clients.forEach(c => c.vote = null);
|
this.clients.forEach(c => {
|
||||||
this.voteTimeout = 180;
|
c.IP.vote = null;
|
||||||
this.voteTimeoutInterval = setInterval(() => {
|
});
|
||||||
this.voteTimeout--;
|
this.voteCooldown = this.Config.collabvm.voteCooldown;
|
||||||
if (this.voteTimeout < 1)
|
this.voteCooldownInterval = setInterval(() => {
|
||||||
clearInterval(this.voteTimeoutInterval);
|
this.voteCooldown--;
|
||||||
|
if (this.voteCooldown < 1)
|
||||||
|
clearInterval(this.voteCooldownInterval);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -646,7 +664,7 @@ export default class WSServer {
|
|||||||
getVoteCounts() : {yes:number,no:number} {
|
getVoteCounts() : {yes:number,no:number} {
|
||||||
var yes = 0;
|
var yes = 0;
|
||||||
var no = 0;
|
var no = 0;
|
||||||
this.clients.forEach((c) => {
|
this.ips.forEach((c) => {
|
||||||
if (c.vote === true) yes++;
|
if (c.vote === true) yes++;
|
||||||
if (c.vote === false) no++;
|
if (c.vote === false) no++;
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user