added current files to dev branch.
This commit is contained in:
parent
808be57871
commit
bf2b7d9f36
|
@ -0,0 +1,5 @@
|
|||
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"
|
|
@ -0,0 +1,276 @@
|
|||
<?PHP
|
||||
|
||||
|
||||
|
||||
|
||||
require __DIR__.'/scripts/func.downloadFile.php';
|
||||
require __DIR__.'/scripts/class.FactorioVersion.php';
|
||||
require __DIR__.'/scripts/class.Systemctl.php';
|
||||
require __DIR__.'/scripts/class.ValveRcon.php';
|
||||
|
||||
|
||||
|
||||
// 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";
|
||||
|
||||
// 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);
|
||||
echo "CURRENT_VERSION: ".$current_version->getVersion().PHP_EOL;
|
||||
|
||||
|
||||
|
||||
// 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]);
|
||||
echo "LATEST_VERSION: ".$latest_version->getVersion().PHP_EOL.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;
|
||||
|
||||
echo "# [ PRÜFE AUF FACTORIO UPDATES ]".PHP_EOL;
|
||||
|
||||
if($latest_version->isNewer($current_version)) { // neue Version verfügbar?
|
||||
|
||||
echo "## [ NEUE VERSION GEFUNDEN : UPDATE STARTET ]".PHP_EOL;
|
||||
|
||||
if(file_exists($download_output)) { // liegt noch ein altes Server Archiv im Vertzeichnis?
|
||||
|
||||
echo PHP_EOL."[ ALTE SERVER FILES GEFUNDEN : STARTE LÖSCHVORGANG ]".PHP_EOL;
|
||||
|
||||
if( unlink($download_output) ) { // altes Archiv löschen
|
||||
|
||||
echo "-> ALTE SERVER FILES ERFOLGREICH GELÖSCHT!".PHP_EOL;
|
||||
|
||||
} else {
|
||||
|
||||
echo "-> ERR : ALTE SERVER FILES ERFOLGREICH GELÖSCHT!".PHP_EOL;
|
||||
die(1);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
echo PHP_EOL."[ STARTE DOWNLOAD DER SERVER FILES ]".PHP_EOL;
|
||||
|
||||
if(\NAE\Functions\Curl\downloadFile($download_output, $download_source)) { // Download der neuen Server Files
|
||||
|
||||
echo "-> DOWNLOAD SUCCESS!".PHP_EOL;
|
||||
$download_success = true;
|
||||
|
||||
} else {
|
||||
|
||||
echo "-> ERR : DOWNLOAD FEHLGESCHLAGEN!".PHP_EOL;
|
||||
die(1);
|
||||
|
||||
}
|
||||
|
||||
|
||||
if($download_success) {
|
||||
|
||||
echo PHP_EOL."[ STARTE DAS ENTPACKEN DER NEUEN SERVER FILES ]".PHP_EOL;
|
||||
|
||||
exec("tar -xvf \"$download_output\" > /dev/null", $output, $return); // Entpacken
|
||||
|
||||
if($return === 0) {
|
||||
|
||||
if( rename(__DIR__."/factorio", __DIR__."/factorio-".$latest_version->getVersion()) ) { // Umbenennen mit Versionsnummer
|
||||
|
||||
echo "-> Neue Server Files wurden Erfolgreich entpackt!".PHP_EOL;
|
||||
$extract_success = true;
|
||||
|
||||
} else {
|
||||
|
||||
echo "-> ERR : Umbenennen des Factorio Ordners mit Versionsnummer Fehlgeschlagen!".PHP_EOL;
|
||||
die(1);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
echo "-> ERR : Entpacken der Server Files ist Fehlgeschlagen!".PHP_EOL;
|
||||
die(1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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) {
|
||||
echo "[!] ERR : RCON Verbindung konnte nicht aufgebaut werden!".PHP_EOL;
|
||||
$rcon = null;
|
||||
}
|
||||
|
||||
} catch(\Exception $e) {
|
||||
|
||||
echo "[!] ERR : RCON Verbindung konnte nicht aufgebaut werden!".PHP_EOL;
|
||||
$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()) {
|
||||
echo "[+] FACTORIO SERVER WURDE GESTOPPT!".PHP_EOL;
|
||||
}
|
||||
|
||||
// neue Versionsnummer in .env Datei übernehmen
|
||||
if(writeBackVersion()) {
|
||||
echo "[+] Version in Environment File ist aktualisiert".PHP_EOL;
|
||||
}
|
||||
|
||||
// Dateien aus alten Server Files kopieren..
|
||||
if( is_dir(__DIR__."/factorio-".$current_version->getVersion()) && is_dir(__DIR__."/factorio-".$latest_version->getVersion()) ) {
|
||||
|
||||
echo PHP_EOL."[ Kopiere Konfigurations-Dateien in den neuen Server Pfad ]".PHP_EOL;
|
||||
|
||||
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)) {
|
||||
|
||||
echo "[ Kopierenvorgang Nr. ".($copy_id+1)." von ".count($copy_paths)." - $copy_name ] ";
|
||||
if(copy($copy_source, $copy_dest)) {
|
||||
|
||||
echo "-> Kopiervorgang Erfolgreich!".PHP_EOL;
|
||||
|
||||
} else {
|
||||
|
||||
echo "-> ERR : Kopiervorgang Fehlgeschlagen!".PHP_EOL;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
echo " - Quelle nicht vorhanden!".PHP_EOL;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Fix file permissions..
|
||||
(function(){
|
||||
|
||||
global $latest_version;
|
||||
|
||||
exec("chown -R factorio:factorio \"".__DIR__."/factorio-".$latest_version->getVersion()."\"", $output, $return);
|
||||
if($return === 0) {
|
||||
echo "[+] Rechte im neuen Server verzeichnis korrigiert.".PHP_EOL;
|
||||
} else {
|
||||
echo "[!] ERR : Rechte im neuen Server verzeichnis konnten nicht korrigiert werden.".PHP_EOL;
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
|
||||
if($service->start()) {
|
||||
echo "[+] FACTORIO SERVER WURDE WIEDER GESTARTET!".PHP_EOL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
// Keine aktuellere Version verfügbar!
|
||||
echo "-> Kein Update verfügbar.".PHP_EOL;
|
||||
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
namespace NAE\Factorio;
|
||||
|
||||
|
||||
class FactorioVersion {
|
||||
|
||||
private $version;
|
||||
private $intVersion;
|
||||
|
||||
|
||||
/**
|
||||
* Füllt eine Zeichenkette am anfang mit Nullen auf bis die Ziellänge erreicht ist.
|
||||
* @param string Zu füllende Zeichenkette
|
||||
* @param int Ziellänge der gefüllten Zeichenkette
|
||||
* @return string die Zeichenkette mit Nullen vorne angefügt um die Ziellänge zu erreichen
|
||||
*/
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatiert die Factorio Versionsnummern um zu einem Vergleichbaren Integer.
|
||||
* @param string Factorio Versions Zeichenkette Beispiel: 2.0.14
|
||||
* @return int zum einfachen Vergleich formatierter Versions-Integer. Beispiel: versionsFormat("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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function __construct(string $version) {
|
||||
$this->version = $version;
|
||||
$this->intVersion = $this->versionFormat($version);
|
||||
}
|
||||
|
||||
public function getVersion() : string {
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
public function getIntVersion() : int {
|
||||
return $this->intVersion;
|
||||
}
|
||||
|
||||
public function isNewer(FactorioVersion $other) : bool {
|
||||
return $this->intVersion > $other->getIntVersion();
|
||||
}
|
||||
|
||||
public function isOlder(FactorioVersion $other) : bool {
|
||||
return $this->intVersion < $other->getIntVersion();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
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 );
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
<?php
|
||||
|
||||
namespace NAE\Valve\Rcon;
|
||||
|
||||
class ValveRcon {
|
||||
|
||||
private $ip;
|
||||
private $port;
|
||||
private $password;
|
||||
private $timeout;
|
||||
|
||||
private $socket;
|
||||
private $err;
|
||||
|
||||
public function __construct(string $ip, int $port, string $password, int $timeout=2) {
|
||||
$this->ip = $ip;
|
||||
$this->port = $port;
|
||||
$this->password = $password;
|
||||
$this->timeout = $timeout;
|
||||
}
|
||||
|
||||
private function connect() : bool {
|
||||
|
||||
$errno = null;
|
||||
$errmsg = "";
|
||||
|
||||
$this->socket = fsockopen(
|
||||
"udp://{$this->ip}",
|
||||
$this->port,
|
||||
$errno,
|
||||
$errmsg,
|
||||
$this->timeout
|
||||
);
|
||||
|
||||
if(!$this->socket) {
|
||||
$this->err = [
|
||||
"code" => $errno,
|
||||
"message" => "Socket connection failed: $errmsg"
|
||||
];
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private function disconnect() : void {
|
||||
|
||||
if ( $this->isConnected() ) {
|
||||
fclose($this->socket);
|
||||
$this->socket = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function isConnected() : bool {
|
||||
|
||||
return ( get_resource_type($this->socket) !== null ); // check if socket is resource type, as it should be
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace NAE\Functions\Curl;
|
||||
|
||||
/**
|
||||
* Lädt eine Dei herunter mit Hilfe von php-curl.
|
||||
* @param string Zielpfad
|
||||
* @param string Quellpfad/URL
|
||||
* @return bool Download Erfolgreich?
|
||||
*/
|
||||
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"] );
|
||||
|
||||
}
|
Loading…
Reference in New Issue