Switch BinatoStream to use tokens rather than user ids

This commit is contained in:
Ethan Stubbs 2021-02-01 03:01:37 +00:00
parent 4fe479ae39
commit 0848c0b1e4
17 changed files with 184 additions and 55 deletions

View file

@ -15,6 +15,7 @@
"express": "^4.17.1",
"fs": "0.0.1-security",
"osu-packet": "^4.1.2",
"python-struct": "^1.1.3",
"request": "^2.88.2",
"sync-request": "^6.1.0",
"tcp-netx": "^1.2.11",

19
server/ActionBuffer.js Normal file
View file

@ -0,0 +1,19 @@
module.exports = class {
constructor(initialData = Buffer) {
this.actionBuffer;
if (initialData.length == 0) {
this.actionBuffer = Buffer.alloc(0);
} else {
this.actionBuffer = initialData;
}
}
bufferAction(data = Buffer) {
if (data.length != 0)
this.actionBuffer = Buffer.concat([this.actionBuffer, data], this.actionBuffer.length + data.length);
}
toBuffer() {
return this.actionBuffer;
}
}

View file

@ -38,7 +38,7 @@ module.exports = class {
slot.playerId = -1;
slot.status = 2;
// Remove the kicked player from the match's stream
global.StreamsHandler.removeUserFromStream(this.MultiplayerMatch.matchStreamName, kickedPlayer.id);
global.StreamsHandler.removeUserFromStream(this.MultiplayerMatch.matchStreamName, kickedPlayer.uuid);
// Remove the kicked player's referance this this match
kickedPlayer.currentMatch = null;

View file

@ -16,7 +16,7 @@ module.exports = class {
currentUser.currentMatch.leaveMatch(currentUser);
// Add user to the stream for the lobby
global.StreamsHandler.addUserToStream("multiplayer_lobby", currentUser.id);
global.StreamsHandler.addUserToStream("multiplayer_lobby", currentUser.uuid);
// Send user ids of all online users to all users in the lobby
global.StreamsHandler.sendToStream("multiplayer_lobby", UserPresenceBundle(currentUser, false), null);
@ -43,8 +43,8 @@ module.exports = class {
const osuPacketWriter = new osu.Bancho.Writer;
// Add the user to the #lobby channel
if (!global.StreamsHandler.isUserInStream("#lobby", currentUser.id)) {
global.StreamsHandler.addUserToStream("#lobby", currentUser.id);
if (!global.StreamsHandler.isUserInStream("#lobby", currentUser.uuid)) {
global.StreamsHandler.addUserToStream("#lobby", currentUser.uuid);
osuPacketWriter.ChannelJoinSuccess("#lobby");
}
@ -53,8 +53,8 @@ module.exports = class {
userLeaveLobby(currentUser) {
// Remove user from the stream for the multiplayer lobby if they are a part of it
if (global.StreamsHandler.isUserInStream("multiplayer_lobby", currentUser.id))
global.StreamsHandler.removeUserFromStream("multiplayer_lobby", currentUser.id);
if (global.StreamsHandler.isUserInStream("multiplayer_lobby", currentUser.uuid))
global.StreamsHandler.removeUserFromStream("multiplayer_lobby", currentUser.uuid);
}
updateMatchListing() {
@ -141,7 +141,7 @@ module.exports = class {
JoiningUser.currentMatch = match;
// Add user to the stream for the match
global.StreamsHandler.addUserToStream(streamName, JoiningUser.id);
global.StreamsHandler.addUserToStream(streamName, JoiningUser.uuid);
// Inform all users in the match that a new user has joined
global.StreamsHandler.sendToStream(streamName, osuPacketWriter1.toBuffer, null);
@ -212,4 +212,26 @@ module.exports = class {
this.updateMatchListing();
}, 1000);
}
getMatchInfoForTourneyClient(MatchID) {
let match = null;
for (let amatch in this.matches) {
if (amatch.matchId == MatchID) {
match = amatch;
}
}
if (match == null) return null;
else return match.createOsuMatchJSON();
}
getMatch(MatchID) {
let match = null;
for (let amatch in this.matches) {
if (amatch.matchId == MatchID) {
match = amatch;
}
}
if (match == null) return null;
else return match;
}
}

View file

@ -47,6 +47,9 @@ module.exports = class {
this.multiplayerExtras = null;
this.isTourneyMatch = false;
this.tourneyClientUsers = [];
const osuPacketWriter = new osu.Bancho.Writer;
// Update the status of the current user
@ -118,7 +121,7 @@ module.exports = class {
osuPacketWriter.MatchUpdate(this.createOsuMatchJSON());
// Remove the leaving user from the match's stream
global.StreamsHandler.removeUserFromStream(this.matchStreamName, MatchUser.id);
global.StreamsHandler.removeUserFromStream(this.matchStreamName, MatchUser.uuid);
// Inform all users in the match that the leaving user has left
global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null);
@ -212,6 +215,22 @@ module.exports = class {
global.MultiplayerManager.updateMatchListing();
}
changeTeam(MatchUser) {
const slot = this.slots[MatchUser.matchSlotId];
if (slot.team == 0) {
slot.team = 1;
} else {
slot.team = 0;
}
const osuPacketWriter = new osu.Bancho.Writer;
osuPacketWriter.MatchUpdate(this.createOsuMatchJSON());
// Send this change to all users in the match
global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null);
}
setReadyState(MatchUser, ReadyState) {
// Get the match the user is in
const osuPacketWriter = new osu.Bancho.Writer;
@ -245,7 +264,7 @@ module.exports = class {
// Get the data of the slot at the index sent by the client
const slot = this.slots[MatchUserToKick];
let cachedPlayerId = slot.playerId;
let cachedPlayerToken = getUserById(slot.playerId).uuid;
// If the slot is empty lock instead of kicking
if (slot.playerId === -1) { // Slot is empty, lock it
@ -268,9 +287,9 @@ module.exports = class {
// Update the match listing in the lobby listing to reflect this change
global.MultiplayerManager.updateMatchListing();
if (cachedPlayerId !== null && cachedPlayerId !== -1) {
if (cachedPlayerToken !== null && cachedPlayerToken !== "") {
// Remove the kicked user from the match stream
global.StreamsHandler.removeUserFromStream(this.matchStreamName, cachedPlayerId);
global.StreamsHandler.removeUserFromStream(this.matchStreamName, cachedPlayerToken);
}
}

View file

@ -2,6 +2,7 @@ const StatusUpdate = require("./StatusUpdate.js");
module.exports = function(currentUser, data) {
currentUser.updatePresence(data);
if (global.StreamsHandler.doesStreamExist(`sp_${currentUser.username}`)) {
const statusUpdate = StatusUpdate(currentUser, currentUser.id, false);
global.StreamsHandler.sendToStream(`sp_${currentUser.username}`, statusUpdate, null);

View file

@ -2,14 +2,14 @@ const osu = require("osu-packet");
module.exports = function(CurrentUser, channelName = "") {
// Make sure the user is not already in the channel
if (global.StreamsHandler.isUserInStream(channelName, CurrentUser.id))
if (global.StreamsHandler.isUserInStream(channelName, CurrentUser.uuid))
return global.consoleHelper.printBancho(`Did not add user to channel ${channelName} because they are already in it`);
const osuPacketWriter = new osu.Bancho.Writer;
osuPacketWriter.ChannelJoinSuccess(channelName);
if (!global.StreamsHandler.isUserInStream(channelName, CurrentUser.id))
global.StreamsHandler.addUserToStream(channelName, CurrentUser.id);
if (!global.StreamsHandler.isUserInStream(channelName, CurrentUser.uuid))
global.StreamsHandler.addUserToStream(channelName, CurrentUser.uuid);
CurrentUser.addActionToQueue(osuPacketWriter.toBuffer);
}

View file

@ -1,5 +1,5 @@
module.exports = function(CurrentUser, data) {
if (data == "#multiplayer") return; // Ignore requests for multiplayer
global.StreamsHandler.removeUserFromStream(data, CurrentUser.id);
global.StreamsHandler.removeUserFromStream(data, CurrentUser.uuid);
}

View file

@ -6,8 +6,8 @@ module.exports = function(CurrentUser) {
const streamList = global.StreamsHandler.getStreams();
for (let i = 0; i < streamList.length; i++) {
if (global.StreamsHandler.isUserInStream(streamList[i], CurrentUser.id)) {
global.StreamsHandler.removeUserFromStream(streamList[i], CurrentUser.id);
if (global.StreamsHandler.isUserInStream(streamList[i], CurrentUser.uuid)) {
global.StreamsHandler.removeUserFromStream(streamList[i], CurrentUser.uuid);
}
}

View file

@ -36,7 +36,7 @@ module.exports = function(CurrentUser, CurrentPacket) {
});
if (CurrentPacket.data.target == "#multiplayer") {
global.StreamsHandler.sendToStream(CurrentUser.currentMatch.matchStreamName, osuPacketWriter.toBuffer, CurrentUser.id);
global.StreamsHandler.sendToStream(CurrentUser.currentMatch.matchStreamName, osuPacketWriter.toBuffer, CurrentUser.uuid);
botCommandHandler(CurrentUser, CurrentPacket.data.message, CurrentUser.currentMatch.matchStreamName, true);
return;
}
@ -45,7 +45,7 @@ module.exports = function(CurrentUser, CurrentPacket) {
if (!global.StreamsHandler.doesStreamExist(CurrentPacket.data.target)) return;
// Write chat message to stream asociated with chat channel
global.StreamsHandler.sendToStream(CurrentPacket.data.target, osuPacketWriter.toBuffer, CurrentUser.id);
global.StreamsHandler.sendToStream(CurrentPacket.data.target, osuPacketWriter.toBuffer, CurrentUser.uuid);
if (CurrentPacket.data.target == "#osu")
global.addChatMessage(`${CurrentUser.username}: ${CurrentPacket.data.message}`);
botCommandHandler(CurrentUser, CurrentPacket.data.message, CurrentPacket.data.target);

View file

@ -0,0 +1,26 @@
const osu = require("osu-packet");
module.exports = function(CurrentUser, MatchID) {
const match = global.MultiplayerManager.getMatch(MatchID);
if (match != null) {
match.isTourneyMatch = true;
for (let i = 0; i < global.users.length; i++) {
if (global.users[i].id == CurrentUser.id) {
match.tourneyClientUsers.push(global.users[i]);
}
}
if (global.StreamsHandler.isUserInStream(match.matchStreamName, CurrentUser.uuid))
return global.consoleHelper.printBancho(`Did not add user to channel ${match.matchStreamName} because they are already in it`);
const osuPacketWriter = new osu.Bancho.Writer;
osuPacketWriter.ChannelJoinSuccess("#multiplayer");
if (!global.StreamsHandler.isUserInStream(match.matchStreamName, CurrentUser.uuid))
global.StreamsHandler.addUserToStream(match.matchStreamName, CurrentUser.uuid);
CurrentUser.addActionToQueue(osuPacketWriter.toBuffer);
}
}

View file

@ -0,0 +1,24 @@
const osu = require("osu-packet"),
ActionBuffer = require("../ActionBuffer.js");
const UserPresence = require("./UserPresence.js"),
StatusUpdate = require("./StatusUpdate.js");
module.exports = function(CurrentUser, MatchID) {
const matchData = global.MultiplayerManager.getMatchInfoForTourneyClient(MatchID);
if (matchData != null) {
const osuPacketWriter = new osu.Bancho.Writer();
osuPacketWriter.MatchUpdate(matchData);
let actions = new ActionBuffer(osuPacketWriter.toBuffer);
for (let i = 0; i < matchData.slots.length; i++) {
const slot = matchData.slots[i];
actions.bufferAction(UserPresence(CurrentUser, slot.playerId, false));
actions.bufferAction(StatusUpdate(CurrentUser, slot.playerId, false));
}
CurrentUser.addActionToQueue(actions.toBuffer());
}
}

View file

@ -7,11 +7,11 @@ module.exports = {
const User = getUserById(spectatedId);
if (global.StreamsHandler.doesStreamExist(`sp_${User.username}`)) {
// Just add user to stream since it already exists
global.StreamsHandler.addUserToStream(`sp_${User.username}`, currentUser.id);
global.StreamsHandler.addUserToStream(`sp_${User.username}`, currentUser.uuid);
} else {
// Stream doesn't exist, create it and add the spectator
global.StreamsHandler.addStream(`sp_${User.username}`, true, spectatedId);
global.StreamsHandler.addUserToStream(`sp_${User.username}`, currentUser.id);
global.StreamsHandler.addUserToStream(`sp_${User.username}`, currentUser.uuid);
}
// We want to do this stuff regardless
@ -61,7 +61,7 @@ module.exports = {
spectatedUser.addActionToQueue(osuPacketWriter.toBuffer);
// Remove this user from the spectator stream
global.StreamsHandler.removeUserFromStream(`sp_${spectatedUser.username}`, currentUser.id);
global.StreamsHandler.removeUserFromStream(`sp_${spectatedUser.username}`, currentUser.uuid);
// Make a new clear osu packet writer
osuPacketWriter = new osu.Bancho.Writer;

View file

@ -1,4 +1,4 @@
const getUserById = require("./util/getUserById.js");
const getUserByToken = require("./util/getUserByToken.js");
module.exports = class {
constructor() {
@ -12,7 +12,7 @@ module.exports = class {
return global.consoleHelper.printBancho(`Did not add stream [${streamName}] A stream with the same name already exists`);
// Add new stream to the list of streams
this.avaliableStreams[streamName] = {
streamUsers: [], // An array containing a list of user IDs of the users in a given stream
streamUsers: [], // An array containing a list of user tokens of the users in a given stream
streamSpectatorHost: spectatorHostId, // null unless stream is for spectating
removeIfEmpty: removeIfEmpty
}
@ -47,14 +47,14 @@ module.exports = class {
try {
// Loop through the users in this stream
for (let i = 0; i < currentStream.streamUsers.length; i++) {
// Get the user id of the user in the queue
const currentUserId = currentStream.streamUsers[i];
// Get the user token of the user in the queue
const currentUserToken = currentStream.streamUsers[i];
// Make sure we don't send this data back to the user requesting this data to be sent
if (initUser != null && currentUserId == initUser && (streamName[0] == "#" || streamName.includes("mp_"))) continue;
if (currentUserId == 3) continue; // Skip if user is bot
if (initUser != null && currentUserToken == initUser && (streamName[0] == "#" || streamName.includes("mp_"))) continue;
if (currentUserToken == 3) continue; // Skip if user is bot
// Get user object
const currentUser = getUserById(currentUserId);
const currentUser = getUserByToken(currentUserToken);
// Skip if user is nonexistant
if (currentUser == null) continue;
@ -64,41 +64,41 @@ module.exports = class {
} catch (e) {}
}
addUserToStream(streamName, userId) {
addUserToStream(streamName, userToken) {
// Make sure the stream we are attempting to add this user to even exists
if (!this.doesStreamExist(streamName))
return global.consoleHelper.printBancho(`Did not add user to stream [${streamName}] because it does not exist!`);
// Make sure the user isn't already in the stream
if (this.avaliableStreams[streamName].streamUsers.includes(userId))
if (this.avaliableStreams[streamName].streamUsers.includes(userToken))
return global.consoleHelper.printBancho(`Did not add user to stream [${streamName}] because they are already in it!`);
// Make sure this isn't an invalid user (userId can't be lower than 1)
if (userId <= 0 || userId == null)
return global.consoleHelper.printBancho(`Did not add user to stream [${streamName}] because their userId is invalid!`);
if (userToken == "" || userToken == null)
return global.consoleHelper.printBancho(`Did not add user to stream [${streamName}] because their token is invalid!`);
// Add user's id to the stream's user list
this.avaliableStreams[streamName].streamUsers.push(userId);
global.consoleHelper.printBancho(`Added user [${userId}] to stream ${streamName}`);
// Add user's token to the stream's user list
this.avaliableStreams[streamName].streamUsers.push(userToken);
global.consoleHelper.printBancho(`Added user [${userToken}] to stream ${streamName}`);
}
removeUserFromStream(streamName, userId) {
removeUserFromStream(streamName, userToken) {
// Make sure the stream we are attempting to add this user to even exists
if (!this.doesStreamExist(streamName))
return global.consoleHelper.printBancho(`Did not remove user from stream [${streamName}] because it does not exist!`);
// Make sure the user isn't already in the stream
if (!this.avaliableStreams[streamName].streamUsers.includes(userId))
if (!this.avaliableStreams[streamName].streamUsers.includes(userToken))
return global.consoleHelper.printBancho(`Did not remove user from stream [${streamName}] because they are not in it!`);
// Make sure this isn't an invalid user (userId can't be lower than 1)
if (userId <= 0 || userId == null)
if (userToken == "" || userToken == null)
return global.consoleHelper.printBancho(`Did not remove user from stream [${streamName}] because their userId is invalid!`);
try {
// Find index of user to remove
let userCurrentIndex;
for (let i = 0; i < this.avaliableStreams[streamName].streamUsers.length; i++) {
if (userId == this.avaliableStreams[streamName].streamUsers[i]) {
if (userToken == this.avaliableStreams[streamName].streamUsers[i]) {
userCurrentIndex = i;
break;
}
@ -106,8 +106,8 @@ module.exports = class {
// Remove user from stream's user list
this.avaliableStreams[streamName].streamUsers.splice(userCurrentIndex, 1);
global.consoleHelper.printBancho(`Removed user [${userId}] from stream ${streamName}`);
} catch (e) { global.consoleHelper.printBancho(`Can't Remove user [${userId}] from stream ${streamName}`); }
global.consoleHelper.printBancho(`Removed user [${userToken}] from stream ${streamName}`);
} catch (e) { global.consoleHelper.printBancho(`Can't Remove user [${userToken}] from stream ${streamName}`); }
}
doesStreamExist(streamName) {
@ -119,8 +119,8 @@ module.exports = class {
return this.avaliableStreamKeys;
}
isUserInStream(streamName, userId) {
if (this.avaliableStreams[streamName].streamUsers.includes(userId)) return true;
isUserInStream(streamName, userToken) {
if (this.avaliableStreams[streamName].streamUsers.includes(userToken)) return true;
else return false;
}

View file

@ -1,7 +1,7 @@
const StatusUpdate = require("./Packets/StatusUpdate.js");
module.exports = class {
constructor(id, username, uuid, connectTime) {
constructor(id, username, uuid, connectTime, isTourneyUser = false) {
this.id = id;
this.username = username;
this.uuid = uuid;
@ -34,6 +34,8 @@ module.exports = class {
// Multiplayer data
this.currentMatch = null;
this.matchSlotId = -1;
this.isTourneyUser = isTourneyUser;
}
// Adds new actions to the user's queue

View file

@ -47,23 +47,24 @@ module.exports = function(req, res, loginInfo) {
// Make sure user is not already connected, kick off if so.
const checkForPreexistingUser = getUserByUsername(loginInfo.username);
if (checkForPreexistingUser != null) {
if (checkForPreexistingUser != null && !loginInfo.osuversion.includes("tourney")) {
if (checkForPreexistingUser.uuid != newClientToken) {
let userCurrentIndex;
let userCurrentIndex, isTourneyUser = false;
// Find the index that the user's class is at
for (let i = 0; i < global.users.length; i++) {
if (checkForPreexistingUser.uuid == global.users[i].uuid) {
if (checkForPreexistingUser.uuid == global.users[i].uuid && !global.users[i].isTourneyUser) {
userCurrentIndex = i;
isTourneyUser = global.users[i].isTourneyUser;
break;
}
}
global.users.splice(userCurrentIndex, 1);
if (!isTourneyUser) global.users.splice(userCurrentIndex, 1);
}
}
// Create user object
global.users.push(new User(userDB.id, loginInfo.username, newClientToken, new Date().getTime()));
global.users.push(new User(userDB.id, loginInfo.username, newClientToken, new Date().getTime(), loginInfo.osuversion.includes("tourney")));
// Retreive the newly created user
const NewUser = getUserByToken(newClientToken);
@ -113,12 +114,12 @@ module.exports = function(req, res, loginInfo) {
// Add user to chat channels
osuPacketWriter.ChannelJoinSuccess("#osu");
if (!global.StreamsHandler.isUserInStream("#osu", NewUser.id))
global.StreamsHandler.addUserToStream("#osu", NewUser.id);
if (!global.StreamsHandler.isUserInStream("#osu", NewUser.uuid))
global.StreamsHandler.addUserToStream("#osu", NewUser.uuid);
osuPacketWriter.ChannelJoinSuccess("#userlog");
if (!global.StreamsHandler.isUserInStream("#userlog", NewUser.id))
global.StreamsHandler.addUserToStream("#userlog", NewUser.id);
if (!global.StreamsHandler.isUserInStream("#userlog", NewUser.uuid))
global.StreamsHandler.addUserToStream("#userlog", NewUser.uuid);
// List all channels out to the client
for (let i = 0; i < global.channels.length; i++) {

View file

@ -112,7 +112,9 @@ const ChangeAction = require("./Packets/ChangeAction.js"),
UserPresenceBundle = require("./Packets/UserPresenceBundle.js"),
UserPresence = require("./Packets/UserPresence.js"),
UserStatsRequest = require("./Packets/UserStatsRequest.js"),
MultiplayerInvite = require("./Packets/MultiplayerInvite.js");
MultiplayerInvite = require("./Packets/MultiplayerInvite.js"),
TourneyMatchSpecialInfo = require("./Packets/TourneyMatchSpecialInfo.js"),
TourneyMatchJoinChannel = require("./Packets/TourneyMatchSpecialInfo.js");
// A class for managing everything multiplayer
global.MultiplayerManager = new MultiplayerManager();
@ -272,6 +274,10 @@ module.exports = function(req, res) {
PacketUser.currentMatch.matchFailed(PacketUser);
break;
case packetIDs.client_matchChangeTeam:
PacketUser.currentMatch.changeTeam(PacketUser);
break;
case packetIDs.client_channelJoin:
ChannelJoin(PacketUser, CurrentPacket.data);
break;
@ -292,6 +298,14 @@ module.exports = function(req, res) {
UserStatsRequest(PacketUser, CurrentPacket.data);
break;
case packetIDs.client_specialMatchInfoRequest:
TourneyMatchSpecialInfo(PacketUser, CurrentPacket.data);
break;
case packetIDs.client_specialJoinMatchChannel:
TourneyMatchJoinChannel(PacketUser, CurrentPacket.data);
break;
case packetIDs.client_invite:
MultiplayerInvite(PacketUser, CurrentPacket.data);
break;