Compare commits

..

No commits in common. "dev" and "main" have entirely different histories.
dev ... main

11 changed files with 0 additions and 1536 deletions

View File

@ -1,5 +0,0 @@
FACTORIO_SAVE_PATH="/home/factorio/saves"
FACTORIO_SAVE_NAME="spaceage-01-2024-11-01-v2"
FACTORIO_MOD_PATH="/home/factorio/mods/default"
FACTORIO_SETTINGS_JSON="/home/factorio/server-settings.json"
FACTORIO_VERSION="2.0.14"

View File

@ -1,341 +0,0 @@
<?PHP
define("INDEX_DIR", __DIR__);
require __DIR__.'/scripts/class.TerminalMessage.php';
require __DIR__.'/scripts/func.downloadFile.php';
require __DIR__.'/scripts/class.FactorioVersion.php';
require __DIR__.'/scripts/class.FactorioMod.php';
require __DIR__.'/scripts/class.Systemctl.php';
require __DIR__.'/scripts/class.ValveRcon.php';
require __DIR__.'/scripts/func.rrmdir.php';
require __DIR__.'/scripts/func.rcopy.php';
$cli = new \NAE\Terminal\TerminalMessage();
// Welches Build ist gewünscht?
$target_build = "stable";
$target_edition = "headless";
// Wo wird der Server dieses Builds heruntergeladen?
$download_source = "https://factorio.com/get-download/stable/headless/linux64";
// sha256 hash Source
$download_hash_source = "https://www.factorio.com/download/sha256sums/";
// In welcher Datei soll der Download gespeichert werden?
// Wichtig da Factorio eine .tar.gz datei als linux64 Datei anbietet.
$download_output = __DIR__."/factorio.tar";
// Welche Dateien oder Ordner sollen vom alten Server übernommen werden?
$copy_paths = [
"/server-adminlist.json",
"/player-data.json",
"/config",
"/config-path.cfg"
];
// In welcher Datei steht die aktuelle Versionsnummer?
$current_version_str = (function(){
$env = file_get_contents(__DIR__."/factorio-settings.env");
$version = preg_replace("/.*FACTORIO_VERSION\=\"((\d+\.)+\d+)\".*/su","$1",$env);
return $version;
})();
$current_version = new \NAE\Factorio\FactorioVersion($current_version_str);
$cli->sendInfo( "CURRENT_VERSION: ".$current_version->getVersion() );
// Aktuelle Versionsnummern aus der Factorio-API abrufen.
$live_versions = json_decode(file_get_contents("https://factorio.com/api/latest-releases"), true);
// Anhand von Build und Edition die richtige Version auswählen.
$latest_version = new \NAE\Factorio\FactorioVersion($live_versions[$target_build][$target_edition]);
$cli->sendInfo( "LATEST_VERSION: ".$latest_version->getVersion() );
echo PHP_EOL;
/**
* Schreibt die neue Versionsnummer in die environment (env) datei des servers
* @return bool Schreiben erfolgreich?
*/
function writeBackVersion() : bool {
global $latest_version;
$env_file = __DIR__."/factorio-settings.env";
$env = file_get_contents($env_file);
$new_env = preg_replace("/FACTORIO_VERSION\=\"((\d+\.)+\d+)\"/su", "FACTORIO_VERSION=\"".$latest_version->getVersion()."\"", $env);
return ( file_put_contents($env_file, $new_env) !== false );
}
// Variablen zum speichern des Fortschrittes bzw. Erfolgs.
$download_success = false;
$extract_success = false;
$cli->sendTitle( "PRÜFE AUF FACTORIO UPDATES" );
if($latest_version->isNewer($current_version)) { // neue Version verfügbar?
$cli->sendTitle( "NEUE VERSION GEFUNDEN : UPDATE STARTET" );
if(file_exists($download_output)) { // liegt noch ein altes Server Archiv im Vertzeichnis?
$cli->sendTitle( "ALTE SERVER FILES GEFUNDEN : STARTE LÖSCHVORGANG", 1 );
if( unlink($download_output) ) { // altes Archiv löschen
$cli->sendSuccess( "ALTE SERVER FILES ERFOLGREICH GELÖSCHT!" );
} else {
$cli->sendError( "ALTE SERVER FILES KONNTEN NICHT GELÖSCHT WERDEN!", true );
}
}
echo PHP_EOL;
$cli->sendTitle( "STARTE DOWNLOAD DER SERVER FILES", 1 );
if(\NAE\Functions\Curl\downloadFile($download_output, $download_source)) { // Download der neuen Server Files
$dl_real_out = $download_output;
$sha256file = file_get_contents($download_hash_source); // sha256 hash liste von factorio
$fileHash = hash_file("sha256", $download_output);
$cli->sendInfo("Umbenennen des Heruntergeladenen Archivs..");
$realFilename = (function(array $lst, string $hash) : ?string {
$hashLen = strlen($hash);
foreach($lst as $file) {
if(substr($file, 0, $hashLen) == $hash && substr($file, $hashLen, 1) == " ") {
return trim(substr($file, $hashLen+1));
}
}
return null;
})(explode("\n", $sha256file), $fileHash);
if($realFilename === null) {
$cli->sendError( "FEHLGESCHLAGEN: Kann den richtigen Dateinamen aus der sha256 hash liste nicht ermitteln!", true );
} else {
$orig_download_output = $download_output;
$download_output = __DIR__."/$realFilename";
if(@rename( $orig_download_output, $download_output )) {
$cli->sendSuccess( "DOWNLOAD SUCCESS!" );
$download_success = true;
}
}
} else {
$cli->sendError( "DOWNLOAD FEHLGESCHLAGEN!", true );
}
if($download_success) {
echo PHP_EOL;
$cli->sendTitle( "STARTE DAS ENTPACKEN DER NEUEN SERVER FILES", 1 );
$unxz_download_output = preg_replace("/.tar.xz$/", ".tar", $download_output);
exec("unxz -vfd \"$download_output\" && tar -xvf \"$unxz_download_output\" > /dev/null", $output, $return); // Entpacken
if($return === 0) {
if( @rename(__DIR__."/factorio", __DIR__."/factorio-".$latest_version->getVersion()) ) { // Umbenennen mit Versionsnummer
$cli->sendSuccess( "Neue Server Files wurden Erfolgreich entpackt!" );
$extract_success = true;
} else {
$cli->sendError( "Umbenennen des Factorio Ordners mit Versionsnummer Fehlgeschlagen!", true );
}
} else {
$cli->sendError( "Entpacken der Server Files ist Fehlgeschlagen!", true );
}
}
if($extract_success) {
// RCON Kommunikation zum Server starten
$rcon_data = (function() : ?array {
global $current_version;
$cfg = parse_ini_file(__DIR__."/factorio-".$current_version->getVersion()."/config/config.ini", true);
if(!$cfg) return null;
$cd = [];
if(isset($cfg["other"])) {
$parts = explode(":", $cfg["other"]["local-rcon-socket"]??"127.0.0.1:27015");
$cd["ip"] = $parts[0];
$cd["port"] = $parts[1];
if(isset($cfg["other"]["local-rcon-socket"])) {
$cd["password"] = $cfg["other"]["local-rcon-password"]??"";
}
}
return $cd;
})();
$rcon = null;
if($rcon_data) {
try {
$rcon = new \NAE\Valve\Rcon\ValveRcon($rcon_data["ip"], $rcon_data["port"], $rcon_data["password"]);
$rcon->sendCommand("ACHTUNG: Server wird in kürze für ein Update gestoppt, bitte trennen Sie Ihre Verbindung zum Server. Der Server wird in kürze wieder verfügbar sein. Zeit bis zum Stopp: 60 Sekunden.", false);
if($rcon->getError() !== null) {
$cli->sendWarning( "RCON Verbindung konnte nicht aufgebaut werden!" );
$rcon = null;
}
} catch(\Exception $e) {
$cli->sendWarning( "RCON Verbindung konnte nicht aufgebaut werden!" );
$rcon = null;
}
}
if($rcon) sleep(60); // Falls die Meldung geklappt hat 60s warten, damit Spieler den Server verlassen können.
// inititialize Systemctl Service interface
$service = new \NAE\Service\Systemctl("factorio");
// Server Stoppen
if($service->stop()) {
$cli->sendInfo( "FACTORIO SERVER WURDE GESTOPPT!" );
}
// neue Versionsnummer in .env Datei übernehmen
if(writeBackVersion()) {
$cli->sendInfo( "Version in Environment File wurde aktualisiert" );
}
// Dateien aus alten Server Files kopieren..
if( is_dir(__DIR__."/factorio-".$current_version->getVersion()) && is_dir(__DIR__."/factorio-".$latest_version->getVersion()) ) {
echo PHP_EOL;
$cli->sendTitle( "Kopiere Konfigurations-Dateien in den neuen Server Pfad", 1 );
foreach($copy_paths as $copy_id => $copy_name) {
$copy_source = __DIR__."/factorio-".$current_version->getVersion().$copy_name;
$copy_dest = __DIR__."/factorio-".$latest_version->getVersion().$copy_name;
if(file_exists($copy_source)) {
if(is_dir($copy_source)) {
$cli->sendTitle( "Kopierenvorgang Nr. ".($copy_id+1)." von ".count($copy_paths)." - $copy_name", 2 );
try {
\NAE\Functions\Folder\rcopy($copy_source, $copy_dest);
$cli->sendSuccess( "Kopiervorgang Erfolgreich!" );
} catch (\Exception $e) {
$cli->sendError( "Kopiervorgang Fehlgeschlagen!" );
}
} else {
$cli->sendTitle( "Kopierenvorgang Nr. ".($copy_id+1)." von ".count($copy_paths)." - $copy_name", 2 );
if(@copy($copy_source, $copy_dest)) {
$cli->sendSuccess( "Kopiervorgang Erfolgreich!" );
} else {
$cli->sendError( "Kopiervorgang Fehlgeschlagen!" );
}
}
} else {
$cli->sendWarning( "Quelle nicht vorhanden!" );
}
}
}
// Fix file permissions..
(function(){
global $latest_version, $cli;
$cli->sendTitle( "Rechte im neuen Server-Verzeichnis werden korrigiert", 1 );
exec("chown -R factorio:factorio \"".__DIR__."/factorio-".$latest_version->getVersion()."\"", $output, $return);
if($return === 0) {
$cli->sendSuccess( "Rechte erfolgreich korrigiert!" );
} else {
$cli->sendError( "Rechte konnten nicht korrigiert werden!", true );
}
})();
if($service->start()) {
$cli->sendSuccess( "FACTORIO SERVER WURDE WIEDER GESTARTET!" );
} else {
$cli->sendError( "FACTORIO SERVER KONNTE NICHT WIEDER GESTARTET WERDEN!", true );
}
}
} else {
// Keine aktuellere Version verfügbar!
$cli->sendInfo( "Kein Update verfügbar." );
}

