From bd3875743e748c5ea0775fb312835a9abb92654f Mon Sep 17 00:00:00 2001 From: Frank Harris Date: Wed, 17 Jun 2026 08:28:31 -0500 Subject: [PATCH] server status fix --- Panel/includes/functions.php | 8 + Panel/modules/dashboard/dashboard.css | 82 ++-- Panel/modules/dashboard/dashboard.php | 57 ++- Panel/modules/faq/faq.rss | 2 +- Panel/modules/faq/local.rss | 2 +- Panel/server_status.php | 643 ++++++++++++++++---------- docs/modules/dashboard.md | 21 +- docs/modules/status.md | 46 +- 8 files changed, 555 insertions(+), 306 deletions(-) diff --git a/Panel/includes/functions.php b/Panel/includes/functions.php index 19359ef3..71f1ee59 100644 --- a/Panel/includes/functions.php +++ b/Panel/includes/functions.php @@ -66,6 +66,14 @@ function gsp_project_request_url(): string { return 'https://runlevelsystems.com/start-project.php'; } +function gsp_discord_invite_url(): string { + return 'https://discord.gg/qt9Hnkj6cv'; +} + +function gsp_server_status_url(): string { + return 'server_status.php'; +} + function gsp_panel_footer_copyright(): string { return "\u{00A9} 2026 " . gsp_company_name(); } diff --git a/Panel/modules/dashboard/dashboard.css b/Panel/modules/dashboard/dashboard.css index 4db9abff..d354b9b0 100644 --- a/Panel/modules/dashboard/dashboard.css +++ b/Panel/modules/dashboard/dashboard.css @@ -63,30 +63,29 @@ color: #d2def4; } -.dashboard-service-grid { - display: grid; - grid-template-columns: 2fr 1fr; - gap: 16px; - margin-top: 20px; +.dashboard-widget-copy { + position: relative; + padding-right: 56px; } -.dashboard-promo-card, -.dashboard-secondary-card { - padding: 18px 20px; - background: linear-gradient(180deg, rgba(12, 22, 40, 0.94) 0%, rgba(8, 16, 29, 0.96) 100%); - border: 1px solid rgba(77, 160, 255, 0.2); - border-radius: 8px; - box-shadow: 0 16px 36px rgba(0, 0, 0, 0.24); -} - -.dashboard-promo-card { - border-left: 3px solid #48c4f5; -} - -.dashboard-promo-card p, -.dashboard-secondary-card p { +.dashboard-widget-copy p { margin: 0 0 12px; - color: #d2def4; +} + +.dashboard-widget-icon { + position: absolute; + top: 4px; + right: 0; + width: 40px; + height: 40px; + opacity: 0.9; +} + +.dashboard-link-group { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-top: 14px; } .dashboard-card-note { @@ -121,6 +120,11 @@ color: #f0f5ff; } +.dashboard-support-link-secondary { + background: rgba(72, 196, 245, 0.08); + border-color: rgba(72, 196, 245, 0.24); +} + .dashboard-support-link:hover, .dashboard-support-link:focus { color: #ffffff; @@ -128,16 +132,32 @@ box-shadow: 0 0 0 3px rgba(90, 199, 247, 0.12); } -@media (max-width: 991px) { - .dashboard-service-grid { - grid-template-columns: 1fr; - } +.dashboard-status-panel { + margin-top: 20px; +} + +.dashboard-status-content { + padding: 18px 20px; + text-align: center; + color: #d2def4; +} + +.dashboard-status-content p { + margin: 0 0 14px; +} + +.dashboard-status-button { + margin-bottom: 10px; +} + +.dashboard-status-note { + display: block; + color: #9fb5d8; } @media (max-width: 430px) { - .dashboard-promo-card, - .dashboard-secondary-card { - padding: 16px; + .dashboard-widget-copy { + padding-right: 0; } .dashboard-cta-button, @@ -145,4 +165,10 @@ width: 100%; text-align: center; } + + .dashboard-widget-icon { + position: static; + display: block; + margin: 0 0 12px auto; + } } diff --git a/Panel/modules/dashboard/dashboard.php b/Panel/modules/dashboard/dashboard.php index 1eb7d144..695ed32b 100644 --- a/Panel/modules/dashboard/dashboard.php +++ b/Panel/modules/dashboard/dashboard.php @@ -32,6 +32,8 @@ function exec_ogp_module() global $db, $settings, $loggedInUserInfo; $projectRequestUrl = htmlspecialchars(gsp_project_request_url(), ENT_QUOTES, 'UTF-8'); + $discordInviteUrl = htmlspecialchars(gsp_discord_invite_url(), ENT_QUOTES, 'UTF-8'); + $serverStatusUrl = htmlspecialchars(gsp_server_status_url(), ENT_QUOTES, 'UTF-8'); $isAdmin = $db->isAdmin($_SESSION['user_id']); $user_id = $_SESSION['user_id']; @@ -85,16 +87,27 @@ function exec_ogp_module() $content[3] = 'View all your notifications. '; $href[3] = 'home.php?m=circular&p=show_circular&list=true'; - // Support Resources quick link - $title[4] = 'Support Resources'; - $content[4] ='Need routine help? Use the support section for tickets, service problems, documentation, and troubleshooting with existing features.'; - $href[4] = 'home.php?m=tickets'; + // Custom Server Code + $title[4] = 'Custom Server Code'; + $content[4] = '
' + . '

