From 5525ebcb8489ce6a5849c98ff88670c8625fd96b Mon Sep 17 00:00:00 2001 From: sebola3461 Date: Thu, 28 Dec 2023 19:30:18 -0300 Subject: [PATCH] Keep rate-change beatmap files for 5 minutes --- models/core/AxerBot.ts | 6 +- modules/osu/ratechanger/BeatmapRateChanger.ts | 14 ++- .../ratechanger/RateChangeDeletionManager.ts | 117 ++++++++++++++++++ 3 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 modules/osu/ratechanger/RateChangeDeletionManager.ts diff --git a/models/core/AxerBot.ts b/models/core/AxerBot.ts index 6ab4e180..7761f126 100644 --- a/models/core/AxerBot.ts +++ b/models/core/AxerBot.ts @@ -10,7 +10,7 @@ import { UserEventsListener } from "./UserEventsListener"; import { handleMapperTrackerUserEvent } from "../../modules/tracking/mapperTracker"; import { RemindersManager } from "../../modules/reminders/remindersChecker"; import { AxerBancho } from "../../modules/bancho/client"; - +import { RateChangeDeletionManager } from "../../modules/osu/ratechanger/RateChangeDeletionManager"; import "../../modules/osu/fetcher/startConnection"; import "../../modules/automation/start"; @@ -20,6 +20,7 @@ export class AxerBot extends Client { public UserEvents = new UserEventsListener(); public Reminders = new RemindersManager(this); public Bancho = new AxerBancho(this); + public RateChangeDeletionManager = new RateChangeDeletionManager(); constructor(options: ClientOptions) { super(options); @@ -33,6 +34,7 @@ export class AxerBot extends Client { this.Discussions.events.on.bind(this.Discussions); this.UserEvents.listen.bind(this.UserEvents); this.UserEvents.events.on.bind(this.UserEvents); + this.RateChangeDeletionManager.listen.bind(this.RateChangeDeletionManager); this.login(process.env.TOKEN).then(() => { this.Bancho.connect().catch(console.error); @@ -41,6 +43,8 @@ export class AxerBot extends Client { startAvatarListener(this); this.Reminders.start(); + this.RateChangeDeletionManager.listen(); + this.Discussions.listen(); this.Discussions.events.on("any", handleDiscussionEvent); diff --git a/modules/osu/ratechanger/BeatmapRateChanger.ts b/modules/osu/ratechanger/BeatmapRateChanger.ts index 4d4d84a7..87e6c2ee 100644 --- a/modules/osu/ratechanger/BeatmapRateChanger.ts +++ b/modules/osu/ratechanger/BeatmapRateChanger.ts @@ -15,6 +15,7 @@ import { bufferToStream } from "../../../helpers/transform/bufferToStream"; import { BeatmapEncoder, HoldableObject, SpinnableObject } from "osu-parsers"; import Ffmpeg from "fluent-ffmpeg"; import archiver from "archiver"; +import { bot } from "../../.."; export interface BeatmapRateChangerOptions { scaleOd?: boolean; @@ -43,7 +44,14 @@ export class BeatmapRateChanger { this.options = options; } + private addToDeletionQueue() { + console.log("test"); + bot.RateChangeDeletionManager.addToQueue(this.fileHash, new Date()); + } + generate() { + this.addToDeletionQueue.bind(this); + return new Promise((resolve, reject) => { const encoder = new BeatmapEncoder(); @@ -64,7 +72,11 @@ export class BeatmapRateChanger { encoder .encodeToPath(path.join(this.tempPath, output), this.beatmap) - .then(() => resolve(this.fileHash)); + .then(() => { + this.addToDeletionQueue(); + + resolve(this.fileHash); + }); }) .catch(reject); }); diff --git a/modules/osu/ratechanger/RateChangeDeletionManager.ts b/modules/osu/ratechanger/RateChangeDeletionManager.ts new file mode 100644 index 00000000..8c0fe778 --- /dev/null +++ b/modules/osu/ratechanger/RateChangeDeletionManager.ts @@ -0,0 +1,117 @@ +// This should delete rate change files after 5 minutes + +import { existsSync, readFileSync, rmSync, unlinkSync, writeFileSync } from "fs"; +import path from "path"; +import { LoggerClient } from "../../../models/core/LoggerClient"; + +export interface RateChangeTempFile { + info: string; + format: string; + duration: number; + files: RateChangeTempFileEntry[]; +} + +export interface RateChangeTempFileEntry { + fileId: string; + createdAt: string; +} + +export class RateChangeDeletionManager { + private tempFilePath = path.resolve(path.join("./temp/ratechange/temp.json")); + private baseTempPath = path.resolve("./temp/ratechange"); + private logger = new LoggerClient("RateChangeDeletionManager"); + + constructor() {} + + private tempFileBase = { + info: "Files here will be deleted after the time scheduled below", + format: "{ fileId: string, createdAt: Date }", + duration: 300, + files: [], + }; + + private checkAndCreateTempFile() { + if (!existsSync(this.tempFilePath)) { + writeFileSync(this.tempFilePath, JSON.stringify(this.tempFileBase)); + + this.logger.printSuccess("temp.json created!"); + } + } + + public addToQueue(fileId: string, createdAt?: Date) { + const fileContent: RateChangeTempFile = JSON.parse(readFileSync(this.tempFilePath, "utf8")); + + if (fileContent.files.find((file) => file.fileId == fileId)) return; + + fileContent.files.push({ + fileId: fileId.trim(), + createdAt: (createdAt || new Date()).toISOString(), + }); + + writeFileSync(this.tempFilePath, JSON.stringify(fileContent)); + + this.logger.printSuccess(`Added file ${fileId} to deletion queue!`); + } + + public removeFromQueue(fileId: string) { + const fileContent: RateChangeTempFile = JSON.parse(readFileSync(this.tempFilePath, "utf8")); + + if (!fileContent.files.find((file) => file.fileId == fileId)) return; + + fileContent.files = fileContent.files.filter((file) => file.fileId != fileId); + + writeFileSync(this.tempFilePath, JSON.stringify(fileContent)); + + this.logger.printSuccess(`Removed file ${fileId} from deletion queue!`); + } + + private getMaxFileAge() { + const fileContent: RateChangeTempFile = JSON.parse(readFileSync(this.tempFilePath, "utf8")); + + return fileContent.duration; + } + + private checkTimeDifference(from: Date, to: Date) { + return (to.getTime() - from.getTime()) / 1000; + } + + private canDelete(date: Date, maxAge: number) { + return this.checkTimeDifference(date, new Date()) > maxAge; + } + + private checkQueue() { + const fileContent: RateChangeTempFile = JSON.parse(readFileSync(this.tempFilePath, "utf8")); + const entries = fileContent.files; + + const filesToDelete = entries.filter((entry) => + this.canDelete(new Date(entry.createdAt), fileContent.duration) + ); + + for (const file of filesToDelete) { + try { + this.logger.printInfo(`Removing ${file.fileId}...`); + + rmSync(path.join(this.baseTempPath, file.fileId), { recursive: true }); + rmSync(path.join(this.baseTempPath, "osz", file.fileId), { recursive: true }); + + this.removeFromQueue(file.fileId); + + this.logger.printSuccess(`${file.fileId} removed!`); + } catch (e: any) { + if (e.code == "ENOENT") { + this.removeFromQueue(file.fileId); + } else { + this.logger.printError(`${file.fileId} can't be removed!`, e); + } + } + } + } + + public listen() { + this.logger.printInfo("Starting listener..."); + + this.checkAndCreateTempFile(); + + setInterval(this.checkQueue.bind(this), 1000); + } +}