View File

@ -1,376 +0,0 @@
<?php
/**
* Namespace for classes and functions related to the game Factorio.
* @package NAE\Factorio
*/
namespace NAE\Factorio;
/**
* Class for managing Factorio mods.
* @author "Marcel Naeve" <php@naeve.info>
* @license MIT License (http://www.opensource.org/licenses/mit)
*/
class FactorioMod {
/**
* @var int INIT_TYPE_PATH - Mod is initialized from a zip file.
*/
const INIT_TYPE_PATH = 1;
/**
* @var int INIT_TYPE_NAME - Mod is initialized from a mod name.
*/
const INIT_TYPE_NAME = 3;
/**
* @var object|null $info - Mod information from Zip file.
*/
private $info = null;
/**
* @var object|null $api - Mod information from Factorio API.
*/
private $api = null;
/**
* @var object|null $mod_settings - Mod settings enabled/disabled from json in mods folder.
*/
private $mod_settings = null;
/**
* @var string|null $mod_folder - Path to the mods folder.
*/
private $mod_folder = null;
/**
* @var string $game_folder - Path to the Factorio game folder.
*/
private $game_folder = "factorio";
/**
* Reads all Mods as FactorioMod objects to an array.
* @param string $modFolder Path to the mods folder.
* @return array Array of FactorioMod objects.
*/
static function readModFolder(string $modFolder) : array {
$mods = [];
$dh = opendir($modFolder); // open the directory handle
while ( false !== ($entry = readdir($dh)) ) { // read directory entries
if(preg_match("/\.zip$/ui", $entry)) { // if the file is a zip file
$mods[] = new FactorioMod(
$modFolder. "/". $entry,
FactorioMod::INIT_TYPE_PATH
);
}
}
closedir($dh); // close the directory handle
return $mods;
}
/**
* Reads mod information from info.json file in mod Zip file.
* @param string $zipPath Path to the mod Zip file.
* @return object|null Mod information from info.json file.
*/
private function readInfo(string $zipPath) : ?object {
if(!file_exists($zipPath)) { // file does not exist?
return null;
}
$za = new \ZipArchive();
$res = $za->open($zipPath); // open the zip file
if($res !== true) { // open the zip file failed?
return null;
}
$c = null;
for( $i = 0; $i < $za->numFiles; $i++ ){ // Iterate over all files in the zip file
$name = $za->getNameIndex( $i ); // get the name of current file
if(basename($name) == "info.json") { // if the file is info.json
$c = $za->getFromIndex($i); // get the content of info.json
$i = $za->numFiles; // break the loop by condition
break; // break the loop by force (double tap)
}
}
$za->close(); // close the zip file
return json_decode( $c, false ); // return decoded json object or null on failure
}
/**
* Sends a GET request to Factorio API to get mod information.
* @param string $name Mod name to get information from Factorio API.
* @return object|null Mod information from Factorio API.
*/
private function callApi(string $name="") : ?object {
if($name === "") { // no name given?
if($this->info === null) { // also no path to module for info.json?
return null;
}
$name = $this->info->name; // get name from info.json
}
$api = "https://mods.factorio.com/api/mods/" . $name;
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $api);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($curl);
$cri = curl_getinfo($curl);
curl_close($curl);
if($cri["http_code"] != 200) { // request failed?
return null;
}
if(trim($response) < 1) { // response body empty?
return null;
}
$r = json_decode($response, false); // decode json object or null on failure
return $r;
}
/**
* Constructor.
* @param string $init Path to the mod Zip file or mod name.
* @param int $init_type Initialization type (FactorioMod::INIT_TYPE_PATH or FactorioMod::INIT_TYPE_NAME).
* @param string $mod_folder Path to the mods folder.
*/
public function __construct(string $init, int $init_type=self::INIT_TYPE_PATH, string $mod_folder="") {
if($init_type === self::INIT_TYPE_PATH) {
$this->info = $this->readInfo($init);
if($this->info !== null) {
$this->mod_folder = dirname($init);
$this->callApi();
}
}
if($init_type === self::INIT_TYPE_NAME) {
$this->mod_folder = $mod_folder;
$this->callApi($init);
// TODO: look if mod is installed..
}
}
/**
* Returns last release version information of the mod.
* @return object|null Last release version information of the mod.
*/
public function getLastVersionInfo() : ?object {
$target = count($this->api->releases) - 1;
return $this->api->releases[ $target ];
}
/**
* Checks if the latest release mod version is newer than the installed version.
* @return bool True if the latest release mod version is newer, false otherwise.
*/
public function isUpdateable() : bool {
$lv = new \NAE\Factorio\FactorioVersion(
$this->getLastVersionInfo()->version
);
$cv = new \NAE\Factorio\FactorioVersion(
$this->info->version
);
return $lv->isNewer($cv);
}
/**
* Deletes the mod from the mods folder file.
* @return bool True if the mod was deleted, false otherwise.
*/
private function delete() : bool {
// TODO: implement
return false;
}
/**
* Downloads the latest release mod version to the mods folder.
* @return bool True if the mod was downloaded, false otherwise.
*/
private function download() : bool {
// TODO: continue implementing.. where player-data.json..
$player_data = json_decode(file_get_contents($this->game_folder. "/player-data.json"), true);
$token = $player_data["service-token"];
$username = $player_data["service-username"];
$url = "https://mods.factorio.com" . $this->getLastVersionInfo()->download_url . "?username=$username&token=$token";
return false;
}
/**
* Uninstalls the mod from the mods folder and the settings.json file.
* @return bool True if the mod was uninstalled, false otherwise.
*/
public function uninstall() : bool {
// TODO: implement
return false;
}
/**
* Installs the mod in the mods folder and adds it to the settings.json file as enabled.
* @return bool True if the mod was installed, false otherwise.
*/
public function install() : bool {
// TODO: implement
return false;
}
/**
* Updates the mod to the latest release mod version.
* @return bool True if the mod was updated, false otherwise.
*/
public function update() : bool {
// TODO: implement
return false;
}
/**
* Loads the mod settings for all mods (enabled/disabled) from the settings.json file.
* @return bool True if the mod settings have been loaded successfully, false otherwise.
*/
private function loadModSettings() : bool {
$this->mod_settings = json_decode(
file_get_contents($this->mod_folder. "/settings.json")
);
return false;
}
/**
* Returns the mod settings for all mods (enabled/disabled) from settings.json.
* @return object|null Mod settings for all mods.
*/
public function getModSettings() :?object {
return $this->mod_settings;
}
/**
* Sets the path to the game folder.
* @param string $game_folder Path to the game folder.
* @return FactorioMod The instance of FactorioMod for chaining.
*/
public function setGameFolder(string $game_folder) : FactorioMod {
$this->game_folder = $game_folder;
return $this;
}
/**
* Returns the path to the game folder.
* @return string Path to the game folder.
*/
public function getGameFolder() : string {
return $this->game_folder;
}
/**
* Saves the changes in the mod settings for all mods (enabled/disabled) to the settings.json file.
* @return bool True if the mod settings have been saved successfully, false otherwise.
*/
private function saveModSettings() : bool {
$j = json_encode($this->mod_settings);
$r = file_put_contents($this->mod_folder. "/settings.json", $j);
if($r === false) {
return false;
}
return ( $r === strlen($j) );
}
/**
* Sets the mod settings for all mods (enabled/disabled) in the settings.json file.
* @param object $mod_settings Mod settings for all mods.
* @return FactorioMod The instance of FactorioMod for chaining.
*/
public function setModSettings(object $mod_settings) : FactorioMod {
$this->mod_settings = $mod_settings;
return $this;
}
/**
* Checks if this mod is enabled in the settings.json.
* @return bool True if this mod is enabled, false otherwise.
*/
public function isEnabled() : bool {
// TODO: implement
return false;
}
/**
* Checks if this mod is disabled in the settings.json.
* @return bool True if this mod is disabled, false otherwise.
*/
public function isDisabled() : bool {
// TODO: implement
return false;
}
/**
* Sets this mod to enabled in the settings.json
*/
public function enable() {
// TODO: implement
}
/**
* Sets this mod to disabled in the settings.json
*/
public function disable() {
// TODO: implement
}
}

