diff --git a/Minecraft-BungeeCord-Status/minecraft-bungeecord-status.php b/Minecraft-BungeeCord-Status/minecraft-bungeecord-status.php index 024a788..fa7e65a 100644 --- a/Minecraft-BungeeCord-Status/minecraft-bungeecord-status.php +++ b/Minecraft-BungeeCord-Status/minecraft-bungeecord-status.php @@ -488,25 +488,89 @@ function mcss_render_row($srv, $i, $font_sizes, $announcement_types) { } /* ---------------- LOGIC: STATUS API FETCHER ---------------- */ -function mcss_fetch_data_via_api($host, $port, $timeout = 2) { +function mcss_socket_http_json($host, $port, $path = '/', $timeout = 2.0) { $socket = @fsockopen($host, $port, $errno, $errstr, $timeout); - if (!$socket) return false; + if (!$socket) { + return false; + } - $out = "GET / HTTP/1.1\r\n"; + stream_set_timeout($socket, (int)ceil($timeout)); + + $out = "GET " . $path . " HTTP/1.1\r\n"; $out .= "Host: " . $host . "\r\n"; - $out .= "Connection: Close\r\n\r\n"; - fwrite($socket, $out); + $out .= "User-Agent: MCSS-WordPress/3.6.6\r\n"; + $out .= "Accept: application/json\r\n"; + $out .= "Connection: close\r\n\r\n"; + + if (@fwrite($socket, $out) === false) { + @fclose($socket); + return false; + } $response = ''; while (!feof($socket)) { - $response .= fgets($socket, 128); + $chunk = @fread($socket, 2048); + if ($chunk === false) { + break; + } + if ($chunk === '') { + $meta = stream_get_meta_data($socket); + if (!empty($meta['timed_out'])) { + break; + } + usleep(10000); + continue; + } + $response .= $chunk; } - fclose($socket); - $parts = explode("\r\n\r\n", $response); - $body = end($parts); - $data = json_decode($body, true); - return $data; + $meta = stream_get_meta_data($socket); + @fclose($socket); + + if (!empty($meta['timed_out'])) { + return false; + } + + $parts = explode("\r\n\r\n", $response, 2); + if (count($parts) !== 2) { + return false; + } + + $statusLine = strtok($parts[0], "\r\n"); + if (!is_string($statusLine) || stripos($statusLine, '200') === false) { + return false; + } + + $data = json_decode($parts[1], true); + return is_array($data) ? $data : false; +} + +function mcss_fetch_data_via_api($host, $port, $timeout = 2) { + // Primärer Endpunkt mit Detaildaten + $full = mcss_socket_http_json($host, $port, '/', $timeout); + if (is_array($full) && isset($full['online'])) { + return $full; + } + + // Fallback auf Health-Endpunkt (StatusAPI >= hardened build) + $health = mcss_socket_http_json($host, $port, '/health', $timeout); + if (is_array($health) && !empty($health['online'])) { + return [ + 'online' => true, + 'players' => [], + 'version' => 'BungeeCord', + 'ping' => 1, + 'motd' => 'StatusAPI erreichbar (Health)', + ]; + } + + // Ein zweiter kurzer Versuch reduziert False Negatives bei Paketverlust. + $retry = mcss_socket_http_json($host, $port, '/', max(1.0, $timeout)); + if (is_array($retry) && isset($retry['online'])) { + return $retry; + } + + return false; } function mcss_parse_bungeecord_version($raw_version) { @@ -517,16 +581,26 @@ function mcss_parse_bungeecord_version($raw_version) { } function mcss_fetch_server_with_ranks($srv) { - $cache_key = 'mcss_data_' . md5($srv['host']); + $host = $srv['host']; + $port = $srv['player_port'] ?? 9191; + + $cache_key = 'mcss_data_' . md5($host . ':' . $port); + $last_good_key = 'mcss_last_good_' . md5($host . ':' . $port); + $cached = get_transient($cache_key); if ($cached !== false) return $cached; - $host = $srv['host']; - $port = $srv['player_port'] ?? 9191; - - $api_data = mcss_fetch_data_via_api($host, $port, 1); + $api_data = mcss_fetch_data_via_api($host, $port, 2); if (!$api_data || !isset($api_data['online'])) { + $last_good = get_transient($last_good_key); + if (is_array($last_good) && !empty($last_good['online'])) { + $last_good['stale'] = true; + $last_good['stale_reason'] = 'temporary_connection_loss'; + set_transient($cache_key, $last_good, 5); + return $last_good; + } + return ['online'=>false,'players'=>[],'version'=>'Offline','ping'=>9999,'motd'=>'Verbindung fehlgeschlagen']; } @@ -574,7 +648,7 @@ function mcss_fetch_server_with_ranks($srv) { $clean_version = mcss_parse_bungeecord_version($api_data['version'] ?? 'BungeeCord'); $result = [ - 'online' => true, + 'online' => !empty($api_data['online']), 'players' => $players_info, 'version' => $clean_version, 'ping' => 1, @@ -583,6 +657,9 @@ function mcss_fetch_server_with_ranks($srv) { $fast_cache_ttl = max(2, absint($srv['cache_ttl'] ?? 10)); set_transient($cache_key, $result, $fast_cache_ttl); + if (!empty($result['online'])) { + set_transient($last_good_key, $result, 180); + } return $result; }