diff --git a/Binato.ts b/Binato.ts index a52d263..0f65ade 100644 --- a/Binato.ts +++ b/Binato.ts @@ -11,14 +11,14 @@ if (!existsSync("./config.json")) { import { ChatHistory } from "./server/ChatHistory"; import compression from "compression"; import express from "express"; -import { HandleRequest } from "./server/BanchoServer"; +import { HandleRequest, GetSharedContent, SharedContent } from "./server/BanchoServer"; import { Registry, collectDefaultMetrics } from "prom-client"; const config:any = JSON.parse(readFileSync(__dirname + "/config.json").toString()); +// Pull out shared data from BanchoServer +const sharedContent:SharedContent = GetSharedContent(); const binatoApp:express.Application = express(); -ConsoleHelper.printInfo("Starting Binato..."); - if (config["prometheus"]["enabled"]) { const register:Registry = new Registry(); register.setDefaultLabels({ app: "nodejs_binato" }); diff --git a/server/BanchoServer.ts b/server/BanchoServer.ts index c6bf631..202a509 100644 --- a/server/BanchoServer.ts +++ b/server/BanchoServer.ts @@ -17,29 +17,43 @@ const config:any = JSON.parse(readFileSync("./config.json").toString()); // TODO: Port osu-packet to TypeScript const osu = require("osu-packet"); -const DB:Database = new Database(config.database.address, config.database.port, config.database.username, config.database.password, config.database.name, async () => { +export interface SharedContent { + chatManager:ChatManager, + database:Database, + mutiplayerManager:MultiplayerManager, + streams:DataStreamArray, + users:UserArray, +} + +const sharedContent:any = {}; +// NOTE: This function should only be used externaly in Binato.ts and in this file. +export function GetSharedContent() : SharedContent { + return sharedContent; +} + +const DB:Database = sharedContent.database = new Database(config.database.address, config.database.port, config.database.username, config.database.password, config.database.name, async () => { // Close any unclosed db matches on startup DB.query("UPDATE mp_matches SET close_time = UNIX_TIMESTAMP() WHERE close_time IS NULL"); DB.query("UPDATE osu_info SET value = 0 WHERE name = 'online_now'"); }); // User session storage -const users:UserArray = new UserArray(); +const users:UserArray = sharedContent.users = new UserArray(); // DataStream storage -const streams:DataStreamArray = new DataStreamArray(); +const streams:DataStreamArray = sharedContent.streams = new DataStreamArray(); // ChatManager -const chatManager:ChatManager = new ChatManager(streams); +const chatManager:ChatManager = sharedContent.chatManager = new ChatManager(streams); chatManager.AddChatChannel("osu", "The main channel", true); chatManager.AddChatChannel("lobby", "Talk about multiplayer stuff"); chatManager.AddChatChannel("english", "Talk in exclusively English"); chatManager.AddChatChannel("japanese", "Talk in exclusively Japanese"); -const multiplayerManager:MultiplayerManager = new MultiplayerManager(streams); +const multiplayerManager:MultiplayerManager = sharedContent.mutiplayerManager = new MultiplayerManager(streams); // Add the bot user -const botUser:User = users.add("bot", new User(3, "SillyBot", "bot", DB, users, streams, chatManager)); +const botUser:User = users.add("bot", new User(3, "SillyBot", "bot", GetSharedContent())); // Set the bot's position on the map botUser.location = new LatLng(50, -32); @@ -116,7 +130,7 @@ export async function HandleRequest(req:Request, res:Response, packet:Buffer) { if (DB.connected) { // Client doesn't have a token yet, let's auth them! - await LoginProcess(req, res, packet, DB, users, streams, chatManager); + await LoginProcess(req, res, packet, GetSharedContent()); DB.query("UPDATE osu_info SET value = ? WHERE name = 'online_now'", [users.getLength() - 1]); } } else { diff --git a/server/LoginProcess.ts b/server/LoginProcess.ts index e812141..3a3d407 100644 --- a/server/LoginProcess.ts +++ b/server/LoginProcess.ts @@ -16,6 +16,7 @@ import { ChatManager } from "./ChatManager"; import { UserPresenceBundle } from "./packets/UserPresenceBundle"; import { UserPresence } from "./packets/UserPresence"; import { StatusUpdate } from "./packets/StatusUpdate"; +import { SharedContent } from "./BanchoServer"; const config:any = JSON.parse(readFileSync("./config.json").toString()); const { decrypt: aesDecrypt } = require("aes256"); const osu = require("osu-packet"); @@ -95,11 +96,11 @@ function TestLogin(loginInfo:LoginInfo | undefined, database:Database) { }); } -export async function LoginProcess(req:Request, res:Response, packet:Buffer, database:Database, users:UserArray, streams:DataStreamArray, chatManager:ChatManager) { +export async function LoginProcess(req:Request, res:Response, packet:Buffer, sharedContent:SharedContent) { const loginInfo = LoginInfo.From(packet); const loginStartTime = Date.now(); - const loginCheck:any = await TestLogin(loginInfo, database); + const loginCheck:any = await TestLogin(loginInfo, sharedContent.database); if (loginCheck != null) { res.writeHead(200, loginCheck[1]); return res.end(loginCheck[0]); @@ -143,20 +144,20 @@ export async function LoginProcess(req:Request, res:Response, packet:Buffer, dat } // Get information about the user from the database - const userDB = await database.query("SELECT id FROM users_info WHERE username = ? LIMIT 1", [loginInfo.username]); + const userDB = await sharedContent.database.query("SELECT id FROM users_info WHERE username = ? LIMIT 1", [loginInfo.username]); // Create a token for the client const newClientToken:string = await generateSession(); const isTourneyClient = loginInfo.version.includes("tourney"); // Make sure user is not already connected, kick off if so. - const connectedUser = users.getByUsername(loginInfo.username); + const connectedUser = sharedContent.users.getByUsername(loginInfo.username); if (connectedUser != null && !isTourneyClient && !connectedUser.isTourneyUser) { Logout(connectedUser); } // Retreive the newly created user - const newUser:User = users.add(newClientToken, new User(userDB.id, loginInfo.username, newClientToken, database, users, streams, chatManager)); + const newUser:User = sharedContent.users.add(newClientToken, new User(userDB.id, loginInfo.username, newClientToken, sharedContent)); // Set tourney client flag newUser.isTourneyUser = isTourneyClient; newUser.location = userLocation; @@ -193,11 +194,11 @@ export async function LoginProcess(req:Request, res:Response, packet:Buffer, dat osuPacketWriter.ChannelListingComplete(); // Setup chat - chatManager.ForceJoinChannels(newUser); - chatManager.SendChannelListing(newUser); + sharedContent.chatManager.ForceJoinChannels(newUser); + sharedContent.chatManager.SendChannelListing(newUser); // Construct user's friends list - const userFriends = await database.query("SELECT friendsWith FROM friends WHERE user = ?", [newUser.id]); + const userFriends = await sharedContent.database.query("SELECT friendsWith FROM friends WHERE user = ?", [newUser.id]); const friendsArray:Array = new Array(); for (let i = 0; i < userFriends.length; i++) { friendsArray.push(userFriends[i].friendsWith); diff --git a/server/objects/User.ts b/server/objects/User.ts index 801a7c2..73f63b0 100644 --- a/server/objects/User.ts +++ b/server/objects/User.ts @@ -1,13 +1,9 @@ -import { Database } from "./Database"; import { LatLng } from "./LatLng"; import { RankingModes } from "../enums/RankingModes"; import { Match } from "./Match"; import { DataStream } from "./DataStream"; -import { UserArray } from "./UserArray"; -import { DataStreamArray } from "./DataStreamArray"; -import { ChatManager } from "../ChatManager"; import { StatusUpdate } from "../packets/StatusUpdate"; -//const StatusUpdate = require("./Packets/StatusUpdate.js"); +import { SharedContent } from "../BanchoServer"; const rankingModes = [ "pp_raw", @@ -18,9 +14,7 @@ const rankingModes = [ export class User { private static readonly EMPTY_BUFFER = Buffer.alloc(0); - public users:UserArray; - public streams:DataStreamArray; - public chatManager:ChatManager; + public sharedContent:SharedContent; public id:number; public username:string; @@ -65,18 +59,12 @@ export class User { // Tournament client flag public isTourneyUser:boolean = false; - public dbConnection:Database; - - public constructor(id:number, username:string, uuid:string, dbConnection:Database, users:UserArray, streams:DataStreamArray, chatManager:ChatManager) { + public constructor(id:number, username:string, uuid:string, sharedContent:SharedContent) { this.id = id; this.username = username; this.uuid = uuid; - this.dbConnection = dbConnection; - - this.users = users; - this.streams = streams; - this.chatManager = chatManager; + this.sharedContent = sharedContent; } // Concats new actions to the user's queue @@ -104,9 +92,9 @@ export class User { // Gets the user's score information from the database and caches it async updateUserInfo(forceUpdate:boolean = false) : Promise { - const userScoreDB = await this.dbConnection.query("SELECT * FROM users_modes_info WHERE user_id = ? AND mode_id = ? LIMIT 1", [this.id, this.playMode]); + const userScoreDB = await this.sharedContent.database.query("SELECT * FROM users_modes_info WHERE user_id = ? AND mode_id = ? LIMIT 1", [this.id, this.playMode]); const mappedRankingMode = rankingModes[this.rankingMode]; - const userRankDB = await this.dbConnection.query(`SELECT user_id, ${mappedRankingMode} FROM users_modes_info WHERE mode_id = ? ORDER BY ${mappedRankingMode} DESC`, [this.playMode]); + const userRankDB = await this.sharedContent.database.query(`SELECT user_id, ${mappedRankingMode} FROM users_modes_info WHERE mode_id = ? ORDER BY ${mappedRankingMode} DESC`, [this.playMode]); if (userScoreDB == null || userRankDB == null) throw "fuck"; diff --git a/server/packets/Logout.ts b/server/packets/Logout.ts index 656ea35..ec09c7e 100644 --- a/server/packets/Logout.ts +++ b/server/packets/Logout.ts @@ -8,12 +8,12 @@ export async function Logout(user:User) { const logoutStartTime = Date.now(); - user.streams.RemoveUserFromAllStreams(user); + user.sharedContent.streams.RemoveUserFromAllStreams(user); // Remove user from user list - user.users.remove(user.uuid); + user.sharedContent.users.remove(user.uuid); - await user.dbConnection.query("UPDATE osu_info SET value = ? WHERE name = 'online_now'", [user.users.getLength() - 1]); + await user.sharedContent.database.query("UPDATE osu_info SET value = ? WHERE name = 'online_now'", [user.sharedContent.users.getLength() - 1]); ConsoleHelper.printBancho(`User logged out, took ${Date.now() - logoutStartTime}ms. [User: ${user.username}]`); } \ No newline at end of file diff --git a/server/packets/StatusUpdate.ts b/server/packets/StatusUpdate.ts index e82878b..a4d6a23 100644 --- a/server/packets/StatusUpdate.ts +++ b/server/packets/StatusUpdate.ts @@ -9,7 +9,7 @@ export function StatusUpdate(user:User, id:number, sendImmidiate:boolean = false const osuPacketWriter = new osu.Bancho.Writer; // Get user's class - const userData = user.users.getById(id); + const userData = user.sharedContent.users.getById(id); if (userData == null) return; diff --git a/server/packets/UserPresence.ts b/server/packets/UserPresence.ts index d0b747a..83258b0 100644 --- a/server/packets/UserPresence.ts +++ b/server/packets/UserPresence.ts @@ -4,7 +4,7 @@ const osu = require("osu-packet"); export function UserPresence(user:User, id:number, sendImmidiate:boolean = true) { const osuPacketWriter = new osu.Bancho.Writer; - const userData = user.users.getById(id); + const userData = user.sharedContent.users.getById(id); if (userData == null) return; diff --git a/server/packets/UserPresenceBundle.ts b/server/packets/UserPresenceBundle.ts index 33069dc..30d0ef0 100644 --- a/server/packets/UserPresenceBundle.ts +++ b/server/packets/UserPresenceBundle.ts @@ -6,7 +6,7 @@ export function UserPresenceBundle(user:User, sendImmidiate:boolean = true) { let userIds:Array = new Array(); - for (let userData of user.users.getIterableItems()) { + for (let userData of user.sharedContent.users.getIterableItems()) { userIds.push(userData.id); }