Need something beyond the standard server options? Our developers can customize, repair, automate, or extend your game server with mods, scripts, integrations, migrations, and server-specific tools.

' + . '

Tell us what you want to build or improve, and we will review the request with you.

' + . 'Request Custom Development' + . '
'; + $href[4] = null; // Support - $title[5] = (isset($settings['support_widget_title']) && $settings['support_widget_title'] != "") ? - $settings['support_widget_title'] : get_lang('support'); - $content[5] = ' Submit a SUPPORT TICKET or use our Discord Chat at the bottom right. Click this box to JOIN our Discord'; - $href[5] = 'https://discord.gg/cWHAbav'; + $title[5] = 'Support'; + $content[5] = '
' + . '' + . '

Need help with an existing service? Submit a support ticket or join our Discord support server.

' + . '

Support is for service problems, broken functionality, routine troubleshooting, and help using the features already included with your server.

' + . '' + . '
'; + $href[5] = null; @@ -145,30 +158,14 @@ function exec_ogp_module() echo $html.''; } - echo "
-
-

CUSTOM SERVER DEVELOPMENT

-

Need something beyond the standard server options? Our developers can customize, repair, automate, or extend your game server with mods, scripts, integrations, migrations, and server-specific tools.

-

Tell us what you want to build or improve, and we will review the request with you.

- Request Custom Development -
-
-

Support and Troubleshooting

-

Use support when something is broken, you need routine troubleshooting, or you need help with the features already included with your service.

- Open Support Resources -
-
"; - // Server Status Link - Available to all users - echo "
-
+ echo "
+

Server Status

-
-

View the status of all game servers

- - 🖥️ View Server Status - -
Opens in a new window +
+

Check the current state of configured remote servers without delaying the main dashboard.

