Agent update

This commit is contained in:
Frank Harris 2026-06-06 11:41:17 -05:00
parent c195c0930b
commit cc5f7bb90c
16 changed files with 474 additions and 85 deletions

View file

@ -134,6 +134,17 @@ $repo_root = gsp_detect_repo_root();
if (!$repo_root || !function_exists('exec')) {
return null;
}
$out = [];
$ret = 0;
exec('git -C ' . escapeshellarg($repo_root) . ' rev-parse HEAD 2>/dev/null', $out, $ret);
if ($ret === 0 && !empty($out[0])) {
$sha = trim($out[0]);
if (preg_match('/^[0-9a-f]{40,64}$/i', $sha)) {
return $sha;
}
}
return null;
}
function gsp_update_settings()
{
@ -169,17 +180,6 @@ $errors[] = 'Panel Path must point to the Panel folder inside Repository Root.';
}
return $errors;
}
$out = [];
$ret = 0;
exec('git -C ' . escapeshellarg($repo_root) . ' rev-parse HEAD 2>/dev/null', $out, $ret);
if ($ret === 0 && !empty($out[0])) {
$sha = trim($out[0]);
if (preg_match('/^[0-9a-f]{40,64}$/i', $sha)) {
return $sha;
}
}
return null;
}
function gsp_read_version_json()
{
@ -2254,19 +2254,7 @@ foreach ((array)$apache_scan_result['ssl_issues'] as $ssl_issue) {
echo htmlspecialchars($ssl_issue['vhost'] . ' ' . $ssl_issue['directive'] . ': ' . $ssl_issue['path'] . ' (' . $ssl_issue['reason'] . ')') . "<br>";
}
echo "</p>\n";
echo "<p style='color:#8a6d3b;'><strong>Renew certificate command:</strong> <code>certbot --apache -d gameservers.world -d www.gameservers.world</code></p>";
foreach ((array)$apache_scan_result['ssl_issues'] as $ssl_issue) {
$vhost = basename((string)$ssl_issue['vhost']);
if (strpos($vhost, '-ssl.conf') === false) {
continue;
}
echo "<form method='POST' style='display:inline-block;margin-right:8px;'>";
echo "<input type='hidden' name='gsp_update_action' value='disable_ssl_vhost'>";
echo "<input type='hidden' name='gsp_update_csrf' value='" . htmlspecialchars($csrf_token) . "'>";
echo "<input type='hidden' name='gsp_ssl_vhost' value='" . htmlspecialchars($vhost) . "'>";
echo "<button type='submit' onclick='return confirm(\"Disable broken SSL site " . htmlspecialchars($vhost) . " in sites-enabled?\\n\\nThis keeps path fixes while SSL certs are missing.\");'>Disable Broken SSL Vhost: " . htmlspecialchars($vhost) . "</button>";
echo "</form>";
}
echo "<p style='color:#8a6d3b;'>SSL certificate issues are diagnostic only and do not block Panel updates.</p>";
}
echo "<form method='POST'>\n";
echo "<input type='hidden' name='gsp_update_action' value='fix_apache'>\n";

View file

@ -55,11 +55,90 @@ function get_agent_server_status($remote, $server_xml, $home_id, $server_ip, $se
$rcon_port = (string)$server_xml->rcon_port;
}
if (!method_exists($remote, 'remote_server_status')) {
return array('status' => 'UNKNOWN', 'last_error' => 'Panel remote library does not support agent status.');
$agent_status = array(
'status' => 'UNKNOWN',
'ready' => 0,
'process_running' => 0,
'session_running' => 0,
'game_port_listening' => 0,
'query_port_listening' => 0,
'rcon_port_listening' => 0,
'ip' => $server_ip,
'port' => $server_port,
'query_port' => $query_port,
'rcon_port' => $rcon_port,
'last_error' => 'Panel remote library does not support agent status.',
);
if (method_exists($remote, 'remote_server_status')) {
$remote_status = $remote->remote_server_status($home_id, $server_ip, $server_port, $query_port, $rcon_port, $startup_timeout, $state_hint);
if (is_array($remote_status)) {
$agent_status = array_merge($agent_status, $remote_status);
}
}
return $remote->remote_server_status($home_id, $server_ip, $server_port, $query_port, $rcon_port, $startup_timeout, $state_hint);
$fallback_session = gsp_agent_screen_running($remote, $home_id);
$fallback_port = gsp_agent_port_listening($remote, $server_port);
if ($fallback_session === true) {
$agent_status['session_running'] = 1;
$agent_status['process_running'] = 1;
}
if ($fallback_port === true) {
$agent_status['game_port_listening'] = 1;
}
if ($fallback_session === true || $fallback_port === true || !empty($agent_status['session_running']) || !empty($agent_status['process_running']) || !empty($agent_status['game_port_listening'])) {
$agent_status['status'] = 'ONLINE';
$agent_status['ready'] = 1;
if (empty($agent_status['last_error']) || $agent_status['last_error'] === 'Agent status RPC unavailable.' || $agent_status['last_error'] === 'Panel remote library does not support agent status.') {
$agent_status['last_error'] = '';
}
$agent_status['status_source'] = ($fallback_port === true) ? 'port' : 'session';
return $agent_status;
}
if (isset($agent_status['status']) && strtoupper((string)$agent_status['status']) === 'UNKNOWN') {
if ($fallback_session === false && $fallback_port === false) {
$agent_status['status'] = 'OFFLINE';
$agent_status['last_error'] = '';
}
}
return $agent_status;
}
function gsp_agent_screen_running($remote, $home_id)
{
if (!method_exists($remote, 'is_screen_running')) {
return null;
}
$result = $remote->is_screen_running(OGP_SCREEN_TYPE_HOME, $home_id);
if ($result === 1) {
return true;
}
if ($result === 0) {
return false;
}
return null;
}
function gsp_agent_port_listening($remote, $server_port)
{
$server_port = (int)$server_port;
if ($server_port <= 0 || !method_exists($remote, 'exec')) {
return null;
}
$port_arg = escapeshellarg((string)$server_port);
$command = 'p='.$port_arg.'; '
. 'if command -v ss >/dev/null 2>&1; then ss -lntu 2>/dev/null; else netstat -an 2>/dev/null; fi '
. '| tr -d "\r" '
. '| grep -Eai "(LISTEN|LISTENING|UDP|tcp|udp)" '
. '| grep -E "[:.]$p([[:space:]]|$)" >/dev/null '
. '&& echo GSP_PORT_LISTENING || echo GSP_PORT_CLOSED';
$output = $remote->exec($command);
if (strpos((string)$output, 'GSP_PORT_LISTENING') !== false) {
return true;
}
if (strpos((string)$output, 'GSP_PORT_CLOSED') !== false) {
return false;
}
return null;
}
function is_agent_status_online($agent_status)

