Codex documentstion created
This commit is contained in:
parent
3dc017421e
commit
b5dcf01a8c
27 changed files with 6648 additions and 1069 deletions
66
AI_GSP_ARCHITECTURE.md
Normal file
66
AI_GSP_ARCHITECTURE.md
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
# GSP Component Architecture
|
||||
|
||||
This repository contains the related GSP components together:
|
||||
|
||||
- `/Agent-Windows` - Cygwin/Windows game server agent.
|
||||
- `/Agent_Linux` - Linux game server agent.
|
||||
- `/Panel` - PHP control panel used by customers and staff.
|
||||
- `/Website` - public website and related customer-facing pages.
|
||||
|
||||
## Panel And Agent Communication
|
||||
|
||||
The Panel talks to agents through XML-RPC using the encrypted parameter helpers in `Panel/includes/lib_remote.php`. The Panel should request actions from the agent and treat the agent as the source of truth for server state.
|
||||
|
||||
The shared server control backend is still `screen` for both Linux and Cygwin/Windows agents. The Panel should not decide that a game server is online only because a web request, LGSL query, or GameQ query succeeded.
|
||||
|
||||
## Status Source Of Truth
|
||||
|
||||
The agent is the source of truth for start, stop, restart, and status. Marker files such as `SERVER_STOPPED` or startup flag files may still exist for legacy autorestart and startup bookkeeping, but they are not trusted as the current server state.
|
||||
|
||||
The minimum readiness check is:
|
||||
|
||||
1. The configured process/session exists.
|
||||
2. The configured game port is listening.
|
||||
|
||||
LGSL/GameQ query data is optional metadata only. It can provide player counts, maps, hostname, and other query details. If query fails while the process/session exists and the game port is listening, the Panel should show the server as online with a small "query info unavailable" note.
|
||||
|
||||
## Status Model
|
||||
|
||||
- `OFFLINE`: no managed process/session and no listening game port.
|
||||
- `STARTING`: managed process/session exists, but the game port is not listening yet.
|
||||
- `ONLINE`: managed process/session exists and the game port is listening.
|
||||
- `STOPPING`: stop was requested and the managed process/session still exists.
|
||||
- `UNRESPONSIVE`: the managed process/session exists but the game port did not become ready before timeout, or stop did not complete cleanly.
|
||||
- `UNKNOWN`: the agent cannot be reached or did not return structured status.
|
||||
|
||||
## Start
|
||||
|
||||
Start should launch the configured screen/session and immediately report a starting state if the session exists. Slow games, including Arma 2 and DayZ Mod, must not be marked failed just because LGSL/GameQ did not answer quickly.
|
||||
|
||||
Startup timeout should be configurable per game XML when possible, with a default of 180 seconds.
|
||||
|
||||
## Stop
|
||||
|
||||
Stop should issue the configured graceful control command when available. The agent then checks whether the managed screen/session is gone and whether the game port is no longer listening. If the process/session remains after the wait period, the agent escalates by closing the screen session.
|
||||
|
||||
The Panel should only show stopped after the agent confirms `OFFLINE`.
|
||||
|
||||
## Restart
|
||||
|
||||
Restart is intentionally simple:
|
||||
|
||||
1. Stop server.
|
||||
2. Wait 60 seconds.
|
||||
3. Start server.
|
||||
|
||||
Do not use a separate shortcut that skips stop verification or depends on query responses.
|
||||
|
||||
## Log Viewer
|
||||
|
||||
The gamemanager log viewer should update the log text through AJAX/live fetches only. It should not reload the full page for each refresh and should not show the old manual refresh interval dropdown or plus/update button.
|
||||
|
||||
The live log should preserve mobile scrolling behavior and only auto-scroll when the user is already near the bottom.
|
||||
|
||||
## Agent Parity
|
||||
|
||||
Keep Linux and Cygwin/Windows agent behavior as similar as possible. Both should continue using `screen` as the shared backend for now and expose the same status model to the Panel.
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
866
COMPANION_PROGRAMS_DESIGN.md
Normal file
866
COMPANION_PROGRAMS_DESIGN.md
Normal file
|
|
@ -0,0 +1,866 @@
|
|||
# Companion Programs Design Investigation
|
||||
|
||||
This is an investigation-only design report for adding first-class companion/sidecar application support to GSP game servers. No implementation is included here.
|
||||
|
||||
Repository layout reviewed:
|
||||
|
||||
- `/Agent-Windows`
|
||||
- `/Agent_Linux`
|
||||
- `/Panel`
|
||||
- `/Website`
|
||||
|
||||
Note: the repository currently uses `Agent_Linux` on disk, not `Agent-Linux`.
|
||||
|
||||
## 1. Current Flow Found
|
||||
|
||||
### Main Agent Files
|
||||
|
||||
Relevant files:
|
||||
|
||||
- `Agent_Linux/ogp_agent.pl`
|
||||
- `Agent-Windows/ogp_agent.pl`
|
||||
- `Panel/includes/lib_remote.php`
|
||||
- `Panel/modules/gamemanager/mini_start.php`
|
||||
- `Panel/modules/gamemanager/home_handling_functions.php`
|
||||
- `Panel/modules/gamemanager/start_server.php`
|
||||
- `Panel/modules/gamemanager/stop_server.php`
|
||||
- `Panel/modules/gamemanager/restart_server.php`
|
||||
- `Panel/modules/config_games/schema_server_config.xml`
|
||||
- `Panel/modules/config_games/server_config_parser.php`
|
||||
- `Panel/modules/config_games/config_servers.php`
|
||||
- `Panel/modules/config_games/cli-params.php`
|
||||
|
||||
### Agent Startup Directory And Autostart
|
||||
|
||||
Both agents define an agent run directory and a startup flag directory:
|
||||
|
||||
- Linux: `AGENT_RUN_DIR`, `GAME_STARTUP_DIR`, `SCREEN_LOGS_DIR`, `SCREENRC_FILE`
|
||||
- Windows/Cygwin: same general constants, with Windows-specific SteamCMD executable paths
|
||||
|
||||
Both agents create/read the `startups` directory on agent startup. If startup files exist and `--no-startups` is not set, the agent reads each startup file and calls `universal_start_without_decrypt(...)` with the saved startup arguments.
|
||||
|
||||
Startup files are CSV-like records containing:
|
||||
|
||||
```text
|
||||
home_id, home_path, server_exe, run_dir, startup_cmd, server_port, server_ip, cpu, nice, preStart, envVars, game_key, console_log
|
||||
```
|
||||
|
||||
These files are useful for agent autostart but should not be treated as runtime status truth.
|
||||
|
||||
### Screen Usage
|
||||
|
||||
Both agents use `screen` as the shared runtime backend.
|
||||
|
||||
Linux:
|
||||
|
||||
- `create_screen_id(SCREEN_TYPE_HOME, $home_id)` creates names like `OGP_HOME_000000123`.
|
||||
- `create_screen_cmd(...)` returns a `screen -d -m -t ... -S ...` command.
|
||||
- `create_screen_cmd_loop(...)` creates a generated shell script named like `OGP_HOME_000000123_startup_scr.sh`, then runs that script inside `screen`.
|
||||
- The generated shell script loops/restarts the server when autorestart is enabled.
|
||||
- The script checks for `SERVER_STOPPED` before respawning.
|
||||
|
||||
Windows/Cygwin:
|
||||
|
||||
- Uses the same `create_screen_id(...)` naming pattern.
|
||||
- `create_screen_cmd(...)` launches a command in `screen`.
|
||||
- `create_screen_cmd_loop(...)` writes `_serverStart.bat`, then runs it through `cmd /Q /C` inside `screen`.
|
||||
- The generated batch file loops/restarts the server when autorestart is enabled.
|
||||
- The batch file checks `SERVER_STOPPED` before respawning.
|
||||
|
||||
### Start Flow
|
||||
|
||||
Panel start path:
|
||||
|
||||
- `Panel/modules/gamemanager/mini_start.php` builds `$start_cmd`.
|
||||
- It collects XML `pre_start`, `environment_variables`, `lock_files`, executable name, executable location, port, IP, CPU affinity, nice value, game key, and console log.
|
||||
- It calls `$remote->universal_start(...)`.
|
||||
|
||||
Linux agent start:
|
||||
|
||||
- `universal_start_without_decrypt(...)` validates the home path and executable.
|
||||
- It may create a per-game Linux user when that preference is enabled.
|
||||
- It writes/updates the startup flag file in `GAME_STARTUP_DIR`.
|
||||
- It converts `pre_start` and environment variables between multiline and startup-safe formats.
|
||||
- It builds the command according to executable type:
|
||||
- `.exe` / `.bat`: Wine command
|
||||
- `.jar`: startup command
|
||||
- other: `./server_exe startup_cmd`
|
||||
- It creates a generated shell startup script through `create_screen_cmd_loop(...)`.
|
||||
- It backs up `screenlogs/screenlog.<screen_id>`.
|
||||
- It runs pre-start commands through `run_before_start_commands(...)`.
|
||||
- It launches the generated command through `sudo_exec_without_decrypt($cli_bin, $owner)`.
|
||||
- It renices server processes after launch.
|
||||
|
||||
Windows/Cygwin agent start:
|
||||
|
||||
- `universal_start_without_decrypt(...)` validates the home path and executable.
|
||||
- It converts paths with `cygpath -wa`.
|
||||
- It converts `pre_start` and environment variables.
|
||||
- It builds Windows commands using `cmd /Q /C start ... /WAIT`.
|
||||
- With autorestart enabled, it uses `create_screen_cmd_loop(...)` and `_serverStart.bat`.
|
||||
- Without autorestart, it uses `create_screen_cmd(...)`.
|
||||
- It backs up `screenlogs/screenlog.<screen_id>`.
|
||||
- It runs pre-start commands through `run_before_start_commands(...)`.
|
||||
- It launches the screen command with `system($cli_bin)`.
|
||||
- It writes a startup file named `_serverStart.bat` under `GAME_STARTUP_DIR`, though the name is generic rather than per IP/port in the current Windows path.
|
||||
|
||||
### Stop Flow
|
||||
|
||||
Panel stop path:
|
||||
|
||||
- `Panel/modules/gamemanager/stop_server.php` calls `$remote->remote_stop_server(...)`.
|
||||
- Stop parameters include home ID, IP, port, control protocol, control password, control type, and home path.
|
||||
|
||||
Linux agent stop:
|
||||
|
||||
- `stop_server_without_decrypt(...)` removes the startup flag for `$server_ip-$server_port`.
|
||||
- If autorestart is enabled, it creates `SERVER_STOPPED` in the game home.
|
||||
- It attempts a graceful stop when configured:
|
||||
- `rcon`
|
||||
- `rcon2`
|
||||
- `armabe`
|
||||
- `minecraft`
|
||||
- If graceful stop does not complete, it collects PIDs from the screen session using `get_home_pids(...)`.
|
||||
- It sends `kill 15`, then `kill 9` if needed.
|
||||
- It runs `screen -wipe`.
|
||||
|
||||
Windows/Cygwin agent stop:
|
||||
|
||||
- `stop_server_without_decrypt(...)` removes the startup flag.
|
||||
- If autorestart is enabled, it creates `SERVER_STOPPED` in the game home.
|
||||
- It finds the screen PID from `screen -list`.
|
||||
- It maps that to a Windows PID using `ps -W`.
|
||||
- It calls `cmd /C taskkill /f /fi 'PID eq ...' /T`.
|
||||
- It runs `screen -wipe`.
|
||||
|
||||
### Restart Flow
|
||||
|
||||
Both agents expose `restart_server` and `restart_server_without_decrypt(...)`.
|
||||
|
||||
The current intended restart flow is:
|
||||
|
||||
1. Stop server.
|
||||
2. Wait 60 seconds.
|
||||
3. Start server.
|
||||
|
||||
That flow is now present in the current agent files. Any companion system should hook into this sequence explicitly:
|
||||
|
||||
1. Stop companions.
|
||||
2. Stop game server.
|
||||
3. Wait 60 seconds.
|
||||
4. Start game server.
|
||||
5. Start companions after their configured delays.
|
||||
|
||||
### PID Tracking
|
||||
|
||||
Current PID tracking exists but is inconsistent:
|
||||
|
||||
- The agents write their own `ogp_agent.pid`.
|
||||
- FastDownload has `fd.pid`.
|
||||
- Scheduler has `scheduler.pid`.
|
||||
- Linux game server child PIDs are discovered from the screen PID with `pgrep -P`.
|
||||
- Windows/Cygwin maps a screen PID to a Windows PID through `ps -W`.
|
||||
- Some game XML uses the `PID_FILE` CLI param, for example Source-engine servers.
|
||||
- Windows `_alsoRun.bat` behavior expects `_alsoRun.pid` to contain helper PIDs.
|
||||
|
||||
There is no general companion PID registry today.
|
||||
|
||||
### Marker Files
|
||||
|
||||
Relevant marker files:
|
||||
|
||||
- `GAME_STARTUP_DIR/<ip>-<port>` startup flag on Linux.
|
||||
- Windows writes a startup file under `GAME_STARTUP_DIR`, currently `_serverStart.bat`.
|
||||
- `SERVER_STOPPED` in the game home when autorestart is enabled.
|
||||
- `_alsoRun.pid` for the current Windows helper behavior.
|
||||
|
||||
`SERVER_STOPPED` is used by generated autorestart scripts to decide whether to respawn. It should not be used as the source of truth for current runtime status.
|
||||
|
||||
### Logs
|
||||
|
||||
Game screen logs are written under:
|
||||
|
||||
```text
|
||||
screenlogs/screenlog.<screen_id>
|
||||
```
|
||||
|
||||
The agents call `backup_home_log(...)` before starting a server. If XML defines `console_log`, Panel/agent log functions may read the game-specific console log instead.
|
||||
|
||||
There is no dedicated companion stdout/stderr log path today.
|
||||
|
||||
## 2. Current Helper Script Behavior
|
||||
|
||||
### `_alsoRun.bat`
|
||||
|
||||
The clearest current companion behavior is Windows-only.
|
||||
|
||||
In `Agent-Windows/ogp_agent.pl`, `create_screen_cmd_loop(...)` generates `_serverStart.bat`. That generated batch file contains:
|
||||
|
||||
```bat
|
||||
if exist "_alsoRun.bat" call "_alsoRun.bat"
|
||||
start ... /wait <game command>
|
||||
for /f %%p in (_alsoRun.pid) do taskkill /PID %%p /F
|
||||
```
|
||||
|
||||
This means:
|
||||
|
||||
- `_alsoRun.bat` is executed before the game server process.
|
||||
- `_alsoRun.pid` is read after the game server exits.
|
||||
- Each PID listed in `_alsoRun.pid` is force-killed.
|
||||
- This only exists in the Windows/Cygwin agent path.
|
||||
- It only works when the generated `_serverStart.bat` loop path is used.
|
||||
- It relies on files in or near the game server working directory.
|
||||
- It depends on the helper script correctly writing `_alsoRun.pid`.
|
||||
|
||||
Some DayZ/Arma XML files generate `_alsoRun.bat` in `pre_start`. Examples found include:
|
||||
|
||||
- `Panel/modules/config_games/server_configs/dayz_arma2co_win32.xml`
|
||||
- `Panel/modules/config_games/server_configs/dayz_epoch_mod_win32.xml`
|
||||
|
||||
Those XML files build `_alsoRun.bat` to start BEC and use WMIC to find/write the BEC PID into `_alsoRun.pid`.
|
||||
|
||||
Problems:
|
||||
|
||||
- The helper file lives in a customer-accessible game area.
|
||||
- The customer may be able to edit/delete `_alsoRun.bat` or `_alsoRun.pid`.
|
||||
- It is Windows-specific.
|
||||
- PID capture depends on executable path matching and WMIC.
|
||||
- Cleanup happens after the game process exits, not as a first-class stop action.
|
||||
- It is not centrally visible to the Panel as companion state.
|
||||
|
||||
### `pre_start`
|
||||
|
||||
The XML schema supports `pre_start`.
|
||||
|
||||
Panel reads `pre_start` in:
|
||||
|
||||
- `Panel/modules/gamemanager/mini_start.php`
|
||||
- `Panel/modules/gamemanager/restart_server.php`
|
||||
- `Panel/modules/gamemanager/home_handling_functions.php`
|
||||
|
||||
The value is passed to the agent as `$preStart`.
|
||||
|
||||
Linux behavior:
|
||||
|
||||
- `run_before_start_commands(...)` writes `${home_path}/prestart_ogp.sh`.
|
||||
- It writes each XML line into the shell file.
|
||||
- It runs `bash prestart_ogp.sh` as the game owner.
|
||||
- The script removes itself at the end.
|
||||
|
||||
Windows/Cygwin behavior:
|
||||
|
||||
- `run_before_start_commands(...)` writes `_prestart.bat` in the Windows-converted home path.
|
||||
- It writes each XML line into the batch file.
|
||||
- It runs `cmd /Q /C start /wait "<_prestart.bat>"`.
|
||||
- It deletes `_prestart.bat`.
|
||||
|
||||
Concerns:
|
||||
|
||||
- `pre_start` is trusted XML/admin-defined script content, but it executes in/against the customer game home.
|
||||
- It is not structured.
|
||||
- It is not tracked.
|
||||
- It is only "before start"; it is not a companion lifecycle model.
|
||||
- It cannot reliably stop helper processes unless custom script authors implement that themselves.
|
||||
|
||||
### `post_start`
|
||||
|
||||
The schema and config editor order include `post_start`.
|
||||
|
||||
Found references:
|
||||
|
||||
- `Panel/modules/config_games/schema_server_config.xml`
|
||||
- `Panel/modules/config_games/config_servers.php`
|
||||
- `Panel/modules/config_games/xml_tag_descriptions.php`
|
||||
- One example XML: `Panel/modules/config_games/server_configs/nexuiz_win.xml`
|
||||
|
||||
I did not find a start path that reads `server_xml->post_start` or sends it to the agents. As currently written, `post_start` appears schema-visible but not operational.
|
||||
|
||||
### `post_install`
|
||||
|
||||
Both agents include workshop/mod post-install script generation logic. This is install/update-related, not game-server runtime lifecycle management.
|
||||
|
||||
`post_install` should not be used for companion processes because it is not tied to server start/stop/restart.
|
||||
|
||||
### Custom Fields And Custom Scripts
|
||||
|
||||
Custom fields are supported in XML and stored per server. They are used by config replacement logic:
|
||||
|
||||
- `Panel/modules/gamemanager/cfg_text_replace.php`
|
||||
- `Panel/modules/config_games/schema_server_config.xml`
|
||||
|
||||
Custom fields can influence config file content. They are not currently a safe or structured way to define executable companion commands.
|
||||
|
||||
Customers can also use extra startup parameters where permissions allow. That should not become the companion command source because it would permit arbitrary command injection into managed helper launches.
|
||||
|
||||
## 3. Recommended Method 1
|
||||
|
||||
### First-Class Companion Programs System
|
||||
|
||||
The best design is a first-class, structured companion program system.
|
||||
|
||||
Game XML should define the allowed companion programs for that game. The Panel should store per-server choices such as enabled/disabled and optional safe settings. The agent should own runtime launch, PID tracking, log paths, stop, and restart cleanup.
|
||||
|
||||
Example XML shape:
|
||||
|
||||
```xml
|
||||
<companion_programs>
|
||||
<program key="bec" name="BattlEye Extended Controls" os="windows">
|
||||
<enabled_default>0</enabled_default>
|
||||
<delay_seconds_default>30</delay_seconds_default>
|
||||
<working_dir>{GAME_PATH}\BEC</working_dir>
|
||||
<command>Bec.exe</command>
|
||||
<args>-f Config.cfg</args>
|
||||
<process_name>Bec.exe</process_name>
|
||||
<stop_on_server_stop>1</stop_on_server_stop>
|
||||
<restart_on_server_restart>1</restart_on_server_restart>
|
||||
<stdout_log>companions/bec.out.log</stdout_log>
|
||||
<stderr_log>companions/bec.err.log</stderr_log>
|
||||
</program>
|
||||
</companion_programs>
|
||||
```
|
||||
|
||||
Recommended XML fields:
|
||||
|
||||
- `key`: stable internal ID.
|
||||
- `name`: display name.
|
||||
- `os`: `linux`, `windows`, or `any`.
|
||||
- `enabled_default`: default panel setting.
|
||||
- `delay_seconds_default`: default delay after game start.
|
||||
- `working_dir`: trusted template path.
|
||||
- `command`: trusted executable/script name or path template.
|
||||
- `args`: trusted default arguments.
|
||||
- `process_name`: optional verification aid only, not the kill target by itself.
|
||||
- `stop_command`: optional graceful stop command.
|
||||
- `stop_timeout_seconds`: default graceful wait.
|
||||
- `kill_after_timeout`: boolean.
|
||||
- `stop_on_server_stop`: boolean.
|
||||
- `restart_on_server_restart`: boolean.
|
||||
- `stdout_log` / `stderr_log`: relative managed log paths.
|
||||
- `required_files`: optional list for Panel validation.
|
||||
- `requires_game_online`: whether to delay until the game port is online.
|
||||
|
||||
### Where XML Defines Allowed Companion Programs
|
||||
|
||||
Add `companion_programs` to `Panel/modules/config_games/schema_server_config.xml` as an optional top-level element.
|
||||
|
||||
Only admins/editors of game XML should be able to define:
|
||||
|
||||
- executable path
|
||||
- arguments
|
||||
- working directory
|
||||
- stop command
|
||||
- process name
|
||||
- default delay
|
||||
- log paths
|
||||
|
||||
Customers should not be able to enter arbitrary commands.
|
||||
|
||||
### Where Panel Stores Per-Server Settings
|
||||
|
||||
Panel should store per-home companion settings in the database, not in customer-editable files.
|
||||
|
||||
Possible table:
|
||||
|
||||
```sql
|
||||
server_companion_settings (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
home_id INT NOT NULL,
|
||||
companion_key VARCHAR(64) NOT NULL,
|
||||
enabled TINYINT(1) NOT NULL DEFAULT 0,
|
||||
delay_seconds INT NULL,
|
||||
settings_json LONGTEXT NULL,
|
||||
UNIQUE KEY uniq_home_companion (home_id, companion_key)
|
||||
)
|
||||
```
|
||||
|
||||
`settings_json` should only contain safe, schema-defined options. Do not allow free-form command or shell text. For example:
|
||||
|
||||
- config profile selection
|
||||
- config file name from an allowed list
|
||||
- delay override within min/max bounds
|
||||
- environment preset key
|
||||
|
||||
### How The Agent Receives Settings
|
||||
|
||||
Extend the encrypted XML-RPC start/restart call to include a companion payload, or add a dedicated agent RPC after start:
|
||||
|
||||
Recommended:
|
||||
|
||||
- `universal_start(..., companion_payload)` for direct lifecycle coupling.
|
||||
- `server_companion_start(home_id, payload)` for explicit start action.
|
||||
- `server_companion_stop(home_id)` for explicit stop action.
|
||||
- `server_companion_status(home_id)` for status display.
|
||||
|
||||
The payload should be generated by the Panel from trusted XML plus stored per-server enabled settings.
|
||||
|
||||
Payload should contain fully resolved, validated data:
|
||||
|
||||
```json
|
||||
{
|
||||
"home_id": 123,
|
||||
"server_ip": "1.2.3.4",
|
||||
"server_port": 2302,
|
||||
"companions": [
|
||||
{
|
||||
"key": "bec",
|
||||
"enabled": true,
|
||||
"delay_seconds": 30,
|
||||
"working_dir": "/home/ogp_agent/OGP_User_Files/123/BEC",
|
||||
"command": "Bec.exe",
|
||||
"args": ["-f", "Config.cfg"],
|
||||
"stdout_log": "bec.out.log",
|
||||
"stderr_log": "bec.err.log"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
For XML-RPC compatibility, this may be passed as JSON text.
|
||||
|
||||
### How The Agent Starts Companions
|
||||
|
||||
The agent should start companions after the game screen/session has launched.
|
||||
|
||||
Recommended approach:
|
||||
|
||||
- Use separate `screen` sessions per companion.
|
||||
- Session naming:
|
||||
- Game: `OGP_HOME_000000123`
|
||||
- Companion: `OGP_COMPANION_000000123_bec`
|
||||
- Write companion runtime state under an agent-controlled path outside the game FTP/file-manager root.
|
||||
- Start delayed companions through a small agent-owned delay wrapper:
|
||||
- Linux: `screen -d -m -S OGP_COMPANION_... bash -lc 'sleep 30; cd ...; exec ...'`
|
||||
- Windows/Cygwin: `screen -d -m -S OGP_COMPANION_... cmd /Q /C "timeout /t 30 ... && cd /d ... && ..."`
|
||||
|
||||
This avoids blocking game startup. The Panel can show the game as `STARTING`/`ONLINE` independently while companion statuses move through `PENDING`, `STARTING`, `RUNNING`, or `FAILED`.
|
||||
|
||||
### How The Agent Records PIDs
|
||||
|
||||
Create an agent-owned runtime directory, for example:
|
||||
|
||||
```text
|
||||
<AGENT_RUN_DIR>/companions/<home_id>/
|
||||
```
|
||||
|
||||
Files:
|
||||
|
||||
```text
|
||||
companions/<home_id>/state.json
|
||||
companions/<home_id>/pids/<companion_key>.pid
|
||||
companions/<home_id>/logs/<companion_key>.out.log
|
||||
companions/<home_id>/logs/<companion_key>.err.log
|
||||
```
|
||||
|
||||
State should include:
|
||||
|
||||
- home ID
|
||||
- companion key
|
||||
- screen session name
|
||||
- agent PID/screen PID
|
||||
- child PID if known
|
||||
- command hash or executable path
|
||||
- start time
|
||||
- last status
|
||||
- last error
|
||||
|
||||
For Linux:
|
||||
|
||||
- Prefer launching through `screen`.
|
||||
- Use the screen PID plus child process lookup.
|
||||
- If possible, make the wrapper write `echo $$` and the exec child PID to a PID file.
|
||||
- Use process group/session cleanup where possible.
|
||||
|
||||
For Windows/Cygwin:
|
||||
|
||||
- Keep `screen` for parity.
|
||||
- Prefer a wrapper that starts the companion and writes the Windows PID to a PID file.
|
||||
- Use Cygwin `ps -W` or PowerShell/WMIC alternatives where available.
|
||||
- Avoid killing by executable name alone.
|
||||
|
||||
### How The Agent Stops Companions
|
||||
|
||||
Stop by the recorded handle, not by executable name.
|
||||
|
||||
Recommended stop order:
|
||||
|
||||
1. Load `companions/<home_id>/state.json`.
|
||||
2. For each running companion:
|
||||
- If `stop_command` exists, run it in the configured working directory.
|
||||
- Wait up to `stop_timeout_seconds`.
|
||||
- If still alive and `kill_after_timeout=1`, kill only recorded PID/process tree/session.
|
||||
- Close the companion screen session.
|
||||
- Update state.
|
||||
3. Clean stale PID files only after verifying the process is gone.
|
||||
|
||||
Avoid:
|
||||
|
||||
- `pkill Bec.exe`
|
||||
- `taskkill /IM Bec.exe`
|
||||
- broad executable-name matching
|
||||
|
||||
Those can kill unrelated customer processes.
|
||||
|
||||
### Restart Behavior
|
||||
|
||||
Recommended restart sequence:
|
||||
|
||||
1. Stop companions for the home.
|
||||
2. Stop game server.
|
||||
3. Wait 60 seconds.
|
||||
4. Start game server.
|
||||
5. Start enabled companions according to delay settings.
|
||||
|
||||
Do not let companions survive a restart unless explicitly marked as persistent and safe.
|
||||
|
||||
### Companion Logging
|
||||
|
||||
Companion stdout/stderr should be logged separately from game screen logs.
|
||||
|
||||
Recommended default:
|
||||
|
||||
```text
|
||||
<AGENT_RUN_DIR>/companions/<home_id>/logs/<key>.out.log
|
||||
<AGENT_RUN_DIR>/companions/<home_id>/logs/<key>.err.log
|
||||
```
|
||||
|
||||
Panel can add a companion log viewer later, separate from the game server log viewer.
|
||||
|
||||
For customer visibility, expose logs through the agent RPC after permission checks rather than placing them inside the customer FTP root by default.
|
||||
|
||||
### Security
|
||||
|
||||
This method is secure because:
|
||||
|
||||
- Commands come from trusted game XML/admin configuration.
|
||||
- Customer UI stores only enable/disable and bounded safe settings.
|
||||
- Runtime files live outside the customer file manager/FTP root.
|
||||
- The agent launches only known companion keys for the current game config.
|
||||
- Stop/kill uses recorded PIDs/screen sessions, not executable names.
|
||||
- Logs are controlled by the agent.
|
||||
|
||||
### Portability
|
||||
|
||||
This method is portable because:
|
||||
|
||||
- XML can define Linux and Windows variants with the same logical companion key.
|
||||
- Agent receives normalized companion payload.
|
||||
- Both agents use screen sessions.
|
||||
- PID capture is platform-specific behind the same agent RPC model.
|
||||
|
||||
## 4. Recommended Method 2
|
||||
|
||||
### Agent-Managed Generated Startup/Cleanup Scripts
|
||||
|
||||
Alternate design: keep using scripts, but generate and store them in an agent-controlled directory outside customer-editable game files.
|
||||
|
||||
Example layout:
|
||||
|
||||
```text
|
||||
<AGENT_RUN_DIR>/companions/<home_id>/
|
||||
companions.json
|
||||
start_companions.sh
|
||||
stop_companions.sh
|
||||
start_companions.bat
|
||||
stop_companions.bat
|
||||
pids/
|
||||
logs/
|
||||
```
|
||||
|
||||
The Panel still defines companions from trusted XML and stores per-server enabled settings. The agent generates scripts from those trusted definitions.
|
||||
|
||||
Start flow:
|
||||
|
||||
1. Game server launches.
|
||||
2. Agent starts an agent-owned companion startup script in its own screen session.
|
||||
3. Script handles delays and PID capture.
|
||||
|
||||
Stop flow:
|
||||
|
||||
1. Agent runs an agent-owned cleanup script.
|
||||
2. Script kills only PIDs listed in the agent-owned `pids` directory.
|
||||
3. Agent verifies cleanup.
|
||||
|
||||
### Pros
|
||||
|
||||
- Closer to the existing `_serverStart.bat` and generated shell script model.
|
||||
- Easier to debug for admins because generated scripts are readable.
|
||||
- Can work with the existing screen backend.
|
||||
- Avoids customer-editable `_alsoRun.bat`.
|
||||
- Can be implemented incrementally.
|
||||
|
||||
### Cons
|
||||
|
||||
- Still script-heavy.
|
||||
- Quoting rules remain difficult across Linux, Cygwin, and Windows.
|
||||
- Risk of script injection if generation is not strict.
|
||||
- PID capture still needs platform-specific care.
|
||||
- State management can drift if scripts are edited manually by admins.
|
||||
- Less clean than direct agent-managed process APIs.
|
||||
|
||||
### Comparison To Method 1
|
||||
|
||||
Method 1 is better long term because the agent owns lifecycle state directly. Method 2 is a reasonable migration bridge if implementation speed matters, but it should still use trusted XML/admin definitions and agent-owned control paths.
|
||||
|
||||
## 5. Security Considerations
|
||||
|
||||
### Do Not Trust Customer-Editable Startup Files
|
||||
|
||||
Avoid using customer-editable files such as:
|
||||
|
||||
- `_alsoRun.bat`
|
||||
- `_alsoRun.pid`
|
||||
- arbitrary `.bat` or `.sh` helper files in the game home
|
||||
|
||||
Those files can be edited, deleted, replaced, or used to run unintended commands.
|
||||
|
||||
### Managed Files Should Live Outside The FTP/File Manager Root
|
||||
|
||||
Recommended location:
|
||||
|
||||
```text
|
||||
<AGENT_RUN_DIR>/companions/<home_id>/
|
||||
```
|
||||
|
||||
This directory should be owned by the agent or game server runner user and should not be directly writable by customers.
|
||||
|
||||
### Commands Must Come From Trusted Configuration
|
||||
|
||||
Companion commands should come from:
|
||||
|
||||
- shipped game XML
|
||||
- admin-managed XML
|
||||
- a future admin-only companion catalog
|
||||
|
||||
They should not come from:
|
||||
|
||||
- customer text fields
|
||||
- startup extra parameters
|
||||
- uploaded files
|
||||
- customer-editable config files
|
||||
|
||||
### Validate Commands
|
||||
|
||||
Validation should include:
|
||||
|
||||
- companion key exists in the current game XML
|
||||
- OS matches the agent OS
|
||||
- command path resolves under an allowed directory unless explicitly admin-approved
|
||||
- working directory resolves under game home or an admin-approved path
|
||||
- no unexpanded `{...}` tokens remain
|
||||
- no shell metacharacters in fields that are supposed to be argv tokens
|
||||
- delay is numeric and capped
|
||||
- log paths are relative and cannot escape managed log directories
|
||||
|
||||
### Avoid Arbitrary Command Execution
|
||||
|
||||
Use argv-style execution where possible.
|
||||
|
||||
When shell/batch is unavoidable:
|
||||
|
||||
- generate commands from trusted fields only
|
||||
- quote every path/argument consistently
|
||||
- avoid concatenating customer-provided strings into shell code
|
||||
- keep generated files outside customer write paths
|
||||
|
||||
### Avoid Killing Unrelated Processes
|
||||
|
||||
Do not kill by executable name alone.
|
||||
|
||||
Preferred kill targets:
|
||||
|
||||
- recorded companion PID
|
||||
- recorded process group
|
||||
- recorded screen session
|
||||
- recorded Windows process tree for that PID
|
||||
|
||||
Process name should be used only as a verification hint, not as the primary kill selector.
|
||||
|
||||
## 6. Cross-platform Considerations
|
||||
|
||||
### Linux Agent
|
||||
|
||||
Linux can use:
|
||||
|
||||
- `screen`
|
||||
- `bash`
|
||||
- PID files
|
||||
- `/proc`
|
||||
- `pgrep -P`
|
||||
- `kill 15`, then `kill 9`
|
||||
|
||||
Recommended Linux companion launch:
|
||||
|
||||
```text
|
||||
screen -d -m -S OGP_COMPANION_<home_id>_<key> bash -lc '<agent-owned wrapper>'
|
||||
```
|
||||
|
||||
Use an agent-owned wrapper or direct fork/exec to record PID and redirect logs.
|
||||
|
||||
### Windows/Cygwin Agent
|
||||
|
||||
Windows/Cygwin can use:
|
||||
|
||||
- `screen`
|
||||
- `cmd /Q /C`
|
||||
- `start`
|
||||
- `taskkill /PID ... /T`
|
||||
- `ps -W`
|
||||
- possibly WMIC or PowerShell depending on environment
|
||||
|
||||
Current `_alsoRun.bat` depends on WMIC in some XML. WMIC is not reliable on all modern Windows installations, so future code should not require it.
|
||||
|
||||
Recommended Windows companion launch:
|
||||
|
||||
```text
|
||||
screen -d -m -S OGP_COMPANION_<home_id>_<key> cmd /Q /C "<agent-owned wrapper.bat>"
|
||||
```
|
||||
|
||||
The wrapper should record the Windows PID or enough process/session information for cleanup.
|
||||
|
||||
### Batch vs Shell Differences
|
||||
|
||||
Risks:
|
||||
|
||||
- quoting spaces in paths
|
||||
- escaping backslashes
|
||||
- environment variable syntax differences
|
||||
- `start` window title behavior on Windows
|
||||
- delayed expansion in batch files
|
||||
- Cygwin path vs Windows path conversion
|
||||
- signal semantics: Linux signals vs Windows taskkill
|
||||
|
||||
The Panel should not build platform command strings. It should send trusted structured definitions to the agent and let the agent perform OS-specific quoting/execution.
|
||||
|
||||
### Screen Behavior
|
||||
|
||||
Screen remains the default shared backend for now.
|
||||
|
||||
Use separate screen sessions for companions rather than attaching them to the game server screen. This gives:
|
||||
|
||||
- independent status
|
||||
- independent logs
|
||||
- safer cleanup
|
||||
- clearer restart behavior
|
||||
|
||||
### Process Cleanup Risks
|
||||
|
||||
Companion processes may:
|
||||
|
||||
- fork children
|
||||
- daemonize
|
||||
- spawn background processes
|
||||
- exit while leaving children
|
||||
- fail before writing PID
|
||||
- be started manually by the customer/admin
|
||||
|
||||
The agent should track process trees where possible and verify stop results.
|
||||
|
||||
## 7. Suggested Implementation Phases
|
||||
|
||||
### Phase 1: Inventory Current Flow And Add Report Only
|
||||
|
||||
This report is Phase 1.
|
||||
|
||||
No source code changes should be made for companion behavior in this phase.
|
||||
|
||||
### Phase 2: XML Schema Design
|
||||
|
||||
Add `companion_programs` to:
|
||||
|
||||
- `Panel/modules/config_games/schema_server_config.xml`
|
||||
- `Panel/modules/config_games/config_servers.php`
|
||||
- `Panel/modules/config_games/xml_tag_descriptions.php`
|
||||
|
||||
Create example XML for BEC, B3, and a generic log watcher.
|
||||
|
||||
### Phase 3: Panel Storage/UI Design
|
||||
|
||||
Add storage for per-server companion settings.
|
||||
|
||||
Initial UI:
|
||||
|
||||
- show companion list from XML
|
||||
- enable/disable checkbox
|
||||
- delay override
|
||||
- safe predefined options only
|
||||
|
||||
Do not expose raw command editing to customers.
|
||||
|
||||
### Phase 4: Agent Start/Stop Integration
|
||||
|
||||
Add encrypted RPCs:
|
||||
|
||||
- `server_companion_start`
|
||||
- `server_companion_stop`
|
||||
- `server_companion_status`
|
||||
|
||||
Extend start/restart flow to call companion start/stop at the right time.
|
||||
|
||||
### Phase 5: PID Tracking And Cleanup
|
||||
|
||||
Implement:
|
||||
|
||||
- agent-owned state directory
|
||||
- PID files
|
||||
- screen session names
|
||||
- process tree cleanup
|
||||
- stale PID detection
|
||||
- companion status reporting
|
||||
|
||||
### Phase 6: DayZ/BEC Test
|
||||
|
||||
Migrate one DayZ/Arma BEC case away from `_alsoRun.bat`.
|
||||
|
||||
Test:
|
||||
|
||||
- start game
|
||||
- delayed BEC start
|
||||
- BEC status
|
||||
- stop game
|
||||
- BEC cleanup
|
||||
- restart flow
|
||||
- crash/recovery behavior
|
||||
- agent restart behavior
|
||||
|
||||
### Phase 7: Generalized Docs
|
||||
|
||||
Document:
|
||||
|
||||
- XML authoring
|
||||
- admin setup
|
||||
- supported placeholders
|
||||
- security rules
|
||||
- troubleshooting
|
||||
- log locations
|
||||
- migration path from `_alsoRun.bat`
|
||||
|
||||
## 8. Open Questions
|
||||
|
||||
1. Should companions be started after the game process exists, after the game port is listening, or after query/RCON succeeds when available?
|
||||
2. Should companions be allowed to keep running if the game server crashes and autorestarts, or should they always restart with each game process cycle?
|
||||
3. Should some companions be marked "persistent" across game restarts?
|
||||
4. Which user should run companions on Linux when `LINUX_USER_PER_GAME_SERVER` is enabled?
|
||||
5. Should companion logs be visible to customers by default, or admin-only?
|
||||
6. Should companion config files be editable through the existing config file module?
|
||||
7. How should Windows PID capture work on systems without WMIC?
|
||||
8. Is PowerShell guaranteed available in the supported Windows/Cygwin agent environment?
|
||||
9. Should the Panel support companion install/update packages, or only runtime start/stop of already-installed files?
|
||||
10. Should companion definitions live only in game XML, or should there be a reusable global companion catalog?
|
||||
11. How should firewall rules handle companion ports if a companion needs one?
|
||||
12. What should happen if a companion fails but the game server is online?
|
||||
13. Should companion failure affect billing/status/customer-facing uptime?
|
||||
14. How should agent autostart restore companion state after power loss or agent restart?
|
||||
15. Should the agent stop companions before or after graceful game stop for tools that send shutdown messages to the game?
|
||||
16. Should companion environment variables be separate from game environment variables?
|
||||
17. How should command placeholders be standardized across Linux and Windows?
|
||||
18. What is the maximum acceptable startup delay for companion programs?
|
||||
19. Should admins be able to override companion commands per server, or only per game XML?
|
||||
20. How should existing `_alsoRun.bat` game configs be migrated without breaking current customers?
|
||||
|
||||
## Summary Recommendation
|
||||
|
||||
Build Method 1: a first-class companion programs system driven by trusted XML/admin configuration, stored per server in the Panel, and executed/owned by the agent.
|
||||
|
||||
Do not continue expanding `_alsoRun.bat`. It is a useful proof of need, but it is Windows-specific, customer-editable, hard to audit, and unreliable for stop/restart cleanup.
|
||||
|
||||
Use `screen` as the shared backend for now, with one screen session per companion and agent-owned PID/log/state files outside the customer file root.
|
||||
1020
GSP_PLATFORM_IMPROVEMENT_REPORT.md
Normal file
1020
GSP_PLATFORM_IMPROVEMENT_REPORT.md
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -627,8 +627,8 @@ class OGPRemoteLibrary
|
|||
/// \return 1 If is
|
||||
/// \return 0 If is not
|
||||
/// \return -1 If agent could not be reached.
|
||||
public function is_screen_running($screen_type,$home_id)
|
||||
{
|
||||
public function is_screen_running($screen_type,$home_id)
|
||||
{
|
||||
$params = $this->encrypt_params($screen_type,$home_id);
|
||||
$this->add_enc_chk($params);
|
||||
$request = xmlrpc_encode_request("is_screen_running", $params);
|
||||
|
|
@ -638,10 +638,40 @@ class OGPRemoteLibrary
|
|||
else if ( $status === 0 )
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public function mon_stats()
|
||||
public function remote_server_status($home_id, $server_ip, $server_port, $query_port = "", $rcon_port = "", $startup_timeout = 180, $state_hint = "")
|
||||
{
|
||||
$params = $this->encrypt_params($home_id, $server_ip, $server_port, $query_port, $rcon_port, $startup_timeout, $state_hint);
|
||||
$this->add_enc_chk($params);
|
||||
$request = xmlrpc_encode_request("server_status", $params);
|
||||
$status = $this->sendRequest($request);
|
||||
|
||||
if (is_array($status) && !xmlrpc_is_fault($status)) {
|
||||
return $status;
|
||||
}
|
||||
|
||||
return array(
|
||||
'status' => 'UNKNOWN',
|
||||
'ready' => 0,
|
||||
'process_running' => 0,
|
||||
'session_running' => 0,
|
||||
'game_port_listening' => 0,
|
||||
'query_port_listening' => 0,
|
||||
'rcon_port_listening' => 0,
|
||||
'pid' => '',
|
||||
'session_name' => '',
|
||||
'ip' => $server_ip,
|
||||
'port' => $server_port,
|
||||
'query_port' => $query_port,
|
||||
'rcon_port' => $rcon_port,
|
||||
'last_error' => 'Agent status RPC unavailable.',
|
||||
'query_info' => ''
|
||||
);
|
||||
}
|
||||
|
||||
public function mon_stats()
|
||||
{
|
||||
$args = $this->encrypt_params("mon_stats");
|
||||
$this->add_enc_chk($args);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,45 @@ function get_query_port($server_xml, $server_port) {
|
|||
return $server_port;
|
||||
}
|
||||
|
||||
function get_agent_server_status($remote, $server_xml, $home_id, $server_ip, $server_port, $state_hint = "", $startup_timeout = 180)
|
||||
{
|
||||
$query_port = "";
|
||||
$rcon_port = "";
|
||||
|
||||
if (isset($server_xml->protocol) && (string)$server_xml->protocol === "gameq") {
|
||||
$query_port = get_query_port($server_xml, $server_port);
|
||||
} elseif (isset($server_xml->protocol) && (string)$server_xml->protocol === "lgsl" && isset($server_xml->lgsl_query_name)) {
|
||||
require_once('protocol/lgsl/lgsl_protocol.php');
|
||||
$get_ports = lgsl_port_conversion((string)$server_xml->lgsl_query_name, $server_port, "", "");
|
||||
$query_port = isset($get_ports['1']) ? $get_ports['1'] : "";
|
||||
} elseif (isset($server_xml->protocol) && (string)$server_xml->protocol === "teamspeak3") {
|
||||
$query_port = "10011";
|
||||
}
|
||||
|
||||
if (isset($server_xml->rcon_port) && is_numeric((string)$server_xml->rcon_port)) {
|
||||
$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.');
|
||||
}
|
||||
|
||||
return $remote->remote_server_status($home_id, $server_ip, $server_port, $query_port, $rcon_port, $startup_timeout, $state_hint);
|
||||
}
|
||||
|
||||
function is_agent_status_online($agent_status)
|
||||
{
|
||||
return is_array($agent_status) && isset($agent_status['status']) && strtoupper($agent_status['status']) === 'ONLINE';
|
||||
}
|
||||
|
||||
function is_agent_status_active($agent_status)
|
||||
{
|
||||
if (!is_array($agent_status) || !isset($agent_status['status'])) {
|
||||
return false;
|
||||
}
|
||||
return in_array(strtoupper($agent_status['status']), array('STARTING', 'ONLINE', 'STOPPING', 'UNRESPONSIVE'));
|
||||
}
|
||||
|
||||
function get_start_cmd($remote,$server_xml,$home_info,$mod_id,$ip,$port,$db)
|
||||
{
|
||||
$last_param = json_decode($home_info['last_param'], True);
|
||||
|
|
@ -250,19 +289,23 @@ function exec_operation( $action, $home_id, $mod_id, $ip, $port, $override = fal
|
|||
}
|
||||
}
|
||||
|
||||
$screen_running = $remote->is_screen_running(OGP_SCREEN_TYPE_HOME,$home_info['home_id']) === 1;
|
||||
$agent_status = get_agent_server_status($remote, $server_xml, $home_info['home_id'], $ip, $port);
|
||||
$screen_running = is_agent_status_active($agent_status);
|
||||
|
||||
if ( $action == "stop" AND $screen_running )
|
||||
{
|
||||
$remote_retval = $remote->remote_stop_server($home_info['home_id'],
|
||||
$ip, $port, $server_xml->control_protocol,
|
||||
$home_info['control_password'],$server_xml->control_protocol_type, $home_info['home_path']);
|
||||
$db->logger(get_lang_f('server_stopped', $home_info['home_name'] ) . "($ip:$port)");
|
||||
if ( $remote_retval === -1 )
|
||||
return FALSE;
|
||||
elseif( $remote_retval === -2 )
|
||||
return FALSE;
|
||||
else
|
||||
$remote_retval = $remote->remote_stop_server($home_info['home_id'],
|
||||
$ip, $port, $server_xml->control_protocol,
|
||||
$home_info['control_password'],$server_xml->control_protocol_type, $home_info['home_path']);
|
||||
$agent_status = get_agent_server_status($remote, $server_xml, $home_info['home_id'], $ip, $port, "STOPPING");
|
||||
$db->logger(get_lang_f('server_stopped', $home_info['home_name'] ) . "($ip:$port)");
|
||||
if ( $remote_retval === -1 )
|
||||
return FALSE;
|
||||
elseif( $remote_retval === -2 )
|
||||
return FALSE;
|
||||
elseif( isset($agent_status['status']) && strtoupper($agent_status['status']) !== "OFFLINE" )
|
||||
return FALSE;
|
||||
else
|
||||
{
|
||||
$firewall_settings = $db->getFirewallSettings($home_info['remote_server_id']);
|
||||
if ($firewall_settings['status'] == "enable")
|
||||
|
|
|
|||
|
|
@ -8,25 +8,25 @@ require_once("modules/config_games/server_config_parser.php");
|
|||
|
||||
echo "home id = " .$home_id;
|
||||
$user_id = $_SESSION['user_id'];
|
||||
|
||||
|
||||
|
||||
|
||||
$isAdmin = $db->isAdmin( $user_id );
|
||||
if($isAdmin)
|
||||
if($isAdmin)
|
||||
$home_info = $db->getGameHome($home_id);
|
||||
else
|
||||
$home_info = $db->getUserGameHome($user_id,$home_id);
|
||||
|
||||
$current_mod_info = $home_info['mods'][$mod_id];
|
||||
|
||||
$current_mod_info = $home_info['mods'][$mod_id];
|
||||
$home_cfg_id = $current_mod_info['home_cfg_id'];
|
||||
$mod_cfg_id = $current_mod_info['mod_cfg_id'];
|
||||
|
||||
|
||||
if($home_cfg_id === null && $mod_cfg_id === null){
|
||||
$home_cfg_id = 67;
|
||||
$mod_cfg_id = 68;
|
||||
//print_failure(get_lang('invalid_game_mod_id'));
|
||||
//return;
|
||||
}
|
||||
|
||||
|
||||
if ( $home_info === FALSE )
|
||||
{
|
||||
//print_failure( get_lang("no_access_to_home") );
|
||||
|
|
@ -45,7 +45,7 @@ require_once("modules/config_games/server_config_parser.php");
|
|||
$remote = new OGPRemoteLibrary($home_info['agent_ip'],$home_info['agent_port'],$home_info['encryption_key'],$home_info['timeout']);
|
||||
|
||||
$home_log = "";
|
||||
|
||||
|
||||
if( isset( $server_xml->console_log ) )
|
||||
{
|
||||
$log_retval = $remote->get_log(OGP_SCREEN_TYPE_HOME,
|
||||
|
|
@ -72,72 +72,50 @@ require_once("modules/config_games/server_config_parser.php");
|
|||
if(hasValue($home_log)){
|
||||
$home_log = utf8_encode($home_log);
|
||||
}
|
||||
|
||||
// Using the refreshed class
|
||||
if( isset($_GET['refreshed']) )
|
||||
{
|
||||
echo "<pre class='log'>".htmlentities($home_log)."</pre>";
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "<h2>".htmlentities($home_info['home_name'])."</h2>";
|
||||
if($log_retval == 1)
|
||||
|
||||
// Using the refreshed class
|
||||
if( isset($_GET['refreshed']) )
|
||||
{
|
||||
require_once("includes/refreshed.php");
|
||||
|
||||
$control = '<form method="GET" >
|
||||
<input type="hidden" name="m" value="gamemanager" />
|
||||
<input type="hidden" name="p" value="log" />
|
||||
<input type="hidden" name="home_id-mod_id-ip-port" value="'.$_GET['home_id-mod_id-ip-port'].'" />';
|
||||
if(isset($_GET['setInterval']))
|
||||
$control .= "<input type='hidden' name='setInterval' value='" . $_GET['setInterval'] . "' />";
|
||||
if(isset($_GET['view_player_commands']))
|
||||
$control .= "<input type='hidden' name='view_player_commands' value='" . $_GET['view_player_commands'] . "' />";
|
||||
$control .= '<input type="submit" name="size" value="';
|
||||
if( isset( $_GET['size'] ) and $_GET['size'] == "+" )
|
||||
{
|
||||
$height = "100%";
|
||||
$control .= '-';
|
||||
}
|
||||
else
|
||||
{
|
||||
$height = "500px";
|
||||
$control .= '+';
|
||||
if (!headers_sent()) {
|
||||
header('Content-Type: text/plain; charset=UTF-8');
|
||||
}
|
||||
$control .= '" /></form>';
|
||||
|
||||
$intervals = array( "4s" => "4000",
|
||||
"8s" => "8000",
|
||||
"30s" => "30000",
|
||||
"2m" => "120000",
|
||||
"5m" => "300000" );
|
||||
|
||||
$intSel = '<form action="" method="GET" >
|
||||
<input type="hidden" name="m" value="gamemanager" />
|
||||
<input type="hidden" name="p" value="log" />
|
||||
<input type="hidden" name="home_id-mod_id-ip-port" value="'.$_GET['home_id-mod_id-ip-port'].'" />';
|
||||
if(isset($_GET['size']))
|
||||
$intSel .= "<input type='hidden' name='size' value='" . $_GET['size'] . "' />";
|
||||
if(isset($_GET['view_player_commands']))
|
||||
$intSel .= "<input type='hidden' name='view_player_commands' value='" . $_GET['view_player_commands'] . "' />";
|
||||
$intSel .= get_lang("refresh_interval") . ':<select name="setInterval" onchange="this.form.submit();">';
|
||||
foreach ((array)$intervals as $interval => $value )
|
||||
echo $home_log;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "<h2>".htmlentities($home_info['home_name'])."</h2>";
|
||||
if($log_retval == 1)
|
||||
{
|
||||
$selected = "";
|
||||
if ( isset( $_GET['setInterval'] ) AND $_GET['setInterval'] == $value )
|
||||
$selected = 'selected="selected"';
|
||||
$intSel .= '<option value="'.$value.'" '.$selected.' >'.$interval.'</option>';
|
||||
}
|
||||
$intSel .= "</select></form>";
|
||||
|
||||
$setInterval = isset($_GET['setInterval']) ? $_GET['setInterval'] : 4000;
|
||||
$refresh = new refreshed();
|
||||
$pos = $refresh->add("home.php?m=gamemanager&p=log&type=cleared&refreshed&home_id-mod_id-ip-port=". $_GET['home_id-mod_id-ip-port']);
|
||||
echo $refresh->getdiv($pos,"height:".$height.";overflow:auto;max-width:1600px;");
|
||||
?><script type="text/javascript">$(document).ready(function(){ <?php echo $refresh->build("$setInterval"); ?>} ); </script><?php
|
||||
echo "<table class='center' ><tr><td>$intSel</td><td>$control</td></tr></table>";
|
||||
if( ($server_xml->control_protocol and preg_match("/^r?l?con2?$/", $server_xml->control_protocol)) OR
|
||||
($server_xml->gameq_query_name and $server_xml->gameq_query_name == "minecraft") OR
|
||||
$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>';
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
(function(){
|
||||
var logBox = document.getElementById('live-server-log');
|
||||
if (!logBox) return;
|
||||
function isAtBottom() {
|
||||
return (logBox.scrollTop + logBox.clientHeight) >= (logBox.scrollHeight - 24);
|
||||
}
|
||||
function refreshLog() {
|
||||
var shouldScroll = isAtBottom();
|
||||
fetch('<?php echo $log_url; ?>', {cache: 'no-store'})
|
||||
.then(function(response){ return response.text(); })
|
||||
.then(function(text){
|
||||
logBox.value = text;
|
||||
if (shouldScroll) {
|
||||
logBox.scrollTop = logBox.scrollHeight;
|
||||
}
|
||||
})
|
||||
.catch(function(){});
|
||||
}
|
||||
logBox.scrollTop = logBox.scrollHeight;
|
||||
window.setInterval(refreshLog, 4000);
|
||||
})();
|
||||
</script>
|
||||
<?php
|
||||
if( ($server_xml->control_protocol and preg_match("/^r?l?con2?$/", $server_xml->control_protocol)) OR
|
||||
($server_xml->gameq_query_name and $server_xml->gameq_query_name == "minecraft") OR
|
||||
($server_xml->lgsl_query_name and $server_xml->lgsl_query_name == "7dtd") )
|
||||
require('modules/gamemanager/rcon.php');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,77 +114,33 @@ function exec_ogp_module() {
|
|||
print_failure(get_lang_f('unable_to_get_log',$log_retval));
|
||||
}
|
||||
|
||||
// If game is not supported by lgsl we skip the lgsl checks and
|
||||
// assume successfull start.
|
||||
if ( $home_info['use_nat'] == 1 )
|
||||
$query_ip = $home_info['agent_ip'];
|
||||
else
|
||||
$query_ip = $ip;
|
||||
|
||||
$running = TRUE;
|
||||
$startup_timeout = isset($server_xml->startup_timeout) && is_numeric((string)$server_xml->startup_timeout) ? (int)$server_xml->startup_timeout : 180;
|
||||
$agent_status = get_agent_server_status($remote, $server_xml, $home_id, $ip, $port, "STARTING", $startup_timeout);
|
||||
$status_name = isset($agent_status['status']) ? strtoupper($agent_status['status']) : "UNKNOWN";
|
||||
|
||||
if ( $server_xml->lgsl_query_name )
|
||||
{
|
||||
require('protocol/lgsl/lgsl_protocol.php');
|
||||
$get_q_and_s = lgsl_port_conversion((string)$server_xml->lgsl_query_name, $port, "", "");
|
||||
|
||||
//Connection port
|
||||
$c_port = $get_q_and_s['0'];
|
||||
//query port
|
||||
$q_port = $get_q_and_s['1'];
|
||||
//software port
|
||||
$s_port = $get_q_and_s['2'];
|
||||
|
||||
$data = lgsl_query_live((string)$server_xml->lgsl_query_name, $query_ip, $c_port, $q_port, $s_port, "sa");
|
||||
|
||||
if ( $data['b']['status'] == "0" )
|
||||
{
|
||||
$running = FALSE;
|
||||
}
|
||||
}
|
||||
elseif ( $server_xml->gameq_query_name )
|
||||
{
|
||||
require_once 'protocol/GameQ/Autoloader.php';
|
||||
|
||||
$query_port = get_query_port($server_xml, $port);
|
||||
|
||||
$servers = array(
|
||||
array(
|
||||
'id' => 'server',
|
||||
'type' => (string)$server_xml->gameq_query_name,
|
||||
'host' => $query_ip . ":" . $query_port,
|
||||
)
|
||||
);
|
||||
$gq = new \GameQ\GameQ();
|
||||
$gq->addServers($servers);
|
||||
$gq->setOption('timeout', 4);
|
||||
$gq->setOption('debug', FALSE);
|
||||
$gq->addFilter('normalise');
|
||||
$game = $gq->process();
|
||||
|
||||
if ( ! $game['server']['gq_online'] )
|
||||
{
|
||||
$running = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if( ! $running )
|
||||
if( $status_name !== "ONLINE" )
|
||||
{
|
||||
if (!isset($_GET['retry']))
|
||||
$retry = 0;
|
||||
else
|
||||
$retry = $_GET['retry'];
|
||||
|
||||
if ($retry >= 5)
|
||||
if ($status_name === "UNKNOWN")
|
||||
{
|
||||
echo "<p>".get_lang('server_running_not_responding')."
|
||||
<a href=?m=gamemanager&p=stop&home_id=".$home_id.
|
||||
"&ip=".$ip."&port=".
|
||||
$port.">".get_lang('already_running_stop_server').".</a></p>";
|
||||
echo "<table class='center'><tr><td><a href='?m=gamemanager&p=game_monitor&home_id-mod_id-ip-port=$home_id-$mod_id-$ip-$port'><< ".get_lang('back')."</a></td></tr></table>";
|
||||
print_failure(get_lang("agent_offline"));
|
||||
$view->refresh("?m=gamemanager&p=game_monitor&home_id-mod_id-ip-port=$home_id-$mod_id-$ip-$port",3);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($status_name === "UNRESPONSIVE")
|
||||
{
|
||||
$message = isset($agent_status['last_error']) && $agent_status['last_error'] !== "" ? $agent_status['last_error'] : "Server process exists but the game port is not ready.";
|
||||
print_failure(htmlentities($message));
|
||||
$view->refresh("?m=gamemanager&p=game_monitor&home_id-mod_id-ip-port=$home_id-$mod_id-$ip-$port",5);
|
||||
return;
|
||||
}
|
||||
|
||||
echo "</b>Retry #".$retry.".</b>";
|
||||
echo "<p class='note'>Server status: ".htmlentities($status_name).". Waiting for the game port to become ready.</p>";
|
||||
$retry++;
|
||||
print("<p class='note'>".get_lang('starting_server')."</p>");
|
||||
$view->refresh("?m=gamemanager&p=start&refresh&ip=$ip&port=$port&home_id=$home_id&mod_id=$mod_id&retry=".$retry,3);
|
||||
|
|
@ -266,12 +222,12 @@ function exec_ogp_module() {
|
|||
print_failure(get_lang('server_cant_stop'));
|
||||
$view->refresh("?m=gamemanager&p=game_monitor&home_id-mod_id-ip-port=". $home_id . "-". $mod_id . "-" . $ip . "-" . $port,3);
|
||||
}
|
||||
else
|
||||
{
|
||||
$screen_running = $remote->is_screen_running(OGP_SCREEN_TYPE_HOME,$home_id);
|
||||
if ( $screen_running == 1 )
|
||||
else
|
||||
{
|
||||
print("<p class='note'>".get_lang('restarting_server')."</p>");
|
||||
$agent_status = get_agent_server_status($remote, $server_xml, $home_id, $ip, $port, "STARTING");
|
||||
if ( is_agent_status_active($agent_status) )
|
||||
{
|
||||
print("<p class='note'>".get_lang('restarting_server')."</p>");
|
||||
$view->refresh("?m=gamemanager&p=restart&refresh&ip=$ip&port=$port&home_id=$home_id&mod_id=$mod_id",3);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -480,13 +480,21 @@ echo "<table id='servermonitor' class='tablesorter' data-sortlist='[[0,0],[3,1]]
|
|||
$displayIP = checkDisplayPublicIP($server_home['display_public_ip'], $ip);
|
||||
$address = "";
|
||||
|
||||
$screen_running = $remote->is_screen_running(OGP_SCREEN_TYPE_HOME,$server_home['home_id']) === 1;
|
||||
$agent_status = get_agent_server_status($remote, $server_xml, $server_home['home_id'], $server_home['ip'], $server_home['port']);
|
||||
$agent_state = isset($agent_status['status']) ? strtoupper($agent_status['status']) : "UNKNOWN";
|
||||
$screen_running = is_agent_status_active($agent_status);
|
||||
$update_in_progress = $remote->is_screen_running(OGP_SCREEN_TYPE_UPDATE,$server_home['home_id']) === 1;
|
||||
if($screen_running)
|
||||
{
|
||||
// Check if the screen running the server is running.
|
||||
$status = "online";
|
||||
$order = 1 + $j;
|
||||
if($agent_state !== "ONLINE")
|
||||
{
|
||||
$address = "<span class='note'>".htmlentities($agent_state)."</span>";
|
||||
if(isset($agent_status['last_error']) && $agent_status['last_error'] !== "")
|
||||
$address .= " <span class='failure'>".htmlentities($agent_status['last_error'])."</span>";
|
||||
}
|
||||
if ($server_xml->protocol == "lgsl")
|
||||
{
|
||||
$get_q_and_s = lgsl_port_conversion($query_name, $server_home['port'], "", "");
|
||||
|
|
@ -496,14 +504,17 @@ echo "<table id='servermonitor' class='tablesorter' data-sortlist='[[0,0],[3,1]]
|
|||
$q_port = $get_q_and_s['1'];
|
||||
//software port
|
||||
$s_port = $get_q_and_s['2'];
|
||||
$address = "<a href='" . lgsl_software_link($query_name, $query_ip, $c_port, $q_port, $s_port) . "' >Connect</a>";
|
||||
if($agent_state === "ONLINE")
|
||||
$address = "<a href='" . lgsl_software_link($query_name, $query_ip, $c_port, $q_port, $s_port) . "' >Connect</a>";
|
||||
|
||||
|
||||
}
|
||||
if ($server_xml->protocol == "teamspeak3")
|
||||
if ($server_xml->protocol == "teamspeak3" && $agent_state === "ONLINE")
|
||||
$address = "<a href='ts3server://" . $query_ip . ":" . $server_home['port'] . "'>".$displayIP.":".$server_home['port']."</a>";
|
||||
if($server_xml->protocol == "gameq" and $server_xml->installer == 'steamcmd')
|
||||
if($server_xml->protocol == "gameq" and $server_xml->installer == 'steamcmd' && $agent_state === "ONLINE")
|
||||
$address = "<a href='steam://connect/" . $query_ip . ":" . $server_home['port'] . "'>" . $displayIP . ":" . $server_home['port'] . "</a>";
|
||||
if($agent_state === "ONLINE" && isset($agent_status['query_port']) && $agent_status['query_port'] !== "" && empty($agent_status['query_port_listening']))
|
||||
$address .= " <span class='note'>Query info unavailable.</span>";
|
||||
$pos = $refresh->add("home.php?m=gamemanager&p=ref_servermonitor&type=cleared&home_id=". $server_home['home_id'] . "&mod_id=". $server_home['mod_id'] . "&ip=" . $server_home['ip'] . "&port=" . $server_home['port']);
|
||||
|
||||
if ($server_xml->protocol == "teamspeak3")
|
||||
|
|
|
|||
|
|
@ -175,79 +175,33 @@ function exec_ogp_module()
|
|||
</script>
|
||||
<?php
|
||||
|
||||
// If game is not supported by lgsl we skip the lgsl checks and
|
||||
// assume successfull start.
|
||||
if ( $home_info['use_nat'] == 1 )
|
||||
$query_ip = $home_info['agent_ip'];
|
||||
else
|
||||
$query_ip = $ip;
|
||||
$startup_timeout = isset($server_xml->startup_timeout) && is_numeric((string)$server_xml->startup_timeout) ? (int)$server_xml->startup_timeout : 180;
|
||||
$agent_status = get_agent_server_status($remote, $server_xml, $home_id, $ip, $port, "STARTING", $startup_timeout);
|
||||
$status_name = isset($agent_status['status']) ? strtoupper($agent_status['status']) : "UNKNOWN";
|
||||
|
||||
$running = $remote->is_screen_running(OGP_SCREEN_TYPE_HOME,$home_info['home_id']);
|
||||
|
||||
if ( $server_xml->lgsl_query_name )
|
||||
{
|
||||
require('protocol/lgsl/lgsl_protocol.php');
|
||||
$get_q_and_s = lgsl_port_conversion((string)$server_xml->lgsl_query_name, $port, "", "");
|
||||
|
||||
//Connection port
|
||||
$c_port = $get_q_and_s['0'];
|
||||
//query port
|
||||
$q_port = $get_q_and_s['1'];
|
||||
//software port
|
||||
$s_port = $get_q_and_s['2'];
|
||||
|
||||
$data = lgsl_query_live((string)$server_xml->lgsl_query_name, $query_ip, $c_port, $q_port, $s_port, "sa");
|
||||
|
||||
if ( $data['b']['status'] == "0" )
|
||||
{
|
||||
$running = FALSE;
|
||||
}
|
||||
}
|
||||
elseif ( $server_xml->gameq_query_name )
|
||||
{
|
||||
require_once 'protocol/GameQ/Autoloader.php';
|
||||
|
||||
$query_port = get_query_port($server_xml, $port);
|
||||
|
||||
$servers = array(
|
||||
array(
|
||||
'id' => 'server',
|
||||
'type' => (string)$server_xml->gameq_query_name,
|
||||
'host' => $query_ip . ":" . $query_port,
|
||||
)
|
||||
);
|
||||
$gq = new \GameQ\GameQ();
|
||||
$gq->addServers($servers);
|
||||
$gq->setOption('timeout', 4);
|
||||
$gq->setOption('debug', FALSE);
|
||||
$gq->addFilter('normalise');
|
||||
$game = $gq->process();
|
||||
|
||||
if ( ! $game['server']['gq_online'] )
|
||||
{
|
||||
$running = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if( ! $running )
|
||||
if( $status_name !== "ONLINE" )
|
||||
{
|
||||
if (!isset($_GET['retry']))
|
||||
$retry = 0;
|
||||
else
|
||||
$retry = $_GET['retry'];
|
||||
|
||||
if ($retry > 3)
|
||||
if ($status_name === "UNKNOWN")
|
||||
{
|
||||
//echo "<p>".get_lang('server_running_not_responding').
|
||||
// "<a href='?m=gamemanager&p=stop&home_id=$home_id&mod_id=$mod_id&ip=$ip&port=$port' >".
|
||||
// get_lang('already_running_stop_server').".</a></p>".
|
||||
//"<table class='center'><tr><td><a href='?m=gamemanager&p=game_monitor&home_id-mod_id-ip-port=$home_id-$mod_id-$ip-$port'><< ".
|
||||
$view->refresh("?m=gamemanager&p=game_monitor&home_id-mod_id-ip-port=$home_id-$mod_id-$ip-$port");
|
||||
//get_lang('back')."</a></td></tr></table>";
|
||||
return;
|
||||
print_failure(get_lang("agent_offline"));
|
||||
$view->refresh("?m=gamemanager&p=game_monitor&home_id-mod_id-ip-port=$home_id-$mod_id-$ip-$port",3);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($status_name === "UNRESPONSIVE")
|
||||
{
|
||||
$message = isset($agent_status['last_error']) && $agent_status['last_error'] !== "" ? $agent_status['last_error'] : "Server process exists but the game port is not ready.";
|
||||
print_failure(htmlentities($message));
|
||||
$view->refresh("?m=gamemanager&p=game_monitor&home_id-mod_id-ip-port=$home_id-$mod_id-$ip-$port",5);
|
||||
return;
|
||||
}
|
||||
|
||||
//echo "</b>Retry #".$retry.".</b>";
|
||||
echo "<p class='note'>Server status: ".htmlentities($status_name).". Waiting for the game port to become ready.</p>";
|
||||
$retry++;
|
||||
print("<p class='note'>".get_lang('starting_server')."</p>");
|
||||
$view->refresh("?m=gamemanager&p=start&refresh&ip=$ip&port=$port&home_id=$home_id&mod_id=$mod_id&retry=".$retry,3);
|
||||
|
|
|
|||
|
|
@ -99,10 +99,14 @@ function exec_ogp_module() {
|
|||
$query_port = "10011";
|
||||
}
|
||||
|
||||
$remote_retval = $remote->remote_stop_server($home_id,
|
||||
$ip, $port, $server_xml->control_protocol,
|
||||
$home_info['control_password'],$control_type, $home_path);
|
||||
$db->logger(get_lang_f('server_stopped', $home_info['home_name'] ) . "($ip:$port)");
|
||||
$remote_retval = $remote->remote_stop_server($home_id,
|
||||
$ip, $port, $server_xml->control_protocol,
|
||||
$home_info['control_password'],$control_type, $home_path);
|
||||
$agent_status = get_agent_server_status($remote, $server_xml, $home_id, $ip, $port, "STOPPING");
|
||||
if ($remote_retval === 1 && isset($agent_status['status']) && strtoupper($agent_status['status']) !== "OFFLINE") {
|
||||
$remote_retval = -2;
|
||||
}
|
||||
$db->logger(get_lang_f('server_stopped', $home_info['home_name'] ) . "($ip:$port)");
|
||||
$firewall_settings = $db->getFirewallSettings($home_info['remote_server_id']);
|
||||
if ( $remote_retval === 1 )
|
||||
{
|
||||
|
|
@ -137,9 +141,13 @@ function exec_ogp_module() {
|
|||
}
|
||||
elseif ( $remote_retval === 0 )
|
||||
{
|
||||
$remote_retval = $remote->remote_stop_server($home_info['home_id'],
|
||||
$ip, $port, $server_xml->control_protocol,"",$control_type,$home_path);
|
||||
if ($remote_retval === 1 )
|
||||
$remote_retval = $remote->remote_stop_server($home_info['home_id'],
|
||||
$ip, $port, $server_xml->control_protocol,"",$control_type,$home_path);
|
||||
$agent_status = get_agent_server_status($remote, $server_xml, $home_id, $ip, $port, "STOPPING");
|
||||
if ($remote_retval === 1 && isset($agent_status['status']) && strtoupper($agent_status['status']) !== "OFFLINE") {
|
||||
$remote_retval = -2;
|
||||
}
|
||||
if ($remote_retval === 1 )
|
||||
{
|
||||
print_success(get_lang_f("server_stopped",htmlentities($home_info['home_name'])));
|
||||
if ($firewall_settings['status'] == "enable")
|
||||
|
|
@ -176,8 +184,12 @@ function exec_ogp_module() {
|
|||
|
||||
if ( $remote_retval === 0 )
|
||||
print_failure(get_lang("agent_offline"));
|
||||
elseif ( $remote_retval !== 1 )
|
||||
print_failure("Error occurred on the remote host.");
|
||||
elseif ( $remote_retval !== 1 )
|
||||
{
|
||||
$status_name = isset($agent_status['status']) ? strtoupper($agent_status['status']) : "UNKNOWN";
|
||||
$message = isset($agent_status['last_error']) && $agent_status['last_error'] !== "" ? $agent_status['last_error'] : "Remote stop did not verify that the process/session and game port are stopped.";
|
||||
print_failure("Error occurred on the remote host. Agent status: ".htmlentities($status_name).". ".htmlentities($message));
|
||||
}
|
||||
}
|
||||
$view->refresh("?m=gamemanager&p=game_monitor&home_id-mod_id-ip-port=". $home_id . "-". $mod_id . "-" . $ip . "-" . $port,3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,23 +33,23 @@ function exec_ogp_module()
|
|||
|
||||
list($home_id, $mod_id, $ip, $port) = explode("-", $_GET['home_id-mod_id-ip-port']);
|
||||
$user_id = $_SESSION['user_id'];
|
||||
|
||||
|
||||
|
||||
|
||||
$isAdmin = $db->isAdmin( $user_id );
|
||||
if($isAdmin)
|
||||
if($isAdmin)
|
||||
$home_info = $db->getGameHome($home_id);
|
||||
else
|
||||
$home_info = $db->getUserGameHome($user_id,$home_id);
|
||||
|
||||
$current_mod_info = $home_info['mods'][$mod_id];
|
||||
|
||||
$current_mod_info = $home_info['mods'][$mod_id];
|
||||
$home_cfg_id = $current_mod_info['home_cfg_id'];
|
||||
$mod_cfg_id = $current_mod_info['mod_cfg_id'];
|
||||
|
||||
|
||||
if($home_cfg_id === null && $mod_cfg_id === null){
|
||||
print_failure(get_lang('invalid_game_mod_id'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ( $home_info === FALSE )
|
||||
{
|
||||
print_failure( get_lang("no_access_to_home") );
|
||||
|
|
@ -68,7 +68,7 @@ function exec_ogp_module()
|
|||
$remote = new OGPRemoteLibrary($home_info['agent_ip'],$home_info['agent_port'],$home_info['encryption_key'],$home_info['timeout']);
|
||||
|
||||
$home_log = "";
|
||||
|
||||
|
||||
if( isset( $server_xml->console_log ) )
|
||||
{
|
||||
$log_retval = $remote->get_log(OGP_SCREEN_TYPE_HOME,
|
||||
|
|
@ -104,72 +104,50 @@ function exec_ogp_module()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Using the refreshed class
|
||||
if( isset($_GET['refreshed']) )
|
||||
{
|
||||
echo "<pre class='log'>".htmlentities($home_log)."</pre>";
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "<h2>".htmlentities($home_info['home_name'])."</h2>";
|
||||
if($log_retval == 1)
|
||||
|
||||
// Using the refreshed class
|
||||
if( isset($_GET['refreshed']) )
|
||||
{
|
||||
require_once("includes/refreshed.php");
|
||||
|
||||
$control = '<form method="GET" >
|
||||
<input type="hidden" name="m" value="gamemanager" />
|
||||
<input type="hidden" name="p" value="log" />
|
||||
<input type="hidden" name="home_id-mod_id-ip-port" value="'.$_GET['home_id-mod_id-ip-port'].'" />';
|
||||
if(isset($_GET['setInterval']))
|
||||
$control .= "<input type='hidden' name='setInterval' value='" . $_GET['setInterval'] . "' />";
|
||||
if(isset($_GET['view_player_commands']))
|
||||
$control .= "<input type='hidden' name='view_player_commands' value='" . $_GET['view_player_commands'] . "' />";
|
||||
$control .= '<input type="submit" name="size" value="';
|
||||
if( isset( $_GET['size'] ) and $_GET['size'] == "+" )
|
||||
{
|
||||
$height = "100%";
|
||||
$control .= '-';
|
||||
}
|
||||
else
|
||||
{
|
||||
$height = "500px";
|
||||
$control .= '+';
|
||||
if (!headers_sent()) {
|
||||
header('Content-Type: text/plain; charset=UTF-8');
|
||||
}
|
||||
$control .= '" /></form>';
|
||||
|
||||
$intervals = array( "4s" => "4000",
|
||||
"8s" => "8000",
|
||||
"30s" => "30000",
|
||||
"2m" => "120000",
|
||||
"5m" => "300000" );
|
||||
|
||||
$intSel = '<form action="" method="GET" >
|
||||
<input type="hidden" name="m" value="gamemanager" />
|
||||
<input type="hidden" name="p" value="log" />
|
||||
<input type="hidden" name="home_id-mod_id-ip-port" value="'.$_GET['home_id-mod_id-ip-port'].'" />';
|
||||
if(isset($_GET['size']))
|
||||
$intSel .= "<input type='hidden' name='size' value='" . $_GET['size'] . "' />";
|
||||
if(isset($_GET['view_player_commands']))
|
||||
$intSel .= "<input type='hidden' name='view_player_commands' value='" . $_GET['view_player_commands'] . "' />";
|
||||
$intSel .= get_lang("refresh_interval") . ':<select name="setInterval" onchange="this.form.submit();">';
|
||||
foreach ((array)$intervals as $interval => $value )
|
||||
echo $home_log;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "<h2>".htmlentities($home_info['home_name'])."</h2>";
|
||||
if($log_retval == 1)
|
||||
{
|
||||
$selected = "";
|
||||
if ( isset( $_GET['setInterval'] ) AND $_GET['setInterval'] == $value )
|
||||
$selected = 'selected="selected"';
|
||||
$intSel .= '<option value="'.$value.'" '.$selected.' >'.$interval.'</option>';
|
||||
}
|
||||
$intSel .= "</select></form>";
|
||||
|
||||
$setInterval = isset($_GET['setInterval']) ? $_GET['setInterval'] : 4000;
|
||||
$refresh = new refreshed();
|
||||
$pos = $refresh->add("home.php?m=gamemanager&p=log&type=cleared&refreshed&home_id-mod_id-ip-port=". $_GET['home_id-mod_id-ip-port']);
|
||||
echo $refresh->getdiv($pos,"height:".$height.";overflow:auto;max-width:1600px;");
|
||||
?><script type="text/javascript">$(document).ready(function(){ <?php echo $refresh->build("$setInterval"); ?>} ); </script><?php
|
||||
echo "<table class='center' ><tr><td>$intSel</td><td>$control</td></tr></table>";
|
||||
if( ($server_xml->control_protocol and preg_match("/^r?l?con2?$/", $server_xml->control_protocol)) OR
|
||||
($server_xml->gameq_query_name and $server_xml->gameq_query_name == "minecraft") OR
|
||||
$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>';
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
(function(){
|
||||
var logBox = document.getElementById('live-server-log');
|
||||
if (!logBox) return;
|
||||
function isAtBottom() {
|
||||
return (logBox.scrollTop + logBox.clientHeight) >= (logBox.scrollHeight - 24);
|
||||
}
|
||||
function refreshLog() {
|
||||
var shouldScroll = isAtBottom();
|
||||
fetch('<?php echo $log_url; ?>', {cache: 'no-store'})
|
||||
.then(function(response){ return response.text(); })
|
||||
.then(function(text){
|
||||
logBox.value = text;
|
||||
if (shouldScroll) {
|
||||
logBox.scrollTop = logBox.scrollHeight;
|
||||
}
|
||||
})
|
||||
.catch(function(){});
|
||||
}
|
||||
logBox.scrollTop = logBox.scrollHeight;
|
||||
window.setInterval(refreshLog, 4000);
|
||||
})();
|
||||
</script>
|
||||
<?php
|
||||
if( ($server_xml->control_protocol and preg_match("/^r?l?con2?$/", $server_xml->control_protocol)) OR
|
||||
($server_xml->gameq_query_name and $server_xml->gameq_query_name == "minecraft") OR
|
||||
($server_xml->lgsl_query_name and $server_xml->lgsl_query_name == "7dtd") )
|
||||
require('modules/gamemanager/rcon.php');
|
||||
}
|
||||
|
|
|
|||
810
SCHEDULER_ACTIONS_DESIGN.md
Normal file
810
SCHEDULER_ACTIONS_DESIGN.md
Normal file
|
|
@ -0,0 +1,810 @@
|
|||
# GSP Scheduler Actions Design
|
||||
|
||||
## Scope
|
||||
|
||||
This is an investigation and design report only. It does not implement code.
|
||||
|
||||
The goal is to redesign GSP's Scheduler / CRON feature into a safer, more useful automation system for game hosting customers and administrators.
|
||||
|
||||
Repository layout reviewed:
|
||||
|
||||
- `Agent-Windows`
|
||||
- `Agent_Linux` (the Linux agent directory currently uses an underscore in this repository)
|
||||
- `Panel`
|
||||
- `Website`
|
||||
|
||||
## 1. Current Scheduler Module Findings
|
||||
|
||||
### Files inspected
|
||||
|
||||
Panel Scheduler module:
|
||||
|
||||
- `Panel/modules/cron/module.php`
|
||||
- `Panel/modules/cron/navigation.xml`
|
||||
- `Panel/modules/cron/cron.php`
|
||||
- `Panel/modules/cron/user_cron.php`
|
||||
- `Panel/modules/cron/shared_cron_functions.php`
|
||||
- `Panel/modules/cron/events.php`
|
||||
- `Panel/modules/cron/thetime.php`
|
||||
|
||||
Panel remote/API integration:
|
||||
|
||||
- `Panel/includes/lib_remote.php`
|
||||
- `Panel/includes/api_functions.php`
|
||||
- `Panel/modules/gamemanager/start_server.php`
|
||||
- `Panel/modules/gamemanager/stop_server.php`
|
||||
- `Panel/modules/gamemanager/restart_server.php`
|
||||
- `Panel/modules/gamemanager/update_actions.php`
|
||||
- `Panel/modules/gamemanager/rcon.php`
|
||||
- `Panel/modules/addonsmanager/server_content_actions.php`
|
||||
|
||||
Agent scheduler implementation:
|
||||
|
||||
- `Agent_Linux/ogp_agent.pl`
|
||||
- `Agent-Windows/ogp_agent.pl`
|
||||
|
||||
### Current database tables used
|
||||
|
||||
The current Scheduler module does not appear to own database tables. Module metadata has:
|
||||
|
||||
- `Panel/modules/cron/module.php`
|
||||
- `$db_version = 0`
|
||||
|
||||
Scheduled jobs are stored on each agent in a flat file:
|
||||
|
||||
- Linux: `AGENT_RUN_DIR/Schedule/scheduler.tasks`
|
||||
- Linux: `AGENT_RUN_DIR/Schedule/scheduler.pid`
|
||||
- Linux: `AGENT_RUN_DIR/Schedule/scheduler.log`
|
||||
- Windows/Cygwin: `AGENT_RUN_DIR/scheduler.tasks`
|
||||
- Windows/Cygwin: `AGENT_RUN_DIR/scheduler.pid`
|
||||
- Windows/Cygwin: `AGENT_RUN_DIR/scheduler.log`
|
||||
|
||||
This means the agent is currently the storage location for task definitions, and the Panel reconstructs task lists by asking each agent for its task file.
|
||||
|
||||
### Current actions
|
||||
|
||||
Current customer-visible scheduled actions from `get_action_selector()`:
|
||||
|
||||
- `restart`
|
||||
- `stop`
|
||||
- `start`
|
||||
- `steam_auto_update` when the game XML installer is `steamcmd`
|
||||
|
||||
Additional server content actions are appended when `addonsmanager` is installed:
|
||||
|
||||
- `server_content_check_updates`
|
||||
- `server_content_check_workshop_updates`
|
||||
- `server_content_install_updates_if_stopped`
|
||||
- `server_content_install_updates_next_restart`
|
||||
- `server_content_install_updates_now`
|
||||
- `server_content_install_updates_and_restart`
|
||||
- `server_content_notify_updates_only`
|
||||
- `server_content_update_all`
|
||||
- `server_content_validate_files`
|
||||
- `server_content_backup_before_update`
|
||||
|
||||
Admin-only raw command path:
|
||||
|
||||
- `Panel/modules/cron/cron.php` exposes a second form where an admin selects a remote server and enters a raw shell command.
|
||||
|
||||
### How tasks are created
|
||||
|
||||
Customer task creation path:
|
||||
|
||||
1. User opens `Panel/modules/cron/user_cron.php`.
|
||||
2. User selects a game server and action.
|
||||
3. Panel validates the five CRON fields using `checkCronInput()`.
|
||||
4. Panel calls `build_cron_scheduler_command()`.
|
||||
5. The command is built as a `wget` callback to `ogp_api.php`.
|
||||
6. Panel sends the whole CRON line to the agent through `scheduler_add_task()`.
|
||||
7. Agent appends the task line to `scheduler.tasks`.
|
||||
8. Agent restarts its scheduler process.
|
||||
|
||||
Admin task creation path:
|
||||
|
||||
1. Admin opens `Panel/modules/cron/cron.php`.
|
||||
2. Admin can use the same server/action selector.
|
||||
3. Admin can also enter a raw command for a remote server.
|
||||
4. Panel writes the raw command into the agent task file.
|
||||
|
||||
Current scheduled API callback examples:
|
||||
|
||||
```text
|
||||
wget -qO- "<panel>/ogp_api.php?gamemanager/stop&token=<token>&ip=<ip>&port=<port>&mod_key=<mod_key>" --no-check-certificate > /dev/null 2>&1
|
||||
```
|
||||
|
||||
```text
|
||||
wget -qO- "<panel>/ogp_api.php?server_content/run_scheduled_action&token=<token>&home_id=<home_id>&action=<action>&options=<json>" --no-check-certificate > /dev/null 2>&1
|
||||
```
|
||||
|
||||
### How tasks execute
|
||||
|
||||
Both agents use Perl `Schedule::Cron`.
|
||||
|
||||
Agent startup:
|
||||
|
||||
- Stops prior scheduler process using `scheduler_stop()`.
|
||||
- Creates a `Schedule::Cron` object.
|
||||
- Adds a read/reload task that runs every second:
|
||||
- `* * * * * *`
|
||||
- Starts scheduler detached with `scheduler.pid`.
|
||||
|
||||
Agent task reload:
|
||||
|
||||
- `scheduler_read_tasks()` opens `scheduler.tasks`.
|
||||
- It clears the in-memory timetable.
|
||||
- It splits each line into five CRON fields plus command args.
|
||||
- If args start with `%ACTION`, it uses `scheduler_server_action()`.
|
||||
- Otherwise it adds a generic shell command task.
|
||||
|
||||
Current Panel-generated jobs are generic shell commands, not `%ACTION` jobs. They execute through:
|
||||
|
||||
- `scheduler_dispatcher()`
|
||||
- backtick execution of the scheduled command
|
||||
- append to `scheduler.log`
|
||||
|
||||
The older `%ACTION=start|stop|restart` direct-agent scheduler path still exists but does not appear to be the primary current Panel path.
|
||||
|
||||
### How task results are logged
|
||||
|
||||
Agent logging:
|
||||
|
||||
- `scheduler_log_events()` appends plain text to `scheduler.log`.
|
||||
- Generic commands log:
|
||||
- the command text
|
||||
- any response text
|
||||
|
||||
Panel viewing:
|
||||
|
||||
- `Panel/modules/cron/events.php` reads `scheduler.log` from the selected remote server.
|
||||
- It refreshes the log area periodically.
|
||||
|
||||
Limitations:
|
||||
|
||||
- No structured per-task run records.
|
||||
- No status model such as pending/running/success/failed/skipped.
|
||||
- No reliable per-run output attached to a task ID.
|
||||
- No last run / next run / duration / exit code storage in the Panel DB.
|
||||
- `wget` callbacks redirect output to `/dev/null`, so useful API responses are discarded.
|
||||
|
||||
### Current limitations and bugs
|
||||
|
||||
1. No Scheduler-owned database tables.
|
||||
2. Tasks are stored per agent, so offline agents make task state invisible or stale.
|
||||
3. Tasks contain API tokens in plain text inside agent task files.
|
||||
4. Generic command scheduler can run arbitrary shell commands.
|
||||
5. Admin raw command scheduling is powerful and should remain admin-only or be removed from the normal Scheduler UI.
|
||||
6. Current customer tasks call the Panel through `wget`, so task execution depends on the agent reaching the Panel HTTP URL.
|
||||
7. `--no-check-certificate` weakens TLS verification.
|
||||
8. Task output is discarded for Panel API callbacks.
|
||||
9. No retry policy.
|
||||
10. No overlap prevention.
|
||||
11. No conflict prevention, such as update and restart at the same time.
|
||||
12. No job lock per game server.
|
||||
13. No missed-run handling after agent downtime.
|
||||
14. No clear timezone UX.
|
||||
15. Admin and customer scheduling models are mixed in the same module.
|
||||
16. Server content scheduled actions include duplicates and placeholders.
|
||||
17. Some action names are not customer-friendly.
|
||||
18. There is no typed argument system for warnings, backup paths, retention, RCON command allowlists, or wipe options.
|
||||
19. There is no first-class notification support.
|
||||
20. Linux and Windows store scheduler files in different relative locations.
|
||||
|
||||
## 2. Current Action Review
|
||||
|
||||
| Action | Keep/Remove/Admin Only | Why | Security Risk | Agent Support | Notes |
|
||||
|---|---|---|---|---|---|
|
||||
| `restart` | Keep | Core hosting feature. | Low if implemented through safe action. | Existing Panel API and agent restart support. | Should support warnings, save-world, lock, timeout, and result logging. |
|
||||
| `stop` | Keep | Useful for scheduled shutdown windows and cost/resource control. | Low. | Existing Panel API and agent stop support. | Should verify stopped state through agent status. |
|
||||
| `start` | Keep | Useful after maintenance windows. | Low. | Existing Panel API and agent start support. | Should show STARTING/ONLINE result, not only command fired. |
|
||||
| `steam_auto_update` | Keep, rename | Useful but name is technical. | Medium due Steam credentials/update side effects. | Existing `steam_cmd` update path. | Rename to `update_server_files`; require game XML installer support. |
|
||||
| `server_content_check_updates` | Keep internally, remove from customer dropdown for now | Useful as backend action but unclear to customers. | Low. | Partial Panel support. | Replace with clearer `check_content_updates`. |
|
||||
| `server_content_check_workshop_updates` | Keep internally, remove from customer dropdown for now | Useful once Workshop system is mature. | Low/medium. | Partial support. | Expose later as `check_workshop_updates`. |
|
||||
| `server_content_install_updates_if_stopped` | Keep internally | Safe behavior for automatic content updates. | Low. | Panel support. | Customer label should be `Update content when stopped`. |
|
||||
| `server_content_install_updates_next_restart` | Keep internally | Useful queued-update pattern. | Low. | Panel support. | Needs real next-restart integration. |
|
||||
| `server_content_install_updates_now` | Keep advanced customer/admin | Updates while server may be running can break files. | Medium. | Partial support. | Gate by game support and require warning. |
|
||||
| `server_content_install_updates_and_restart` | Keep advanced customer/admin | Very useful but needs locking and warnings. | Medium. | Partial support. | Should become `update_mods_and_restart`. |
|
||||
| `server_content_update_workshop` | Remove from dropdown; keep as internal alias | Duplicate with Workshop update action. | Medium. | Partial support. | Hide until Workshop redesign is implemented. |
|
||||
| `server_content_update_all` | Remove/merge | Duplicate with install/update all. | Medium. | Partial support. | Replace with one clear `update_all_content`. |
|
||||
| `server_content_notify_updates_only` | Remove for now | Name suggests notification but no notification system exists. | Low. | Partial check-only path. | Reintroduce after notifications exist. |
|
||||
| `server_content_validate_files` | Keep admin/advanced | Useful repair/validate action. | Medium. | Partial support via generic script action. | Rename to `validate_content_files`; game support required. |
|
||||
| `server_content_backup_before_update` | Remove or redesign | Currently sets an option but there is no clear backup implementation in that path. | Medium due false confidence. | Incomplete. | Replace with first-class backup action and update workflow option. |
|
||||
| Raw remote shell command | Admin only or remove from normal UI | Powerful but dangerous. | High. | Existing generic scheduler execution. | Should not be available to customers. Should be audited if kept. |
|
||||
| Legacy `%ACTION=start` | Remove/deprecate | Current Panel uses API callbacks. | Low. | Agent support exists. | Keep only during migration if old task files contain it. |
|
||||
| Legacy `%ACTION=stop` | Remove/deprecate | Same as above. | Low. | Agent support exists. | Migrate to action registry. |
|
||||
| Legacy `%ACTION=restart` | Remove/deprecate | Same as above. | Low. | Agent support exists. | Migrate to action registry. |
|
||||
|
||||
## 3. Competitor Feature Research
|
||||
|
||||
Sources reviewed:
|
||||
|
||||
- Nitrado automated tasks guide: https://server.nitrado.net/guides/automated-tasks-en
|
||||
- Nitrado backup guide/FAQ: https://server.nitrado.net/en-US/guides/how-to-manage-and-restore-nitrado-server-backups/
|
||||
- BisectHosting Starbase schedules: https://help.bisecthosting.com/hc/en-us/articles/40101097661083-How-to-Schedule-Tasks-on-the-Starbase-panel
|
||||
- ZAP-Hosting scheduled tasks: https://zap-hosting.com/guides/docs/gameserver-scheduled-tasks
|
||||
- Pterodactyl client schedules API docs: https://pterodactyl-panel.mintlify.app/api/client/schedules
|
||||
- Shockbyte backups guide: https://shockbyte.com/help/knowledgebase/articles/how-to-backup-your-server-files
|
||||
- PingPerfect scheduled server messages guide: https://pingperfect.com/knowledgebase/706/7-Days-to-Die--Scheduled-Server-Messages.html
|
||||
- Host Havoc scheduled backups guide: https://hosthavoc.com/billing/knowledgebase/479/Creating-Scheduled-Backups.html
|
||||
- GTXGaming Rust restart warning task guide: https://help.gtxgaming.co.uk/en/article/how-to-setup-restart-tasks-with-messages-for-your-rust-server-15zwnyr/
|
||||
|
||||
Common commercial features:
|
||||
|
||||
- Scheduled start/stop/restart.
|
||||
- Scheduled backups.
|
||||
- Scheduled console/RCON commands.
|
||||
- Restart warning messages.
|
||||
- Task offsets within a schedule.
|
||||
- Backup retention limits.
|
||||
- Restart-only-if-online option.
|
||||
- Manual and automatic backup creation.
|
||||
- Custom task scheduling.
|
||||
- Game-specific tasks such as Rust wipes or server message tools.
|
||||
|
||||
Notable competitor patterns:
|
||||
|
||||
- Nitrado exposes simple automated power tasks: restart, start, stop. It also has automatic backups, but docs note timezone issues and game-specific backup behavior.
|
||||
- BisectHosting Starbase schedules support separate schedules and tasks, including power actions and command tasks with time offsets.
|
||||
- Pterodactyl's design is strong: schedules have multiple ordered tasks, time offsets, power actions, command actions, backup actions, `only_when_online`, and continue-on-failure behavior.
|
||||
- ZAP-Hosting exposes start/stop/restart, restart-if-online, create backup, and execute command, with rate limits.
|
||||
- Shockbyte emphasizes scheduled backup intervals and backup slot/auto-replace retention.
|
||||
- PingPerfect supports scheduled messages and Console/RCON commands for games like 7 Days to Die.
|
||||
- GTXGaming documents restart warnings/countdowns for Rust.
|
||||
|
||||
What GSP can do better:
|
||||
|
||||
- Use typed, safe game-aware actions instead of raw commands.
|
||||
- Provide prebuilt restart workflows with save-world and warning steps.
|
||||
- Tie Workshop/mod updates into the Scheduler.
|
||||
- Add per-task locks and conflict prevention.
|
||||
- Add structured logs and visible success/failure.
|
||||
- Add notifications through Discord/email/panel.
|
||||
- Add game XML capability detection so users only see actions that work.
|
||||
- Add maintenance windows and "run when empty" automation.
|
||||
- Add resource-based triggers using existing status/resource collection work.
|
||||
|
||||
## 4. Recommended GSP Scheduler Actions
|
||||
|
||||
### Customer-safe actions
|
||||
|
||||
- Restart server.
|
||||
- Stop server.
|
||||
- Start server.
|
||||
- Backup server.
|
||||
- Backup selected folders.
|
||||
- Update Workshop mods.
|
||||
- Update server content.
|
||||
- Send warning message.
|
||||
- Run allowed RCON command.
|
||||
- Rotate logs.
|
||||
- Delete old logs using admin-defined retention limits.
|
||||
- Save world, if the game supports it.
|
||||
- Check server status.
|
||||
- Auto-restart if crashed.
|
||||
|
||||
### Advanced customer actions
|
||||
|
||||
- Scheduled wipe/reset for supported games.
|
||||
- Validate/repair server files.
|
||||
- Update SteamCMD game files.
|
||||
- Clone backup to another server.
|
||||
- Restore backup.
|
||||
- Update mods and restart.
|
||||
- Restart when player count is zero for X minutes.
|
||||
- Restart if memory too high for X minutes.
|
||||
- Restart if CPU stuck/high for X minutes.
|
||||
- Scheduled config file replacement from approved templates.
|
||||
- Scheduled database backup where applicable.
|
||||
|
||||
### Admin-only actions
|
||||
|
||||
- Arbitrary shell command.
|
||||
- Raw script execution.
|
||||
- Permission repair.
|
||||
- Force kill process/session.
|
||||
- Agent/node maintenance.
|
||||
- Cleanup storage outside a server home.
|
||||
- Clear global Workshop cache.
|
||||
- Repair file ownership.
|
||||
- Restart agent.
|
||||
- Reboot node.
|
||||
- Run panel update/maintenance.
|
||||
|
||||
## 5. Proposed Action System
|
||||
|
||||
Replace free-form action lists with a typed action registry.
|
||||
|
||||
Each action definition should include:
|
||||
|
||||
- `action_key`
|
||||
- `display_name`
|
||||
- `description`
|
||||
- `category`
|
||||
- `allowed_roles`
|
||||
- `required_permissions`
|
||||
- `supported_os`
|
||||
- `required_agent_capability`
|
||||
- `requires_game_running`
|
||||
- `requires_game_stopped`
|
||||
- `requires_rcon`
|
||||
- `requires_workshop_support`
|
||||
- `requires_steamcmd`
|
||||
- `arguments_schema`
|
||||
- `validation_rules`
|
||||
- `timeout_seconds`
|
||||
- `retry_policy`
|
||||
- `overlap_policy`
|
||||
- `conflict_group`
|
||||
- `log_policy`
|
||||
- `notification_events`
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
scheduled_actions:
|
||||
restart_server:
|
||||
display_name: Restart Server
|
||||
role: customer
|
||||
agent_action: stop_wait_start
|
||||
required_permissions: [server.power.restart]
|
||||
args:
|
||||
warning_minutes:
|
||||
type: integer
|
||||
min: 0
|
||||
max: 60
|
||||
default: 5
|
||||
warning_message:
|
||||
type: string
|
||||
max_length: 160
|
||||
default: "Server restart in {minutes} minutes."
|
||||
save_world:
|
||||
type: boolean
|
||||
default: true
|
||||
timeout_seconds: 600
|
||||
conflict_group: server_power
|
||||
overlap_policy: skip_if_running
|
||||
```
|
||||
|
||||
### Recommended schedule model
|
||||
|
||||
Move from "one CRON line equals one command" to:
|
||||
|
||||
- Schedule:
|
||||
- name
|
||||
- cron expression or interval
|
||||
- timezone
|
||||
- enabled
|
||||
- only_when_online
|
||||
- missed_run_policy
|
||||
|
||||
- Tasks:
|
||||
- ordered tasks within a schedule
|
||||
- action key
|
||||
- arguments
|
||||
- time offset
|
||||
- continue on failure
|
||||
|
||||
This matches the strongest commercial pattern and allows:
|
||||
|
||||
- 10 minutes before restart: send warning.
|
||||
- 5 minutes before restart: save world.
|
||||
- At restart time: restart server.
|
||||
- 5 minutes after restart: send Discord notification.
|
||||
|
||||
### Suggested DB tables
|
||||
|
||||
`gsp_schedules`
|
||||
|
||||
- `id`
|
||||
- `home_id`
|
||||
- `remote_server_id`
|
||||
- `name`
|
||||
- `cron_minute`
|
||||
- `cron_hour`
|
||||
- `cron_day_of_month`
|
||||
- `cron_month`
|
||||
- `cron_day_of_week`
|
||||
- `timezone`
|
||||
- `enabled`
|
||||
- `only_when_online`
|
||||
- `missed_run_policy`
|
||||
- `max_runtime_seconds`
|
||||
- `created_by`
|
||||
- `created_at`
|
||||
- `updated_at`
|
||||
|
||||
`gsp_schedule_tasks`
|
||||
|
||||
- `id`
|
||||
- `schedule_id`
|
||||
- `sort_order`
|
||||
- `time_offset_seconds`
|
||||
- `action_key`
|
||||
- `arguments_json`
|
||||
- `continue_on_failure`
|
||||
- `enabled`
|
||||
- `created_at`
|
||||
- `updated_at`
|
||||
|
||||
`gsp_schedule_runs`
|
||||
|
||||
- `id`
|
||||
- `schedule_id`
|
||||
- `home_id`
|
||||
- `status`
|
||||
- `scheduled_for`
|
||||
- `started_at`
|
||||
- `finished_at`
|
||||
- `duration_seconds`
|
||||
- `trigger`
|
||||
- `last_error`
|
||||
|
||||
`gsp_schedule_task_runs`
|
||||
|
||||
- `id`
|
||||
- `schedule_run_id`
|
||||
- `schedule_task_id`
|
||||
- `action_key`
|
||||
- `status`
|
||||
- `started_at`
|
||||
- `finished_at`
|
||||
- `exit_code`
|
||||
- `message`
|
||||
- `error`
|
||||
- `log_path`
|
||||
- `output_excerpt`
|
||||
|
||||
## 6. XML Integration
|
||||
|
||||
Game XML should declare game-specific Scheduler support.
|
||||
|
||||
Example:
|
||||
|
||||
```xml
|
||||
<scheduler_support>
|
||||
<action key="restart" enabled="1" />
|
||||
<action key="rcon_warning" enabled="1" />
|
||||
<action key="world_save" enabled="1">
|
||||
<command>save</command>
|
||||
</action>
|
||||
<action key="workshop_update" enabled="1" />
|
||||
<action key="wipe" enabled="1">
|
||||
<strategy>rust_wipe</strategy>
|
||||
</action>
|
||||
</scheduler_support>
|
||||
```
|
||||
|
||||
Global actions:
|
||||
|
||||
- Start server.
|
||||
- Stop server.
|
||||
- Restart server.
|
||||
- Backup server files.
|
||||
- Rotate logs.
|
||||
- Delete old backups/logs.
|
||||
- Check status.
|
||||
|
||||
Game-specific actions:
|
||||
|
||||
- Send RCON warning.
|
||||
- Save world.
|
||||
- Run console command.
|
||||
- Workshop update.
|
||||
- Mod update.
|
||||
- Wipe/reset.
|
||||
- Database backup.
|
||||
- Validate files.
|
||||
|
||||
Actions requiring RCON:
|
||||
|
||||
- Warning message.
|
||||
- Save world.
|
||||
- Player-count-aware empty restart if query is not enough.
|
||||
- Allowed RCON command.
|
||||
- Game-specific graceful shutdown.
|
||||
|
||||
Actions requiring SteamCMD:
|
||||
|
||||
- Update SteamCMD game files.
|
||||
- Validate/repair Steam game files.
|
||||
|
||||
Actions requiring Workshop support:
|
||||
|
||||
- Update Workshop mods.
|
||||
- Repair Workshop mods.
|
||||
- Update mods and restart.
|
||||
|
||||
Actions requiring backup support:
|
||||
|
||||
- Backup server.
|
||||
- Backup selected folders.
|
||||
- Restore backup.
|
||||
- Clone backup.
|
||||
|
||||
## 7. Agent Integration
|
||||
|
||||
### Preferred direction
|
||||
|
||||
The agent should execute typed scheduled actions, not raw customer shell text.
|
||||
|
||||
New agent methods could be:
|
||||
|
||||
- `scheduler_action_start(home_id, action_manifest_json)`
|
||||
- `scheduler_action_status(home_id, action_run_id)`
|
||||
- `scheduler_action_log(home_id, action_run_id, offset)`
|
||||
- `scheduler_action_cancel(home_id, action_run_id)`
|
||||
|
||||
The Panel should store schedules and send due actions to agents, or the agent should receive a structured schedule manifest from Panel. The cleanest long-term design is Panel-owned schedules plus an agent-side runner for actions.
|
||||
|
||||
### Start/stop/restart
|
||||
|
||||
Agent should:
|
||||
|
||||
- Use existing start/stop/restart functions.
|
||||
- Use the new agent status model as source of truth.
|
||||
- Wait for state transitions.
|
||||
- Return structured result.
|
||||
|
||||
Restart should:
|
||||
|
||||
1. Optional RCON warning.
|
||||
2. Optional save-world.
|
||||
3. Stop.
|
||||
4. Wait configured seconds.
|
||||
5. Start.
|
||||
6. Poll until STARTING/ONLINE/UNRESPONSIVE.
|
||||
|
||||
### Backup
|
||||
|
||||
Agent should:
|
||||
|
||||
- Create compressed archives through a typed backup action.
|
||||
- Support include/exclude folders from safe config.
|
||||
- Store backup manifests.
|
||||
- Enforce retention.
|
||||
- Avoid backing up transient cache/log folders unless configured.
|
||||
|
||||
### Update
|
||||
|
||||
Agent should:
|
||||
|
||||
- Run SteamCMD update or server content update through typed job actions.
|
||||
- Avoid overlapping update with running backup/restart.
|
||||
- Mark restart required when applicable.
|
||||
|
||||
### RCON/console command
|
||||
|
||||
Agent should:
|
||||
|
||||
- Use existing `send_rcon_command` support.
|
||||
- Validate commands against action rules.
|
||||
- Log command and response.
|
||||
- Redact credentials.
|
||||
|
||||
Customer-safe RCON should use templates:
|
||||
|
||||
- `say {message}`
|
||||
- `save`
|
||||
- `save-all`
|
||||
- game-specific warning command
|
||||
|
||||
Raw RCON text should be advanced/admin controlled.
|
||||
|
||||
### Mod update
|
||||
|
||||
Agent should:
|
||||
|
||||
- Run Workshop/server-content job runner from the Workshop design.
|
||||
- Return job status and logs.
|
||||
- Mark restart required.
|
||||
|
||||
### Log cleanup
|
||||
|
||||
Agent should:
|
||||
|
||||
- Delete only configured log paths.
|
||||
- Enforce age/size limits.
|
||||
- Log every removed path count/bytes.
|
||||
|
||||
### Status/resource actions
|
||||
|
||||
Agent should:
|
||||
|
||||
- Check process/session/port status.
|
||||
- Optionally check memory/CPU samples.
|
||||
- Execute conditional restart only after threshold duration.
|
||||
|
||||
### Timeouts and failure reporting
|
||||
|
||||
Every action should have:
|
||||
|
||||
- timeout
|
||||
- retry count
|
||||
- retry delay
|
||||
- result status
|
||||
- error message
|
||||
- log excerpt
|
||||
- correlation ID
|
||||
|
||||
## 8. Task Logs and User Feedback
|
||||
|
||||
Recommended run statuses:
|
||||
|
||||
- `pending`
|
||||
- `running`
|
||||
- `success`
|
||||
- `failed`
|
||||
- `skipped`
|
||||
- `canceled`
|
||||
- `timed_out`
|
||||
|
||||
The UI should show:
|
||||
|
||||
- schedule name
|
||||
- enabled/disabled
|
||||
- next run time
|
||||
- last run time
|
||||
- last status
|
||||
- last duration
|
||||
- current running task
|
||||
- output log
|
||||
- error message
|
||||
- retry count
|
||||
|
||||
Run details should show:
|
||||
|
||||
- each task in the schedule
|
||||
- action arguments summary
|
||||
- start time
|
||||
- finish time
|
||||
- result
|
||||
- output/log
|
||||
|
||||
Do not rely only on `scheduler.log`.
|
||||
|
||||
## 9. Notifications
|
||||
|
||||
Supported notification channels:
|
||||
|
||||
- Panel notification.
|
||||
- Email.
|
||||
- Discord webhook.
|
||||
- Generic webhook later.
|
||||
|
||||
Notification events:
|
||||
|
||||
- Before restart.
|
||||
- After restart.
|
||||
- Backup succeeded.
|
||||
- Backup failed.
|
||||
- Update available.
|
||||
- Update installed.
|
||||
- Task skipped because server was offline/running.
|
||||
- Task failed.
|
||||
- Disk retention cleanup ran.
|
||||
|
||||
Security:
|
||||
|
||||
- Webhook URLs must be stored securely.
|
||||
- Do not expose tokens in task logs.
|
||||
- Customers should not be able to send arbitrary webhooks from shared infrastructure unless allowed by policy.
|
||||
|
||||
Pre-restart warning types:
|
||||
|
||||
- RCON in-game message.
|
||||
- Console command.
|
||||
- Discord/webhook message.
|
||||
- Panel notification.
|
||||
|
||||
## 10. Implementation Phases
|
||||
|
||||
### Phase 1: Inventory/report only
|
||||
|
||||
- Complete this report.
|
||||
- Do not modify code.
|
||||
|
||||
### Phase 2: Remove or hide useless actions
|
||||
|
||||
- Hide duplicate server-content actions from customer dropdown.
|
||||
- Keep internal aliases for backward compatibility.
|
||||
- Hide `server_content_backup_before_update` until real backup exists.
|
||||
- Keep raw remote command admin-only.
|
||||
|
||||
### Phase 3: Safe action registry
|
||||
|
||||
- Add PHP action registry.
|
||||
- Define roles, permissions, arguments, validation, and display names.
|
||||
- Replace hardcoded dropdown arrays.
|
||||
|
||||
### Phase 4: Task logging
|
||||
|
||||
- Add schedule/task/run tables.
|
||||
- Store run status and results.
|
||||
- Keep agent `scheduler.log` as low-level debug only.
|
||||
|
||||
### Phase 5: Restart/backup/update actions
|
||||
|
||||
- Implement typed restart with warning/save-world hooks.
|
||||
- Implement first-class server backup action.
|
||||
- Implement update server files action.
|
||||
|
||||
### Phase 6: RCON warnings
|
||||
|
||||
- Add game XML `scheduler_support`.
|
||||
- Add allowed warning/save commands.
|
||||
- Add command templates and validation.
|
||||
|
||||
### Phase 7: Workshop update integration
|
||||
|
||||
- Integrate with the redesigned Workshop/server-content job system.
|
||||
- Add update mods and update mods then restart workflows.
|
||||
|
||||
### Phase 8: Notifications
|
||||
|
||||
- Add panel notifications.
|
||||
- Add Discord webhook.
|
||||
- Add email.
|
||||
|
||||
### Phase 9: Commercial polish
|
||||
|
||||
- Multi-task schedules with offsets.
|
||||
- Clone schedule to another server.
|
||||
- Maintenance window mode.
|
||||
- Conditional empty-server restart.
|
||||
- Resource threshold triggers.
|
||||
- Missed-run handling.
|
||||
- Conflict and overlap visualization.
|
||||
|
||||
## 11. Final Recommendation
|
||||
|
||||
### Remove or hide
|
||||
|
||||
- Hide raw server-content internal actions from customer dropdown.
|
||||
- Remove customer-facing `server_content_notify_updates_only` until notifications exist.
|
||||
- Remove customer-facing `server_content_backup_before_update` until backup is real.
|
||||
- Merge duplicate update actions into clear labels.
|
||||
- Deprecate legacy `%ACTION=` task format after migration.
|
||||
|
||||
### Keep
|
||||
|
||||
- Start server.
|
||||
- Stop server.
|
||||
- Restart server.
|
||||
- SteamCMD update, renamed to `Update server files`.
|
||||
- Server content / Workshop update, once the Workshop system is mature.
|
||||
- Admin raw command only behind explicit admin permissions.
|
||||
|
||||
### Build first
|
||||
|
||||
1. Typed action registry.
|
||||
2. DB-backed schedules and run logs.
|
||||
3. Restart server with warning and optional save-world.
|
||||
4. Backup server with retention.
|
||||
5. Update server files.
|
||||
6. Update Workshop mods.
|
||||
7. Notifications.
|
||||
|
||||
### Admin-only
|
||||
|
||||
- Shell command.
|
||||
- Raw script execution.
|
||||
- Force kill.
|
||||
- Permission repair.
|
||||
- Node cleanup.
|
||||
- Agent restart/reboot.
|
||||
|
||||
### Delay until later
|
||||
|
||||
- Resource-triggered restarts.
|
||||
- Wipe/reset workflows.
|
||||
- Restore backup scheduling.
|
||||
- Clone schedules.
|
||||
- Generic webhooks.
|
||||
- Advanced conditional schedules.
|
||||
|
||||
## Summary
|
||||
|
||||
The current GSP Scheduler is functional but primitive. It stores CRON lines on agents, executes shell commands, and often calls back into the Panel through `wget`. That makes it flexible, but it does not provide the safety, visibility, or polish expected from a modern commercial game hosting panel.
|
||||
|
||||
The recommended path is a typed, DB-backed schedule system with safe action definitions, game XML capability flags, agent-side action execution, structured run logs, notifications, and first-class workflows for restart, backup, update, Workshop mods, and RCON warnings.
|
||||
|
||||
1396
STEAM_WORKSHOP_DESIGN.md
Normal file
1396
STEAM_WORKSHOP_DESIGN.md
Normal file
File diff suppressed because it is too large
Load diff
109
docs/agents/LINUX_AGENT.md
Normal file
109
docs/agents/LINUX_AGENT.md
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
# Linux Agent
|
||||
|
||||
## Role
|
||||
|
||||
`Agent_Linux/ogp_agent.pl` is the Linux execution agent for GSP. It is responsible for:
|
||||
|
||||
- starting and stopping game servers
|
||||
- managing `screen` sessions
|
||||
- reading logs
|
||||
- running update/install tasks
|
||||
- handling scheduler jobs
|
||||
- performing query checks and status checks
|
||||
|
||||
## Important Files
|
||||
|
||||
- `Agent_Linux/ogp_agent.pl`
|
||||
- `Agent_Linux/startups/`
|
||||
- `Agent_Linux/includes/`
|
||||
- `Agent_Linux/php-query/`
|
||||
- `Agent_Linux/Cfg/`
|
||||
- `Agent_Linux/Schedule/`
|
||||
- `Agent_Linux/steamcmd/`
|
||||
- `Agent_Linux/systemd/`
|
||||
|
||||
## Startup Logic
|
||||
|
||||
The Linux agent creates a managed `screen` session per server.
|
||||
|
||||
Key flow in `ogp_agent.pl`:
|
||||
|
||||
- `universal_start_without_decrypt`
|
||||
- `create_screen_cmd`
|
||||
- `create_screen_cmd_loop`
|
||||
- `replace_OGP_Env_Vars`
|
||||
|
||||
The agent builds the startup command from:
|
||||
|
||||
- the game XML template
|
||||
- server parameters
|
||||
- mod data
|
||||
- control password
|
||||
- path variables
|
||||
|
||||
The session name follows the OGP naming convention, for example:
|
||||
|
||||
```text
|
||||
OGP_HOME_000000123
|
||||
```
|
||||
|
||||
## Status Logic
|
||||
|
||||
Relevant functions:
|
||||
|
||||
- `is_screen_running_without_decrypt`
|
||||
- `get_screen_pid_without_decrypt`
|
||||
- `server_status_without_decrypt`
|
||||
- `verify_server_stopped_without_decrypt`
|
||||
|
||||
The status implementation should check:
|
||||
|
||||
- screen/session existence
|
||||
- PID or child process information when available
|
||||
- whether the game port is listening
|
||||
- whether query metadata can be fetched
|
||||
|
||||
Marker files such as `SERVER_STOPPED` should not be treated as the final source of truth.
|
||||
|
||||
## Logging
|
||||
|
||||
Relevant function:
|
||||
|
||||
- `get_log`
|
||||
|
||||
The agent reads screen logs and may also copy a local log file into the game home. Logs should be treated as runtime output, not as a state store.
|
||||
|
||||
## Scheduler
|
||||
|
||||
Linux scheduler functions live in `ogp_agent.pl`:
|
||||
|
||||
- `scheduler_dispatcher`
|
||||
- `scheduler_server_action`
|
||||
- `scheduler_log_events`
|
||||
- `scheduler_add_task`
|
||||
- `scheduler_del_task`
|
||||
- `scheduler_edit_task`
|
||||
- `scheduler_read_tasks`
|
||||
- `scheduler_stop`
|
||||
- `scheduler_list_tasks`
|
||||
|
||||
The scheduler is agent-driven. Panel pages create or edit jobs, but the agent executes them.
|
||||
|
||||
## Configuration Files
|
||||
|
||||
Useful configuration and runtime areas:
|
||||
|
||||
- `Agent_Linux/Cfg/`
|
||||
- `Agent_Linux/startups/`
|
||||
- `Agent_Linux/steamcmd/`
|
||||
- `Agent_Linux/systemd/`
|
||||
|
||||
The agent also maintains screen logs and helper scripts inside its runtime area.
|
||||
|
||||
## Linux-Specific Notes
|
||||
|
||||
- The Linux agent uses `screen` and `sudo_exec_without_decrypt`.
|
||||
- It can resolve server ownership and screen users via helper functions such as `find_user_by_screen_id`.
|
||||
- It must remain portable across distro variants, so avoid assuming one exact init system or one exact binary path.
|
||||
- For Windows-targeted games running under Linux, Wine-related path conversion appears in startup path handling.
|
||||
|
||||
94
docs/agents/WINDOWS_AGENT.md
Normal file
94
docs/agents/WINDOWS_AGENT.md
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
# Windows Agent
|
||||
|
||||
## Role
|
||||
|
||||
`Agent-Windows/ogp_agent.pl` is the Windows/Cygwin execution agent for GSP. It mirrors the Linux agent as closely as practical, while using Windows-compatible paths, processes, and wrappers.
|
||||
|
||||
## Important Files
|
||||
|
||||
- `Agent-Windows/ogp_agent.pl`
|
||||
- `Agent-Windows/php-query/`
|
||||
- `Agent-Windows/ArmaBE/`
|
||||
- `Agent-Windows/Cfg/`
|
||||
- `Agent-Windows/Install/`
|
||||
- `Agent-Windows/ServerFiles/`
|
||||
- `Agent-Windows/Schedule/`
|
||||
|
||||
## Cygwin Requirements
|
||||
|
||||
The Windows agent assumes a Cygwin-style environment that can provide:
|
||||
|
||||
- `screen`
|
||||
- Perl
|
||||
- shell utilities such as `ps`, `grep`, `cut`, `awk`, `sed`
|
||||
- `cygpath`
|
||||
- a usable `bash`
|
||||
|
||||
The goal is to keep the Windows agent behavior close to the Linux agent so the Panel does not need separate semantics for basic lifecycle operations.
|
||||
|
||||
## Startup Logic
|
||||
|
||||
Relevant functions:
|
||||
|
||||
- `universal_start_without_decrypt`
|
||||
- `create_screen_cmd`
|
||||
- `create_screen_cmd_loop`
|
||||
- `replace_OGP_Env_Vars`
|
||||
|
||||
The Windows agent also uses `screen` sessions for managed server execution. Depending on the game and binary type, it may wrap commands in `cmd /Q /C start` or run a batch file wrapper.
|
||||
|
||||
The session naming scheme also follows the OGP convention:
|
||||
|
||||
```text
|
||||
OGP_HOME_000000123
|
||||
```
|
||||
|
||||
## Status Logic
|
||||
|
||||
Relevant functions:
|
||||
|
||||
- `is_screen_running_without_decrypt`
|
||||
- `get_screen_pid_without_decrypt`
|
||||
- `server_status_without_decrypt`
|
||||
- `verify_server_stopped_without_decrypt`
|
||||
|
||||
The status model should check:
|
||||
|
||||
- screen/session existence
|
||||
- process/PID information when available
|
||||
- game port listening
|
||||
- optional query metadata
|
||||
|
||||
The old `SERVER_STOPPED` file should not be the source of truth.
|
||||
|
||||
## Logging
|
||||
|
||||
Relevant function:
|
||||
|
||||
- `get_log`
|
||||
|
||||
Windows/Cygwin logs come from screen logs and/or local copies. Log retrieval should remain compatible with the Panel's AJAX log view.
|
||||
|
||||
## Scheduler
|
||||
|
||||
Relevant functions:
|
||||
|
||||
- `scheduler_dispatcher`
|
||||
- `scheduler_server_action`
|
||||
- `scheduler_log_events`
|
||||
- `scheduler_add_task`
|
||||
- `scheduler_del_task`
|
||||
- `scheduler_edit_task`
|
||||
- `scheduler_read_tasks`
|
||||
- `scheduler_stop`
|
||||
- `scheduler_list_tasks`
|
||||
|
||||
The Windows scheduler implementation should remain aligned with the Linux scheduler implementation so the Panel can treat both the same way.
|
||||
|
||||
## Windows-Specific Notes
|
||||
|
||||
- Path conversion between Cygwin and native Windows paths matters during startup.
|
||||
- Batch wrappers are often needed for Windows executables.
|
||||
- Process cleanup must avoid killing unrelated processes that happen to share an executable name.
|
||||
- The agent should continue to use `screen` where it already does so, to stay aligned with Linux behavior.
|
||||
|
||||
103
docs/architecture/PANEL_AGENT_FLOW.md
Normal file
103
docs/architecture/PANEL_AGENT_FLOW.md
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
# Panel Agent Flow
|
||||
|
||||
## Overview
|
||||
|
||||
The Panel does not directly run servers. It prepares the request, sends it to the agent, and interprets the response.
|
||||
|
||||
```text
|
||||
User action
|
||||
-> Panel module page
|
||||
-> OGPRemoteLibrary in lib_remote.php
|
||||
-> XML-RPC request to agent /RPC2
|
||||
-> ogp_agent.pl method
|
||||
-> local screen/process/port work
|
||||
-> return status or payload
|
||||
-> Panel renders result
|
||||
```
|
||||
|
||||
## Request Path
|
||||
|
||||
Important Panel files:
|
||||
|
||||
- `Panel/includes/lib_remote.php`
|
||||
- `Panel/modules/gamemanager/start_server.php`
|
||||
- `Panel/modules/gamemanager/stop_server.php`
|
||||
- `Panel/modules/gamemanager/restart_server.php`
|
||||
- `Panel/modules/gamemanager/server_monitor.php`
|
||||
- `Panel/modules/gamemanager/view_server_log.php`
|
||||
- `Panel/modules/gamemanager/get_server_log.php`
|
||||
- `Panel/modules/gamemanager/home_handling_functions.php`
|
||||
|
||||
### Start
|
||||
|
||||
1. Panel loads the selected server home and game XML.
|
||||
2. Panel composes startup parameters from stored values and XML templates.
|
||||
3. Panel calls `universal_start` on the agent.
|
||||
4. Agent creates the `screen` session and starts the server command.
|
||||
5. Panel polls `remote_server_status`.
|
||||
6. When the agent reports that the process/session exists and the game port listens, the server is treated as ONLINE.
|
||||
|
||||
### Stop
|
||||
|
||||
1. Panel calls `remote_stop_server`.
|
||||
2. Agent sends the configured graceful stop command if one exists.
|
||||
3. Agent watches the session/process and required port.
|
||||
4. If the session/process does not exit in time, the agent escalates to screen quit or process kill.
|
||||
5. Panel treats the server as stopped only when the agent confirms it is actually gone.
|
||||
|
||||
### Restart
|
||||
|
||||
Restart should be:
|
||||
|
||||
```text
|
||||
stop
|
||||
-> wait
|
||||
-> start
|
||||
```
|
||||
|
||||
The wait period should be explicit and visible in logs. Restart should not depend on marker files or query success.
|
||||
|
||||
### Status
|
||||
|
||||
1. Panel calls `remote_server_status`.
|
||||
2. Agent checks:
|
||||
- managed screen/session
|
||||
- PID or process tree when available
|
||||
- required game port
|
||||
- optional query/RCON ports
|
||||
3. Agent returns a structured status object.
|
||||
4. Panel maps the result to the UI state.
|
||||
|
||||
### Logs
|
||||
|
||||
1. Panel calls `get_log`.
|
||||
2. Agent returns the latest screen or console log data.
|
||||
3. The log view updates via AJAX instead of full-page refresh.
|
||||
4. The UI should preserve scroll position and only auto-scroll when the user is already at the bottom.
|
||||
|
||||
## Data Returned by Status
|
||||
|
||||
Recommended status fields:
|
||||
|
||||
- `status`
|
||||
- `ready`
|
||||
- `process_running`
|
||||
- `session_running`
|
||||
- `game_port_listening`
|
||||
- `query_port_listening`
|
||||
- `rcon_port_listening`
|
||||
- `pid`
|
||||
- `session_name`
|
||||
- `ip`
|
||||
- `port`
|
||||
- `query_port`
|
||||
- `last_error`
|
||||
- optional query metadata
|
||||
|
||||
## Practical Notes
|
||||
|
||||
- The Panel should not mark a server failed only because query metadata was unavailable.
|
||||
- The agent should be the source of truth.
|
||||
- Marker files may exist, but they should be treated as hints only.
|
||||
- The same high-level flow should work for Linux and Windows/Cygwin.
|
||||
|
||||
159
docs/architecture/REPOSITORY_OVERVIEW.md
Normal file
159
docs/architecture/REPOSITORY_OVERVIEW.md
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
# Repository Overview
|
||||
|
||||
## Purpose
|
||||
|
||||
This repository contains the GSP game server hosting platform:
|
||||
|
||||
- `Panel` - the web control panel and customer/admin UI.
|
||||
- `Agent_Linux` - the Linux agent that starts, stops, monitors, updates, and logs game servers.
|
||||
- `Agent-Windows` - the Windows/Cygwin agent that mirrors the Linux agent as closely as possible.
|
||||
- `Website` - the public marketing, customer, and commerce site.
|
||||
|
||||
## Top-Level Layout
|
||||
|
||||
```text
|
||||
/
|
||||
Agent_Linux/
|
||||
Agent-Windows/
|
||||
Panel/
|
||||
Website/
|
||||
docs/
|
||||
```
|
||||
|
||||
## Major Components
|
||||
|
||||
### Panel
|
||||
|
||||
The Panel is the orchestration layer. It:
|
||||
|
||||
- loads module pages from `Panel/modules/*`
|
||||
- talks to agents through `Panel/includes/lib_remote.php`
|
||||
- stores panel-side state in the database
|
||||
- renders server lifecycle, file, backup, scheduler, Workshop, support, and billing pages
|
||||
|
||||
Important Panel files:
|
||||
|
||||
- `Panel/includes/lib_remote.php`
|
||||
- `Panel/modules/gamemanager/home_handling_functions.php`
|
||||
- `Panel/modules/gamemanager/server_monitor.php`
|
||||
- `Panel/modules/config_games/schema_server_config.xml`
|
||||
- `Panel/modules/addonsmanager/module.php`
|
||||
- `Panel/modules/cron/module.php`
|
||||
- `Panel/modules/user_games/module.php`
|
||||
|
||||
### Agents
|
||||
|
||||
The agents are the execution layer. They:
|
||||
|
||||
- launch game servers inside `screen`
|
||||
- stop and restart servers
|
||||
- read logs
|
||||
- run updates and install jobs
|
||||
- execute scheduler jobs
|
||||
- report status back to the Panel
|
||||
|
||||
Important agent files:
|
||||
|
||||
- `Agent_Linux/ogp_agent.pl`
|
||||
- `Agent-Windows/ogp_agent.pl`
|
||||
- `Agent_Linux/startups/`
|
||||
- `Agent-Windows/ServerFiles/`
|
||||
- `Agent_Linux/php-query/`
|
||||
- `Agent-Windows/php-query/`
|
||||
|
||||
### Website
|
||||
|
||||
The Website is separate from the server runtime path. It is used for:
|
||||
|
||||
- public product pages
|
||||
- documentation links
|
||||
- customer onboarding
|
||||
- billing and commerce surfaces
|
||||
|
||||
## Panel <-> Agent Communication
|
||||
|
||||
The Panel uses XML-RPC over HTTP to call methods exposed by `ogp_agent.pl`.
|
||||
|
||||
The remote wrapper lives in:
|
||||
|
||||
- `Panel/includes/lib_remote.php`
|
||||
|
||||
The most important calls are:
|
||||
|
||||
- `universal_start`
|
||||
- `remote_stop_server`
|
||||
- `remote_restart_server`
|
||||
- `remote_server_status`
|
||||
- `is_screen_running`
|
||||
- `get_log`
|
||||
- `remote_query`
|
||||
- scheduler methods
|
||||
|
||||
The agents decode the request, execute the action locally, and return a status code or payload.
|
||||
|
||||
## Database Usage
|
||||
|
||||
The Panel database stores:
|
||||
|
||||
- server homes and assigned ports
|
||||
- game definitions and mod mappings
|
||||
- user permissions and subusers
|
||||
- scheduler definitions and related data
|
||||
- content and Workshop metadata
|
||||
- tickets/support records
|
||||
- billing and provisioning records
|
||||
|
||||
Key tables discovered in current code:
|
||||
|
||||
- `server_homes`
|
||||
- `home_ip_ports`
|
||||
- `game_mods`
|
||||
- `status_cache`
|
||||
- `config_homes`
|
||||
- `config_mods`
|
||||
- `addons`
|
||||
- `server_content_workshop`
|
||||
- `server_content_manifest`
|
||||
- `server_content_install_history`
|
||||
- `tickets`
|
||||
- `ticket_messages`
|
||||
- `ticket_attachments`
|
||||
- `ticket_settings`
|
||||
- billing-related tables in `Panel/modules/billing`
|
||||
|
||||
The agents also keep runtime files such as screen logs, update logs, scheduler state, and helper manifests, but those should be treated as runtime state rather than the source of truth.
|
||||
|
||||
## Startup Flow
|
||||
|
||||
1. User clicks start in the Panel.
|
||||
2. Panel builds the startup command from the game XML and stored server parameters.
|
||||
3. Panel sends `universal_start` to the agent.
|
||||
4. Agent creates a `screen` session and launches the server command.
|
||||
5. Panel polls status and logs.
|
||||
6. If the managed session exists and the required port listens, the server is considered online.
|
||||
|
||||
## Status Reporting Flow
|
||||
|
||||
The desired status flow is:
|
||||
|
||||
```text
|
||||
Panel asks agent for status
|
||||
-> agent checks managed session/process
|
||||
-> agent checks required listening port
|
||||
-> agent optionally performs query metadata lookup
|
||||
-> agent returns structured status
|
||||
-> Panel renders ONLINE / STARTING / STOPPING / UNRESPONSIVE / OFFLINE / UNKNOWN
|
||||
```
|
||||
|
||||
Query results are metadata only. They are not the source of truth for online/offline state.
|
||||
|
||||
## What To Read First
|
||||
|
||||
For future investigations, start with:
|
||||
|
||||
1. `docs/development/CODEX_GUIDE.md`
|
||||
2. `docs/architecture/PANEL_AGENT_FLOW.md`
|
||||
3. `docs/modules/GAMEMANAGER.md`
|
||||
4. `docs/features/STATUS_SYSTEM.md`
|
||||
5. `docs/features/XML_SYSTEM.md`
|
||||
|
||||
138
docs/development/CODEX_GUIDE.md
Normal file
138
docs/development/CODEX_GUIDE.md
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
# Codex Guide
|
||||
|
||||
This file is the first stop for future Codex sessions working in this repository.
|
||||
|
||||
## Repository Layout
|
||||
|
||||
```text
|
||||
/
|
||||
Agent_Linux/
|
||||
Agent-Windows/
|
||||
Panel/
|
||||
Website/
|
||||
docs/
|
||||
```
|
||||
|
||||
## What To Read First
|
||||
|
||||
1. `docs/architecture/REPOSITORY_OVERVIEW.md`
|
||||
2. `docs/architecture/PANEL_AGENT_FLOW.md`
|
||||
3. `docs/modules/MODULE_INDEX.md`
|
||||
4. `docs/modules/GAMEMANAGER.md`
|
||||
5. `docs/features/STATUS_SYSTEM.md`
|
||||
6. `docs/features/XML_SYSTEM.md`
|
||||
7. `docs/modules/SCHEDULER.md`
|
||||
8. `docs/modules/SERVER_CONTENT_MANAGER.md`
|
||||
|
||||
## Important Files By Topic
|
||||
|
||||
### Startup Logic
|
||||
|
||||
- `Panel/modules/gamemanager/home_handling_functions.php`
|
||||
- `Panel/modules/gamemanager/start_server.php`
|
||||
- `Panel/modules/gamemanager/restart_server.php`
|
||||
- `Panel/modules/config_games/schema_server_config.xml`
|
||||
- `Panel/modules/config_games/server_config_parser.php`
|
||||
- `Panel/includes/lib_remote.php`
|
||||
- `Agent_Linux/ogp_agent.pl`
|
||||
- `Agent-Windows/ogp_agent.pl`
|
||||
|
||||
### Status Logic
|
||||
|
||||
- `Panel/includes/lib_remote.php`
|
||||
- `Panel/modules/gamemanager/home_handling_functions.php`
|
||||
- `Panel/modules/gamemanager/server_monitor.php`
|
||||
- `Agent_Linux/ogp_agent.pl`
|
||||
- `Agent-Windows/ogp_agent.pl`
|
||||
|
||||
### Scheduler Logic
|
||||
|
||||
- `Panel/modules/cron/module.php`
|
||||
- `Panel/modules/cron/cron.php`
|
||||
- `Panel/modules/cron/shared_cron_functions.php`
|
||||
- `Agent_Linux/ogp_agent.pl`
|
||||
- `Agent-Windows/ogp_agent.pl`
|
||||
|
||||
### Workshop / Server Content Logic
|
||||
|
||||
- `Panel/modules/addonsmanager/module.php`
|
||||
- `Panel/modules/addonsmanager/addons_manager.php`
|
||||
- `Panel/modules/addonsmanager/user_addons.php`
|
||||
- `Panel/modules/addonsmanager/workshop_content.php`
|
||||
- `Panel/modules/addonsmanager/workshop_action.php`
|
||||
- `Panel/modules/steam_workshop/module.php`
|
||||
|
||||
### XML Definitions
|
||||
|
||||
- `Panel/modules/config_games/schema_server_config.xml`
|
||||
- `Panel/modules/config_games/xml_config_creator.php`
|
||||
- `Panel/modules/config_games/set_params.php`
|
||||
- `Panel/modules/config_games/cli-params.php`
|
||||
- `Panel/modules/config_games/config_servers.php`
|
||||
|
||||
### Agent Communication
|
||||
|
||||
- `Panel/includes/lib_remote.php`
|
||||
- `Agent_Linux/ogp_agent.pl`
|
||||
- `Agent-Windows/ogp_agent.pl`
|
||||
|
||||
## Common Development Workflows
|
||||
|
||||
### Debug a start/stop/restart issue
|
||||
|
||||
1. Read `docs/modules/GAMEMANAGER.md`.
|
||||
2. Check `Panel/includes/lib_remote.php`.
|
||||
3. Check `Panel/modules/gamemanager/home_handling_functions.php`.
|
||||
4. Check the matching `ogp_agent.pl`.
|
||||
5. Compare session/process/port logic in both agents.
|
||||
|
||||
### Debug a status issue
|
||||
|
||||
1. Read `docs/features/STATUS_SYSTEM.md`.
|
||||
2. Check `remote_server_status` in `Panel/includes/lib_remote.php`.
|
||||
3. Check `server_status_without_decrypt` in both agents.
|
||||
4. Check game XML query definitions in `config_games`.
|
||||
|
||||
### Debug scheduler behavior
|
||||
|
||||
1. Read `docs/modules/SCHEDULER.md`.
|
||||
2. Check `Panel/modules/cron/cron.php`.
|
||||
3. Check scheduler subroutines in both agents.
|
||||
4. Verify whether the action is customer-safe or admin-only.
|
||||
|
||||
### Debug Workshop or add-on behavior
|
||||
|
||||
1. Read `docs/modules/SERVER_CONTENT_MANAGER.md`.
|
||||
2. Check `Panel/modules/addonsmanager/module.php`.
|
||||
3. Check the user/admin content pages.
|
||||
4. Check whether the action should be treated as install, update, or uninstall.
|
||||
|
||||
## Things Already Investigated
|
||||
|
||||
The repository has already been mapped in these areas:
|
||||
|
||||
- module inventory
|
||||
- panel-agent remote library
|
||||
- Linux and Windows agent `screen` use
|
||||
- status model direction
|
||||
- game XML startup and query variables
|
||||
- current Server Content Manager structure
|
||||
- current scheduler structure
|
||||
- module-level roles and dependency patterns
|
||||
|
||||
## Things Intentionally Not Yet Implemented
|
||||
|
||||
This documentation-only pass does not implement:
|
||||
|
||||
- lifecycle code changes
|
||||
- status model code changes
|
||||
- scheduler redesign
|
||||
- Workshop/content redesign
|
||||
- backup system replacement
|
||||
- file manager or FTP rewrites
|
||||
- billing/provisioning changes
|
||||
|
||||
## Practical Rule for Future Sessions
|
||||
|
||||
Before scanning code broadly, read the docs layer first. Only open source files when the documentation does not already answer the question.
|
||||
|
||||
54
docs/features/STATUS_SYSTEM.md
Normal file
54
docs/features/STATUS_SYSTEM.md
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
# Status System
|
||||
|
||||
## Current Goal
|
||||
|
||||
The status system should tell the truth about a server's state without depending on stale marker files or query success alone.
|
||||
|
||||
## Current Direction
|
||||
|
||||
The current codebase is moving toward agent-owned structured status.
|
||||
|
||||
Important files:
|
||||
|
||||
- `Panel/includes/lib_remote.php`
|
||||
- `Panel/modules/gamemanager/home_handling_functions.php`
|
||||
- `Panel/modules/gamemanager/server_monitor.php`
|
||||
- `Agent_Linux/ogp_agent.pl`
|
||||
- `Agent-Windows/ogp_agent.pl`
|
||||
|
||||
## Recommended State Model
|
||||
|
||||
| State | Meaning |
|
||||
|---|---|
|
||||
| `OFFLINE` | No managed session/process and no required port listening. |
|
||||
| `STARTING` | Managed session/process exists but the required port is not ready yet. |
|
||||
| `ONLINE` | Managed session/process exists and the required port is listening. |
|
||||
| `STOPPING` | Stop is in progress and the session/process still exists. |
|
||||
| `UNRESPONSIVE` | The server did not become ready in time or stop did not complete cleanly. |
|
||||
| `UNKNOWN` | The agent cannot be reached or cannot determine state. |
|
||||
|
||||
## What Should Be Checked
|
||||
|
||||
The agent should check, in this order:
|
||||
|
||||
1. managed session or screen name
|
||||
2. process or PID tree when available
|
||||
3. required game port listening
|
||||
4. optional query/RCON port listening
|
||||
5. optional query metadata
|
||||
|
||||
## Known Problems To Remember
|
||||
|
||||
- LGSL/GameQ may fail for supported games, blocked ports, or slow startups.
|
||||
- Marker files can become stale after crashes or power loss.
|
||||
- A game can be online even if query metadata is temporarily unavailable.
|
||||
- Some games need long startup windows, so timeouts must be configurable per game.
|
||||
|
||||
## Planned Improvement Shape
|
||||
|
||||
- make the agent the source of truth
|
||||
- preserve optional query metadata
|
||||
- use state hints for start/stop transitions
|
||||
- expose clear messages for `STARTING` and `UNRESPONSIVE`
|
||||
- add precise log excerpts when startup fails
|
||||
|
||||
53
docs/features/WORKSHOP_SYSTEM.md
Normal file
53
docs/features/WORKSHOP_SYSTEM.md
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
# Workshop System
|
||||
|
||||
## Current State
|
||||
|
||||
The current Workshop/content work is split across two module lines:
|
||||
|
||||
- `Panel/modules/steam_workshop` - deprecated compatibility layer
|
||||
- `Panel/modules/addonsmanager` - the active Server Content Manager path
|
||||
|
||||
Important files:
|
||||
|
||||
- `Panel/modules/addonsmanager/module.php`
|
||||
- `Panel/modules/addonsmanager/user_addons.php`
|
||||
- `Panel/modules/addonsmanager/addons_manager.php`
|
||||
- `Panel/modules/addonsmanager/workshop_content.php`
|
||||
- `Panel/modules/addonsmanager/workshop_action.php`
|
||||
- `Panel/modules/steam_workshop/module.php`
|
||||
- `Panel/modules/steam_workshop/agent_update_workshop.php`
|
||||
|
||||
## What Exists Today
|
||||
|
||||
The current direction already supports:
|
||||
|
||||
- content records in the Panel database
|
||||
- Workshop item IDs
|
||||
- installation metadata
|
||||
- install history tables
|
||||
- game compatibility fields
|
||||
- launch parameter additions
|
||||
- post-install behavior fields
|
||||
|
||||
## Main Limitations
|
||||
|
||||
- Workshop metadata is still incomplete.
|
||||
- load order is not yet a full first-class UX concept.
|
||||
- update/uninstall/enable/disable flows need a cleaner product model.
|
||||
- DayZ/Arma-specific folder and key-copy behavior needs a stronger canonical path.
|
||||
- caching and cleanup policy need product-level design, not just ad hoc scripts.
|
||||
|
||||
## Recommended Mental Model
|
||||
|
||||
Use `addonsmanager` as the main future home for:
|
||||
|
||||
- mods
|
||||
- add-ons
|
||||
- Workshop items
|
||||
- scripts
|
||||
- config packs
|
||||
- server content manifests
|
||||
- install history
|
||||
|
||||
Treat `steam_workshop` as a legacy bridge for migration only.
|
||||
|
||||
105
docs/features/XML_SYSTEM.md
Normal file
105
docs/features/XML_SYSTEM.md
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
# XML Game Configuration System
|
||||
|
||||
## Purpose
|
||||
|
||||
The XML game configuration system describes how a game server should be started, queried, and customized.
|
||||
|
||||
Primary files:
|
||||
|
||||
- `Panel/modules/config_games/schema_server_config.xml`
|
||||
- `Panel/modules/config_games/server_config_parser.php`
|
||||
- `Panel/modules/config_games/xml_config_creator.php`
|
||||
- `Panel/modules/config_games/config_servers.php`
|
||||
- `Panel/modules/config_games/cli-params.php`
|
||||
- `Panel/modules/config_games/set_params.php`
|
||||
|
||||
## What XML Controls
|
||||
|
||||
The schema supports:
|
||||
|
||||
- game and installer names
|
||||
- startup command templates
|
||||
- CLI parameter substitution
|
||||
- reserved ports
|
||||
- query port calculation
|
||||
- control protocol selection
|
||||
- mod definitions
|
||||
- custom fields
|
||||
- server parameter groups
|
||||
- text replacement helpers
|
||||
|
||||
## Important Variables
|
||||
|
||||
The schema and startup builder can work with variables such as:
|
||||
|
||||
- `GAME_TYPE`
|
||||
- `HOSTNAME`
|
||||
- `IP`
|
||||
- `MAP`
|
||||
- `PID_FILE`
|
||||
- `PLAYERS`
|
||||
- `PORT`
|
||||
- `QUERY_PORT`
|
||||
- `BASE_PATH`
|
||||
- `HOME_PATH`
|
||||
- `SAVE_PATH`
|
||||
- `OUTPUT_PATH`
|
||||
- `USER_PATH`
|
||||
- `CONTROL_PASSWORD`
|
||||
|
||||
## Startup Parameters
|
||||
|
||||
The Panel builds startup parameters from the XML template and the stored server configuration.
|
||||
|
||||
Key concepts:
|
||||
|
||||
- `cli_template`
|
||||
- `cli_params`
|
||||
- `reserve_ports`
|
||||
- `server_params`
|
||||
- `custom_fields`
|
||||
- `clean_server_param_value`
|
||||
|
||||
The XML file defines:
|
||||
|
||||
- which parameters exist
|
||||
- how they are quoted or spaced
|
||||
- whether the parameter is editable by the customer
|
||||
- what defaults should be used
|
||||
|
||||
## Query Definitions
|
||||
|
||||
The XML schema supports query-related concepts such as:
|
||||
|
||||
- `gameq`
|
||||
- `lgsl`
|
||||
- `teamspeak3`
|
||||
- query port offset calculations
|
||||
- control protocol selection
|
||||
|
||||
These values are used by `gamemanager` and the agent status logic to calculate query metadata, not to decide online/offline by themselves.
|
||||
|
||||
## Installation and File Editing
|
||||
|
||||
XML definitions also feed:
|
||||
|
||||
- config file shortcuts
|
||||
- install-time behavior
|
||||
- docs links
|
||||
- reserved ports
|
||||
- mod or content behavior
|
||||
|
||||
## Recommended Mental Model
|
||||
|
||||
Think of the XML system as the capability definition layer:
|
||||
|
||||
```text
|
||||
game XML
|
||||
-> startup template
|
||||
-> parameter rules
|
||||
-> query rules
|
||||
-> content/mod hooks
|
||||
-> docs links
|
||||
-> scheduler and status hints
|
||||
```
|
||||
|
||||
82
docs/modules/GAMEMANAGER.md
Normal file
82
docs/modules/GAMEMANAGER.md
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
# GameManager
|
||||
|
||||
## Role
|
||||
|
||||
`Panel/modules/gamemanager` is the core customer server control module. It owns:
|
||||
|
||||
- start
|
||||
- stop
|
||||
- restart
|
||||
- logs
|
||||
- server monitor
|
||||
- update flow hooks
|
||||
- RCON integration
|
||||
- status display
|
||||
|
||||
## Important Files
|
||||
|
||||
- `Panel/modules/gamemanager/module.php`
|
||||
- `Panel/modules/gamemanager/home_handling_functions.php`
|
||||
- `Panel/modules/gamemanager/server_monitor.php`
|
||||
- `Panel/modules/gamemanager/start_server.php`
|
||||
- `Panel/modules/gamemanager/stop_server.php`
|
||||
- `Panel/modules/gamemanager/restart_server.php`
|
||||
- `Panel/modules/gamemanager/log.php`
|
||||
- `Panel/modules/gamemanager/view_server_log.php`
|
||||
- `Panel/modules/gamemanager/get_server_log.php`
|
||||
- `Panel/modules/gamemanager/update_server.php`
|
||||
|
||||
## Start / Stop / Restart
|
||||
|
||||
The module calls the agent through `Panel/includes/lib_remote.php`.
|
||||
|
||||
Current shape:
|
||||
|
||||
- start -> `universal_start`
|
||||
- stop -> `remote_stop_server`
|
||||
- restart -> `remote_restart_server`
|
||||
|
||||
The right behavior is:
|
||||
|
||||
- start shows `STARTING` as soon as the managed session exists
|
||||
- online status requires the process/session plus the game port
|
||||
- restart should be stop, wait, start
|
||||
- stop should not be treated as complete until the session/process is actually gone
|
||||
|
||||
## Status Reporting
|
||||
|
||||
The current flow now points toward agent-truth status reporting via:
|
||||
|
||||
- `remote_server_status`
|
||||
- `get_agent_server_status` in `home_handling_functions.php`
|
||||
- `server_status_without_decrypt` in both agents
|
||||
|
||||
Useful state labels:
|
||||
|
||||
- `OFFLINE`
|
||||
- `STARTING`
|
||||
- `ONLINE`
|
||||
- `STOPPING`
|
||||
- `UNRESPONSIVE`
|
||||
- `UNKNOWN`
|
||||
|
||||
Query checks should remain optional metadata only.
|
||||
|
||||
## Log Viewer
|
||||
|
||||
Relevant files:
|
||||
|
||||
- `Panel/modules/gamemanager/log.php`
|
||||
- `Panel/modules/gamemanager/view_server_log.php`
|
||||
- `Panel/modules/gamemanager/get_server_log.php`
|
||||
|
||||
The log view should be treated as live, AJAX-updated output rather than a full page reload workflow.
|
||||
|
||||
## What This Module Depends On
|
||||
|
||||
- `config_games` for startup parameters and protocol definitions
|
||||
- `lib_remote.php` for agent calls
|
||||
- `user_games` for server home records
|
||||
- `rcon` for command support where available
|
||||
- `addonsmanager` for content/mod interactions
|
||||
|
||||
68
docs/modules/MODULE_INDEX.md
Normal file
68
docs/modules/MODULE_INDEX.md
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
# Module Index
|
||||
|
||||
This is the current Panel module inventory. It is intentionally concise so future Codex sessions can decide which module to inspect in code.
|
||||
|
||||
| Module | Purpose | Current State | Dependencies | Notes |
|
||||
|---|---|---|---|---|
|
||||
| `TS3Admin` | Teamspeak 3 admin interface | Required, legacy niche | TS3 admin files | Keep if TS3 hosting is sold. |
|
||||
| `addonsmanager` | Server Content Manager | Required, actively evolving | DB tables, game XML, agent install scripts | Best current home for mods, add-ons, Workshop, and content installs. |
|
||||
| `administration` | Admin utilities | Required | Core admin pages | Includes logger/watch tools. |
|
||||
| `backup-restore` | Backup/restore UI | Optional, broken/testing | Hard-coded backup host/path logic | Hide until replaced. |
|
||||
| `billing` | Billing, provisioning, commerce | Optional, large custom module | Payment gateways, invoices, shop/provisioning docs | Important for commercial hosting. |
|
||||
| `circular` | Notification/circular messages | Optional | Panel UI | Good candidate for maintenance and announcement notices. |
|
||||
| `config_games` | Game XML definitions and CLI builder | Required | XML schema/parser | Critical for startup templates, queries, custom fields, and game capabilities. |
|
||||
| `cron` | Scheduler / CRON | Required | Agent scheduler methods, Panel action selection | Needs safe action registry and task history. |
|
||||
| `dashboard` | Main landing dashboard | Required | Panel auth and server summaries | Should surface status, support, billing, and alerts. |
|
||||
| `dsi` | Dynamic Server Image | Optional | Game imagery and cached assets | Useful for server cards and branding. |
|
||||
| `editconfigfiles` | Config file shortcuts | Optional | Game config metadata | Good for surfacing common editable files. |
|
||||
| `faq` | FAQ/help | Required | Site docs/content | Should link to game docs and common workflows. |
|
||||
| `fast_download` | FastDL support | Required | Source/GoldSrc-style web distribution | Still useful for older Source engine communities. |
|
||||
| `ftp` | FTP admin | Required | File transfer service, access rights | Needs security review but remains important. |
|
||||
| `gamemanager` | Server monitor, lifecycle, logs, RCON | Required | Agent RPC, game XML, query libraries | Core customer workflow module. |
|
||||
| `lgsl_with_img_mod` | LGSL server status images | Optional legacy | Query/image cache data | Secondary to agent truth. |
|
||||
| `litefm` | In-panel file manager | Required | File system access rights | Should be the preferred in-panel file tool. |
|
||||
| `lostpwd` | Password recovery | Required | Auth/account flow | Basic account support. |
|
||||
| `modulemanager` | Module installation/configuration | Required | Module metadata | Admin maintenance tool. |
|
||||
| `mysql` | MySQL hosting/admin | Required | MySQL service setup | Good future product tie-in for databases. |
|
||||
| `news` | Legacy news/announcements | Optional legacy | Old CMS-like data | Consider hiding unless modernized. |
|
||||
| `rcon` | RCON admin tool | Required | Server protocol support | Useful for commands, warnings, and scheduler integration. |
|
||||
| `register` | Account registration | Required | Auth flow | Basic customer onboarding. |
|
||||
| `server` | Server manager | Required | Agent/node management | Admin-facing node controls. |
|
||||
| `settings` | Global settings | Required | Auth, site config | Admin configuration area. |
|
||||
| `status` | Status page | Optional alpha | Status data | Not ready for customer-facing critical use. |
|
||||
| `steam_workshop` | Legacy Workshop module | Optional deprecated | Workshop DB helpers | Hidden/deprecated in favor of `addonsmanager`. |
|
||||
| `subusers` | Subuser permissions | Required | Authorization model | Important for commercial teams and communities. |
|
||||
| `support` | Support landing page | Required | Ticketing/docs | Better as an entry point than the full ticket workflow. |
|
||||
| `teamspeak3` | Teamspeak 3 web interface | Required if sold | TS3 service | Hide if not part of the product offering. |
|
||||
| `tickets` | Support ticket system | Optional but useful | DB tables, attachments, notifications | Stronger support workflow than `support` alone. |
|
||||
| `tshock` | Terraria/TShock utilities | Optional niche | Terraria/TShock game support | Expose only for supported games. |
|
||||
| `update` | Panel updates | Required admin tool | Patch/update system | Admin-only maintenance. |
|
||||
| `user_admin` | User management | Required | Auth/admin roles | Important for staff administration. |
|
||||
| `user_games` | Server provisioning and assignment | Required | Game homes, ports, billing integration | Core provisioning path. |
|
||||
| `util` | Utility tools | Required | Misc tools | Keep useful tools, hide legacy helpers that are not maintained. |
|
||||
|
||||
## Dependency Notes
|
||||
|
||||
Common dependencies across many modules:
|
||||
|
||||
- `includes/lib_remote.php`
|
||||
- auth/session and role checks
|
||||
- `config_games` XML parsing
|
||||
- DB access helpers
|
||||
- server home and IP/port records
|
||||
|
||||
## High-Value Modules
|
||||
|
||||
The modules most likely to matter in future investigations are:
|
||||
|
||||
1. `gamemanager`
|
||||
2. `config_games`
|
||||
3. `user_games`
|
||||
4. `addonsmanager`
|
||||
5. `cron`
|
||||
6. `litefm`
|
||||
7. `ftp`
|
||||
8. `billing`
|
||||
9. `tickets`
|
||||
10. `subusers`
|
||||
|
||||
96
docs/modules/SCHEDULER.md
Normal file
96
docs/modules/SCHEDULER.md
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
# Scheduler
|
||||
|
||||
## Current Implementation
|
||||
|
||||
The scheduler lives in the `cron` module on the Panel and in scheduler methods inside the agents.
|
||||
|
||||
Important files:
|
||||
|
||||
- `Panel/modules/cron/module.php`
|
||||
- `Panel/modules/cron/cron.php`
|
||||
- `Panel/modules/cron/shared_cron_functions.php`
|
||||
- `Agent_Linux/ogp_agent.pl`
|
||||
- `Agent-Windows/ogp_agent.pl`
|
||||
|
||||
## How It Works Today
|
||||
|
||||
The Panel builds cron-like jobs and sends them to the agent using RPC methods such as:
|
||||
|
||||
- `scheduler_add_task`
|
||||
- `scheduler_edit_task`
|
||||
- `scheduler_del_task`
|
||||
- `scheduler_list_tasks`
|
||||
- `scheduler_read_tasks`
|
||||
|
||||
The agent stores and executes the tasks locally.
|
||||
|
||||
## Current Task Model
|
||||
|
||||
Current jobs are built as cron expressions plus a command string.
|
||||
|
||||
The command can be:
|
||||
|
||||
- a safe predefined server action
|
||||
- an update-related action
|
||||
- a server content action
|
||||
- a raw admin command
|
||||
|
||||
## Scheduled Actions Observed
|
||||
|
||||
From the current codebase and related Server Content work, the action set includes:
|
||||
|
||||
- restart server
|
||||
- stop server
|
||||
- start server
|
||||
- Steam auto update
|
||||
- server content update checks
|
||||
- server content install/update actions
|
||||
- validate files
|
||||
- backup before update
|
||||
- notify-only update flow
|
||||
|
||||
## Problems With the Current Design
|
||||
|
||||
- The task model is not strongly typed.
|
||||
- Customer-safe and admin-only actions are too easy to blur together.
|
||||
- Task output and run history are not user-friendly enough.
|
||||
- The agent is the executor, but the Panel needs a better task record and result view.
|
||||
- Overlap/conflict rules are not explicit.
|
||||
- Missed-task behavior after reboot should be documented and normalized.
|
||||
|
||||
## Recommended Next-Step Shape
|
||||
|
||||
Use typed actions instead of raw command strings for customer-facing scheduler tasks.
|
||||
|
||||
Suggested fields:
|
||||
|
||||
- action key
|
||||
- display name
|
||||
- role
|
||||
- arguments
|
||||
- timeout
|
||||
- retry behavior
|
||||
- conflict rules
|
||||
- log policy
|
||||
|
||||
## Agent Interaction Pattern
|
||||
|
||||
```text
|
||||
Panel schedules task
|
||||
-> Panel stores intent and UI data
|
||||
-> Panel sends job to agent
|
||||
-> agent writes/loads scheduler state
|
||||
-> agent executes action at the right time
|
||||
-> agent logs result
|
||||
-> Panel reads back task state
|
||||
```
|
||||
|
||||
## What To Inspect in Code
|
||||
|
||||
If scheduler behavior needs deeper investigation, start with:
|
||||
|
||||
- `Panel/modules/cron/cron.php`
|
||||
- `Panel/modules/cron/shared_cron_functions.php`
|
||||
- `Agent_Linux/ogp_agent.pl` scheduler subroutines
|
||||
- `Agent-Windows/ogp_agent.pl` scheduler subroutines
|
||||
|
||||
70
docs/modules/SERVER_CONTENT_MANAGER.md
Normal file
70
docs/modules/SERVER_CONTENT_MANAGER.md
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
# Server Content Manager
|
||||
|
||||
## Current State
|
||||
|
||||
`Panel/modules/addonsmanager` is the current home of GSP's Server Content / Add-ons / Workshop work.
|
||||
|
||||
The module title has already been moved toward `Server Content Manager`, but the schema and some folder names remain backward-compatible.
|
||||
|
||||
Important files:
|
||||
|
||||
- `Panel/modules/addonsmanager/module.php`
|
||||
- `Panel/modules/addonsmanager/addons_manager.php`
|
||||
- `Panel/modules/addonsmanager/user_addons.php`
|
||||
- `Panel/modules/addonsmanager/workshop_content.php`
|
||||
- `Panel/modules/addonsmanager/workshop_action.php`
|
||||
- `Panel/modules/addonsmanager/server_content_helpers.php`
|
||||
- `Panel/modules/addonsmanager/server_content_categories.php`
|
||||
|
||||
## Database Tables
|
||||
|
||||
Known tables used by the module:
|
||||
|
||||
- `addons`
|
||||
- `server_content_workshop`
|
||||
- `server_content_manifest`
|
||||
- `server_content_install_history`
|
||||
|
||||
## What It Already Does
|
||||
|
||||
The module can already represent several content types, including:
|
||||
|
||||
- downloads/extracted packages
|
||||
- post-script driven installs
|
||||
- workshop-oriented items
|
||||
- config packs
|
||||
- future profile-type content
|
||||
|
||||
For Workshop items, the current flow lets users enter IDs and routes the install through module pages and agent-side scripts.
|
||||
|
||||
## Current Limitations
|
||||
|
||||
- Workshop and content metadata is still partial.
|
||||
- Load order and enable/disable behavior need a cleaner first-class model.
|
||||
- Async install job progress should be more visible.
|
||||
- Install strategies are still being broadened and need consistent game-specific rules.
|
||||
- DayZ/Arma style key-copy and startup-param behavior needs a stronger canonical implementation.
|
||||
- Cache and cleanup policy need a clearer product design.
|
||||
|
||||
## Where To Start Reading
|
||||
|
||||
1. `Panel/modules/addonsmanager/module.php`
|
||||
2. `Panel/modules/addonsmanager/addons_manager.php`
|
||||
3. `Panel/modules/addonsmanager/user_addons.php`
|
||||
4. `Panel/modules/addonsmanager/workshop_content.php`
|
||||
5. `Panel/modules/addonsmanager/workshop_action.php`
|
||||
|
||||
## Important Concept
|
||||
|
||||
This module is the right place for:
|
||||
|
||||
- mods
|
||||
- add-ons
|
||||
- Workshop content
|
||||
- config packs
|
||||
- script-driven installs
|
||||
- server content manifests
|
||||
- install history
|
||||
|
||||
The old `steam_workshop` module should be treated as a deprecated compatibility layer, not the main future path.
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue