DB access cleanup

This commit is contained in:
Holly Stubbs 2023-10-07 13:09:10 +01:00
parent 877592bb94
commit 9d53d82997
Signed by: tgpholly
GPG key ID: B8583C4B7D18119E
10 changed files with 138 additions and 40 deletions

View file

@ -37,7 +37,7 @@ enum LoginResult {
function TestLogin(loginInfo:LoginInfo, shared:Shared) { function TestLogin(loginInfo:LoginInfo, shared:Shared) {
return new Promise<LoginResult>(async (resolve, reject) => { return new Promise<LoginResult>(async (resolve, reject) => {
const userDBData = await shared.userInfoRepository.getByUsername(loginInfo.username); const userDBData = await shared.userInfoRepository.selectByUsername(loginInfo.username);
// Make sure a user was found in the database // Make sure a user was found in the database
if (userDBData == null) return resolve(LoginResult.INCORRECT); if (userDBData == null) return resolve(LoginResult.INCORRECT);
@ -123,7 +123,7 @@ export default async function LoginProcess(req:IncomingMessage, res:ServerRespon
} }
// Get information about the user from the database // Get information about the user from the database
const userInfo = await shared.userInfoRepository.getByUsername(loginInfo.username); const userInfo = await shared.userInfoRepository.selectByUsername(loginInfo.username);
if (userInfo == null) { if (userInfo == null) {
return; return;
} }

View file

@ -1,6 +1,6 @@
import Channel from "../objects/Channel"; import Channel from "../objects/Channel";
import User from "../objects/User"; import User from "../objects/User";
import { RankingModes } from "../enums/RankingModes"; import { RankingMode } from "../enums/RankingMode";
import BaseCommand from "./BaseCommand"; import BaseCommand from "./BaseCommand";
export default class RankingCommand extends BaseCommand { export default class RankingCommand extends BaseCommand {
@ -18,15 +18,15 @@ export default class RankingCommand extends BaseCommand {
switch (args[0].toLowerCase()) { switch (args[0].toLowerCase()) {
case "pp": case "pp":
sender.rankingMode = RankingModes.PP; sender.rankingMode = RankingMode.PP;
channel.SendBotMessage("Set ranking mode to pp."); channel.SendBotMessage("Set ranking mode to pp.");
break; break;
case "score": case "score":
sender.rankingMode = RankingModes.RANKED_SCORE; sender.rankingMode = RankingMode.RANKED_SCORE;
channel.SendBotMessage("Set ranking mode to score."); channel.SendBotMessage("Set ranking mode to score.");
break; break;
case "acc": case "acc":
sender.rankingMode = RankingModes.AVG_ACCURACY; sender.rankingMode = RankingMode.AVG_ACCURACY;
channel.SendBotMessage("Set ranking mode to accuracy."); channel.SendBotMessage("Set ranking mode to accuracy.");
break; break;
} }

7
server/enums/Mode.ts Normal file
View file

@ -0,0 +1,7 @@
export enum Mode {
Unknown = -1,
Osu,
Taiko,
Catch,
Mania
}

View file

@ -1,4 +1,4 @@
export enum RankingModes { export enum RankingMode {
PP, PP,
RANKED_SCORE, RANKED_SCORE,
AVG_ACCURACY AVG_ACCURACY

View file

@ -12,6 +12,7 @@ import Bot from "../Bot";
import { ConsoleHelper } from "../../ConsoleHelper"; import { ConsoleHelper } from "../../ConsoleHelper";
import UserInfoRepository from "../repos/UserInfoRepository"; import UserInfoRepository from "../repos/UserInfoRepository";
import { Permissions } from "../enums/Permissions"; import { Permissions } from "../enums/Permissions";
import UserModesInfoRepository from "../repos/UserModesInfoRepository";
export default class Shared { export default class Shared {
public readonly chatManager:ChatManager; public readonly chatManager:ChatManager;
@ -24,6 +25,7 @@ export default class Shared {
public readonly bot:Bot; public readonly bot:Bot;
public readonly userInfoRepository:UserInfoRepository; public readonly userInfoRepository:UserInfoRepository;
public readonly userModesInfoRepository:UserModesInfoRepository;
public constructor() { public constructor() {
if (!existsSync("./config.json")) { if (!existsSync("./config.json")) {
@ -53,5 +55,6 @@ export default class Shared {
// DB Repos // DB Repos
this.userInfoRepository = new UserInfoRepository(this); this.userInfoRepository = new UserInfoRepository(this);
this.userModesInfoRepository = new UserModesInfoRepository(this);
} }
} }

View file

@ -1,5 +1,5 @@
import LatLng from "./LatLng"; import LatLng from "./LatLng";
import { RankingModes } from "../enums/RankingModes"; import { RankingMode } from "../enums/RankingMode";
import Match from "./Match"; import Match from "./Match";
import DataStream from "./DataStream"; import DataStream from "./DataStream";
import StatusUpdate from "../packets/StatusUpdate"; import StatusUpdate from "../packets/StatusUpdate";
@ -9,12 +9,6 @@ import Channel from "./Channel";
import PresenceData from "../interfaces/packetTypes/PresenceData"; import PresenceData from "../interfaces/packetTypes/PresenceData";
import { Permissions } from "../enums/Permissions"; import { Permissions } from "../enums/Permissions";
const rankingModes = [
"pp_raw",
"ranked_score",
"avg_accuracy"
];
export default class User { export default class User {
public shared:Shared; public shared:Shared;
@ -26,7 +20,7 @@ export default class User {
public queue:Buffer = Buffer.allocUnsafe(0); public queue:Buffer = Buffer.allocUnsafe(0);
// Binato data // Binato data
public rankingMode:RankingModes = RankingModes.PP; public rankingMode:RankingMode = RankingMode.PP;
public spectatorStream?:DataStream; public spectatorStream?:DataStream;
public spectatingUser?:User; public spectatingUser?:User;
public permissions:Permissions; public permissions:Permissions;
@ -101,26 +95,27 @@ export default class User {
// Gets the user's score information from the database and caches it // Gets the user's score information from the database and caches it
async updateUserInfo(forceUpdate:boolean = false) { async updateUserInfo(forceUpdate:boolean = false) {
const userScoreDB = await this.shared.database.querySingle("SELECT * FROM users_modes_info WHERE user_id = ? AND mode_id = ? LIMIT 1", [this.id, this.playMode]); const userScoreDB = await this.shared.userModesInfoRepository.selectByUserIdModeId(this.id, this.playMode);
const mappedRankingMode = rankingModes[this.rankingMode]; const userRank = await this.shared.userModesInfoRepository.selectRankByIdModeIdRankingMode(this.id, this.playMode, this.rankingMode);
const userRankDB = await this.shared.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"; if (userScoreDB == null || userRank == null) throw "fuck";
this.rank = userRank;
// Handle "if we should update" checks for each rankingMode // Handle "if we should update" checks for each rankingMode
let userScoreUpdate = false; let userScoreUpdate = false;
switch (this.rankingMode) { switch (this.rankingMode) {
case RankingModes.PP: case RankingMode.PP:
if (this.pp != userScoreDB.pp_raw) if (this.pp != userScoreDB.pp_raw)
userScoreUpdate = true; userScoreUpdate = true;
break; break;
case RankingModes.RANKED_SCORE: case RankingMode.RANKED_SCORE:
if (this.rankedScore != userScoreDB.ranked_score) if (this.rankedScore != userScoreDB.ranked_score)
userScoreUpdate = true; userScoreUpdate = true;
break; break;
case RankingModes.AVG_ACCURACY: case RankingMode.AVG_ACCURACY:
if (this.accuracy != userScoreDB.avg_accuracy) if (this.accuracy != userScoreDB.avg_accuracy)
userScoreUpdate = true; userScoreUpdate = true;
break; break;
@ -131,14 +126,6 @@ export default class User {
this.accuracy = userScoreDB.avg_accuracy; this.accuracy = userScoreDB.avg_accuracy;
this.playCount = userScoreDB.playcount; this.playCount = userScoreDB.playcount;
// Fetch rank
for (let i = 0; i < userRankDB.length; i++) {
if (userRankDB[i]["user_id"] == this.id) {
this.rank = i + 1;
break;
}
}
// Set PP to none if ranking mode is not PP // Set PP to none if ranking mode is not PP
if (this.rankingMode == 0) this.pp = userScoreDB.pp_raw; if (this.rankingMode == 0) this.pp = userScoreDB.pp_raw;
else this.pp = 0; else this.pp = 0;

View file

@ -0,0 +1,24 @@
import { Mode } from "../../enums/Mode";
export default class UserModeInfo {
n:number = Number.MIN_VALUE;
user_id:number = Number.MIN_VALUE;
mode_id:Mode = Mode.Unknown;
count300:number = Number.MIN_VALUE;
count100:number = Number.MIN_VALUE;
count50:number = Number.MIN_VALUE;
countmiss:number = Number.MIN_VALUE;
playcount:number = Number.MIN_VALUE;
total_score:number = Number.MIN_VALUE;
ranked_score:number = Number.MIN_VALUE;
pp_rank:number = Number.MIN_VALUE;
pp_raw:number = Number.MIN_VALUE;
count_rank_ss:number = Number.MIN_VALUE;
count_rank_s:number = Number.MIN_VALUE;
count_rank_a:number = Number.MIN_VALUE;
pp_country_rank:number = Number.MIN_VALUE;
playtime:number = Number.MIN_VALUE;
avg_accuracy:number = Number.MIN_VALUE;
level:number = Number.MIN_VALUE;
is_deleted:boolean = false;
}

View file

@ -1,10 +1,13 @@
import Shared from "../objects/Shared"; import Shared from "../objects/Shared";
import { RankingModes } from "../enums/RankingModes"; import { RankingMode } from "../enums/RankingMode";
import User from "../objects/User"; import User from "../objects/User";
import osu from "../../osuTyping"; import osu from "../../osuTyping";
export default function StatusUpdate(arg0:User | Shared, id:number) { export default function StatusUpdate(arg0:User | Shared, id:number) {
if (id == 3) return; // Ignore Bot // Ignore Bot
if (id == 3) {
return Buffer.allocUnsafe(0);
}
// Create new osu packet writer // Create new osu packet writer
const osuPacketWriter = osu.Bancho.Writer(); const osuPacketWriter = osu.Bancho.Writer();
@ -18,7 +21,9 @@ export default function StatusUpdate(arg0:User | Shared, id:number) {
// Get user's class // Get user's class
const userData = shared.users.getById(id); const userData = shared.users.getById(id);
if (userData == null) return; if (userData == null) {
return Buffer.allocUnsafe(0);
}
osuPacketWriter.HandleOsuUpdate({ osuPacketWriter.HandleOsuUpdate({
userId: userData.id, userId: userData.id,
@ -33,7 +38,7 @@ export default function StatusUpdate(arg0:User | Shared, id:number) {
playCount: userData.playCount, playCount: userData.playCount,
totalScore: userData.totalScore, totalScore: userData.totalScore,
rank: userData.rank, rank: userData.rank,
performance: (userData.rankingMode == RankingModes.PP ? userData.pp : 0) performance: (userData.rankingMode == RankingMode.PP ? userData.pp : 0)
}); });
// Send data to user's queue // Send data to user's queue

View file

@ -9,11 +9,11 @@ export default class UserInfoRepository {
this.database = shared.database; this.database = shared.database;
} }
public async getById(id:number) { public async selectById(id:number) {
const query = await this.database.query("SELECT * FROM users_info WHERE id = ? AND is_deleted = 0 LIMIT 1", [id]); const query = await this.database.query("CALL SelectUserInfoById(?)", [id]);
if (query != null) { if (query != null) {
const userInfo = new UserInfo(); const userInfo = new UserInfo();
populateUserInfoFromRowDataPacket(userInfo, query[0]); populateUserInfoFromRowDataPacket(userInfo, query[0][0]);
return userInfo; return userInfo;
} }
@ -21,11 +21,11 @@ export default class UserInfoRepository {
return null; return null;
} }
public async getByUsername(username:string) { public async selectByUsername(username:string) {
const query = await this.database.query("SELECT * FROM users_info WHERE username = ? AND is_deleted = 0 LIMIT 1", [username]); const query = await this.database.query("CALL SelectUserInfoByUsername(?)", [username]);
if (query != null) { if (query != null) {
const userInfo = new UserInfo(); const userInfo = new UserInfo();
populateUserInfoFromRowDataPacket(userInfo, query[0]); populateUserInfoFromRowDataPacket(userInfo, query[0][0]);
return userInfo; return userInfo;
} }

View file

@ -0,0 +1,72 @@
import { RowDataPacket } from "mysql2";
import Database from "../objects/Database";
import Shared from "../objects/Shared";
import UserModeInfo from "../objects/database/UserModeInfo";
import { Mode } from "fs";
import { RankingMode } from "../enums/RankingMode";
export default class UserModesInfoRepository {
private database:Database;
public constructor(shared:Shared) {
this.database = shared.database;
}
public async selectByUserIdModeId(id:number, mode:Mode) {
const query = await this.database.query("CALL SelectUserModesInfoByUserIdModeId(?,?)", [id, mode]);
if (query != null) {
const userModeInfo = new UserModeInfo();
populateUserModeInfoFromRowDataPacket(userModeInfo, query[0][0]);
return userModeInfo;
}
return null;
}
public async selectRankByIdModeIdRankingMode(id:number, mode:Mode, rankingMode:RankingMode) : Promise<number | null> {
let query:RowDataPacket[] | undefined;
switch (rankingMode) {
case RankingMode.RANKED_SCORE:
query = await this.database.query("CALL SelectUserScoreRankByIdModeId(?,?)", [id, mode]);
break;
case RankingMode.AVG_ACCURACY:
query = await this.database.query("CALL SelectUserAccRankByIdModeId(?,?)", [id, mode]);
break;
case RankingMode.PP:
default:
query = await this.database.query("CALL SelectUserPPRankByIdModeId(?,?)", [id, mode]);
break;
}
if (query != null && query.length != 0) {
return query[0][0].rank;
}
return null;
}
}
function populateUserModeInfoFromRowDataPacket(userModeInfo:UserModeInfo, rowDataPacket:RowDataPacket) {
userModeInfo.n = rowDataPacket["n"];
userModeInfo.user_id = rowDataPacket["user_id"];
userModeInfo.mode_id = rowDataPacket["mode_id"];
userModeInfo.count300 = rowDataPacket["count300"];
userModeInfo.count100 = rowDataPacket["count100"];
userModeInfo.count50 = rowDataPacket["count50"];
userModeInfo.countmiss = rowDataPacket["countmiss"];
userModeInfo.playcount = rowDataPacket["playcount"];
userModeInfo.total_score = rowDataPacket["total_score"];
userModeInfo.ranked_score = rowDataPacket["ranked_score"];
userModeInfo.pp_rank = rowDataPacket["pp_rank"];
userModeInfo.pp_raw = rowDataPacket["pp_raw"];
userModeInfo.count_rank_ss = rowDataPacket["count_rank_ss"];
userModeInfo.count_rank_s = rowDataPacket["count_rank_s"];
userModeInfo.count_rank_a = rowDataPacket["count_rank_a"];
userModeInfo.pp_country_rank = rowDataPacket["pp_country_rank"];
userModeInfo.playtime = rowDataPacket["playtime"];
userModeInfo.avg_accuracy = rowDataPacket["avg_accuracy"];
userModeInfo.level = rowDataPacket["level"];
userModeInfo.is_deleted = rowDataPacket["is_deleted"];
}