View file

@ -89,31 +89,38 @@ require_once("modules/config_games/server_config_parser.php");
{
$log_url = "home.php?m=gamemanager&p=log&type=cleared&refreshed&home_id-mod_id-ip-port=".rawurlencode($_GET['home_id-mod_id-ip-port']);
echo '<style>
#live-server-log {
#live-server-log.gsp-live-log-panel {
display:block;
width:100%;
max-width:1600px;
min-height:55vh;
min-height:500px;
height:55vh;
max-height:75vh;
box-sizing:border-box;
font-family:Consolas, Monaco, "Courier New", monospace;
font-size:13px;
line-height:1.35;
margin:0 0 12px 0;
padding:12px;
background:#050505;
color:#e6edf3;
border:1px solid #333;
border-radius:4px;
white-space:pre-wrap;
overflow-y:auto;
overflow-x:auto;
resize:vertical;
overflow-wrap:anywhere;
tab-size:4;
}
@media (max-width: 700px) {
#live-server-log {
#live-server-log.gsp-live-log-panel {
min-height:45vh;
height:45vh;
font-size:12px;
}
}
</style>';
echo '<textarea id="live-server-log" class="log" readonly="readonly" wrap="soft">'.htmlentities($home_log, ENT_QUOTES, "UTF-8").'</textarea>';
echo '<pre id="live-server-log" class="gsp-live-log-panel" tabindex="0">'.htmlentities($home_log, ENT_QUOTES, "UTF-8").'</pre>';
?>
<script type="text/javascript">
(function(){
@ -127,7 +134,7 @@ require_once("modules/config_games/server_config_parser.php");
fetch('<?php echo $log_url; ?>', {cache: 'no-store'})
.then(function(response){ return response.text(); })
.then(function(text){
logBox.value = text;
logBox.textContent = text;
if (shouldScroll) {
logBox.scrollTop = logBox.scrollHeight;
}

View file

@ -546,10 +546,10 @@ echo "<table id='servermonitor' class='tablesorter' data-sortlist='[[0,0],[3,1]]
{
$status = "unknown";
$order = 3;
$address = "<span class='note'>Unknown - agent status unavailable.</span>";
$address = "<span class='note'>Unknown - status check unavailable.</span>";
if(isset($agent_status['last_error']) && $agent_status['last_error'] !== "")
$address .= " <span class='failure'>".htmlentities($agent_status['last_error'])."</span>";
$offlineT = "<span class='note'>Server state is unknown. The Panel did not confirm that this server is offline.</span>";
$offlineT = "<span class='note'>Server state is unknown because the Panel could not complete a reliable agent status check.</span>";
}
else
{

View file

@ -120,7 +120,39 @@ function exec_ogp_module()
if($log_retval == 1)
{
$log_url = "home.php?m=gamemanager&p=log&type=cleared&refreshed&home_id-mod_id-ip-port=".rawurlencode($_GET['home_id-mod_id-ip-port']);
echo '<textarea id="live-server-log" class="log" readonly="readonly" style="height:500px;overflow:auto;max-width:1600px;width:100%;box-sizing:border-box;">'.htmlentities($home_log, ENT_QUOTES, "UTF-8").'</textarea>';
?>
<style>
.gsp-live-log-panel {
display: block;
width: 100%;
max-width: 1600px;
min-height: 500px;
height: 55vh;
box-sizing: border-box;
padding: 12px;
border: 1px solid #36475f;
border-radius: 4px;
background: #050a12;
color: #d7dde8;
font-family: Consolas, Menlo, Monaco, "Courier New", monospace;
font-size: 13px;
line-height: 1.45;
white-space: pre-wrap;
word-break: break-word;
overflow-y: auto;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
@media (max-width: 700px) {
.gsp-live-log-panel {
min-height: 45vh;
height: 45vh;
font-size: 12px;
}
}
</style>
<?php
echo '<pre id="live-server-log" class="gsp-live-log-panel" tabindex="0">'.htmlentities($home_log, ENT_QUOTES, "UTF-8").'</pre>';
?>
<script type="text/javascript">
(function(){
@ -134,7 +166,7 @@ function exec_ogp_module()
fetch('<?php echo $log_url; ?>', {cache: 'no-store'})
.then(function(response){ return response.text(); })
.then(function(text){
logBox.value = text;
logBox.textContent = text;
if (shouldScroll) {
logBox.scrollTop = logBox.scrollHeight;
}