+ View Server Status + Opens in a new tab and runs remote checks only when requested.
"; diff --git a/Panel/modules/faq/faq.rss b/Panel/modules/faq/faq.rss index ecab8b54..24417fd4 100644 --- a/Panel/modules/faq/faq.rss +++ b/Panel/modules/faq/faq.rss @@ -13,7 +13,7 @@ https://worlddomination.software/projects/gsp Quick answers for GameServer Panel (GSP) operators en - World Domination Software FAQ Generator + Runlevel Systems FAQ Generator Tue, 11 Feb 2025 12:00:00 GMT diff --git a/Panel/modules/faq/local.rss b/Panel/modules/faq/local.rss index 1e7bceb8..395da9b6 100644 --- a/Panel/modules/faq/local.rss +++ b/Panel/modules/faq/local.rss @@ -43,7 +43,7 @@ General (1) submit a ticket on our Panel menu - (2) join our <a href=https://discord.gg/cWHAbav target=_blank > Discord Server</a> + (2) join our <a href=https://discord.gg/qt9Hnkj6cv target=_blank rel="noopener noreferrer"> Discord Server</a> (3) Look at the LOWER RIGHT of every page: Click the Discord icon diff --git a/Panel/server_status.php b/Panel/server_status.php index 62b78d1b..3b6f055e 100644 --- a/Panel/server_status.php +++ b/Panel/server_status.php @@ -22,270 +22,445 @@ * */ -// Standalone Server Status Page - Available to all users -require_once("includes/functions.php"); -require_once("includes/helpers.php"); -require_once("includes/html_functions.php"); +require_once "includes/functions.php"; +require_once "includes/helpers.php"; +require_once "includes/html_functions.php"; startSession(); -// Report all PHP errors error_reporting(E_ERROR); -// Path definitions -define("IMAGES", "images/"); -define("INCLUDES", "includes/"); -define("MODULES", "modules/"); -define("CONFIG_FILE","includes/config.inc.php"); +define("CONFIG_FILE", "includes/config.inc.php"); require_once CONFIG_FILE; -require_once('includes/lib_remote.php'); +require_once "includes/lib_remote.php"; -// Connect to the database server and select database. -$db = createDatabaseConnection($db_type, $db_host, $db_user, $db_pass, $db_name, $table_prefix, isset($db_port) ? $db_port : NULL); +$db = createDatabaseConnection($db_type, $db_host, $db_user, $db_pass, $db_name, $table_prefix, isset($db_port) ? $db_port : null); -// Load languages. -include_once("includes/lang.php"); +include_once "includes/lang.php"; if (!$db instanceof OGPDatabase) { - ogpLang(); - die(get_lang('no_db_connection')); + ogpLang(); + die(get_lang('no_db_connection')); } -// Check if user is logged in if (!isset($_SESSION['users_login'])) { - header('Location: index.php'); - exit(); + header('Location: index.php'); + exit(); } -// Get user info $loggedInUserInfo = $db->getUserById($_SESSION['user_id']); - -// Get settings $settings = $db->getSettings(); @$GLOBALS['panel_language'] = $settings['panel_language']; ogpLang(); -function ping_host($host, $timeout = 5) { - if (function_exists('exec')) { - $output = array(); - $result = 0; - - // Use ping command based on OS - if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { - exec("ping -n 1 -w " . ($timeout * 1000) . " " . escapeshellarg($host), $output, $result); - } else { - exec("ping -c 1 -W " . $timeout . " " . escapeshellarg($host), $output, $result); - } - - if ($result === 0) { - // Extract ping time from output - foreach ((array)$output as $line) { - if (preg_match('/time[<=]([0-9.]+)\s*ms/i', $line, $matches)) { - return floatval($matches[1]); - } - } - return 0; // Host is up but couldn't extract time - } - } - return false; // Host is down or ping unavailable +function panel_ping_host($host, $timeout = 3) { + if (!function_exists('exec')) { + return false; + } + + $output = array(); + $result = 0; + + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + exec("ping -n 1 -w " . ((int)$timeout * 1000) . " " . escapeshellarg($host), $output, $result); + } else { + exec("ping -c 1 -W " . (int)$timeout . " " . escapeshellarg($host), $output, $result); + } + + if ($result !== 0) { + return false; + } + + foreach ((array)$output as $line) { + if (preg_match('/time[=<]?\s*([0-9.]+)\s*ms/i', $line, $matches)) { + return (float)$matches[1]; + } + } + + return 0.0; } -function get_hostname($ip) { - $hostname = gethostbyaddr($ip); - return ($hostname && $hostname !== $ip) ? $hostname : false; +function agent_socket_reachable($host, $port, $timeout = 2.0) { + $errno = 0; + $errstr = ''; + $socket = @fsockopen($host, (int)$port, $errno, $errstr, $timeout); + if ($socket === false) { + return false; + } + fclose($socket); + return true; } -// Get all remote servers +function status_badge($label, $class) { + return '' . + htmlspecialchars($label, ENT_QUOTES, 'UTF-8') . + ''; +} + +$checkedAt = gmdate('Y-m-d H:i:s') . ' UTC'; $servers = $db->getRemoteServers(); - ?> - - - Server Status - OGP - + + + Server Status | <?php echo htmlspecialchars(gsp_company_name(), ENT_QUOTES, 'UTF-8'); ?> + -
-

