mirror of
https://github.com/xPaw/PHP-Source-Query.git
synced 2026-06-10 21:23:15 +02:00
Docblocks, first pass with Psalm.
This commit is contained in:
+6
-8
@@ -39,7 +39,7 @@ $Timer = number_format(microtime(true) - $Timer, 4, '.', '');
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Source Query PHP Library</title>
|
||||
@@ -111,14 +111,12 @@ $Timer = number_format(microtime(true) - $Timer, 4, '.', '');
|
||||
echo "<pre>";
|
||||
print_r($InfoValue);
|
||||
echo "</pre>";
|
||||
} elseif ($InfoValue === true) {
|
||||
echo 'true';
|
||||
} elseif ($InfoValue === false) {
|
||||
echo 'false';
|
||||
} else {
|
||||
if ($InfoValue === true) {
|
||||
echo 'true';
|
||||
} elseif ($InfoValue === false) {
|
||||
echo 'false';
|
||||
} else {
|
||||
echo htmlspecialchars($InfoValue);
|
||||
}
|
||||
echo htmlspecialchars($InfoValue);
|
||||
}
|
||||
?></td>
|
||||
</tr>
|
||||
|
||||
+67
-17
@@ -23,29 +23,82 @@ use xPaw\SourceQuery\Exception\SocketException;
|
||||
*
|
||||
* @package xPaw\SourceQuery
|
||||
*
|
||||
* @uses xPaw\SourceQuery\Exception\InvalidPacketException
|
||||
* @uses xPaw\SourceQuery\Exception\SocketException
|
||||
* @uses InvalidPacketException
|
||||
* @uses SocketException
|
||||
*/
|
||||
abstract class BaseSocket
|
||||
{
|
||||
/** @var ?resource */
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
public $Socket;
|
||||
public int $Engine;
|
||||
|
||||
public string $Address;
|
||||
public int $Port;
|
||||
public int $Timeout;
|
||||
/**
|
||||
* @var int $Engine
|
||||
*/
|
||||
public int $Engine = SourceQuery::SOURCE;
|
||||
|
||||
/**
|
||||
* @var string $Address
|
||||
*/
|
||||
public string $Address = '';
|
||||
|
||||
/**
|
||||
* @var int $Port
|
||||
*/
|
||||
public int $Port = 0;
|
||||
|
||||
/**
|
||||
* @var int $Timeout
|
||||
*/
|
||||
public int $Timeout = 0;
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->Close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close
|
||||
*/
|
||||
abstract public function Close(): void;
|
||||
|
||||
/**
|
||||
* @param string $Address
|
||||
* @param int $Port
|
||||
* @param int $Timeout
|
||||
* @param int $Engine
|
||||
*/
|
||||
abstract public function Open(string $Address, int $Port, int $Timeout, int $Engine): void;
|
||||
|
||||
/**
|
||||
* @param int $Header
|
||||
* @param string $String
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function Write(int $Header, string $String = ''): bool;
|
||||
|
||||
/**
|
||||
* @param int $Length
|
||||
*
|
||||
* @return Buffer
|
||||
*/
|
||||
abstract public function Read(int $Length = 1400): Buffer;
|
||||
|
||||
/**
|
||||
* @param Buffer $Buffer
|
||||
* @param int $Length
|
||||
* @param callable $SherlockFunction
|
||||
*
|
||||
* @return Buffer
|
||||
*
|
||||
* @throws InvalidPacketException
|
||||
* @throws SocketException
|
||||
*/
|
||||
protected function ReadInternal(Buffer $Buffer, int $Length, callable $SherlockFunction): Buffer
|
||||
{
|
||||
if ($Buffer->Remaining() === 0) {
|
||||
@@ -54,12 +107,14 @@ abstract class BaseSocket
|
||||
|
||||
$Header = $Buffer->GetLong();
|
||||
|
||||
if ($Header === -1) { // Single packet
|
||||
// We don't have to do anything
|
||||
} elseif ($Header === -2) { // Split packet
|
||||
// Single packet, do nothing.
|
||||
if ($Header === -1) {
|
||||
return $Buffer;
|
||||
}
|
||||
|
||||
if ($Header === -2) { // Split packet
|
||||
$Packets = [];
|
||||
$IsCompressed = false;
|
||||
$ReadMore = false;
|
||||
$PacketChecksum = null;
|
||||
|
||||
do {
|
||||
@@ -98,18 +153,13 @@ abstract class BaseSocket
|
||||
|
||||
$Packets[ $PacketNumber ] = $Buffer->Get();
|
||||
|
||||
$ReadMore = $PacketCount > sizeof($Packets);
|
||||
$ReadMore = $PacketCount > count($Packets);
|
||||
} while ($ReadMore && $SherlockFunction($Buffer, $Length));
|
||||
|
||||
$Data = implode($Packets);
|
||||
|
||||
// TODO: Test this
|
||||
if ($IsCompressed) {
|
||||
// Let's make sure this function exists, it's not included in PHP by default
|
||||
if (!function_exists('bzdecompress')) {
|
||||
throw new \RuntimeException('Received compressed packet, PHP doesn\'t have Bzip2 library installed, can\'t decompress.');
|
||||
}
|
||||
|
||||
$Data = bzdecompress($Data);
|
||||
|
||||
if (!is_string($Data) || crc32($Data) !== $PacketChecksum) {
|
||||
|
||||
+21
-1
@@ -22,7 +22,7 @@ use xPaw\SourceQuery\Exception\InvalidPacketException;
|
||||
*
|
||||
* @package xPaw\SourceQuery
|
||||
*
|
||||
* @uses xPaw\SourceQuery\Exception\InvalidPacketException
|
||||
* @uses InvalidPacketException
|
||||
*/
|
||||
final class Buffer
|
||||
{
|
||||
@@ -43,6 +43,8 @@ final class Buffer
|
||||
|
||||
/**
|
||||
* Sets buffer
|
||||
*
|
||||
* @param string $Buffer
|
||||
*/
|
||||
public function Set(string $Buffer): void
|
||||
{
|
||||
@@ -61,10 +63,20 @@ final class Buffer
|
||||
return $this->Length - $this->Position;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmpty(): bool
|
||||
{
|
||||
return $this->Remaining() <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data from buffer
|
||||
*
|
||||
* @param int $Length Bytes to read
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function Get(int $Length = -1): string
|
||||
{
|
||||
@@ -97,6 +109,8 @@ final class Buffer
|
||||
|
||||
/**
|
||||
* Get short from buffer
|
||||
*
|
||||
* @throws InvalidPacketException
|
||||
*/
|
||||
public function GetShort(): int
|
||||
{
|
||||
@@ -111,6 +125,8 @@ final class Buffer
|
||||
|
||||
/**
|
||||
* Get long from buffer
|
||||
*
|
||||
* @throws InvalidPacketException
|
||||
*/
|
||||
public function GetLong(): int
|
||||
{
|
||||
@@ -125,6 +141,8 @@ final class Buffer
|
||||
|
||||
/**
|
||||
* Get float from buffer
|
||||
*
|
||||
* @throws InvalidPacketException
|
||||
*/
|
||||
public function GetFloat(): float
|
||||
{
|
||||
@@ -139,6 +157,8 @@ final class Buffer
|
||||
|
||||
/**
|
||||
* Get unsigned long from buffer
|
||||
*
|
||||
* @throws InvalidPacketException
|
||||
*/
|
||||
public function GetUnsignedLong(): int
|
||||
{
|
||||
|
||||
@@ -15,7 +15,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace xPaw\SourceQuery\Exception;
|
||||
|
||||
abstract class SourceQueryException extends \Exception
|
||||
use Exception;
|
||||
|
||||
abstract class SourceQueryException extends Exception
|
||||
{
|
||||
// Base exception class
|
||||
}
|
||||
|
||||
@@ -33,28 +33,48 @@ final class GoldSourceRcon
|
||||
*
|
||||
* @var BaseSocket
|
||||
*/
|
||||
private $Socket;
|
||||
private BaseSocket $Socket;
|
||||
|
||||
/**
|
||||
* @var string $RconPassword
|
||||
*/
|
||||
private string $RconPassword = '';
|
||||
|
||||
/**
|
||||
* @var string $RconChallenge
|
||||
*/
|
||||
private string $RconChallenge = '';
|
||||
|
||||
/**
|
||||
* @param BaseSocket $Socket
|
||||
*/
|
||||
public function __construct(BaseSocket $Socket)
|
||||
{
|
||||
$this->Socket = $Socket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close
|
||||
*/
|
||||
public function Close(): void
|
||||
{
|
||||
$this->RconChallenge = '';
|
||||
$this->RconPassword = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Open
|
||||
*/
|
||||
public function Open(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public function Write(int $Header, string $String = ''): bool
|
||||
/**
|
||||
* @param string $String
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function Write(string $String = ''): bool
|
||||
{
|
||||
$Command = pack('cccca*', 0xFF, 0xFF, 0xFF, 0xFF, $String);
|
||||
$Length = strlen($Command);
|
||||
@@ -63,17 +83,17 @@ final class GoldSourceRcon
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $Length
|
||||
* @throws AuthenticationException
|
||||
* @throws InvalidPacketException
|
||||
*
|
||||
* @return Buffer
|
||||
*/
|
||||
public function Read(int $Length = 1400): Buffer
|
||||
public function Read(): Buffer
|
||||
{
|
||||
// GoldSource RCON has same structure as Query
|
||||
$Buffer = $this->Socket->Read();
|
||||
|
||||
$StringBuffer = '';
|
||||
$ReadMore = false;
|
||||
|
||||
// There is no indentifier of the end, so we just need to continue reading
|
||||
do {
|
||||
@@ -110,23 +130,36 @@ final class GoldSourceRcon
|
||||
return $Buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $Command
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws AuthenticationException
|
||||
* @throws InvalidPacketException
|
||||
*/
|
||||
public function Command(string $Command): string
|
||||
{
|
||||
if (!$this->RconChallenge) {
|
||||
throw new AuthenticationException('Tried to execute a RCON command before successful authorization.', AuthenticationException::BAD_PASSWORD);
|
||||
}
|
||||
|
||||
$this->Write(0, 'rcon ' . $this->RconChallenge . ' "' . $this->RconPassword . '" ' . $Command . "\0");
|
||||
$this->Write('rcon ' . $this->RconChallenge . ' "' . $this->RconPassword . '" ' . $Command . "\0");
|
||||
$Buffer = $this->Read();
|
||||
|
||||
return $Buffer->Get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $Password
|
||||
*
|
||||
* @throws AuthenticationException
|
||||
*/
|
||||
public function Authorize(string $Password): void
|
||||
{
|
||||
$this->RconPassword = $Password;
|
||||
|
||||
$this->Write(0, 'challenge rcon');
|
||||
$this->Write('challenge rcon');
|
||||
$Buffer = $this->Socket->Read();
|
||||
|
||||
if ($Buffer->Get(14) !== 'challenge rcon') {
|
||||
|
||||
+31
-2
@@ -28,15 +28,26 @@ use xPaw\SourceQuery\Exception\SocketException;
|
||||
*/
|
||||
final class Socket extends BaseSocket
|
||||
{
|
||||
/**
|
||||
* Close
|
||||
*/
|
||||
public function Close(): void
|
||||
{
|
||||
if ($this->Socket !== null) {
|
||||
fclose($this->Socket);
|
||||
|
||||
$this->Socket = null;
|
||||
$this->Socket = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $Address
|
||||
* @param int $Port
|
||||
* @param int $Timeout
|
||||
* @param int $Engine
|
||||
*
|
||||
* @throws SocketException
|
||||
*/
|
||||
public function Open(string $Address, int $Port, int $Timeout, int $Engine): void
|
||||
{
|
||||
$this->Timeout = $Timeout;
|
||||
@@ -55,6 +66,12 @@ final class Socket extends BaseSocket
|
||||
stream_set_blocking($this->Socket, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $Header
|
||||
* @param string $String
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function Write(int $Header, string $String = ''): bool
|
||||
{
|
||||
$Command = pack('ccccca*', 0xFF, 0xFF, 0xFF, 0xFF, $Header, $String);
|
||||
@@ -66,9 +83,13 @@ final class Socket extends BaseSocket
|
||||
/**
|
||||
* Reads from socket and returns Buffer.
|
||||
*
|
||||
* @throws InvalidPacketException
|
||||
* @param int $Length
|
||||
*
|
||||
* @return Buffer Buffer
|
||||
*
|
||||
* @throws InvalidPacketException
|
||||
* @throws SocketException
|
||||
*
|
||||
*/
|
||||
public function Read(int $Length = 1400): Buffer
|
||||
{
|
||||
@@ -80,6 +101,14 @@ final class Socket extends BaseSocket
|
||||
return $Buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Buffer $Buffer
|
||||
* @param int $Length
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws InvalidPacketException
|
||||
*/
|
||||
public function Sherlock(Buffer $Buffer, int $Length): bool
|
||||
{
|
||||
$Data = fread($this->Socket, $Length);
|
||||
|
||||
@@ -15,6 +15,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace xPaw\SourceQuery;
|
||||
|
||||
use RuntimeException;
|
||||
use xPaw\SourceQuery\Exception\AuthenticationException;
|
||||
use xPaw\SourceQuery\Exception\InvalidArgumentException;
|
||||
use xPaw\SourceQuery\Exception\InvalidPacketException;
|
||||
@@ -98,11 +99,17 @@ final class SourceQuery
|
||||
*/
|
||||
private bool $UseOldGetChallengeMethod = false;
|
||||
|
||||
/**
|
||||
* @param BaseSocket|null $Socket
|
||||
*/
|
||||
public function __construct(BaseSocket $Socket = null)
|
||||
{
|
||||
$this->Socket = $Socket ?: new Socket();
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->Disconnect();
|
||||
@@ -137,7 +144,7 @@ final class SourceQuery
|
||||
*
|
||||
* @param bool $Value Set to true to force old method
|
||||
*
|
||||
* @returns bool Previous value
|
||||
* @return bool Previous value
|
||||
*/
|
||||
public function SetUseOldGetChallengeMethod(bool $Value): bool
|
||||
{
|
||||
@@ -299,7 +306,6 @@ final class SourceQuery
|
||||
if ($Flags & 0x10) {
|
||||
$SteamIDLower = $Buffer->GetUnsignedLong();
|
||||
$SteamIDInstance = $Buffer->GetUnsignedLong(); // This gets shifted by 32 bits, which should be steamid instance
|
||||
$SteamID = 0;
|
||||
|
||||
if (PHP_INT_SIZE === 4) {
|
||||
if (extension_loaded('gmp')) {
|
||||
@@ -307,7 +313,7 @@ final class SourceQuery
|
||||
$SteamIDInstance = gmp_abs($SteamIDInstance);
|
||||
$SteamID = gmp_strval(gmp_or($SteamIDLower, gmp_mul($SteamIDInstance, gmp_pow(2, 32))));
|
||||
} else {
|
||||
throw new \RuntimeException('Either 64-bit PHP installation or "gmp" module is required to correctly parse server\'s steamid.');
|
||||
throw new RuntimeException('Either 64-bit PHP installation or "gmp" module is required to correctly parse server\'s steamid.');
|
||||
}
|
||||
} else {
|
||||
$SteamID = $SteamIDLower | ($SteamIDInstance << 32);
|
||||
@@ -334,7 +340,7 @@ final class SourceQuery
|
||||
$Server[ 'GameID' ] = $Buffer->GetUnsignedLong() | ($Buffer->GetUnsignedLong() << 32);
|
||||
}
|
||||
|
||||
if ($Buffer->Remaining() > 0) {
|
||||
if (!$Buffer->isEmpty()) {
|
||||
throw new InvalidPacketException(
|
||||
'GetInfo: unread data? ' . $Buffer->Remaining() . ' bytes remaining in the buffer. Please report it to the library developer.',
|
||||
InvalidPacketException::BUFFER_NOT_EMPTY
|
||||
@@ -431,7 +437,11 @@ final class SourceQuery
|
||||
/**
|
||||
* Get challenge (used for players/rules packets)
|
||||
*
|
||||
* @param int $Header
|
||||
* @param int $ExpectedResult
|
||||
*
|
||||
* @throws InvalidPacketException
|
||||
* @throws SocketException
|
||||
*/
|
||||
private function GetChallenge(int $Header, int $ExpectedResult): void
|
||||
{
|
||||
@@ -488,13 +498,13 @@ final class SourceQuery
|
||||
}
|
||||
|
||||
switch ($this->Socket->Engine) {
|
||||
case SourceQuery::GOLDSOURCE:
|
||||
case self::GOLDSOURCE:
|
||||
{
|
||||
$this->Rcon = new GoldSourceRcon($this->Socket);
|
||||
|
||||
break;
|
||||
}
|
||||
case SourceQuery::SOURCE:
|
||||
case self::SOURCE:
|
||||
{
|
||||
$this->Rcon = new SourceRcon($this->Socket);
|
||||
|
||||
|
||||
@@ -35,15 +35,27 @@ final class SourceRcon
|
||||
*/
|
||||
private BaseSocket $Socket;
|
||||
|
||||
/** @var ?resource */
|
||||
/**
|
||||
* @var ?resource
|
||||
*/
|
||||
private $RconSocket;
|
||||
|
||||
/**
|
||||
* @var int $RconRequestId
|
||||
*/
|
||||
private int $RconRequestId = 0;
|
||||
|
||||
/**
|
||||
* @param BaseSocket $Socket
|
||||
*/
|
||||
public function __construct(BaseSocket $Socket)
|
||||
{
|
||||
$this->Socket = $Socket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close
|
||||
*/
|
||||
public function Close(): void
|
||||
{
|
||||
if ($this->RconSocket) {
|
||||
@@ -55,6 +67,9 @@ final class SourceRcon
|
||||
$this->RconRequestId = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws SocketException
|
||||
*/
|
||||
public function Open(): void
|
||||
{
|
||||
if (!$this->RconSocket) {
|
||||
@@ -70,6 +85,12 @@ final class SourceRcon
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $Header
|
||||
* @param string $String
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function Write(int $Header, string $String = ''): bool
|
||||
{
|
||||
// Pack the packet together
|
||||
@@ -82,6 +103,11 @@ final class SourceRcon
|
||||
return $Length === fwrite($this->RconSocket, $Command, $Length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Buffer
|
||||
*
|
||||
* @throws InvalidPacketException
|
||||
*/
|
||||
public function Read(): Buffer
|
||||
{
|
||||
$Buffer = new Buffer();
|
||||
@@ -117,6 +143,14 @@ final class SourceRcon
|
||||
return $Buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $Command
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws AuthenticationException
|
||||
* @throws InvalidPacketException
|
||||
*/
|
||||
public function Command(string $Command): string
|
||||
{
|
||||
$this->Write(SourceQuery::SERVERDATA_EXECCOMMAND, $Command);
|
||||
@@ -161,6 +195,12 @@ final class SourceRcon
|
||||
return rtrim($Data, "\0");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $Password
|
||||
*
|
||||
* @throws AuthenticationException
|
||||
* @throws InvalidPacketException
|
||||
*/
|
||||
public function Authorize(string $Password): void
|
||||
{
|
||||
$this->Write(SourceQuery::SERVERDATA_AUTH, $Password);
|
||||
|
||||
+194
-24
@@ -6,28 +6,48 @@ use PHPUnit\Framework\TestCase;
|
||||
use xPaw\SourceQuery\BaseSocket;
|
||||
use xPaw\SourceQuery\SourceQuery;
|
||||
use xPaw\SourceQuery\Buffer;
|
||||
use xPaw\SourceQuery\Exception\AuthenticationException;
|
||||
use xPaw\SourceQuery\Exception\InvalidArgumentException;
|
||||
use xPaw\SourceQuery\Exception\InvalidPacketException;
|
||||
use xPaw\SourceQuery\Exception\SocketException;
|
||||
|
||||
final class TestableSocket extends BaseSocket
|
||||
{
|
||||
/** @var \SplQueue<string> */
|
||||
private \SplQueue $PacketQueue;
|
||||
/**
|
||||
* @var SplQueue<string>
|
||||
*/
|
||||
private SplQueue $PacketQueue;
|
||||
|
||||
/**
|
||||
* TestableSocket constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->PacketQueue = new \SplQueue();
|
||||
$this->PacketQueue->setIteratorMode(\SplDoublyLinkedList::IT_MODE_DELETE);
|
||||
$this->PacketQueue = new SplQueue();
|
||||
$this->PacketQueue->setIteratorMode(SplDoublyLinkedList::IT_MODE_DELETE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $Data
|
||||
*/
|
||||
public function Queue(string $Data): void
|
||||
{
|
||||
$this->PacketQueue->push($Data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close.
|
||||
*/
|
||||
public function Close(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $Address
|
||||
* @param int $Port
|
||||
* @param int $Timeout
|
||||
* @param int $Engine
|
||||
*/
|
||||
public function Open(string $Address, int $Port, int $Timeout, int $Engine): void
|
||||
{
|
||||
$this->Timeout = $Timeout;
|
||||
@@ -36,11 +56,25 @@ final class TestableSocket extends BaseSocket
|
||||
$this->Address = $Address;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $Header
|
||||
* @param string $String
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function Write(int $Header, string $String = ''): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $Length
|
||||
*
|
||||
* @return Buffer
|
||||
*
|
||||
* @throws InvalidPacketException
|
||||
* @throws SocketException
|
||||
*/
|
||||
public function Read(int $Length = 1400): Buffer
|
||||
{
|
||||
$Buffer = new Buffer();
|
||||
@@ -51,7 +85,14 @@ final class TestableSocket extends BaseSocket
|
||||
return $Buffer;
|
||||
}
|
||||
|
||||
public function Sherlock(Buffer $Buffer, int $Length): bool
|
||||
/**
|
||||
* @param Buffer $Buffer
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws InvalidPacketException
|
||||
*/
|
||||
public function Sherlock(Buffer $Buffer): bool
|
||||
{
|
||||
if ($this->PacketQueue->isEmpty()) {
|
||||
return false;
|
||||
@@ -65,9 +106,20 @@ final class TestableSocket extends BaseSocket
|
||||
|
||||
final class Tests extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var TestableSocket $Socket
|
||||
*/
|
||||
private TestableSocket $Socket;
|
||||
|
||||
/**
|
||||
* @var SourceQuery $SourceQuery
|
||||
*/
|
||||
private SourceQuery $SourceQuery;
|
||||
|
||||
/**
|
||||
* @throws SocketException
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function setUp(): void
|
||||
{
|
||||
$this->Socket = new TestableSocket();
|
||||
@@ -75,6 +127,9 @@ final class Tests extends TestCase
|
||||
$this->SourceQuery->Connect('', 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* tearDown
|
||||
*/
|
||||
public function tearDown(): void
|
||||
{
|
||||
$this->SourceQuery->Disconnect();
|
||||
@@ -82,65 +137,103 @@ final class Tests extends TestCase
|
||||
unset($this->Socket, $this->SourceQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException
|
||||
* @throws SocketException
|
||||
*/
|
||||
public function testInvalidTimeout(): void
|
||||
{
|
||||
$this->expectException(xPaw\SourceQuery\Exception\InvalidArgumentException::class);
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$SourceQuery = new SourceQuery();
|
||||
$SourceQuery->Connect('', 2, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidPacketException
|
||||
* @throws SocketException
|
||||
*/
|
||||
public function testNotConnectedGetInfo(): void
|
||||
{
|
||||
$this->expectException(xPaw\SourceQuery\Exception\SocketException::class);
|
||||
$this->expectException(SocketException::class);
|
||||
$this->SourceQuery->Disconnect();
|
||||
$this->SourceQuery->GetInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidPacketException
|
||||
* @throws SocketException
|
||||
*/
|
||||
public function testNotConnectedPing(): void
|
||||
{
|
||||
$this->expectException(xPaw\SourceQuery\Exception\SocketException::class);
|
||||
$this->expectException(SocketException::class);
|
||||
$this->SourceQuery->Disconnect();
|
||||
$this->SourceQuery->Ping();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidPacketException
|
||||
* @throws SocketException
|
||||
*/
|
||||
public function testNotConnectedGetPlayers(): void
|
||||
{
|
||||
$this->expectException(xPaw\SourceQuery\Exception\SocketException::class);
|
||||
$this->expectException(SocketException::class);
|
||||
$this->SourceQuery->Disconnect();
|
||||
$this->SourceQuery->GetPlayers();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException xPaw\SourceQuery\Exception\SocketException
|
||||
* @throws InvalidPacketException
|
||||
* @throws SocketException
|
||||
*/
|
||||
public function testNotConnectedGetRules(): void
|
||||
{
|
||||
$this->expectException(xPaw\SourceQuery\Exception\SocketException::class);
|
||||
$this->expectException(SocketException::class);
|
||||
$this->SourceQuery->Disconnect();
|
||||
$this->SourceQuery->GetRules();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws SocketException
|
||||
* @throws AuthenticationException
|
||||
* @throws InvalidPacketException
|
||||
*/
|
||||
public function testNotConnectedSetRconPassword(): void
|
||||
{
|
||||
$this->expectException(xPaw\SourceQuery\Exception\SocketException::class);
|
||||
$this->expectException(SocketException::class);
|
||||
$this->SourceQuery->Disconnect();
|
||||
$this->SourceQuery->SetRconPassword('a');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws AuthenticationException
|
||||
* @throws InvalidPacketException
|
||||
* @throws SocketException
|
||||
*/
|
||||
public function testNotConnectedRcon(): void
|
||||
{
|
||||
$this->expectException(xPaw\SourceQuery\Exception\SocketException::class);
|
||||
$this->expectException(SocketException::class);
|
||||
$this->SourceQuery->Disconnect();
|
||||
$this->SourceQuery->Rcon('a');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws AuthenticationException
|
||||
* @throws InvalidPacketException
|
||||
* @throws SocketException
|
||||
*/
|
||||
public function testRconWithoutPassword(): void
|
||||
{
|
||||
$this->expectException(xPaw\SourceQuery\Exception\SocketException::class);
|
||||
$this->expectException(SocketException::class);
|
||||
$this->SourceQuery->Rcon('a');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $RawInput
|
||||
* @param array $ExpectedOutput
|
||||
*
|
||||
* @throws InvalidPacketException
|
||||
* @throws SocketException
|
||||
*
|
||||
* @dataProvider InfoProvider
|
||||
*/
|
||||
public function testGetInfo(string $RawInput, array $ExpectedOutput): void
|
||||
@@ -156,6 +249,11 @@ final class Tests extends TestCase
|
||||
self::assertEquals($ExpectedOutput, $RealOutput);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*
|
||||
* @throws JsonException
|
||||
*/
|
||||
public function InfoProvider(): array
|
||||
{
|
||||
$DataProvider = [];
|
||||
@@ -166,7 +264,14 @@ final class Tests extends TestCase
|
||||
$DataProvider[] =
|
||||
[
|
||||
hex2bin(trim(file_get_contents($File))),
|
||||
json_decode(file_get_contents(str_replace('.raw', '.json', $File)), true)
|
||||
json_decode(
|
||||
file_get_contents(
|
||||
str_replace('.raw', '.json', $File)
|
||||
),
|
||||
true,
|
||||
512,
|
||||
JSON_THROW_ON_ERROR
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
@@ -174,33 +279,48 @@ final class Tests extends TestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $Data
|
||||
*
|
||||
* @throws InvalidPacketException
|
||||
* @throws SocketException
|
||||
*
|
||||
* @dataProvider BadPacketProvider
|
||||
*/
|
||||
public function testBadGetInfo(string $Data): void
|
||||
{
|
||||
$this->expectException(xPaw\SourceQuery\Exception\InvalidPacketException::class);
|
||||
$this->expectException(InvalidPacketException::class);
|
||||
$this->Socket->Queue($Data);
|
||||
|
||||
$this->SourceQuery->GetInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $Data
|
||||
*
|
||||
* @throws InvalidPacketException
|
||||
* @throws SocketException
|
||||
*
|
||||
* @dataProvider BadPacketProvider
|
||||
*/
|
||||
public function testBadGetChallengeViaPlayers(string $Data): void
|
||||
{
|
||||
$this->expectException(xPaw\SourceQuery\Exception\InvalidPacketException::class);
|
||||
$this->expectException(InvalidPacketException::class);
|
||||
$this->Socket->Queue($Data);
|
||||
|
||||
$this->SourceQuery->GetPlayers();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $Data
|
||||
*
|
||||
* @throws InvalidPacketException
|
||||
* @throws SocketException
|
||||
*
|
||||
* @dataProvider BadPacketProvider
|
||||
*/
|
||||
public function testBadGetPlayersAfterCorrectChallenge(string $Data): void
|
||||
{
|
||||
$this->expectException(xPaw\SourceQuery\Exception\InvalidPacketException::class);
|
||||
$this->expectException(InvalidPacketException::class);
|
||||
$this->Socket->Queue("\xFF\xFF\xFF\xFF\x41\x11\x11\x11\x11");
|
||||
$this->Socket->Queue($Data);
|
||||
|
||||
@@ -208,17 +328,25 @@ final class Tests extends TestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $Data
|
||||
*
|
||||
* @throws InvalidPacketException
|
||||
* @throws SocketException
|
||||
*
|
||||
* @dataProvider BadPacketProvider
|
||||
*/
|
||||
public function testBadGetRulesAfterCorrectChallenge(string $Data): void
|
||||
{
|
||||
$this->expectException(xPaw\SourceQuery\Exception\InvalidPacketException::class);
|
||||
$this->expectException(InvalidPacketException::class);
|
||||
$this->Socket->Queue("\xFF\xFF\xFF\xFF\x41\x11\x11\x11\x11");
|
||||
$this->Socket->Queue($Data);
|
||||
|
||||
$this->SourceQuery->GetRules();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[][]
|
||||
*/
|
||||
public function BadPacketProvider(): array
|
||||
{
|
||||
return
|
||||
@@ -233,6 +361,10 @@ final class Tests extends TestCase
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidPacketException
|
||||
* @throws SocketException
|
||||
*/
|
||||
public function testGetChallengeTwice(): void
|
||||
{
|
||||
$this->Socket->Queue("\xFF\xFF\xFF\xFF\x41\x11\x11\x11\x11");
|
||||
@@ -244,8 +376,13 @@ final class Tests extends TestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $RawInput
|
||||
* @param array $ExpectedOutput
|
||||
*
|
||||
* @throws InvalidPacketException
|
||||
* @throws SocketException
|
||||
*
|
||||
* @dataProvider RulesProvider
|
||||
* @param array<string> $RawInput
|
||||
*/
|
||||
public function testGetRules(array $RawInput, array $ExpectedOutput): void
|
||||
{
|
||||
@@ -260,6 +397,11 @@ final class Tests extends TestCase
|
||||
self::assertEquals($ExpectedOutput, $RealOutput);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*
|
||||
* @throws JsonException
|
||||
*/
|
||||
public function RulesProvider(): array
|
||||
{
|
||||
$DataProvider = [];
|
||||
@@ -270,7 +412,14 @@ final class Tests extends TestCase
|
||||
$DataProvider[] =
|
||||
[
|
||||
file($File, FILE_SKIP_EMPTY_LINES | FILE_IGNORE_NEW_LINES),
|
||||
json_decode(file_get_contents(str_replace('.raw', '.json', $File)), true)
|
||||
json_decode(
|
||||
file_get_contents(
|
||||
str_replace('.raw', '.json', $File)
|
||||
),
|
||||
true,
|
||||
512,
|
||||
JSON_THROW_ON_ERROR
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
@@ -278,8 +427,13 @@ final class Tests extends TestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $RawInput
|
||||
* @param array $ExpectedOutput
|
||||
*
|
||||
* @throws InvalidPacketException
|
||||
* @throws SocketException
|
||||
*
|
||||
* @dataProvider PlayersProvider
|
||||
* @param array<string> $RawInput
|
||||
*/
|
||||
public function testGetPlayers(array $RawInput, array $ExpectedOutput): void
|
||||
{
|
||||
@@ -294,6 +448,11 @@ final class Tests extends TestCase
|
||||
self::assertEquals($ExpectedOutput, $RealOutput);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*
|
||||
* @throws JsonException
|
||||
*/
|
||||
public function PlayersProvider(): array
|
||||
{
|
||||
$DataProvider = [];
|
||||
@@ -304,13 +463,24 @@ final class Tests extends TestCase
|
||||
$DataProvider[] =
|
||||
[
|
||||
file($File, FILE_SKIP_EMPTY_LINES | FILE_IGNORE_NEW_LINES),
|
||||
json_decode(file_get_contents(str_replace('.raw', '.json', $File)), true)
|
||||
json_decode(
|
||||
file_get_contents(
|
||||
str_replace('.raw', '.json', $File)
|
||||
),
|
||||
true,
|
||||
512,
|
||||
JSON_THROW_ON_ERROR
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
return $DataProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidPacketException
|
||||
* @throws SocketException
|
||||
*/
|
||||
public function testPing(): void
|
||||
{
|
||||
$this->Socket->Queue("\xFF\xFF\xFF\xFF\x6A\x00");
|
||||
|
||||
+4
-1
@@ -18,7 +18,10 @@
|
||||
],
|
||||
"require":
|
||||
{
|
||||
"php": ">=7.4"
|
||||
"php": ">=7.4",
|
||||
"ext-bz2": ">7.*",
|
||||
"ext-gmp": ">7.*",
|
||||
"ext-json": ">7.*"
|
||||
},
|
||||
"require-dev":
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user