View File

@ -1,249 +0,0 @@
<?php
/**
* Namespace for classes and functions related to the game Factorio.
* @package NAE\Factorio
*/
namespace NAE\Factorio;
/**
* Class for managing a headless server for the game Factorio.
* @author "Marcel Naeve" <php@naeve.info>
* @license MIT License (http://www.opensource.org/licenses/mit)
*/
class FactorioServer {
/**
* @var FactorioVersion Current Version of Server
*/
private $version;
/**
* @var FactorioMod For Managing Server Mods
*/
private $mods;
/**
* @var ValveRcon for handling Valve Rcon to server
*/
private $rcon;
/**
* @var string Name of the Save to load when starting the server
*/
private $save_name;
/**
* @var string Path to the Server Directory
*/
private $server_dir = INDEX_DIR . "/factorio";
/**
* @var string Path to the Mods Directory
*/
private $mod_dir = INDEX_DIR . "/factorio/mods";
/**
* @var string Path to the Save-File Directory
*/
private $save_dir = INDEX_DIR . "/factorio/saves";
/**
* @var string Name of the user who owns the files and runs this server
*/
private $user_name = "factorio";
/**
* @var string Name of the user-group who owns the files and runs this server
*/
private $user_group = "factorio";
/**
* @var string Name of the Service in systemd/systemctl
*/
private $service_name = "factorio";
/**
* @var callcable Custom function for stopping the server (return bool)
*/
private $customStop = null;
/**
* @var callable Custom function for starting the server (return bool)
*/
private $customStart = null;
/**
* @var callable Custom function for restarting the server (return bool)
*/
private $customReStart = null;
/**
* @var callable Custom function for checking the server status (return bool - true means server is running, false means server is not running)
*/
private $customIsRunning = null;
/**
* @var array Server Settings
*/
private $settings = [];
/**
* @var array Environment Variables for the Server
*/
private $env = [];
/**
* @var array Server Admin List
*/
private $admin_list = [];
/**
* Constructor
*
* @param array $settings Settings for the server
*/
public function __construct(array $settings) {
// TODO: Implement
}
/**
* Updates the Server with optional feedback on cli.
* @param bool $silent Feedback on cli wanted? (default: false)
* @return bool Returns true on success, false on failure
*/
public function updateCli(bool $silent=false) : bool {
// TODO: Implement
return false;
}
/**
* Install a new Server with the current Settings with optional feedback on cli.
* @param string $version Which version should be installed? (default: latest)
* @param bool $silent Feedback on cli wanted? (default: false)
* @return bool Returns true on success, false on failure
*/
public function installCli(string $version="latest", bool $silent=false) : bool {
// TODO: Implement
return false;
}
/**
* Sets a custom function for stopping the server.
* @param callable function that is beeing called for stopping the server
* @return FactorioServer $this for chaining.
*/
public function setCustomStop(callable $customStop) : FactorioServer {
$this->customStop = $customStop;
return $this;
}
/**
* Sets a custom function for starting the server.
* @param callable function that is beeing called for starting the server
* @return FactorioServer $this for chaining.
*/
public function setCustomStart(callable $customStart) : FactorioServer {
$this->customStart = $customStart;
return $this;
}
/**
* Stops the server.
* @return bool true on success, false on failure
*/
public function stop() : bool {
if(is_callable($this->customStop)) {
return call_user_func($this->customStop);
}
$command = "systemctl stop factorio-server";
exec($command, $output, $return);
return ( $return === 0 );
}
/**
* Starts the server.
* @return bool true on success, false on failure
*/
public function start() : bool {
if(is_callable($this->customStart)) {
return call_user_func($this->customStart);
}
$command = "systemctl start ".$this->getServiceName();
exec($command, $output, $return);
return ( $return === 0 );
}
/**
* Restarts the server.
* @return bool true on success, false on failure
*/
public function restart() : bool {
if(is_callable($this->customReStart)) {
return call_user_func($this->customReStart);
}
exec("systemctl restart ".$this->getServiceName()." > /dev/null", $output, $return);
return ( $return === 0 );
}
/**
* Check if the Service is running
*
* @return bool True if the service is running, false otherwise
*/
public function isRunning() : bool {
if(is_callable($this->customIsRunning)) {
return call_user_func($this->customIsRunning);
}
exec("systemctl is-active ".$this->getServiceName(), $output, $return);
return ( $return === 0 );
}
/**
* Get the Name of the Service in systemd/systemctl.
* @return string Name of the service
*/
public function getServiceName() : string {
return $this->service_name;
}
/**
* Sets the Name of the Service in systemd/systemctl.
* @param string $serviceName Name of the Service
* @return FactorioServer $this for chaining.
*/
public function setServiceName(string $serviceName) : FactorioServer {
$this->service_name = $serviceName;
return $this;
}
}

