From a76ed204c96479d4c5ec613a504ee23cbe545eb0 Mon Sep 17 00:00:00 2001 From: IrPgFKS0 <2511445@gmail.com> Date: Sat, 2 Sep 2023 21:58:48 -0700 Subject: [PATCH 1/4] Updated .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f958104..c392902 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ npm-debug.log #env .env +.DS_Store From 1b8d802d06bbccf8e5edb27e15f6f62826290627 Mon Sep 17 00:00:00 2001 From: IrPgFKS0 <2511445@gmail.com> Date: Sat, 2 Sep 2023 22:09:26 -0700 Subject: [PATCH 2/4] Added Nitrado API retry --- util/NitradoAPI.js | 120 ++++++++++++++++++++++++--------------------- 1 file changed, 64 insertions(+), 56 deletions(-) diff --git a/util/NitradoAPI.js b/util/NitradoAPI.js index d3e95e9..5462303 100644 --- a/util/NitradoAPI.js +++ b/util/NitradoAPI.js @@ -3,72 +3,80 @@ const concat = require('concat-stream'); const { Readable } = require('stream'); const FormData = require('form-data'); const fs = require('fs'); +const maxRetries = 5; +const retryDelay = 5000; // 5 second module.exports = { - DownloadNitradoFile: async (client, filename, outputDir) => { - const res = await fetch(`https://api.nitrado.net/services/${client.config.Nitrado.ServerID}/gameservers/file_server/download?file=${filename}`, { - headers: { - "Authorization": client.config.Nitrado.Auth + for (let retries = 0; retries <= maxRetries; retries++) { + try { + const res = await fetch(`https://api.nitrado.net/services/${client.config.Nitrado.ServerID}/gameservers/file_server/download?file=${filename}`, { + headers: { + "Authorization": client.config.Nitrado.Auth + } + }).then(response => + response.json().then(data => data) + ).then(res => res); + + const stream = fs.createWriteStream(outputDir); + if (!res.data || !res.data.token) { + client.error(`Error downloading File "${filename}":`); + client.error(res); + return -1; + } + const { body } = await fetch(res.data.token.url); + await finished(Readable.fromWeb(body).pipe(stream)); + return 0; + } catch (error) { + if (retries === maxRetries) { + throw new Error(`Failed to fetch data after ${maxRetries} retries`); + } } - }).then(response => - response.json().then(data => data) - ).then(res => res); - - const stream = fs.createWriteStream(outputDir); - if (!res.data || !res.data.token) { - client.error(`Error downloading File "${filename}":`); - client.error(res); - return -1; + await new Promise(resolve => setTimeout(resolve, retryDelay)); // Delay before retrying } - const { body } = await fetch(res.data.token.url); - await finished(Readable.fromWeb(body).pipe(stream)); - return 0; }, HandlePlayerBan: async (client, gamertag, ban) => { // get current bans - const res = await fetch(`https://api.nitrado.net/services/${client.config.Nitrado.ServerID}/gameservers`, { - headers: { - "Authorization": client.config.Nitrado.Auth - } - }).then(response => - response.json().then(data => data) - ).then(res => res); - - let bans = res.data.gameserver.settings.general.bans; - if (ban) bans += `\r\n${gamertag}`; - else if (!ban) bans = bans.replace(gamertag, ''); - else client.error("Incorrect Ban Option: HandlePlayerBan"); - - const formData = new FormData(); - formData.append("category", "general"); - formData.append("key", "bans"); - formData.append("value", bans); - formData.pipe(concat(data => { - async function sendList() { - await fetch(`https://api.nitrado.net/services/${client.config.Nitrado.ServerID}/gameservers/settings`, { - method: "POST", - credentials: 'include', + for (let retries = 0; retries <= maxRetries; retries++) { + try { + const res = await fetch(`https://api.nitrado.net/services/${client.config.Nitrado.ServerID}/gameservers`, { headers: { - ...formData.getHeaders(), "Authorization": client.config.Nitrado.Auth - }, - body: data, - }); + } + }).then(response => + response.json().then(data => data) + ).then(res => res); + + let bans = res.data.gameserver.settings.general.bans; + if (ban) bans += `\r\n${gamertag}`; + else if (!ban) bans = bans.replace(gamertag, ''); + else client.error("Incorrect Ban Option: HandlePlayerBan"); + + const formData = new FormData(); + formData.append("category", "general"); + formData.append("key", "bans"); + formData.append("value", bans); + formData.pipe(concat(data => { + async function sendList() { + await fetch(`https://api.nitrado.net/services/${client.config.Nitrado.ServerID}/gameservers/settings`, { + method: "POST", + credentials: 'include', + headers: { + ...formData.getHeaders(), + "Authorization": client.config.Nitrado.Auth + }, + body: data, + }); + } + sendList(); + })); + } catch (error) { + if (retries === maxRetries) { + throw new Error(`Failed to fetch data after ${maxRetries} retries`); + } } - sendList(); - })); - }, - - /* - Allows more explicit function names outside this file; - i.e BanPlayer() & UnbanPlayer() that both call to the - parent function HandlePlayerBan() rather than write - two whole different functions for each. - */ - - BanPlayer: async (client, gamertag) => module.exports.HandlePlayerBan(client, gamertag, true), - UnbanPlayer: async (client, gamertag) => module.exports.HandlePlayerBan(client, gamertag, false), - + await new Promise(resolve => setTimeout(resolve, retryDelay)); // Delay before retrying + } + } } \ No newline at end of file From f021ef0287000cee55ed76cc26ed09c771f7e678 Mon Sep 17 00:00:00 2001 From: IrPgFKS0 <2511445@gmail.com> Date: Sat, 2 Sep 2023 22:27:47 -0700 Subject: [PATCH 3/4] Updated getDateEST() function, added more verbose mongodb error log, removed unnecessary await --- structures/DayzRBot.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/structures/DayzRBot.js b/structures/DayzRBot.js index 953f9a6..4bfeb54 100644 --- a/structures/DayzRBot.js +++ b/structures/DayzRBot.js @@ -104,11 +104,11 @@ class DayzRBot extends Client { error(Text) { this.logger.error(Text); } async getDateEST(time) { - let t = new Date(); // Get current date (PST) - let e = new Date(t.getTime() + 180*60*1000); // Convert to EST to ensure the date is correct for the applied EST time - let n = new Date(`${e.getFullYear()}-${e.getMonth()<10?'0':''}${e.getMonth()+1}-${e.getDate()<10?'0':''}${e.getDate()}T${time.split(' ')[0]}`) // Apply given time to EST date - let f = new Date(n.getTime() - 180*60*1000) // Convert back to PST - return f; + let timeArray = time.split(' ')[0].split(':') + let t = new Date(); // Get current date & time (UTC) + let f = new Date(t.getTime() - 4 * 3600000) // Convert UTC into EST time to roll back the day as necessary + f.setUTCHours(timeArray[0], timeArray[1], timeArray[2]); // Apply the supplied EST time to the converted date (EST is the timezone produced from the Nitrado logs). + return new Date(f.getTime() + 4 * 3600000); // Add EST time offset to return timestamp in UTC } async readLogs(guildId) { @@ -246,12 +246,12 @@ class DayzRBot extends Client { this.databaseConnected = true; } catch (err) { databaselogs.attempts++; - this.error(`Failed to connect to mongodb: attempt ${databaselogs.attempts}`); + this.error(`Failed to connect to mongodb (mongodb://${mongoURI.split('@')[1]}/${dbo}): attempt ${databaselogs.attempts} - Error: ${err}`); failed = true; } // write JSON string to a file - await fs.writeFileSync(dbLogDir, JSON.stringify(databaselogs)); + fs.writeFileSync(dbLogDir, JSON.stringify(databaselogs)); if (failed) process.exit(-1); } From d5507e4276b93bab33e685cde1c72a10199bb4fd Mon Sep 17 00:00:00 2001 From: IrPgFKS0 <2511445@gmail.com> Date: Sat, 2 Sep 2023 22:54:16 -0700 Subject: [PATCH 4/4] Added v9.1.1 change back into NitradoAPI.js --- util/NitradoAPI.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/util/NitradoAPI.js b/util/NitradoAPI.js index 5462303..2689713 100644 --- a/util/NitradoAPI.js +++ b/util/NitradoAPI.js @@ -78,5 +78,16 @@ module.exports = { } await new Promise(resolve => setTimeout(resolve, retryDelay)); // Delay before retrying } - } -} \ No newline at end of file + }, + + /* + Allows more explicit function names outside this file; + i.e BanPlayer() & UnbanPlayer() that both call to the + parent function HandlePlayerBan() rather than write + two whole different functions for each. + */ + + BanPlayer: async (client, gamertag) => module.exports.HandlePlayerBan(client, gamertag, true), + UnbanPlayer: async (client, gamertag) => module.exports.HandlePlayerBan(client, gamertag, false), + + } \ No newline at end of file