> /dev/null 2>&1 * * HOW IT WORKS: * 1. Finds all servers with MODPACK_PLATFORM egg variable set * 2. Loops through each server, checking via ModpackApiService * 3. Stores results in modpackchecker_servers database table * 4. Dashboard badges read from this table (never calling APIs directly) * * RATE LIMITING: * Each API call is followed by a 2-second sleep to avoid rate limits. * For 50 servers, a full check takes ~2 minutes. * * @package Pterodactyl\Console\Commands * @author Firefrost Gaming / Frostystyle * @version 1.0.0 * @see ModpackApiService.php (centralized API logic) * @see ModpackAPIController.php (provides getStatus endpoint for badges) * ============================================================================= */ namespace Pterodactyl\Console\Commands; use Illuminate\Console\Command; use Illuminate\Support\Facades\DB; use Pterodactyl\Models\Server; use Pterodactyl\Services\ModpackApiService; class CheckModpackUpdates extends Command { protected $signature = 'modpackchecker:check'; protected $description = 'Check all servers for modpack updates'; public function __construct(private ModpackApiService $apiService) { parent::__construct(); } /** * Execute the console command. * * @return int Exit code (0 = success) */ public function handle(): int { $this->info('Starting modpack update check...'); // Get all servers that have modpack variables set $servers = Server::whereHas('variables', function ($q) { $q->where('env_variable', 'MODPACK_PLATFORM'); })->get(); $this->info("Found {$servers->count()} servers with modpack configuration"); foreach ($servers as $server) { $this->checkServer($server); // Rate limiting - sleep between checks sleep(2); } $this->info('Modpack update check complete!'); return 0; } /** * Check a single server for modpack updates. * * @param Server $server The server to check * @return void */ private function checkServer(Server $server): void { $this->line("Checking: {$server->name} ({$server->uuid})"); try { $platform = $this->getVariable($server, 'MODPACK_PLATFORM'); $modpackId = $this->getVariable($server, 'MODPACK_ID'); if (!$platform || !$modpackId) { $this->warn(" Skipping - missing platform or modpack ID"); return; } // Centralized API Call via Service $latestData = $this->apiService->fetchLatestVersion($platform, $modpackId); $currentVersion = $this->getVariable($server, 'MODPACK_CURRENT_VERSION'); $updateAvailable = $currentVersion && $currentVersion !== $latestData['version']; $this->updateDatabase($server, [ 'platform' => $platform, 'modpack_id' => $modpackId, 'modpack_name' => $latestData['name'], 'current_version' => $currentVersion, 'latest_version' => $latestData['version'], 'status' => $updateAvailable ? 'update_available' : 'up_to_date', 'error_message' => null, 'last_checked' => now(), ]); $statusIcon = $updateAvailable ? '🟠 UPDATE AVAILABLE' : '🟢 Up to date'; $this->info(" {$statusIcon}: {$latestData['name']} - {$latestData['version']}"); } catch (\Exception $e) { $this->error(" Error: {$e->getMessage()}"); $this->updateDatabase($server, [ 'status' => 'error', 'error_message' => $e->getMessage(), 'last_checked' => now(), ]); } } /** * Get an egg variable value from a server. * * @param Server $server The server to query * @param string $name The variable name * @return string|null The variable value, or null if not set */ private function getVariable(Server $server, string $name): ?string { $variable = $server->variables() ->where('env_variable', $name) ->first(); return $variable?->server_value; } /** * Store or update the modpack check results in the database. * * Uses updateOrInsert for upsert behavior. * The server_uuid column is the unique key for matching. * * @param Server $server The server being checked * @param array $data The data to store * @return void */ private function updateDatabase(Server $server, array $data): void { DB::table('modpackchecker_servers')->updateOrInsert( ['server_uuid' => $server->uuid], array_merge($data, ['updated_at' => now()]) ); } }