1
0
mirror of https://github.com/xPaw/PHP-Source-Query.git synced 2026-06-10 23:03:15 +02:00

Docblocks, first pass with Psalm.

This commit is contained in:
Anthony Birkett
2021-05-30 10:47:59 +01:00
parent e62d011689
commit b5d355514b
11 changed files with 424 additions and 70 deletions
+67 -17
View File
@@ -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
View File
@@ -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
}
+41 -8
View File
@@ -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
View File
@@ -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);
+16 -6
View File
@@ -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);
+41 -1
View File
@@ -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);