From 7d30bf24d95bd3f3e0cecd2899eceec1dd917574 Mon Sep 17 00:00:00 2001 From: DJj123dj <80536295+DJj123dj@users.noreply.github.com> Date: Tue, 14 Jan 2025 17:53:11 +0100 Subject: [PATCH] The bot will now only re-compile when changed The bot will now only re-compile when the plugins or source code changes. (computed using a hash) This reduces the average startup time by 50%. --- index.js | 148 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 114 insertions(+), 34 deletions(-) diff --git a/index.js b/index.js index 13d1eda..25e9576 100644 --- a/index.js +++ b/index.js @@ -1,53 +1,133 @@ -const fs = require("fs") -const ts = require("typescript") -const nodepath = require('path') - /////////////// STARTUP FLAGS /////////////// const flags = [ + // Edit flags here when being unable to use the flags in the command prompt. //PTERODACTYL PANEL //add startup flags here (e.g. "--no-compile") when running via the panel ] process.argv.push(...flags) /////////////// STARTUP FLAGS /////////////// +/* + ██████╗ ██████╗ ███████╗███╗ ██╗ ████████╗██╗ ██████╗██╗ ██╗███████╗████████╗ +██╔═══██╗██╔══██╗██╔════╝████╗ ██║ ╚══██╔══╝██║██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝ +██║ ██║██████╔╝█████╗ ██╔██╗ ██║ ██║ ██║██║ █████╔╝ █████╗ ██║ +██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║ ██║ ██║██║ ██╔═██╗ ██╔══╝ ██║ +╚██████╔╝██║ ███████╗██║ ╚████║ ██║ ██║╚██████╗██║ ██╗███████╗ ██║ + ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚══════╝ ╚═╝ + v4.0.0 - Made by DJj123dj & Contributors + + Discord: https://discord.dj-dj.be + Docs: https://otdocs.dj-dj.be + Support Us: https://github.com/sponsors/DJj123dj/ + + */ +/////////////////////////////////////////// +////////// COMPILATION + STARTUP ////////// +/////////////////////////////////////////// +const fs = require("fs") +const ts = require("typescript") +const {createHash,Hash} = require("crypto") +const nodepath = require('path') + +/** ## What is this? + * This is a function which compares `./src/` with a hash stored in `./dist/hash.txt`. + * The hash is based on the modified date & file metadata of all files in `./src/`. + * + * If the hash is different, the bot will automatically re-compile. + * This will help you save CPU resources because the bot shouldn't re-compile when nothing has been changed :) + * + * @param {string} dir + * @param {Hash|null} upperHash + */ +function computeSourceHash(dir,upperHash){ + const hash = upperHash ? upperHash : createHash("sha256") + const info = fs.readdirSync(dir,{withFileTypes:true}) + + for (const file of info) { + const fullPath = nodepath.join(dir,file.name) + if (file.isFile()){ + const statInfo = fs.statSync(fullPath) + //compute hash using file metadata + const fileInfo = `${fullPath}:${statInfo.size}:${statInfo.mtimeMs}` + hash.update(fileInfo) + + }else if (file.isDirectory()){ + //recursively compute all folders + computeSourceHash(fullPath,hash) + } + } + //return when not being called recursively + if (!upperHash) { + return hash.digest("hex") + } +} +function requiresCompilation(){ + //check hashes when not using "--compile-only" flag + if (process.argv.includes("--compile-only")) return true + + console.log("OT: Comparing prebuilds with source...") + const sourceHash = computeSourceHash("./src/") + const pluginHash = computeSourceHash("./plugins/") + const hash = sourceHash+":"+pluginHash + + if (fs.existsSync("./dist/hash.txt")){ + const distHash = fs.readFileSync("./dist/hash.txt").toString() + if (distHash === hash) return false + else return true + }else return true +} +function saveNewCompilationHash(){ + const sourceHash = computeSourceHash("./src/") + const pluginHash = computeSourceHash("./plugins/") + const hash = sourceHash+":"+pluginHash + fs.writeFileSync("./dist/hash.txt",hash) +} + if (!process.argv.includes("--no-compile")){ - //REMOVE EXISTING BUILDS - console.log("OT: Removing Prebuilds...") - fs.rmSync("./dist",{recursive:true,force:true}) + if (requiresCompilation()){ + console.log("OT: Compilation Required...") - //COMPILE TYPESCRIPT - console.log("OT: Compiling Typescript...") - const configPath = nodepath.resolve('./tsconfig.json') - const configFile = ts.readConfigFile(configPath,ts.sys.readFile) + //REMOVE EXISTING BUILDS + console.log("OT: Removing Prebuilds...") + fs.rmSync("./dist",{recursive:true,force:true}) - //check for tsconfig errors - if (configFile.error){ - const message = ts.formatDiagnosticsWithColorAndContext([configFile.error],ts.createCompilerHost({})) - console.error(message) - process.exit(1) - } + //COMPILE TYPESCRIPT + console.log("OT: Compiling Typescript...") + const configPath = nodepath.resolve('./tsconfig.json') + const configFile = ts.readConfigFile(configPath,ts.sys.readFile) - //parse tsconfig file - const parsedConfig = ts.parseJsonConfigFileContent(configFile.config,ts.sys,nodepath.dirname(configPath)) + //check for tsconfig errors + if (configFile.error){ + const message = ts.formatDiagnosticsWithColorAndContext([configFile.error],ts.createCompilerHost({})) + console.error(message) + process.exit(1) + } - //create program/compiler - const program = ts.createProgram({ - rootNames:parsedConfig.fileNames, - options:parsedConfig.options - }) + //parse tsconfig file + const parsedConfig = ts.parseJsonConfigFileContent(configFile.config,ts.sys,nodepath.dirname(configPath)) - //emit all compiled files - const emitResult = program.emit() + //create program/compiler + const program = ts.createProgram({ + rootNames:parsedConfig.fileNames, + options:parsedConfig.options + }) - //print emit errors/warnings (type errors) - const allDiagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics) - const formattedDiagnostics = ts.formatDiagnosticsWithColorAndContext(allDiagnostics, ts.createCompilerHost(parsedConfig.options)) - console.log(formattedDiagnostics) + //emit all compiled files + const emitResult = program.emit() - if (emitResult.emitSkipped || allDiagnostics.find((d) => d.category == ts.DiagnosticCategory.Error || d.category == ts.DiagnosticCategory.Warning)){ - console.log("OT: Compilation Failed!") - process.exit(1) - } + //print emit errors/warnings (type errors) + const allDiagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics) + const formattedDiagnostics = ts.formatDiagnosticsWithColorAndContext(allDiagnostics, ts.createCompilerHost(parsedConfig.options)) + console.log(formattedDiagnostics) + + if (emitResult.emitSkipped || allDiagnostics.find((d) => d.category == ts.DiagnosticCategory.Error || d.category == ts.DiagnosticCategory.Warning)){ + console.log("OT: Compilation Failed!") + process.exit(1) + } + }else console.log("OT: No Compilation Required...") + + //save new compilation hash + saveNewCompilationHash() } //START BOT