View File

@ -1,106 +0,0 @@
<?php
/**
* Namespace for classes and functions related to the game Factorio.
* @package NAE\Factorio
*/
namespace NAE\Factorio;
/**
* Class for parsing and comparing Factorio versions.
* @author "Marcel Naeve" <php@naeve.info>
* @license MIT License (http://www.opensource.org/licenses/mit)
*/
class FactorioVersion {
/**
* @var string The Factorio Version
*/
private $version;
/**
* @var int The Factorio version converted to an comparable integer.
*/
private $intVersion;
/**
* Fills a string with zeros at the beginning till string length matches the target length.
* @param string $str string to fill
* @param int $target_length Target length of the string
* @return string string with zeros at the beginning till string length matches
*/
private function zero_fill(string $str, int $target_length) {
if(strlen($str) >= $target_length) {
return $str;
}
$missing = ( $target_length - strlen($str) );
for($i=0;$i<$target_length;$i++) {
$str = "0".$str;
}
return $str;
}
/**
* Formats the Factorio version string to a comparable integer.
* @param string $vs Factorio version string (example: 2.0.14)
* @return int factorio version as comparable integer (example: versionFormat("2.0.14") -> "000200000014" -> int(200000014))
*/
private function versionFormat(string $vs) : int {
$parts = explode(".", $vs);
$new = "";
foreach($parts as $i => $v) {
$new .= $this->zero_fill($v, 4);
}
return intval($new);
}
/**
* Constructor.
* @param string $version Factorio version string (example: 2.0.14)
*/
public function __construct(string $version) {
$this->version = $version;
$this->intVersion = $this->versionFormat($version);
}
/**
* Returns the Factorio version string (example: 2.0.14).
* @return string Factorio version string (example: 2.0.14)
*/
public function getVersion() : string {
return $this->version;
}
/**
* Returns the Factorio version as a comparable integer (example: versionFormat("2.0.14") -> int(200000014)).
* @return integer Factorio version as a comparable integer (example: versionFormat("2.0.14") -> int(200000014)).
*/
public function getIntVersion() : int {
return $this->intVersion;
}
/**
* Checks if the current Factorio version is newer than another version.
* @param FactorioVersion $other Another FactorioVersion object
*/
public function isNewer(FactorioVersion $other) : bool {
return $this->intVersion > $other->getIntVersion();
}
/**
* Checks if the current Factorio version is older than another version.
* @param FactorioVersion $other Another FactorioVersion object
*/
public function isOlder(FactorioVersion $other) : bool {
return $this->intVersion < $other->getIntVersion();
}
}

