web/app/Models/GameServer.php

294 lines
6.4 KiB
PHP

<?php
namespace App\Models;
use App\Roles\GameServers;
use App\Enums\GameServerState;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Cache;
use BjornVoesten\CipherSweet\Concerns\WithAttributeEncryption;
use BjornVoesten\CipherSweet\Casts\Encrypted as CipherSweetEncrypted;
use Log;
class GameServer extends Model
{
use SoftDeletes, WithAttributeEncryption;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'uuid',
'access_key',
'ip_address',
'port',
'maximum_place_jobs',
'maximum_thumbnail_jobs',
'is_set_up',
'has_vnc',
'vnc_port',
'vnc_password',
'friendly_name',
'utc_offset',
];
/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
'access_key',
'access_key_index',
'ip_address',
'ip_address_index',
'vnc_port',
'vnc_password',
'friendly_name',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'access_key' => CipherSweetEncrypted::class,
'ip_address' => CipherSweetEncrypted::class,
'vnc_port' => 'encrypted',
'vnc_password' => 'encrypted',
'friendly_name' => 'encrypted',
];
/**
* Unformatted log keys for any game server.
*
* @return array
*/
public static array $logKeys = [
'console' => 'game_server_logs_%s',
'ram' => 'game_server_ram_usage_%s',
'cpu' => 'game_server_cpu_usage_%s',
'network' => 'game_server_network_usage_%s',
'access' => 'game_server_access_%s',
'state' => 'game_server_state_%s',
];
/**
* Gets a log key associated for this game server.
*
* @param string $key
* @return ?string
*/
public function logKey(string $key): ?string
{
if (empty(self::$logKeys[$key]))
{
return null;
}
return sprintf(self::$logKeys[$key], $this->uuid);
}
/**
* Initializes all logs keys.
*/
public function initLogKeys()
{
foreach (array_keys(self::$logKeys) as $key)
{
Cache::put($this->logKey($key), null);
}
}
/**
* Updates the state last ping.
*/
public function ping()
{
Cache::put($this->logKey('state'), [
'last_ping' => time(),
'state' => GameServerState::Online
]);
}
/**
* The complete log of this game server.
*
* @param string $key
* @return mixed
*/
public function retrieveCompleteLog(string $key): mixed
{
return Cache::get($this->logKey($key));
}
/**
* Appends to one of the log files of this game server.
*
* @param string $key
* @param mixed $message
*/
public function appendToLog(string $key, mixed $message)
{
$lock = Cache::lock($this->logKey($key), 10);
try
{
$lock->block(5);
$log = $this->retrieveCompleteLog($key);
if (empty($log))
{
$log = [];
}
$timestamp = time();
$log['latest'] = $timestamp;
$log[$timestamp] = $message;
Cache::put($this->logKey($key), $log);
$lock->release();
}
finally
{
optional($lock)->release();
}
}
/**
* Gets the latest log entry of this game server for a given key.
*
* @param string $key
* @return mixed
*/
public function getLatestLogEntry(string $key): mixed
{
$log = $this->retrieveCompleteLog($key);
return $log[$log['latest']];
}
/**
* Wipes all the logs of this game server.
*/
public function wipeLogs()
{
foreach (array_keys(self::$logKeys) as $key)
{
Cache::forget($this->logKey($key));
}
$this->initLogKeys();
}
/**
* Wipes a specific log file for this game server.
*
* @param string $key
*/
public function wipeLog(string $key)
{
Cache::forget($this->logKey($key));
}
/**
* The places this game server is allowed to access.
*
* @return array
*/
public function allowedPlaces(): array
{
return Cache::get($this->logKey('access')) ?? [];
}
/**
* Allows this game server to access a place.
*
* @param int $place_id
*/
public function allow(int $place_id)
{
$access = $this->allowedPlaces();
$access[] = $place_id;
Cache::store($this->logKey('access'));
}
/**
* Gets the current state of this game server.
*
* @return GameServerState
*/
public function state(): GameServerState
{
if (is_null($state = Cache::get($this->logKey('state'))))
{
$this->setState(GameServerState::Offline);
return GameServerState::Offline;
}
if ($state['state'] == GameServerState::Online && (time() - $state['last_ping']) >= 60)
{
$this->setState(GameServerState::Offline);
return GameServerState::Offline;
}
return $state['state'];
}
/**
* Sets the current state of this game server.
*
* @param GameServerState $state
*/
public function setState(GameServerState $state)
{
if ($state == GameServerState::Offline)
{
$this->wipeLogs();
}
Cache::put($this->logKey('state'), [
'last_ping' => time(),
'state' => $state
]);
}
/**
* Gets all running place jobs of this game server.
*
* @return array
*/
public function getRunningPlaceJobs(): array
{
return [];
}
/**
* Gets all running thumbnail jobs of this game server.
*
* @return array
*/
public function getRunningThumbnailJobs(): array
{
return [];
}
/**
* Generates a random access key.
*
* @return string
*/
public static function generateAccessKey(): string
{
return bin2hex(random_bytes(32));
}
}