Binato/server/BanchoServer.ts

313 lines
9.4 KiB
TypeScript
Raw Normal View History

2023-09-10 12:59:22 +01:00
import Channel from "./objects/Channel";
2022-11-16 11:59:23 +00:00
import { ConsoleHelper } from "../ConsoleHelper";
2023-09-10 12:59:22 +01:00
import Constants from "../Constants";
import LoginProcess from "./LoginProcess";
import { IncomingMessage, ServerResponse } from "http";
2022-11-16 11:59:23 +00:00
import { Packets } from "./enums/Packets";
2022-11-17 00:29:07 +00:00
import { RedisClientType, createClient } from "redis";
2023-09-10 12:59:22 +01:00
import MessageData from "./interfaces/MessageData";
import PrivateMessage from "./packets/PrivateMessage";
import Shared from "./objects/Shared";
import SpectatorManager from "./SpectatorManager";
import osu from "../osuTyping";
2022-11-19 01:06:03 +00:00
2023-08-20 13:03:01 +01:00
const shared:Shared = new Shared();
shared.database.query("UPDATE mp_matches SET close_time = UNIX_TIMESTAMP() WHERE close_time IS NULL");
shared.database.query("UPDATE osu_info SET value = 0 WHERE name = 'online_now'");
2020-08-27 13:09:35 +01:00
2023-08-20 13:03:01 +01:00
// Server Setup
const spectatorManager:SpectatorManager = new SpectatorManager(shared);
2022-11-27 17:37:28 +00:00
2022-11-16 15:25:46 +00:00
let redisClient:RedisClientType;
2020-09-07 19:23:06 +01:00
2022-11-16 15:25:46 +00:00
async function subscribeToChannel(channelName:string, callback:(message:string) => void) {
// Dup and connect new client for channel subscription (required)
2022-11-16 15:25:46 +00:00
const subscriptionClient:RedisClientType = redisClient.duplicate();
await subscriptionClient.connect();
// Subscribe to channel
await subscriptionClient.subscribe(channelName, callback);
2022-11-16 11:59:23 +00:00
ConsoleHelper.printRedis(`Subscribed to ${channelName} channel`);
}
2023-08-20 13:03:01 +01:00
if (shared.config.redis.enabled) {
(async () => {
2022-11-16 15:25:46 +00:00
redisClient = createClient({
2023-08-20 13:03:01 +01:00
url: `redis://${shared.config.redis.password.replaceAll(" ", "") == "" ? "" : `${shared.config.redis.password}@`}${shared.config.redis.address}:${shared.config.redis.port}/${shared.config.redis.database}`
});
2022-11-16 15:25:46 +00:00
redisClient.on('error', e => ConsoleHelper.printRedis(e));
const connectionStartTime = Date.now();
2022-11-16 15:25:46 +00:00
await redisClient.connect();
ConsoleHelper.printRedis(`Connected to redis server. Took ${Date.now() - connectionStartTime}ms`);
// Score submit update channel
subscribeToChannel("binato:update_user_stats", (message) => {
2023-08-20 13:03:01 +01:00
const user = shared.users.getById(parseInt(message));
if (user != null) {
// Update user info
user.updateUserInfo(true);
2022-04-24 02:04:14 +01:00
2023-08-20 13:03:01 +01:00
ConsoleHelper.printRedis(`Score submission stats update request received for ${user.username}`);
2022-11-16 15:25:46 +00:00
}
});
})();
2022-11-16 15:25:46 +00:00
} else ConsoleHelper.printWarn("Redis is disabled!");
2022-11-19 15:06:03 +00:00
// Import packets
2023-09-10 12:59:22 +01:00
import ChangeAction from "./packets/ChangeAction";
import Logout from "./packets/Logout";
import UserPresence from "./packets/UserPresence";
import UserStatsRequest from "./packets/UserStatsRequest";
import UserPresenceBundle from "./packets/UserPresenceBundle";
import TourneyMatchSpecialInfo from "./packets/TourneyMatchSpecialInfo";
import TourneyMatchJoinChannel from "./packets/TourneyJoinMatchChannel";
import TourneyMatchLeaveChannel from "./packets/TourneyMatchLeaveChannel";
import AddFriend from "./packets/AddFriend";
import RemoveFriend from "./packets/RemoveFriend";
import PrivateChannel from "./objects/PrivateChannel";
2023-09-10 18:32:24 +01:00
import MultiplayerInvite from "./packets/MultiplayerInvite";
2023-10-03 10:09:44 +01:00
import SendPublicMessage from "./packets/SendPublicMessage";
2022-11-19 15:06:03 +00:00
// User timeout interval
2020-08-27 13:09:35 +01:00
setInterval(() => {
for (const User of shared.users.getIterableItems()) {
2022-11-17 00:29:07 +00:00
if (User.uuid == "bot") continue; // Ignore the bot
2020-08-27 13:09:35 +01:00
2022-02-23 05:35:32 +00:00
// Logout this user, they're clearly gone.
2022-11-19 15:06:03 +00:00
if (Date.now() >= User.timeoutTime) {
Logout(User);
}
}
2020-08-27 13:09:35 +01:00
}, 10000);
2023-09-10 12:59:22 +01:00
export default async function HandleRequest(req:IncomingMessage, res:ServerResponse, packet:Buffer) {
// Get the client's token string and request data
2023-09-10 12:59:22 +01:00
const requestTokenString = typeof(req.headers["osu-token"]) === "string" ? req.headers["osu-token"] : undefined;
// Check if the user is logged in
2023-09-10 12:59:22 +01:00
if (requestTokenString === undefined) {
// Client doesn't have a token yet, let's auth them!
await LoginProcess(req, res, packet, shared);
shared.database.query("UPDATE osu_info SET value = ? WHERE name = 'online_now'", [shared.users.getLength() - 1]);
} else {
2023-10-04 12:28:47 +01:00
let responseData = Buffer.allocUnsafe(0);
2023-08-20 13:03:01 +01:00
// Client has a token, let's see what they want.
try {
// Get the current user
2023-10-03 10:09:44 +01:00
const user = shared.users.getByToken(requestTokenString);
// Make sure the client's token isn't invalid
2023-10-03 10:09:44 +01:00
if (user != null) {
// Update the session timeout time for each request
2023-10-03 10:09:44 +01:00
user.timeoutTime = Date.now() + 60000;
2022-02-23 05:35:32 +00:00
// Parse bancho packets
2023-08-20 13:03:01 +01:00
const osuPacketReader = osu.Client.Reader(packet);
const packets = osuPacketReader.Parse();
// Go through each packet sent by the client
for (const packet of packets) {
switch (packet.id) {
2022-11-16 11:59:23 +00:00
case Packets.Client_ChangeAction:
2023-10-03 10:09:44 +01:00
ChangeAction(user, packet.data);
2023-09-10 18:31:29 +01:00
break;
2022-11-16 11:59:23 +00:00
case Packets.Client_SendPublicMessage:
2023-10-03 10:09:44 +01:00
SendPublicMessage(user, packet.data);
2023-09-10 18:31:29 +01:00
break;
2022-11-16 11:59:23 +00:00
case Packets.Client_Logout:
2023-10-03 10:09:44 +01:00
await Logout(user);
2023-09-10 18:31:29 +01:00
break;
2022-11-16 11:59:23 +00:00
case Packets.Client_RequestStatusUpdate:
2023-10-03 10:09:44 +01:00
UserPresenceBundle(user);
2023-09-10 18:31:29 +01:00
break;
2022-11-16 11:59:23 +00:00
case Packets.Client_StartSpectating:
2023-10-03 10:09:44 +01:00
spectatorManager.startSpectating(user, packet.data);
2023-09-10 18:31:29 +01:00
break;
2022-11-16 11:59:23 +00:00
case Packets.Client_SpectateFrames:
2023-10-03 10:09:44 +01:00
spectatorManager.spectatorFrames(user, packet.data);
2023-09-10 18:31:29 +01:00
break;
2022-11-16 11:59:23 +00:00
case Packets.Client_StopSpectating:
2023-10-03 10:09:44 +01:00
spectatorManager.stopSpectating(user);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_SendPrivateMessage:
2023-10-03 10:09:44 +01:00
PrivateMessage(user, packet.data);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_JoinLobby:
2023-10-03 10:09:44 +01:00
shared.multiplayerManager.JoinLobby(user);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_PartLobby:
2023-10-03 10:09:44 +01:00
shared.multiplayerManager.LeaveLobby(user);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_CreateMatch:
2023-10-03 10:09:44 +01:00
await shared.multiplayerManager.CreateMatch(user, packet.data);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_JoinMatch:
2023-10-03 10:09:44 +01:00
shared.multiplayerManager.JoinMatch(user, packet.data);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_MatchChangeSlot:
2023-10-03 10:09:44 +01:00
user.match?.moveToSlot(user, packet.data);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_MatchReady:
2023-10-03 10:09:44 +01:00
user.match?.setStateReady(user);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_MatchChangeSettings:
2023-10-03 10:09:44 +01:00
await user.match?.updateMatch(user, packet.data);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_MatchNotReady:
2023-10-03 10:09:44 +01:00
user.match?.setStateNotReady(user);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_PartMatch:
2023-10-03 10:09:44 +01:00
await shared.multiplayerManager.LeaveMatch(user);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_MatchLock:
2023-10-03 10:09:44 +01:00
user.match?.lockOrKick(user, packet.data);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_MatchNoBeatmap:
2023-10-03 10:09:44 +01:00
user.match?.missingBeatmap(user);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_MatchSkipRequest:
2023-10-03 10:09:44 +01:00
user.match?.matchSkip(user);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_MatchHasBeatmap:
2023-10-03 10:09:44 +01:00
user.match?.notMissingBeatmap(user);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_MatchTransferHost:
2023-10-03 10:09:44 +01:00
user.match?.transferHost(user, packet.data);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_MatchChangeMods:
2023-10-03 10:09:44 +01:00
user.match?.updateMods(user, packet.data);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_MatchStart:
2023-10-03 10:09:44 +01:00
user.match?.startMatch();
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_MatchLoadComplete:
2023-10-03 10:09:44 +01:00
user.match?.matchPlayerLoaded(user);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_MatchComplete:
2023-10-03 10:09:44 +01:00
await user.match?.onPlayerFinishMatch(user);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_MatchScoreUpdate:
2023-10-03 10:09:44 +01:00
user.match?.updatePlayerScore(user, packet.data);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_MatchFailed:
2023-10-03 10:09:44 +01:00
user.match?.matchFailed(user);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_MatchChangeTeam:
2023-10-03 10:09:44 +01:00
user.match?.changeTeam(user);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_ChannelJoin:
2023-10-03 10:09:44 +01:00
user.joinChannel(packet.data);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_ChannelPart:
2023-10-03 10:09:44 +01:00
user.leaveChannel(packet.data);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_SetAwayMessage:
2022-11-19 01:06:03 +00:00
//SetAwayMessage(PacketUser, CurrentPacket.data);
2023-09-10 18:31:29 +01:00
break;
2022-01-04 04:43:32 +00:00
2022-11-17 00:29:07 +00:00
case Packets.Client_FriendAdd:
2023-10-03 10:09:44 +01:00
AddFriend(user, packet.data);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_FriendRemove:
2023-10-03 10:09:44 +01:00
RemoveFriend(user, packet.data);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_UserStatsRequest:
2023-10-03 10:09:44 +01:00
UserStatsRequest(user, packet.data);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_SpecialMatchInfoRequest:
2023-10-03 10:09:44 +01:00
TourneyMatchSpecialInfo(user, packet.data);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_SpecialJoinMatchChannel:
2023-10-03 10:09:44 +01:00
TourneyMatchJoinChannel(user, packet.data);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_SpecialLeaveMatchChannel:
2023-10-03 10:09:44 +01:00
TourneyMatchLeaveChannel(user, packet.data);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_Invite:
2023-10-03 10:09:44 +01:00
MultiplayerInvite(user, packet.data);
2023-09-10 18:31:29 +01:00
break;
2022-11-17 00:29:07 +00:00
case Packets.Client_UserPresenceRequest:
2023-10-03 10:09:44 +01:00
UserPresence(user, user.id);
2023-09-10 18:31:29 +01:00
break;
// Ignored packets
case Packets.Client_Pong:
case Packets.Client_BeatmapInfoRequest:
case Packets.Client_ReceiveUpdates:
break;
default:
// Print out unimplemented packet
console.dir(packet);
2023-09-10 18:31:29 +01:00
break;
2022-11-19 01:06:03 +00:00
}
}
2022-02-22 09:42:57 +00:00
2023-10-03 10:09:44 +01:00
responseData = user.queue;
user.clearQueue();
} else {
2023-09-10 12:59:22 +01:00
// User's token is invlid, force a reconnect
2023-09-10 18:31:29 +01:00
ConsoleHelper.printBancho(`Forced client re-connect (Token is invalid)`);
2023-09-10 12:59:22 +01:00
const osuPacketWriter = osu.Bancho.Writer();
osuPacketWriter.Announce("Reconnecting...");
osuPacketWriter.Restart(0);
responseData = osuPacketWriter.toBuffer;
}
} catch (e) {
2023-08-20 13:03:01 +01:00
if (Constants.DEBUG) {
throw e;
}
ConsoleHelper.printError(`${e}`);
} finally {
res.writeHead(200, {
"Connection": "keep-alive",
"Keep-Alive": "timeout=5, max=100",
});
// Send the prepared packet(s) to the client
res.end(responseData);
}
}
2022-11-17 00:29:07 +00:00
}