View File

@ -1,75 +0,0 @@
<?php
/**
* Namespace for classes and functions related to managing services.
* @package NAE\Service
*/
namespace NAE\Service;
/**
* Systemctl Service Management Interface
* @author "Marcel Naeve" <php@naeve.info>
* @license MIT License (http://www.opensource.org/licenses/mit)
*/
class Systemctl {
/**
* @var string Name of the service to manage
*/
private $service_name = "";
/**
* Constructor
*
* @param string $service_name Name of the service to manage
*/
public function __construct(string $service_name) {
$this->service_name = $service_name;
}
/**
* Start the Service
*
* @return bool True if the service was started successfully, false otherwise
*/
public function start () : bool {
exec("systemctl start ".$this->service_name." > /dev/null", $output, $return);
return ( $return === 0 );
}
/**
* Stop the Service
*
* @return bool True if the service was stopped successfully
*/
public function stop () : bool {
exec("systemctl stop ".$this->service_name." > /dev/null", $output, $return);
return ( $return === 0 );
}
/**
* Restart the Service
*
* @return bool True if the service was restarted successfully, false otherwise
*/
public function restart () : bool {
exec("systemctl restart ".$this->service_name." > /dev/null", $output, $return);
return ( $return === 0 );
}
/**
* Check if the Service is running
*
* @return bool True if the service is running, false otherwise
*/
public function isRunning () : bool {
exec("systemctl status ".$this->service_name, $output, $return);
$search_string = implode(";", $output);
return ( strpos($search_string, "Active: active (running)") >= 0 );
}
}

