Files
Epicnabbo-Catalogus-Updated…/Updated_Cms/app/Services/RconService.php
T
Remco d3ef41c9dd 🆙 More fixes 🆙
2026-01-20 17:11:21 +01:00

311 lines
7.9 KiB
PHP

<?php
namespace App\Services;
use App\Enums\CurrencyTypes;
use App\Exceptions\RconConnectionException;
use App\Models\User;
use Illuminate\Support\Facades\Log;
use JsonException;
use Socket;
class RconService
{
protected ?Socket $socket = null;
public private(set) bool $isConnected = false;
/** @var array{ip: string, port: int} */
protected array $config;
public function __construct()
{
$ip = setting('rcon_ip');
$port = setting('rcon_port');
$this->config = [
'ip' => (string) $ip,
'port' => is_numeric($port) ? (int) $port : 3001,
];
$this->initialize();
}
private function initialize(): void
{
$socket = @socket_create(domain: AF_INET, type: SOCK_STREAM, protocol: SOL_TCP);
if ($socket === false) {
$error = socket_strerror(socket_last_error());
Log::error("RCON initialization failed: {$error}");
$this->closeConnection();
return;
}
$this->socket = $socket;
socket_set_option(
socket: $this->socket,
level: SOL_SOCKET,
option: SO_RCVTIMEO,
value: ['sec' => 5, 'usec' => 0]
);
socket_set_option(
socket: $this->socket,
level: SOL_SOCKET,
option: SO_SNDTIMEO,
value: ['sec' => 5, 'usec' => 0]
);
if (! @socket_connect($this->socket, $this->config['ip'], $this->config['port'])) {
$error = socket_strerror(socket_last_error($this->socket));
Log::error("RCON connection failed: {$error}");
$this->closeConnection();
return;
}
$this->isConnected = true;
}
private function closeConnection(): void
{
if ($this->socket instanceof Socket) {
socket_close($this->socket);
}
$this->socket = null;
$this->isConnected = false;
}
public function isConnected(): bool
{
return $this->isConnected;
}
/**
* @param array<string, mixed>|null $data
* @throws RconConnectionException
* @throws JsonException
*/
public function sendCommand(string $command, ?array $data = null): bool
{
if (! $this->isConnected || ! $this->socket) {
Log::error('RCON command failed: Not connected');
$this->closeConnection();
return false;
}
$payload = json_encode(['key' => $command, 'data' => $data], JSON_THROW_ON_ERROR);
if (! @socket_write($this->socket, $payload, strlen($payload))) {
$error = socket_strerror(socket_last_error($this->socket));
Log::error("RCON command ({$command}) failed: {$error}");
$this->closeConnection();
return false;
}
return true;
}
/**
* @throws RconConnectionException|JsonException
*/
public function sendGift(User $user, int $item_id, string $message = 'Here is a gift.'): void
{
$this->sendCommand('sendgift', [
'user_id' => $user->id,
'itemid' => $item_id,
'message' => $message,
]);
}
/**
* @throws RconConnectionException|JsonException
*/
public function giveCredits(User $user, int $credits): void
{
$this->sendCommand('givecredits', [
'user_id' => $user->id,
'credits' => $credits,
]);
}
/**
* @throws RconConnectionException|JsonException
*/
public function giveBadge(User $user, string $badge): void
{
$this->sendCommand('givebadge', [
'user_id' => $user->id,
'badge' => $badge,
]);
}
/**
* @throws RconConnectionException|JsonException
*/
public function setMotto(User $user, string $motto): void
{
$this->sendCommand('setmotto', [
'user_id' => $user->id,
'motto' => $motto,
]);
}
/**
* @throws RconConnectionException|JsonException
*/
public function updateWordFilter(): void
{
$this->sendCommand('updatewordfilter');
}
/**
* @throws RconConnectionException|JsonException
*/
public function disconnectUser(User $user): void
{
$this->sendCommand('disconnect', [
'user_id' => $user->id,
'username' => $user->username,
]);
}
/**
* @throws RconConnectionException|JsonException
*/
public function givePoints(User $user, CurrencyTypes $type, int $amount): void
{
$this->sendCommand('givepoints', [
'user_id' => $user->id,
'points' => $amount,
'type' => $type,
]);
}
/**
* @throws RconConnectionException
* @throws JsonException
*/
public function giveGotw(User $user, int $amount): void
{
$this->givePoints($user, CurrencyTypes::Points, $amount);
}
/**
* @throws RconConnectionException
* @throws JsonException
*/
public function giveDiamonds(User $user, int $amount): void
{
$this->givePoints($user, CurrencyTypes::Diamonds, $amount);
}
/**
* @throws RconConnectionException
* @throws JsonException
*/
public function giveDuckets(User $user, int $amount): void
{
$this->givePoints($user, CurrencyTypes::Duckets, $amount);
}
/**
* @throws RconConnectionException
* @throws JsonException
*/
public function setRank(User $user, int $rank): void
{
$this->sendCommand('setrank', [
'user_id' => $user->id,
'rank' => $rank,
]);
}
/**
* @throws RconConnectionException
* @throws JsonException
*/
public function updateCatalog(): void
{
$this->sendCommand('updatecatalog');
}
/**
* @throws RconConnectionException
* @throws JsonException
*/
public function alertUser(User $user, string $message): void
{
$this->sendCommand('alertuser', [
'user_id' => $user->id,
'message' => $message,
]);
}
/**
* @throws RconConnectionException
* @throws JsonException
*/
public function forwardUser(User $user, int $roomId): void
{
$this->sendCommand('forwarduser', [
'user_id' => $user->id,
'room_id' => $roomId,
]);
}
/**
* @throws RconConnectionException
* @throws JsonException
*/
public function updateConfig(User $user, string $command): void
{
$this->sendCommand('executecommand', [
'user_id' => $user->id,
'command' => $command,
]);
}
public function __destruct()
{
$this->closeConnection();
}
public function sendSafelyFromDashboard(string $action, array $args, string $errorMessage): void
{
try {
switch ($action) {
case 'sendBadge':
/** @var \App\Models\User $user */
$user = $args[0];
/** @var string $badge */
$badge = (string) ($args[1] ?? '');
$this->giveBadge($user, $badge);
break;
case 'removeBadge':
// No direct RCON command defined for removing badges; use alert for now
/** @var \App\Models\User $user */
$user = $args[0];
/** @var string $badge */
$badge = (string) ($args[1] ?? '');
$this->alertUser($user, sprintf('Badge %s removed.', $badge));
break;
default:
break;
}
} catch (\Throwable $e) {
\Filament\Notifications\Notification::make()
->danger()
->title('RCON Error')
->body($errorMessage)
->persistent()
->send();
}
}
}