Add new classes and methods for session management

This commit is contained in:
netkas 2024-09-13 13:52:38 -04:00
parent b9c84aeb27
commit 764ec51fa4
12 changed files with 1026 additions and 28 deletions

View file

@ -0,0 +1,96 @@
<?php
namespace Socialbox\Objects;
use InvalidArgumentException;
use Socialbox\Classes\Validator;
use Socialbox\Enums\ReservedUsernames;
class PeerAddress
{
private string $username;
private string $domain;
/**
* Constructs a PeerAddress object from a given username and domain
*
* @param string $username The username of the peer
* @param string $domain The domain of the peer
*/
public function __construct(string $username, string $domain)
{
$this->username = $username;
$this->domain = $domain;
}
/**
* Constructs a PeerAddress from a full peer address (eg; john@example.com)
*
* @param string $address The full address of the peer
* @return PeerAddress The constructed PeerAddress object
*/
public static function fromAddress(string $address): PeerAddress
{
if(!Validator::validatePeerAddress($address))
{
throw new InvalidArgumentException("Invalid peer address: $address");
}
$parts = explode('@', $address);
return new PeerAddress($parts[0], $parts[1]);
}
/**
* Returns the username of the peer
*
* @return string
*/
public function getUsername(): string
{
return $this->username;
}
/**
* Returns the domain of the peer
*
* @return string
*/
public function getDomain(): string
{
return $this->domain;
}
/**
* Returns whether the peer is the host
*
* @return bool True if the peer is the host, false otherwise
*/
public function isHost(): bool
{
return $this->username === ReservedUsernames::HOST->value;
}
/**
* Returns whether the peer requires authentication, for example, the anonymous user does not require authentication
*
* @return bool True if authentication is required, false otherwise
*/
public function authenticationRequired(): bool
{
return match($this->username)
{
ReservedUsernames::ANONYMOUS->value => false,
default => true
};
}
/**
* Returns the full address of the peer
*
* @return string The full address of the peer
*/
public function getAddress(): string
{
return sprintf("%s@%s", $this->username, $this->domain);
}
}

View file

@ -2,26 +2,27 @@
namespace Socialbox\Objects;
use Socialbox\Enums\StandardError;
use Socialbox\Interfaces\SerializableInterface;
class RpcError implements SerializableInterface
{
private string $id;
private string $error;
private int $code;
private string $message;
private StandardError $code;
/**
* Constructs the RPC error object.
*
* @param string $id The ID of the RPC request
* @param string $error The error message
* @param int $code The error code
* @param StandardError $error The error code
* @param string $message The error message
*/
public function __construct(string $id, string $error, int $code)
public function __construct(string $id, StandardError $error, string $message)
{
$this->id = $id;
$this->error = $error;
$this->code = $code;
$this->code = $error;
$this->message = $message;
}
/**
@ -39,17 +40,17 @@ class RpcError implements SerializableInterface
*
* @return string The error message.
*/
public function getError(): string
public function getMessage(): string
{
return $this->error;
return $this->message;
}
/**
* Returns the error code.
*
* @return int The error code.
* @return StandardError The error code.
*/
public function getCode(): int
public function getCode(): StandardError
{
return $this->code;
}
@ -63,8 +64,8 @@ class RpcError implements SerializableInterface
{
return [
'id' => $this->id,
'error' => $this->error,
'code' => $this->code
'error' => $this->message,
'code' => $this->code->value
];
}
@ -76,6 +77,13 @@ class RpcError implements SerializableInterface
*/
public static function fromArray(array $data): RpcError
{
return new RpcError($data['id'], $data['error'], $data['code']);
$errorCode = StandardError::tryFrom($data['code']);
if($errorCode == null)
{
$errorCode = StandardError::UNKNOWN;
}
return new RpcError($data['id'], $data['error'], $errorCode);
}
}

View file