View File

@ -1,77 +0,0 @@
<?php
/**
* Namespace for Terminal related classes.
* @package NAE\Terminal.
*/
namespace NAE\Terminal;
/**
* A Class to print messages to the terminal with different styles and colors.
* @author "Marcel Naeve" <php@naeve.info>
* @license MIT License (http://www.opensource.org/licenses/mit)
*/
class TerminalMessage {
/**
* Send a message to the terminal ending with a line break at the end.
* @param string $msg The message to send.
*/
public function send(string $msg) {
echo $msg . PHP_EOL;
}
/**
* Send a title to the terminal with a specified layer and and a double line break at the end.
* @param string $msg The title message to send.
* @param string $layer The layer (default: 0)
*/
public function sendTitle(string $msg, int $layer=0) {
$layerString = "#";
for($i=0; $i<$layer; $i++) {
$layerString .= "#";
}
self::send( "\033[1m[$layerString] $msg\033[0m" . PHP_EOL );
}
/**
* Send a success message to the terminal with a green color and a line break at the end.
* @param string $msg The success message to send.
*/
public function sendSuccess(string $msg) {
self::send( "\033[1;32m[SUCCESS] $msg\033[0m" );
}
/**
* Send an info message to the terminal with a blue color and a line break at the end.
* @param string $msg The info message to send.
*/
public function sendInfo(string $msg) {
self::send( "\033[1;34m[INFO] $msg\033[0m" );
}
/**
* Send an error message to the terminal with a red color and a line break at the end.
* @param string $msg The error message to send.
* @param bool $critical If true, the script will terminate with a non-zero exit code (default: false).
*/
public function sendError(string $msg, bool $critical=false) {
self::send( "\033[1;31m[ERROR] $msg\033[0m" );
if ($critical) {
die(1);
}
}
/**
* Send a warning message to the terminal with a yellow color and a line break at the end.
* @param string $msg The warning message to send.
* @param bool $critical If true, the script will terminate with a non-zero exit code (default: false).
*/
public function sendWarning(string $msg, bool $critical=false) {
self::send( "\033[1;33m[WARNING] $msg\033[0m" );
if ($critical) {
die(1);
}
}
}

