const Discord = require('discord.js'); const Docker = require('dockerode'); const { CronJob } = require('cron'); const fs = require('fs').promises; require('dotenv').config(); const client = new Discord.Client({ intents: [ Discord.GatewayIntentBits.Guilds, Discord.GatewayIntentBits.GuildMembers ] }); const mysql = require('mysql2/promise'); const connection = mysql.createConnection({ host: process.env.SQLHOST, user: process.env.SQLUSER, database: process.env.SQLDATABASE, password: process.env.SQLPASSWORD }); // Utility function for delay const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); async function getDiscordID(uid) { if (!uid || typeof uid !== 'string') { console.log("Invalid or undefined UID provided"); return "The user does not Exist"; } try { const [results] = await (await connection).query( "SELECT discord_id FROM users WHERE uid = ?", [uid] ); if (results.length === 0) { console.log(`User with UID ${uid} does not exist`); return "The user does not Exist"; } return results[0].discord_id; } catch (err) { console.log(`Error querying database for UID ${uid}: ${err.message}`); throw err; } } const docker = new Docker(); const DISCORD_TOKEN = process.env.DISCORD_TOKEN; const GUILD_ID = process.env.GUILD_ID; const ROLE_IDS = { standard: process.env.ROLE_ID_STANDARD, manualUpgrade: process.env.ROLE_ID_MANUAL_UPGRADE, noExpire: process.env.NO_EXPIRE_CHANNEL_IDS.split(',') }; const DEFAULT_CPUS = parseInt(process.env.DEFAULT_CPUS); const DEFAULT_MEMORY = parseInt(process.env.DEFAULT_MEMORY) * 1024 * 1024; const DEFAULT_SWAP = parseInt(process.env.DEFAULT_SWAP) * 1024 * 1024; const UPGRADED_CPUS = parseInt(process.env.UPGRADED_CPUS); const UPGRADED_MEMORY = parseInt(process.env.UPGRADED_MEMORY) * 1024 * 1024; const UPGRADED_SWAP = parseInt(process.env.UPGRADED_SWAP) * 1024 * 1024; const RESET_UNKNOWN_TO_DEFAULT = process.env.RESET_UNKNOWN_TO_DEFAULT === 'true'; const CACHE_FILE = '/var/www/html/current_upgraded.json'; async function updateCache(upgradedContainers) { try { const data = JSON.stringify(upgradedContainers, null, 2); await fs.writeFile(CACHE_FILE, data); console.log(` āœ… Cache updated at ${CACHE_FILE} with ${upgradedContainers.length} upgraded containers`); } catch (err) { console.error(` āŒ Error writing to cache file ${CACHE_FILE}: ${err.message}`); } } async function checkContainers() { console.log('\n=== Starting Container Check ===\n'); const upgradedContainers = []; try { const containers = await docker.listContainers({ all: false }); for (const contInfo of containers) { const name = contInfo.Names[0].slice(1); if (name.startsWith('SSH')) { const container = docker.getContainer(contInfo.Id); const inspect = await container.inspect(); const currentCpus = inspect.HostConfig.NanoCpus / 1e9; const currentMem = inspect.HostConfig.Memory; const currentSwap = inspect.HostConfig.MemorySwap; console.log(`šŸ“¦ Container: ${name}`); console.log(` Current Settings:`); console.log(` CPUs: ${currentCpus}`); console.log(` Memory: ${currentMem / 1024 / 1024} MiB`); console.log(` Swap: ${currentSwap / 1024 / 1024} MiB`); const isDefault = currentCpus === DEFAULT_CPUS && currentMem === DEFAULT_MEMORY && currentSwap === DEFAULT_SWAP; const isUpgraded = currentCpus === UPGRADED_CPUS && currentMem === UPGRADED_MEMORY && currentSwap === UPGRADED_SWAP; const discordID = await getDiscordID(name); if (discordID === "The user does not Exist") { console.log(`User ${name} does not exist`); continue; } if (isUpgraded) { upgradedContainers.push({ containerName: name, userId: discordID, upgradeType: 'standard' }); } if (!isDefault && !isUpgraded) { console.log(` āš ļø Warning: Unknown limits detected!`); console.log(` Expected Default: CPUs=${DEFAULT_CPUS}, Memory=${DEFAULT_MEMORY / 1024 / 1024} MiB, Swap=${DEFAULT_SWAP / 1024 / 1024} MiB`); console.log(` Expected Upgraded: CPUs=${UPGRADED_CPUS}, Memory=${UPGRADED_MEMORY / 1024 / 1024} MiB, Swap=${UPGRADED_SWAP / 1024 / 1024} MiB`); if (RESET_UNKNOWN_TO_DEFAULT) { console.log(` šŸ”„ Resetting to default settings...`); await container.update({ NanoCpus: DEFAULT_CPUS * 1e9, Memory: DEFAULT_MEMORY, MemorySwap: DEFAULT_SWAP }); console.log(` āœ… Container reset to default settings.`); } else { console.log(` ā­ļø Skipping due to unknown limits.`); continue; } } const guild = client.guilds.cache.get(GUILD_ID); if (!guild) { console.log(` āŒ Guild ${GUILD_ID} not found.`); continue; } try { const member = await guild.members.fetch(discordID); // Use discordID instead of name const hasNoExpireRole = ROLE_IDS.noExpire.some(roleId => member.roles.cache.has(roleId)); const hasStandardOrManualRole = [ROLE_IDS.standard, ROLE_IDS.manualUpgrade].some(roleId => member.roles.cache.has(roleId)); console.log(` Discord ID: ${discordID}`); console.log(` Role Check: User ${hasNoExpireRole ? 'has no-expire role' : hasStandardOrManualRole ? 'has standard or manual upgrade role' : 'has no relevant roles'} (${[...ROLE_IDS.noExpire, ROLE_IDS.standard, ROLE_IDS.manualUpgrade].join(' or ')})`); if (hasNoExpireRole) { upgradedContainers.push({ containerName: name, userId: discordID, upgradeType: 'no-expire' }); } else if (hasStandardOrManualRole && !isUpgraded) { console.log(` šŸ”¼ Upgrading container...`); await container.update({ NanoCpus: UPGRADED_CPUS * 1e9, Memory: UPGRADED_MEMORY, MemorySwap: UPGRADED_SWAP }); console.log(` āœ… Upgraded to: CPUs=${UPGRADED_CPUS}, Memory=${UPGRADED_MEMORY / 1024 / 1024} MiB, Swap=${UPGRADED_SWAP / 1024 / 1024} MiB`); upgradedContainers.push({ containerName: name, userId: discordID, upgradeType: 'standard' }); } else if (!hasNoExpireRole && !hasStandardOrManualRole && isUpgraded) { console.log(` šŸ”½ Downgrading container...`); await container.update({ NanoCpus: DEFAULT_CPUS * 1e9, Memory: DEFAULT_MEMORY, MemorySwap: DEFAULT_SWAP }); console.log(` āœ… Downgraded to: CPUs=${DEFAULT_CPUS}, Memory=${DEFAULT_MEMORY / 1024 / 1024} MiB, Swap=${DEFAULT_SWAP / 1024 / 1024} MiB`); const index = upgradedContainers.findIndex(c => c.containerName === name); if (index !== -1) upgradedContainers.splice(index, 1); } else { console.log(` āœ… No action needed. Container settings match role status.`); } } catch (err) { console.log(` āŒ Error fetching member with Discord ID ${discordID}: ${err.message}`); continue; } console.log('----------------------------------------'); // Add 3-second delay between container checks await sleep(3000); } } await updateCache(upgradedContainers); console.log('\n=== Container Check Completed ===\n'); } catch (err) { console.error(`\nāŒ Error in container check: ${err.message}\n`); } } client.once('ready', () => { console.log(`āœ… Logged in as ${client.user.tag}. Bot is ready.`); checkContainers(); const job = new CronJob('*/30 * * * *', checkContainers, null, true, 'UTC'); job.start(); }); client.login(DISCORD_TOKEN);