@ -2,6 +2,11 @@
namespace Socialbox\Objects;
use InvalidArgumentException;
use ncc\ThirdParty\nikic\PhpParser\Node\Expr\BinaryOp\BooleanOr;
use Socialbox\Enums\StandardError;
use Socialbox\Exceptions\RpcException;
use Socialbox\Exceptions\StandardException;
use Socialbox\Interfaces\SerializableInterface;
class RpcRequest implements SerializableInterface
@ -13,13 +18,15 @@ class RpcRequest implements SerializableInterface
/**
* Constructs the object from an array of data.
*
* @param array $data The data to construct the object from.
* @param string $method The method of the request.
* @param string|null $id The ID of the request.
* @param array|null $parameters The parameters of the request.
*/
public function __construct(array $data)
public function __construct(string $method, ?string $id, ?array $parameters)
{
$this->id = $data['id'] ?? null;
$this->method = $data['method'];
$this->parameters = $data['parameters'] ?? null;
$this->method = $method;
$this->parameters = $parameters;
$this->id = $id;
}
/**
@ -45,13 +52,106 @@ class RpcRequest implements SerializableInterface
/**
* Returns the parameters of the request.
*
* @return array|null The parameters of the request.
* @return array|null The parameters of the request, null if the request is a notification.
*/
public function getParameters(): ?array
{
return $this->parameters;
}
/**
* Checks if the parameter exists within the RPC request
*
* @param string $parameter The parameter to check
* @return bool True if the parameter exists, False otherwise.
*/
public function containsParameter(string $parameter): bool
{
return isset($this->parameters[$parameter]);
}
/**
* Returns the parameter value from the RPC request
*
* @param string $parameter The parameter name to get
* @return mixed The parameter value, null if the parameter value is null or not found.
*/
public function getParameter(string $parameter): mixed
{
if(!$this->containsParameter($parameter))
{
return null;
}
return $this->parameters[$parameter];
}
/**
* Produces a response based off the request, null if the request is a notification
*
* @param mixed|null $result
* @return RpcResponse|null
*/
public function produceResponse(mixed $result=null): ?RpcResponse
{
if($this->id == null)
{
return null;
}
$valid = false;
if(is_array($result))
{
$valid = true;
}
elseif($result instanceof SerializableInterface)
{
$valid = true;
}
elseif(is_null($result))
{
$valid = true;
}
if(!$valid)
{
throw new InvalidArgumentException('The \'$result\' property must either be array, null or SerializableInterface');
}
return new RpcResponse($this->id, $result);
}
/**
* Produces an error response based off the request, null if the request is a notification
*
* @param StandardError $error
* @param string|null $message
* @return RpcError|null
*/
public function produceError(StandardError $error, ?string $message=null): ?RpcError
{
if($this->id == null)
{
return null;
}
if($message == null)
{
$message = $error->getMessage();
}
return new RpcError($this->id, $error, $message);
}
/**
* @param StandardException $e
* @return RpcError|null
*/
public function handleStandardException(StandardException $e): ?RpcError
{
return $this->produceError($e->getStandardError(), $e->getMessage());
}
/**
* Returns an array representation of the object.
*
@ -74,6 +174,6 @@ class RpcRequest implements SerializableInterface
*/
public static function fromArray(array $data): RpcRequest
{
return static($data);
return new RpcRequest($data['method'], $data['id'] ?? null, $data['parameters'] ?? null);
}
}

View file

@ -7,15 +7,15 @@ use Socialbox\Interfaces\SerializableInterface;
class RpcResponse implements SerializableInterface
{
private string $id;
private ?object $result;
private mixed $result;
/**
* Constructs the response object.
*
* @param string $id The ID of the response.
* @param object|null $result The result of the response.
* @param mixed|null $result The result of the response.
*/
public function __construct(string $id, ?object $result)
public function __construct(string $id, mixed $result)
{
$this->id = $id;
$this->result = $result;
@ -34,13 +34,37 @@ class RpcResponse implements SerializableInterface
/**
* Returns the result of the response.
*
* @return object|null The result of the response.
* @return mixed|null The result of the response.
*/
public function getResult(): ?object
public function getResult(): mixed
{
return $this->result;
}
/**
* Converts the given data to an array.
*
* @param mixed $data The data to be converted. This can be an instance of SerializableInterface, an array, or a scalar value.
* @return mixed The converted data as an array if applicable, or the original data.
*/
private function convertToArray(mixed $data): mixed
{
// If the data is an instance of SerializableInterface, call toArray on it
if ($data instanceof SerializableInterface)
{
return $data->toArray();
}
// If the data is an array, recursively apply this method to each element
if (is_array($data))
{
return array_map([$this, 'convertToArray'], $data);
}
// Otherwise, return the data as-is (e.g., for scalar values)
return $data;
}
/**
* Returns an array representation of the object.
*
@ -50,7 +74,7 @@ class RpcResponse implements SerializableInterface
{
return [
'id' => $this->id,
'result' => $this->result->toArray()
'result' => $this->convertToArray($this->result)
];
}

View file

@ -0,0 +1,82 @@
<?php
namespace Socialbox\Objects;
use DateTime;
use Socialbox\Enums\SessionState;
use Socialbox\Interfaces\SerializableInterface;
class SessionRecord implements SerializableInterface
{
private string $uuid;
private ?string $authenticatedPeerUuid;
private string $publicKey;
private SessionState $state;
private DateTime $created;
private DateTime $lastRequest;
public function __construct(array $data)
{
$this->uuid = $data['uuid'];
$this->authenticatedPeerUuid = $data['authenticated_peer_uuid'] ?? null;
$this->publicKey = $data['public_key'];
$this->created = $data['created'];
$this->lastRequest = $data['last_request'];
if(SessionState::tryFrom($data['state']) == null)
{
$this->state = SessionState::CLOSED;
}
else
{
$this->state = SessionState::from($data['state']);
}
}
public function getUuid(): string
{
return $this->uuid;
}
public function getAuthenticatedPeerUuid(): ?string
{
return $this->authenticatedPeerUuid;
}
public function getPublicKey(): string
{
return $this->publicKey;
}
public function getState(): SessionState
{
return $this->state;
}
public function getCreated(): int
{
return $this->created;
}
public function getLastRequest(): int
{
return $this->lastRequest;
}
public static function fromArray(array $data): object
{
return new self($data);
}
public function toArray(): array
{
return [
'uuid' => $this->uuid,
'authenticated_peer_uuid' => $this->authenticatedPeerUuid,
'public_key' => $this->publicKey,
'state' => $this->state->value,
'created' => $this->created,
'last_request' => $this->lastRequest,
];
}
}