View File

@ -1,206 +0,0 @@
<?php
/**
* Namespace for Valve RCON related classes and functions.
* @package NAE\Valve\Rcon
*/
namespace NAE\Valve\Rcon;
/**
* A Class to interact with a Valve RCON server.
* @author "Marcel Naeve" <php@naeve.info>
* @license MIT License (http://www.opensource.org/licenses/mit)
*/
class ValveRcon {
/**
* @var string IP address of the RCON server
*/
private $ip;
/**
* @var int Port number of the RCON server
*/
private $port;
/**
* @var string Password to authenticate with the RCON server
*/
private $password;
/**
* @var int Timeout for socket operations in seconds
*/
private $timeout;
/**
* @var resource Socket resource for RCON communication
*/
private $socket;
/**
* @var array Error details if any occurs during communication
*/
private $err;
/**
* Constructor, setting variables.
* @param string $ip IP address of the RCON server
* @param int $port Port number of the RCON server
* @param string $password Password to authenticate with the RCON server
* @param int $timeout Timeout for socket operations in seconds (default: 2 seconds)
*/
public function __construct(string $ip, int $port, string $password, int $timeout=2) {
$this->ip = $ip;
$this->port = $port;
$this->password = $password;
$this->timeout = $timeout;
}
/**
* Establishes a connection to the RCON server.
* @return bool Connection established successfully?
*/
private function connect() : bool {
// prepare variables for error handling
$errno = null;
$errmsg = "";
$this->socket = fsockopen( // connect to RCON server
"udp://{$this->ip}",
$this->port,
$errno,
$errmsg,
$this->timeout
);
if(!$this->socket) { // connection failed?
$this->err = [
"code" => $errno,
"message" => "Socket connection failed: $errmsg"
];
return false;
}
return true;
}
/**
* Closes the connection to the RCON server
*/
private function disconnect() : void {
if ( $this->isConnected() ) {
fclose($this->socket);
$this->socket = NULL;
}
}
/**
* Checks if the connection to the RCON server is established.
*/
private function isConnected() : bool {
return ( get_resource_type($this->socket) !== null ); // check if socket is resource type, as it should be
}
/**
* Receives data from the RCON server.
* @return string|null Received data or null if no data is available
*/
private function read() : ?string {
if (!$this->isConnected()) {
return null;
}
stream_set_timeout($this->socket, 0, $this->timeout * 100000); // set timeout
$response = '';
while ($buffer = fread($this->socket, 4096)) { // loop while there's more data
list($header, $content) = explode("\n", $buffer, 2); // split into header and content
$response .= $content; // append content to response
}
$response = trim($response); // remove whitespaces around the response
if (empty($response)) // no data received, return null
return null;
return preg_replace("/\^./","", $response); // return response without prefix
}
/**
* Writes a command to the RCON server.
* @return bool $cmd Command writen successfully?
*/
private function write(string $cmd) : bool {
if (!$this->isConnected()) {
return false;
}
if( false === fwrite($this->socket, str_repeat(chr(255), 4) . "rcon {$this->password} {$cmd}\n") ) {
return false;
}
return true;
}
/**
* Sends a command to the RCON server and optionally reads the response.
* @param string $cmd Command to send to the RCON server
* @param bool $read Should the response be read from the RCON server? (default: false)
* @return string|null Response from the RCON server or null if no response is expected or read fails
*/
public function sendCommand(string $cmd, bool $read=false) : ?string {
$this->connect();
if(!$this->write($cmd)) { // sending the command
$this->err = [
"code" => 0,
"message" => "Command could not be sent"
];
$this->disconnect();
return null;
}
if (!$read) {
$this->disconnect();
return null;
}
if(!$res = $this->read()) { // reading the response
$this->err = [
"code" => 0,
"message" => "Response could not be read"
];
}
$this->disconnect();
return $res;
}
/**
* Returns the last error details if any occurred during communication.
* @return object|null Last error details or null if no error has occurred (error object contains code and message as properties)
*/
public function getError() :?object {
if($this->err === null) {
return null; // no error has occurred, return null
}
return json_decode(json_encode($this->err)); // return last error as object
}
}

