pokemon-showdown/test/users-utils.js
Guangcong Luo 46c9afa2f3
"Remove" the global room (#6885)
I couldn't completely remove the global room in one commit, but this
solves basically every problem with it by making it no longer a `Room`.

In particular, this means:

- It's no longer of type `Room`
- It's no longer in the `Rooms.rooms` table
- Its class name is now `GlobalRoomState` rather than `GlobalRoom`
- It no longer tracks its own user list (online user count is now
  provided by `Users.onlineCount`)
- It's no longer a socket channel (there's new syntax for "send this
  message to every user")
2020-07-02 11:31:34 -07:00

174 lines
4.1 KiB
JavaScript

'use strict';
/** @type {typeof import('../lib/streams').ObjectReadWriteStream} */
const ObjectReadWriteStream = require('../.lib-dist/streams').ObjectReadWriteStream;
/** @extends {ObjectReadWriteStream<string>} */
class WorkerStream extends ObjectReadWriteStream {
constructor(id) {
super();
this.id = id;
this.process = {connected: true};
this.sockets = new Set();
this.rooms = new Map();
this.roomChannels = new Map();
}
_write(msg) {
const cmd = msg.charAt(0);
const params = msg.substr(1).split('\n');
switch (cmd) {
case '!':
return this.removeSocket(...params);
case '>':
return this.sendToSocket(...params);
case '#':
return this.sendToRoom(...params);
case '+':
return this.addToRoom(...params);
case '-':
return this.removeFromRoom(...params);
case '.':
return this.moveToChannel(...params);
case ':':
return this.broadcastToChannels(params[0]);
}
}
addSocket(socketid) {
this.sockets.add(+socketid);
}
removeSocket(socketid) {
socketid = +socketid;
if (!this.sockets.has(socketid)) {
throw new Error(`Attempted to disconnect nonexistent socket ${socketid}`);
}
this.sockets.delete(socketid);
for (const room of this.rooms.values()) {
room.delete(socketid);
}
}
sendToSocket(socketid, msg) {
socketid = +socketid;
if (!this.sockets.has(socketid)) {
throw new Error(`Attempted to send ${msg} to nonexistent socket ${socketid}`);
}
}
sendToRoom(roomid, msg) {
if (!this.rooms.has(roomid)) {
throw new Error(`Attempted to send ${msg} to nonexistent room ${roomid}`);
}
}
addToRoom(roomid, socketid) {
socketid = +socketid;
if (!this.rooms.has(roomid)) {
this.rooms.set(roomid, new Set([socketid]));
return;
}
const room = this.rooms.get(roomid);
if (room.has(socketid)) {
throw new Error(`Attempted to redundantly add socket ${socketid} to room ${roomid}`);
}
room.add(socketid);
}
removeFromRoom(roomid, socketid) {
socketid = +socketid;
if (!this.rooms.has(roomid)) {
throw new Error(`Attempted to remove socket ${socketid} from nonexistent room ${roomid}`);
}
const room = this.rooms.get(roomid);
if (!room.has(socketid)) {
throw new Error(`Attempted to remove nonexistent socket ${socketid} from room ${roomid}`);
}
room.delete(socketid);
if (!room.size) {
this.rooms.delete(roomid);
this.roomChannels.delete(roomid);
}
}
moveToChannel(roomid, channelid, socketid) {
socketid = +socketid;
if (!this.rooms.has(roomid)) {
throw new Error(`Attempted to move socket ${socketid} to channel ${channelid} of nonexistent room ${roomid}`);
}
if (!this.roomChannels.has(roomid)) {
if (channelid === '0') return;
this.roomChannels.set(roomid, new Map([[socketid, channelid]]));
return;
}
const channel = this.roomChannels.get(roomid);
if (!channel.has(socketid)) {
if (channelid !== '0') channel.set(socketid, channelid);
return;
}
if (channelid === '0') {
channel.delete(socketid);
} else {
channel.set(socketid, channelid);
}
}
broadcastToChannels(roomid) {
if (!this.rooms.has(roomid)) {
throw new Error(`Attempted to broadcast to roomChannels of nonexistent room ${roomid}`);
}
if (!this.roomChannels.has(roomid)) {
throw new Error(`Attempted to broadcast to nonexistent roomChannels of room ${roomid}`);
}
}
}
class Worker {
constructor(id) {
this.id = id;
this.stream = new WorkerStream(id);
}
}
const worker = new Worker(1);
function createConnection(ip, workerid, socketid) {
if (workerid || socketid) {
throw new Error("deprecated");
}
workerid = 1;
if (!socketid) {
socketid = 1;
while (Users.connections.has(`${workerid}-${socketid}`)) {
socketid++;
}
}
worker.stream.addSocket(socketid);
const connectionid = `${workerid}-${socketid}`;
const connection = new Users.Connection(connectionid, worker, socketid, null, ip || '127.0.0.1');
Users.connections.set(connectionid, connection);
return connection;
}
function createUser(connection) {
if (!connection) connection = createConnection();
const user = new Users.User(connection);
connection.user = user;
return user;
}
exports.Connection = createConnection;
exports.User = createUser;