Add protocol and image review docs with query wrapper scaffold
Agent-Logs-Url: https://github.com/GameServerPanel/GSP/sessions/c4b059df-09a3-4d61-b0f6-de738ea00a58 Co-authored-by: iaretechnician <2749183+iaretechnician@users.noreply.github.com>
This commit is contained in:
parent
089051fecb
commit
be42868c1c
5 changed files with 407 additions and 0 deletions
|
|
@ -1,6 +1,7 @@
|
|||
# Changelog
|
||||
|
||||
## 2026-05-18
|
||||
- **Protocol/image upgrade Phase 1 scaffolding (non-breaking):** Added `protocol/gsp_query.php` normalized query wrapper (LGSL default provider with future-provider placeholders), documented current protocol integration and migration plan in `protocol/PROTOCOL_UPGRADE_REVIEW.md`, and documented image module comparison/unification direction in `modules/SERVER_IMAGE_MODULE_REVIEW.md` without removing LGSL, dsi, or `lgsl_with_img_mod`.
|
||||
- **Cron ↔ Server Content action hook integration:** Added scheduler-callable Server Content hooks in `modules/addonsmanager/server_content_actions.php`, exposed API route `server_content/run_scheduled_action`, and wired cron/user-cron action builders/parsing to support server content scheduled actions (check/install/queue/restart/validate/backup flows) without embedding game-specific install logic in the scheduler.
|
||||
- **Server Content Workshop Phase 1 in addonsmanager:** Added a new `Workshop Content` flow under Server Content with per-home Workshop ID storage, ID validation/deduplication, install/update/remove/update-all actions, manifest-based script handoff (`gsp_server_content/workshop_manifest.json`), safe placeholder workshop scripts for Linux/Cygwin, and schema support via `server_content_workshop` plus `addons.addon_type VARCHAR(32)`.
|
||||
- **Updater layout hardening + pre-update patch framework:** Reworked `modules/administration/panel_update.php` to resolve explicit GSP root/Panel/Website paths, run mandatory preflight checks, self-update updater files before main sync when drift is detected, and apply ordered required patches from `modules/update/patches/` with DB/local state tracking. Backup/rollback now includes both Panel + Website archives and root `version.json`, logs moved to root `logs/update_trace.log`, and the admin Update UI now exposes preflight, patch apply, Apache path scan/fix, backup, update, and rollback actions.
|
||||
|
|
|
|||
|
|
@ -19,3 +19,4 @@
|
|||
- Add an admin preview/diff panel for Apache path repairs so staff can review exact vhost line changes before confirming `Fix Apache Paths`.
|
||||
- Add Phase 2 Workshop Content UX in `addonsmanager`: browse/search/select Workshop items with metadata while reusing the Phase 1 per-home saved-ID action pipeline.
|
||||
- Add localized language strings/tooltips for the new cron scheduler `server_content_*` action labels across all supported panel locales.
|
||||
- Add a Game Manager "Live Server Status" panel that consumes `Panel/protocol/gsp_query.php` and shows banner preview plus copyable embed code.
|
||||
|
|
|
|||
80
Panel/modules/SERVER_IMAGE_MODULE_REVIEW.md
Normal file
80
Panel/modules/SERVER_IMAGE_MODULE_REVIEW.md
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
# Server Image Module Review (Phase 1)
|
||||
|
||||
## Scope reviewed
|
||||
- `Panel/modules/lgsl_with_img_mod/`
|
||||
- `Panel/modules/dsi/`
|
||||
- Integration touchpoints in `Panel/modules/gamemanager/`
|
||||
|
||||
## Entry points
|
||||
|
||||
### lgsl_with_img_mod
|
||||
- Module metadata: `Panel/modules/lgsl_with_img_mod/module.php`
|
||||
- User/admin pages:
|
||||
- `lgsl.php`
|
||||
- `lgsl_admin.php`
|
||||
- Image endpoint:
|
||||
- `image.php` (reads by `s` argument, supports `img_type`)
|
||||
- Core query/cache/image logic:
|
||||
- `lgsl_files/lgsl_class.php`
|
||||
|
||||
### dsi
|
||||
- Module metadata: `Panel/modules/dsi/module.php`
|
||||
- User/admin/list pages:
|
||||
- `dsi_user.php`
|
||||
- `dsi_admin.php`
|
||||
- `dsi_list.php`
|
||||
- Image endpoint:
|
||||
- `image.php` (`modules/dsi/s-IP_PORT-type.png` style)
|
||||
- Helpers:
|
||||
- `includes/functions.php`
|
||||
- `includes/functions_ui.php`
|
||||
|
||||
## Comparison
|
||||
|
||||
### Which module generates images?
|
||||
- **Both** generate PNG status banners.
|
||||
- `lgsl_with_img_mod` is LGSL-centric and built around the `OGP_DB_PREFIXlgsl` cache model.
|
||||
- `dsi` supports LGSL/GameQ/TS3 monitor includes and can render banner/code snippets directly for panel users.
|
||||
|
||||
### Which has better cache support?
|
||||
- **lgsl_with_img_mod** has deeper cache integration:
|
||||
- DB-backed query cache (`OGP_DB_PREFIXlgsl.cache`, `cache_time`)
|
||||
- image file cache handling
|
||||
- pending/retry semantics in `lgsl_query_cached(...)`
|
||||
- `dsi` has simple file cache (60s TTL) per generated image and relies on protocol monitor include side effects for query state.
|
||||
|
||||
### Which integrates with server monitor better?
|
||||
- **dsi** is currently more user-facing for “banner + embed code” workflows:
|
||||
- `dsi_render_table(...)` outputs HTML/BBCode snippets.
|
||||
- Integrates query handlers by protocol in `dsi/image.php`.
|
||||
- `lgsl_with_img_mod` is more standalone/legacy LGSL module flow.
|
||||
|
||||
### Which supports player info better?
|
||||
- Both are focused on banner status fields (name/map/players/status).
|
||||
- Neither is currently a full player-list UI provider for Game Manager.
|
||||
- Query-level player data comes from monitor protocol paths, not these image modules as a first-class shared API.
|
||||
|
||||
### Which is easier to modernize?
|
||||
- **dsi** is the better base for a future unified GSP banner module:
|
||||
- simpler structure
|
||||
- clear image endpoint + code generation UI
|
||||
- already aware of LGSL/GameQ/TS3 protocol branching
|
||||
- `lgsl_with_img_mod` contains useful mature cache ideas and map/image utilities worth reusing.
|
||||
|
||||
## Recommended future GSP banner direction
|
||||
Future module target: `Panel/modules/server_status_banner/`
|
||||
|
||||
### Plan
|
||||
1. Keep both current modules in place during migration.
|
||||
2. Use `dsi` UX flow and embed-code patterns as baseline.
|
||||
3. Reuse selective `lgsl_with_img_mod` cache + map/image helper ideas.
|
||||
4. Drive data from normalized query cache (planned `server_query_cache`) and wrapper output.
|
||||
5. Generate GSP-owned PNG banners (small / wide / large styles).
|
||||
6. Avoid external GameTracker asset dependency.
|
||||
7. Provide HTML / BBCode / direct image URL output.
|
||||
8. Surface banner preview and code tool in Game Manager.
|
||||
|
||||
## No-removal statement (Phase 1 safety)
|
||||
- `lgsl_with_img_mod` was **not removed**.
|
||||
- `dsi` was **not removed**.
|
||||
- This phase is documentation and direction-setting only.
|
||||
168
Panel/protocol/PROTOCOL_UPGRADE_REVIEW.md
Normal file
168
Panel/protocol/PROTOCOL_UPGRADE_REVIEW.md
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
# Protocol Upgrade Review (Phase 1, safe path)
|
||||
|
||||
## Scope reviewed
|
||||
- `Panel/protocol/lgsl/`
|
||||
- `Panel/protocol/GameQ/`
|
||||
- `Panel/modules/gamemanager/server_monitor.php`
|
||||
- `Panel/modules/gamemanager/ref_servermonitor.php`
|
||||
- `Panel/modules/gamemanager/start_server.php`
|
||||
- `Panel/modules/gamemanager/restart_server.php`
|
||||
- `Panel/modules/gamemanager/mini_start.php`
|
||||
- `Panel/modules/dashboard/query_ref.php`
|
||||
- `Panel/modules/config_games/server_configs/*.xml`
|
||||
|
||||
## Current protocol folders
|
||||
- `Panel/protocol/lgsl/`
|
||||
- Legacy LGSL implementation and protocol map (`lgsl_protocol.php`).
|
||||
- Monitor helper (`LGSLMonitor.php`).
|
||||
- Player list rendering helper (`functions.php`).
|
||||
- `Panel/protocol/GameQ/`
|
||||
- Modern namespaced GameQ implementation with PSR-4 autoloader.
|
||||
- Monitor helper (`GameQMonitor.php`) + player list rendering helper (`functions.php`).
|
||||
- Very large protocol coverage in `Protocols/`.
|
||||
- Also contains legacy-looking `gameq/` subtree alongside modern files (technical debt signal).
|
||||
|
||||
## How LGSL is currently called
|
||||
- Monitor refresh path:
|
||||
- `gamemanager/ref_servermonitor.php` loads `protocol/lgsl/LGSLMonitor.php` when XML protocol is `lgsl`.
|
||||
- `LGSLMonitor.php` calls `lgsl_query_live(...)`, handles panel query cache (`getServerStatusCache`/`saveServerStatusCache`), and sets `$status/$map/$players/$player_list`.
|
||||
- Start/restart detection path:
|
||||
- `gamemanager/start_server.php` and `restart_server.php` call `lgsl_query_live(..., "sa")` after process launch to decide if server is considered running.
|
||||
- Quick checks:
|
||||
- `gamemanager/mini_start.php` and other helpers call `lgsl_port_conversion(...)` and `lgsl_query_live(...)`.
|
||||
- Connection links:
|
||||
- `server_monitor.php` and dsi/lgsl image flows use `lgsl_port_conversion(...)` and `lgsl_software_link(...)`.
|
||||
|
||||
## GameQ status (usable vs incomplete)
|
||||
- Present and actively used in monitor/start/restart flows (`GameQMonitor.php`, `start_server.php`, `restart_server.php`, `dashboard/query_ref.php`).
|
||||
- Usable for configured XML entries (`protocol=gameq` + `gameq_query_name`).
|
||||
- Inconsistencies/risks:
|
||||
- Mixed API usage exists in module code (`process()` and `requestData()` patterns).
|
||||
- Legacy and modern GameQ structures coexist under `Panel/protocol/GameQ/`.
|
||||
- GameQ is integrated, but implementation consistency is incomplete and should be normalized before broad protocol migration.
|
||||
|
||||
## Files that map game configs to protocol names
|
||||
- Primary source of protocol selection:
|
||||
- `Panel/modules/config_games/server_configs/*.xml` fields:
|
||||
- `<protocol>`
|
||||
- `<lgsl_query_name>`
|
||||
- `<gameq_query_name>`
|
||||
- Supporting editor/schema surfaces:
|
||||
- `Panel/modules/config_games/config_servers.php` (schema order includes protocol tags).
|
||||
- `Panel/modules/config_games/xml_tag_descriptions.php` (documents protocol fields).
|
||||
- `Panel/modules/config_games/xml_config_creator.php` (protocol selector and query-name population).
|
||||
|
||||
## Where player list parsing happens
|
||||
- LGSL:
|
||||
- Query payload from `lgsl_query_live(...)` in `lgsl_protocol.php`.
|
||||
- Player table rendering in `protocol/lgsl/functions.php::print_player_list(...)`.
|
||||
- GameQ:
|
||||
- Query payload from `GameQMonitor.php`.
|
||||
- Player table rendering and field normalization in `protocol/GameQ/functions.php::print_player_list_gameq(...)`.
|
||||
|
||||
## Where map/player/server status data is returned
|
||||
- LGSL live payload shape: `b/s/e/p/t` arrays from `lgsl_query_live(...)`:
|
||||
- status: `b.status`
|
||||
- map/name/player counts/password: `s.*`
|
||||
- player list: `p`
|
||||
- extras (including some bot fields): `e`
|
||||
- GameQ normalized payload (after `normalise` filter):
|
||||
- status: `server.gq_online`
|
||||
- map: `server.gq_mapname`
|
||||
- player counts: `server.gq_numplayers`, `server.gq_maxplayers`
|
||||
- player list: `server.players`
|
||||
|
||||
## Known problems (Phase 1 findings)
|
||||
- Query invocation is duplicated in multiple modules (monitor/start/restart/dashboard/image modules), increasing drift risk.
|
||||
- Start detection currently combines process + query checks but does not explicitly represent a `starting` state in monitor output.
|
||||
- LGSL uses hard exits for invalid parameters (`lgsl_query_live`), which is risky for direct callers without guard logic.
|
||||
- GameQ integration style is not fully standardized across all call sites.
|
||||
- Existing cache model is spread across current status cache and module-specific image caches, without one normalized query cache contract.
|
||||
|
||||
## New wrapper prepared in this phase
|
||||
- Added `Panel/protocol/gsp_query.php`.
|
||||
- Introduces `gsp_query_server($server_info, $options = [])` normalized result contract.
|
||||
- Keeps default provider on LGSL (`lgsl_legacy`) for safety.
|
||||
- Adds provider concept placeholders (no broad provider switch in this phase):
|
||||
- `lgsl_legacy`
|
||||
- `gameq`
|
||||
- `xpaw_source_query`
|
||||
- `minecraft_query`
|
||||
- `custom_script`
|
||||
|
||||
## Proposed query cache table (planning only, no migration applied)
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS OGP_DB_PREFIXserver_query_cache (
|
||||
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
home_id INT NOT NULL,
|
||||
ip VARCHAR(64) NOT NULL,
|
||||
port INT NOT NULL,
|
||||
query_port INT NULL,
|
||||
protocol VARCHAR(64) NULL,
|
||||
provider VARCHAR(64) NULL,
|
||||
online TINYINT(1) NOT NULL DEFAULT 0,
|
||||
server_name VARCHAR(255) NULL,
|
||||
map_name VARCHAR(128) NULL,
|
||||
players INT NULL,
|
||||
max_players INT NULL,
|
||||
bots INT NULL,
|
||||
passworded TINYINT(1) NULL,
|
||||
latency_ms INT NULL,
|
||||
player_list_json MEDIUMTEXT NULL,
|
||||
raw_json MEDIUMTEXT NULL,
|
||||
last_query_at DATETIME NULL,
|
||||
last_success_at DATETIME NULL,
|
||||
last_error TEXT NULL,
|
||||
UNIQUE KEY uniq_home_query (home_id),
|
||||
KEY idx_last_query_at (last_query_at),
|
||||
KEY idx_online (online)
|
||||
);
|
||||
```
|
||||
|
||||
Cache TTL target: **60 seconds** default.
|
||||
|
||||
## Server start detection improvement plan (no behavior change yet)
|
||||
- After start command, mark status as **starting**.
|
||||
- Poll on a short interval until timeout:
|
||||
1. Check agent process state.
|
||||
2. Check network port open.
|
||||
3. Check query response (if protocol supported).
|
||||
- Final states:
|
||||
- Process + query OK: **Online**
|
||||
- Process OK but query unavailable: **Running, query unavailable**
|
||||
- Process missing at timeout: **Failed to start**
|
||||
|
||||
## Game Manager integration plan (`server_monitor.php`)
|
||||
Future `Live Server Status` panel should include:
|
||||
- State: Online / Offline / Starting / Running query unavailable
|
||||
- Server name
|
||||
- Current map
|
||||
- Players / max players
|
||||
- Player list
|
||||
- Query latency
|
||||
- Last query time
|
||||
- Banner preview
|
||||
- “Get banner code” action
|
||||
|
||||
## Admin query debug/test page plan
|
||||
Future page: `Panel/protocol/query_test.php` (admin-only)
|
||||
- Inputs: IP, port, query port, protocol, provider, timeout
|
||||
- Outputs: normalized result, raw result, errors
|
||||
- Security:
|
||||
- admin-only access gate
|
||||
- CSRF for submit actions
|
||||
- request limits / timeout caps
|
||||
- no anonymous/public proxy behavior
|
||||
|
||||
## Recommended next phase
|
||||
1. Switch one low-risk monitor path to read `gsp_query_server()` output in parallel with existing behavior (feature-flag style).
|
||||
2. Standardize GameQ call style (single API usage pattern) and document supported protocol mappings.
|
||||
3. Add normalized cache write/read adapter (without removing existing caches yet).
|
||||
4. Add explicit start-state model and timeout policy constants.
|
||||
5. Begin unified banner module implementation against normalized cache payloads.
|
||||
|
||||
## Safety statement
|
||||
- No protocol engines were removed.
|
||||
- LGSL remains in place.
|
||||
- GameQ remains in place.
|
||||
- Existing server monitor behavior remains intact in this phase.
|
||||
157
Panel/protocol/gsp_query.php
Normal file
157
Panel/protocol/gsp_query.php
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
<?php
|
||||
/*
|
||||
* GSP query wrapper (Phase 1 scaffolding)
|
||||
*
|
||||
* Normalizes server query results while keeping LGSL as the default provider.
|
||||
* This file intentionally avoids changing existing monitor paths in this phase.
|
||||
*/
|
||||
|
||||
if (!function_exists('gsp_query_provider_names')) {
|
||||
function gsp_query_provider_names()
|
||||
{
|
||||
return array(
|
||||
// LGSL remains default for legacy/older game coverage.
|
||||
'lgsl_legacy',
|
||||
// TODO: Use for games where current GameQ support is proven reliable.
|
||||
'gameq',
|
||||
// TODO: Prefer for modern Source/Steam query games in a later phase.
|
||||
'xpaw_source_query',
|
||||
// TODO: Prefer dedicated Minecraft query handling in a later phase.
|
||||
'minecraft_query',
|
||||
// TODO: Allow custom scripts for unusual game protocols.
|
||||
'custom_script',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('gsp_query_default_result')) {
|
||||
function gsp_query_default_result()
|
||||
{
|
||||
return array(
|
||||
'success' => false,
|
||||
'online' => false,
|
||||
'provider' => 'lgsl_legacy',
|
||||
'protocol' => '',
|
||||
'game' => '',
|
||||
'server_name' => '',
|
||||
'map' => '',
|
||||
'players' => 0,
|
||||
'max_players' => 0,
|
||||
'bots' => 0,
|
||||
'passworded' => false,
|
||||
'latency_ms' => null,
|
||||
'address' => '',
|
||||
'port' => 0,
|
||||
'query_port' => 0,
|
||||
'player_list' => array(),
|
||||
'raw' => array(),
|
||||
'error' => '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('gsp_query_normalize_player_list')) {
|
||||
function gsp_query_normalize_player_list($players)
|
||||
{
|
||||
$normalized = array();
|
||||
foreach ((array)$players as $player) {
|
||||
$normalized[] = array(
|
||||
'name' => isset($player['name']) ? (string)$player['name'] : '',
|
||||
'score' => isset($player['score']) ? (int)$player['score'] : 0,
|
||||
'time' => isset($player['time']) ? $player['time'] : '',
|
||||
'ping' => isset($player['ping']) ? (int)$player['ping'] : 0,
|
||||
'raw' => (array)$player,
|
||||
);
|
||||
}
|
||||
return $normalized;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('gsp_query_server')) {
|
||||
function gsp_query_server($server_info, $options = array())
|
||||
{
|
||||
$result = gsp_query_default_result();
|
||||
$server = (array)$server_info;
|
||||
$options = (array)$options;
|
||||
|
||||
$provider = isset($options['provider']) ? (string)$options['provider'] : (isset($server['query_provider']) ? (string)$server['query_provider'] : 'lgsl_legacy');
|
||||
$result['provider'] = $provider;
|
||||
|
||||
$ip = isset($server['ip']) ? trim((string)$server['ip']) : '';
|
||||
$port = isset($server['port']) ? (int)$server['port'] : 0;
|
||||
$query_ip = $ip;
|
||||
if (!empty($server['use_nat']) && !empty($server['agent_ip'])) {
|
||||
$query_ip = trim((string)$server['agent_ip']);
|
||||
}
|
||||
|
||||
$result['address'] = ($ip !== '' && $port > 0) ? $ip . ':' . $port : '';
|
||||
$result['port'] = $port;
|
||||
|
||||
if ($provider !== 'lgsl_legacy') {
|
||||
$result['error'] = "Query provider not implemented yet: {$provider}";
|
||||
return $result;
|
||||
}
|
||||
|
||||
$query_name = '';
|
||||
if (isset($server['lgsl_query_name'])) {
|
||||
$query_name = (string)$server['lgsl_query_name'];
|
||||
} elseif (isset($server['query_name'])) {
|
||||
$query_name = (string)$server['query_name'];
|
||||
}
|
||||
$query_name = trim($query_name);
|
||||
$result['protocol'] = $query_name;
|
||||
|
||||
if ($query_name === '') {
|
||||
$result['error'] = 'Missing LGSL query name.';
|
||||
return $result;
|
||||
}
|
||||
|
||||
if ($query_ip === '' || preg_match("/[^0-9a-z\\.\\-\\[\\]\\:]/i", $query_ip)) {
|
||||
$result['error'] = 'Invalid query IP/hostname.';
|
||||
return $result;
|
||||
}
|
||||
|
||||
if ($port <= 0) {
|
||||
$result['error'] = 'Invalid server port.';
|
||||
return $result;
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/lgsl/lgsl_protocol.php';
|
||||
$protocols = lgsl_protocol_list();
|
||||
if (!isset($protocols[$query_name])) {
|
||||
$result['error'] = "Unsupported LGSL protocol type: {$query_name}";
|
||||
return $result;
|
||||
}
|
||||
|
||||
list($c_port, $default_q_port, $s_port) = lgsl_port_conversion($query_name, $port, "", "");
|
||||
$q_port = isset($server['query_port']) && (int)$server['query_port'] > 0 ? (int)$server['query_port'] : (int)$default_q_port;
|
||||
$result['query_port'] = $q_port;
|
||||
|
||||
if ($q_port <= 0) {
|
||||
$result['error'] = 'Invalid query port for LGSL query.';
|
||||
return $result;
|
||||
}
|
||||
|
||||
$raw = lgsl_query_live($query_name, $query_ip, $c_port, $q_port, $s_port, "sep");
|
||||
if (!is_array($raw) || !isset($raw['b']) || !isset($raw['b']['status'])) {
|
||||
$result['error'] = 'LGSL query returned an invalid payload.';
|
||||
return $result;
|
||||
}
|
||||
|
||||
$result['raw'] = $raw;
|
||||
$result['success'] = true;
|
||||
$result['online'] = ((string)$raw['b']['status'] === '1' || (int)$raw['b']['status'] === 1);
|
||||
$result['game'] = isset($raw['s']['game']) ? (string)$raw['s']['game'] : '';
|
||||
$result['server_name'] = isset($raw['s']['name']) ? (string)$raw['s']['name'] : '';
|
||||
$result['map'] = isset($raw['s']['map']) ? (string)$raw['s']['map'] : '';
|
||||
$result['players'] = isset($raw['s']['players']) ? (int)$raw['s']['players'] : 0;
|
||||
$result['max_players'] = isset($raw['s']['playersmax']) ? (int)$raw['s']['playersmax'] : 0;
|
||||
$result['bots'] = isset($raw['e']['bots']) ? (int)$raw['e']['bots'] : 0;
|
||||
$result['passworded'] = !empty($raw['s']['password']);
|
||||
$result['latency_ms'] = isset($raw['t']['ping']) ? (int)$raw['t']['ping'] : null;
|
||||
$result['player_list'] = isset($raw['p']) ? gsp_query_normalize_player_list($raw['p']) : array();
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
?>
|
||||
Loading…
Add table
Add a link
Reference in a new issue