🖥️ Server Status Dashboard

- - - - -
- No servers configured in the system. -
- - - - - - - - - - - - - status_chk(); - $is_online = ($status === 1); - - // Get ping time - $ping_time = ping_host($server_ip, 3); - - // Determine ping color class - $ping_class = ''; - if ($ping_time !== false) { - if ($ping_time <= 50) { - $ping_class = 'ping-good'; - } elseif ($ping_time <= 150) { - $ping_class = 'ping-medium'; - } else { - $ping_class = 'ping-bad'; - } - } - ?> - - - - - - - - - -
Server NameLocation/IPHostnameStatusPing (ms)
- -
() - -
N/A'; ?> - - 🟢 UP - - 🔴 DOWN - - - - - ms - - - N/A - -
- - -
- Last updated: -
- - -
+
+
+
+
+

Server Status

+

Configured remote servers are checked in real time when this page loads. The main dashboard stays fast because these checks do not run until you open this page.

+
+ +
+ +
+
+ Latency label + Panel-to-server latency. This is a server-side connectivity check from the Panel host, not latency from the customer browser. +
+
+ Status source + Remote servers from the active Panel configuration with live agent status checks. +
+
+ Checked + +
+
+ + +

No remote servers are currently configured.

+ +
+ + + + + + + + + + + + + + 0) ? agent_socket_reachable($agentIp, $agentPort, 2.0) : false; + $remote = new OGPRemoteLibrary($agentIp, $agentPort, $server['encryption_key'], $server['timeout']); + $agentStatus = $remote->status_chk(); + $latency = $displayIp !== '' ? panel_ping_host($displayIp, 3) : false; + + if ($agentStatus === 1) { + $overallStatus = status_badge('Online', 'status-online'); + $agentBadge = status_badge('Available', 'status-online'); + } elseif ($agentReachable) { + $overallStatus = status_badge('Unknown', 'status-warning'); + $agentBadge = status_badge('Timed out', 'status-warning'); + } else { + $overallStatus = status_badge('Offline', 'status-offline'); + $agentBadge = status_badge('Unavailable', 'status-offline'); + } + + $latencyClass = 'latency-muted'; + if ($latency !== false) { + if ($latency <= 50) { + $latencyClass = 'latency-good'; + } elseif ($latency <= 150) { + $latencyClass = 'latency-medium'; + } else { + $latencyClass = 'latency-bad'; + } + } + ?> + + + + + + + + + + +
Server NameLocation / IPStatusAgent StatusPanel-to-server latencyLast Checked
+ + Agent port + + + + Resolved IP: + + + + ms + + Unavailable + +
+
+ + + +
+
diff --git a/docs/modules/dashboard.md b/docs/modules/dashboard.md index 4630f168..f3265c51 100644 --- a/docs/modules/dashboard.md +++ b/docs/modules/dashboard.md @@ -9,6 +9,7 @@ Main landing dashboard with widgets and quick server overview. ## Current Status - Functional +- Uses the existing collapsible widget layout for customer-facing quick actions ## Dependencies @@ -39,12 +40,12 @@ Main landing dashboard with widgets and quick server overview. ## Known Issues -- some default widgets are legacy +- some default widget IDs are legacy and limit how far the collapsible layout can be expanded without a schema change ## Missing Functionality - richer status and alert surfaces -- clear separation between support requests and custom project work +- deeper async server-status embedding without adding remote checks to normal dashboard loads ## Suggested Future Improvements @@ -59,6 +60,8 @@ Main landing dashboard with widgets and quick server overview. - Dashboard render file: `Panel/modules/dashboard/dashboard.php` - Dashboard styles: `Panel/modules/dashboard/dashboard.css` - Shared Panel project URL helper: `Panel/includes/functions.php` +- Shared Discord invite helper: `Panel/includes/functions.php` +- Shared server-status route helper: `Panel/includes/functions.php` Current project request URL: @@ -66,5 +69,17 @@ Current project request URL: Dashboard behavior: +- retained collapsible sections: + - `Account Overview` + - `Custom Server Code` + - `Support` +- removed duplicate standalone sections: + - `Custom Server Development` + - `Support and Troubleshooting` - support remains the path for routine troubleshooting, service issues, and existing features -- the custom-development CTA is separate and points users at Runlevel Systems for project work such as custom scripts, mods, integrations, automation, migrations, dashboards, and advanced server tooling +- the custom-development CTA points users at Runlevel Systems for project work such as custom scripts, mods, integrations, automation, migrations, dashboards, and advanced server tooling +- the Discord support invite should use: + - `https://discord.gg/qt9Hnkj6cv` +- `Custom Server Code` should open the Runlevel project request in a new tab +- `Support` should keep ticketing and Discord support separate from paid project work +- `Server Status` stays available from the dashboard, but remote checks are intentionally deferred to the separate status page so normal dashboard loads do not block on agent/network timeouts diff --git a/docs/modules/status.md b/docs/modules/status.md index e553d8d3..2c0ee22b 100644 --- a/docs/modules/status.md +++ b/docs/modules/status.md @@ -8,8 +8,8 @@ Admin status page for server/node state. ## Current Status -- Experimental -- Alpha +- Functional standalone page +- Kept separate from the dashboard request path on purpose ## Dependencies @@ -22,11 +22,13 @@ Admin status page for server/node state. ## Agent Interaction -- may read status summaries +- reads configured remote servers from the active Panel database +- performs live agent availability checks when the status page is opened ## User Workflow -- not a primary customer workflow +- open `Panel/server_status.php` from the dashboard when status information is needed +- refresh manually when a new check is required ## Admin Workflow @@ -38,17 +40,43 @@ Admin status page for server/node state. ## Known Issues -- alpha-grade module +- live remote checks may wait on agent/network timeouts, so the page must not be loaded as part of the normal dashboard request ## Missing Functionality -- stable dashboard integration +- async dashboard embedding if a future implementation can safely avoid blocking dashboard render + +## Current Architecture + +- Render file: `Panel/server_status.php` +- Dashboard entry point: `Panel/modules/dashboard/dashboard.php` +- Data source: `$db->getRemoteServers()` plus `OGPRemoteLibrary::status_chk()` +- Dashboard architecture decision: keep status checks on the separate page so the main dashboard remains responsive even when one or more remote servers are slow or unavailable + +## Display Rules + +- Removed the old `Hostname` column +- Keep: + - `Server Name` + - `Location / IP` + - `Status` + - `Agent Status` + - `Panel-to-server latency` + - `Last Checked` +- Latency wording must remain truthful: + - current label: `Panel-to-server latency` + - this is a server-side connectivity check from the Panel host + - it is not customer-browser latency and must not be presented as the player's ping + +## Theme Notes + +- The status page should visually match the active dark Panel theme +- Use responsive table wrapping for mobile widths instead of forcing a wide desktop table into the viewport ## Suggested Future Improvements -- replace with a proper node health/status dashboard +- optional browser-side latency testing only if each location has a safe public health endpoint and the implementation can remain honest about what is being measured ## Recommendation -- Rewrite / Deprecate - +- Keep / Improve