View File

@ -1,33 +0,0 @@
<?php
/**
* Namespace for PHP-CURL related classes and functions.
* @package NAE\Functions\Curl
*/
namespace NAE\Functions\Curl;
/**
* Lädt eine Dei herunter mit Hilfe von php-curl.
* @param string $fileDestination Zielpfad
* @param string $fileSource Quellpfad/URL
* @return bool Download Erfolgreich? (only works when the file size is known upfront from headers)
*/
function downloadFile(string $fileDestination, string $fileSource) : bool {
$ch = \curl_init($fileSource);
$fp = \fopen($fileDestination, 'wb');
\curl_setopt($ch, CURLOPT_FILE, $fp);
\curl_setopt($ch, CURLOPT_HEADER, 0);
\curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
\curl_exec($ch);
$info = \curl_getinfo($ch);
\curl_close($ch);
\fclose($fp);
return ( $info["download_content_length"]==$info["size_download"] ); // only works when the file size is known upfront from headers
}

View File

@ -1,41 +0,0 @@
<?php
/**
* Namespace for Folder related classes and functions.
* @package NAE\Functions\Folder
*/
namespace NAE\Functions\Folder;
/**
* Recursive copy a directory and its contents to another directory (overwrites existing structures).
* @param string $source Quellpfad/URL
* @param string $destination Zielpfad
*/
function rcopy(string $source, string $destination) {
if (file_exists($destination)) {
rrmdir($destination);
return;
}
if (is_dir($source)) {
mkdir($destination);
$files = scandir($source);
foreach ($files as $file) {
if ($file != "." && $file != "..") {
rcopy("$source/$file", "$destination/$file");
}
}
return;
}
if (file_exists($source)) {
copy($source, $destination);
}
}

View File

@ -1,27 +0,0 @@
<?php
/**
* Namespace for Folder related classes and functions.
* @package NAE\Functions\Folder
*/
namespace NAE\Functions\Folder;
/**
* Recursive removes a directory and its contents
* @param string $dir Target directory to be removed
*/
function rrmdir(string $dir) {
if (is_dir($dir)) {
$files = scandir($dir);
foreach ($files as $file)
if ($file != "." && $file != "..") rrmdir("$dir/$file");
rmdir($dir);
return;
}
if (file_exists($dir)) {
unlink($dir);
}
}