Implemented PeerMetadata Manager & Telegram User Metadata manager
This commit is contained in:
parent
a322c54a69
commit
8e2e1eaba1
11 changed files with 841 additions and 24 deletions
|
@ -6,6 +6,7 @@
|
|||
|
||||
use Exception;
|
||||
use FederationLib\Enums\SerializationMethod;
|
||||
use FederationLib\Interfaces\PeerMetadataInterface;
|
||||
use FederationLib\Interfaces\SerializableObjectInterface;
|
||||
use InvalidArgumentException;
|
||||
use LogLib\Log;
|
||||
|
@ -182,10 +183,14 @@
|
|||
return $outliers;
|
||||
}
|
||||
|
||||
public static function weightedRandomPick( array $data): string
|
||||
/**
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public static function weightedRandomPick(array $data): string
|
||||
{
|
||||
$totalWeight = array_sum($data);
|
||||
if($totalWeight == 0)
|
||||
if($totalWeight === 0)
|
||||
{
|
||||
throw new InvalidArgumentException('Total weight cannot be 0');
|
||||
}
|
||||
|
@ -210,5 +215,37 @@
|
|||
return $item;
|
||||
}
|
||||
}
|
||||
|
||||
// Select a random item if the cumulative weight is 0
|
||||
return array_rand($data);
|
||||
}
|
||||
/**
|
||||
* This function returns an array showing the changed values comparing from $a to $b
|
||||
* if $b contains changes that is different from $a, it will be returned in the array
|
||||
*
|
||||
* @param PeerMetadataInterface $a
|
||||
* @param PeerMetadataInterface $b
|
||||
* @return array
|
||||
*/
|
||||
public static function metadataDifferences(PeerMetadataInterface $a, PeerMetadataInterface $b, array $filter=[]): array
|
||||
{
|
||||
$differences = [];
|
||||
$a_array = $a->toArray();
|
||||
$b_array = $b->toArray();
|
||||
|
||||
foreach ($a_array as $key => $value)
|
||||
{
|
||||
if(in_array($key, $filter, true))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if($value !== $b_array[$key])
|
||||
{
|
||||
$differences[$key] = $b_array[$key];
|
||||
}
|
||||
}
|
||||
|
||||
return $differences;
|
||||
}
|
||||
}
|
|
@ -47,13 +47,25 @@
|
|||
public const CLIENT_DISABLED = 1004;
|
||||
|
||||
|
||||
/**
|
||||
* The given peer metadata is invalid or malformed.
|
||||
*/
|
||||
public const INVALID_PEER_METADATA = 2000;
|
||||
|
||||
public const PEER_METADATA_NOT_FOUND = 2001;
|
||||
|
||||
|
||||
public const ALL = [
|
||||
self::INTERNAL_SERVER_ERROR,
|
||||
self::ACCESS_DENIED,
|
||||
|
||||
self::CLIENT_NOT_FOUND,
|
||||
self::INVALID_CLIENT_NAME,
|
||||
self::INVALID_CLIENT_DESCRIPTION,
|
||||
self::SIGNATURE_VERIFICATION_FAILED,
|
||||
self::CLIENT_DISABLED
|
||||
self::CLIENT_DISABLED,
|
||||
|
||||
self::INVALID_PEER_METADATA,
|
||||
|
||||
];
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace FederationLib\Exceptions\Standard;
|
||||
|
||||
use Exception;
|
||||
use FederationLib\Enums\Standard\ErrorCodes;
|
||||
use Throwable;
|
||||
|
||||
class InvalidPeerMetadataException extends Exception
|
||||
{
|
||||
/**
|
||||
* @param string $message
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(string $message = "", ?Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, ErrorCodes::INVALID_PEER_METADATA, $previous);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace FederationLib\Exceptions\Standard;
|
||||
|
||||
use Exception;
|
||||
use FederationLib\Enums\Standard\ErrorCodes;
|
||||
use Throwable;
|
||||
|
||||
class PeerMetadataNotFoundException extends Exception
|
||||
{
|
||||
/**
|
||||
* @param string $message
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(string $message = "", ?Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, ErrorCodes::PEER_METADATA_NOT_FOUND, $previous);
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace FederationLib\Interfaces;
|
||||
|
||||
interface EntityObjectInterface extends SerializableObjectInterface
|
||||
{
|
||||
/**
|
||||
* Validates the given object and returns true if it is valid.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function validate(): bool;
|
||||
|
||||
/**
|
||||
* Returns the standard federated address of the entity.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFederatedAddress(): string;
|
||||
}
|
91
src/FederationLib/Interfaces/PeerMetadataInterface.php
Normal file
91
src/FederationLib/Interfaces/PeerMetadataInterface.php
Normal file
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
|
||||
namespace FederationLib\Interfaces;
|
||||
|
||||
use FederationLib\Exceptions\Standard\InvalidPeerMetadataException;
|
||||
|
||||
interface PeerMetadataInterface extends SerializableObjectInterface
|
||||
{
|
||||
/**
|
||||
* Validates if the metadata is valid or not
|
||||
* throws InvalidPeerMetadataException if the metadata is invalid
|
||||
*
|
||||
* @throws InvalidPeerMetadataException
|
||||
*/
|
||||
public function validate(): void;
|
||||
|
||||
/**
|
||||
* Returns True if the metadata indicates that the peer is a bot
|
||||
* Returns False if there's no indication that the peer is a bot
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isAutomated(): bool;
|
||||
|
||||
/**
|
||||
* Returns the platform-specific ID of the peer (e.g. Telegram Chat ID)
|
||||
* If no ID is available, the method will try to find a unique ID in the metadata
|
||||
* that can uniquely identify the peer
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPlatformId(): string;
|
||||
|
||||
/**
|
||||
* Returns the calculated standard federated address of the peer
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFederatedAddress(): string;
|
||||
|
||||
/**
|
||||
* Sets the timestamp of when the peer record was last updated (this is usually used internally)
|
||||
*
|
||||
* @param int|null $timestamp
|
||||
* @return void
|
||||
*/
|
||||
public function setLastUpdatedTimestamp(?int $timestamp): void;
|
||||
|
||||
/**
|
||||
* Returns the timestamp of when the peer record was last updated
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function getLastUpdatedTimestamp(): ?int;
|
||||
|
||||
/**
|
||||
* Sets the Client's UUID that last updated the peer record (this is usually used internally)
|
||||
*
|
||||
* @param string|null $client
|
||||
* @return void
|
||||
*/
|
||||
public function setUpdatedClient(?string $client): void;
|
||||
|
||||
/**
|
||||
* Returns the Client's UUID that last updated the peer record
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getUpdatedClient(): ?string;
|
||||
|
||||
/**
|
||||
* Returns an array representation of the object, if $raw is true, the array will contain
|
||||
* additional information that is not part of the standard metadata such as the client UUID
|
||||
* and the last updated timestamp
|
||||
*
|
||||
* @param bool $raw
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(bool $raw=false): array;
|
||||
|
||||
/**
|
||||
* Constructs object from an array representation, if $raw is enabled it will accept
|
||||
* raw data that is not part of the standard metadata, this should be disabled if
|
||||
* the data is coming from an untrusted source such as a user
|
||||
*
|
||||
* @param array $array
|
||||
* @param bool $raw
|
||||
* @return PeerMetadataInterface
|
||||
*/
|
||||
public static function fromArray(array $array, bool $raw=false): PeerMetadataInterface;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace FederationLib\Interfaces;
|
||||
|
||||
use FederationLib\Objects\Client;
|
||||
use FederationLib\Objects\Peer;
|
||||
use FederationLib\Objects\Standard\PeerMetadata\TelegramUserMetadata;
|
||||
|
||||
interface PeerMetadataManagerInterface
|
||||
{
|
||||
/**
|
||||
* Intelligently syncs the metadata of the given federated address, this will ignore raw metadata & use
|
||||
* data from the given $client_uuid
|
||||
*
|
||||
* @param Client|string $client_uuid
|
||||
* @param TelegramUserMetadata $telegram_user_metadata
|
||||
* @return string
|
||||
*/
|
||||
public function syncMetadata(Client|string $client_uuid, TelegramUserMetadata $telegram_user_metadata): string;
|
||||
|
||||
/**
|
||||
* Registers the metadata of the given federated address, this will ignore raw metadata & use data from the
|
||||
* given $client_uuid
|
||||
*
|
||||
* @param Client|string $client_uuid
|
||||
* @param TelegramUserMetadata $telegram_user_metadata
|
||||
* @return string
|
||||
*/
|
||||
public function registerMetadata(Client|string $client_uuid, TelegramUserMetadata $telegram_user_metadata): string;
|
||||
|
||||
/**
|
||||
* Returns the metadata of the given federated address, this returns the full raw metadata
|
||||
*
|
||||
* @param Peer|string $federated_address
|
||||
* @return TelegramUserMetadata
|
||||
*/
|
||||
public function getMetadata(Peer|string $federated_address): TelegramUserMetadata;
|
||||
}
|
|
@ -0,0 +1,284 @@
|
|||
<?php
|
||||
|
||||
namespace FederationLib\Managers\MetadataManagers;
|
||||
|
||||
use Doctrine\DBAL\ParameterType;
|
||||
use Exception;
|
||||
use FederationLib\Classes\Configuration;
|
||||
use FederationLib\Classes\Database;
|
||||
use FederationLib\Classes\Utilities;
|
||||
use FederationLib\Enums\DatabaseTables;
|
||||
use FederationLib\Enums\Misc;
|
||||
use FederationLib\Exceptions\DatabaseException;
|
||||
use FederationLib\Exceptions\Standard\InvalidPeerMetadataException;
|
||||
use FederationLib\Exceptions\Standard\PeerMetadataNotFoundException;
|
||||
use FederationLib\Interfaces\PeerMetadataManagerInterface;
|
||||
use FederationLib\Managers\RedisConnectionManager;
|
||||
use FederationLib\Objects\Client;
|
||||
use FederationLib\Objects\Peer;
|
||||
use FederationLib\Objects\Standard\PeerMetadata\TelegramUserMetadata;
|
||||
use LogLib\Log;
|
||||
|
||||
class TelegramUserManager implements PeerMetadataManagerInterface
|
||||
{
|
||||
/**
|
||||
* @param Client|string $client_uuid
|
||||
* @param TelegramUserMetadata $telegram_user_metadata
|
||||
* @return string
|
||||
* @throws DatabaseException
|
||||
* @throws InvalidPeerMetadataException
|
||||
*/
|
||||
public function syncMetadata(Client|string $client_uuid, TelegramUserMetadata $telegram_user_metadata): string
|
||||
{
|
||||
if($client_uuid instanceof Client)
|
||||
{
|
||||
$client_uuid = $client_uuid->getUuid();
|
||||
}
|
||||
|
||||
$telegram_user_metadata->validate();
|
||||
$cache_key = sprintf('telegram_user_metadata:%s', $telegram_user_metadata->getFederatedAddress());
|
||||
$redis_client = null;
|
||||
|
||||
if(Configuration::isCacheSystemEnabled() && Configuration::getObjectCacheEnabled('peer_objects'))
|
||||
{
|
||||
try
|
||||
{
|
||||
$redis_client = RedisConnectionManager::getConnectionFromConfig('peer_objects');
|
||||
|
||||
if($redis_client->exists($cache_key))
|
||||
{
|
||||
$redis_client->del($cache_key);
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
Log::warning(Misc::FEDERATIONLIB, sprintf('There was an error with the cache system while tyring to sync peer metadata with the Redis server: %s', $e->getMessage()), $e);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$old_metadata = $this->getMetadata($telegram_user_metadata->getFederatedAddress());
|
||||
}
|
||||
catch(PeerMetadataNotFoundException $e)
|
||||
{
|
||||
unset($e);
|
||||
|
||||
// If it doesn't exist, we create it instead of updating it
|
||||
return $this->registerMetadata($client_uuid, $telegram_user_metadata);
|
||||
}
|
||||
|
||||
// Take the old metadata and get the differences
|
||||
$differences = Utilities::metadataDifferences($old_metadata, $telegram_user_metadata);
|
||||
|
||||
try
|
||||
{
|
||||
// If there are no differences, then we don't need to update the database
|
||||
if(count($differences) === 0)
|
||||
{
|
||||
if($redis_client !== null && Configuration::getObjectCacheTtl('peer_objects') > 0)
|
||||
{
|
||||
// Reset the TTL since we just accessed it
|
||||
$redis_client->expire($cache_key, Configuration::getObjectCacheTtl('peer_objects'));
|
||||
}
|
||||
|
||||
return $telegram_user_metadata->getFederatedAddress();
|
||||
}
|
||||
|
||||
$qb = Database::getConnection()->createQueryBuilder();
|
||||
$qb->update(DatabaseTables::PEERS_TELEGRAM_USER);
|
||||
$qb->where('federated_address = :federated_address');
|
||||
$qb->setParameter('federated_address', $telegram_user_metadata->getFederatedAddress());
|
||||
$qb->set('updated_timestamp', $qb->createNamedParameter(time(), ParameterType::INTEGER));
|
||||
$qb->set('updated_client', $qb->createNamedParameter($client_uuid));
|
||||
$qb->setMaxResults(1);
|
||||
|
||||
foreach($differences as $key => $value)
|
||||
{
|
||||
$qb->set($key, $qb->createNamedParameter($value));
|
||||
}
|
||||
|
||||
$qb->executeQuery();
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
throw new DatabaseException(sprintf('There was a database error while trying to sync peer metadata: %s', $e->getMessage()), $e);
|
||||
}
|
||||
|
||||
if($redis_client !== null && count($differences) > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach($differences as $key => $value)
|
||||
{
|
||||
$redis_client->hSet($cache_key, $key, $value);
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
Log::warning(Misc::FEDERATIONLIB, sprintf('There was an error with the cache system while tyring to sync peer metadata with the Redis server: %s', $e->getMessage()), $e);
|
||||
}
|
||||
}
|
||||
|
||||
return $telegram_user_metadata->getFederatedAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the client's metadata with the database
|
||||
*
|
||||
* @param Client|string $client_uuid
|
||||
* @param TelegramUserMetadata $telegram_user_metadata
|
||||
* @return string
|
||||
* @throws DatabaseException
|
||||
*/
|
||||
public function registerMetadata(Client|string $client_uuid, TelegramUserMetadata $telegram_user_metadata): string
|
||||
{
|
||||
if($client_uuid instanceof Client)
|
||||
{
|
||||
$client_uuid = $client_uuid->getUuid();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$telegram_user_metadata->validate();
|
||||
$qb = Database::getConnection()->createQueryBuilder();
|
||||
$qb->insert(DatabaseTables::PEERS_TELEGRAM_USER);
|
||||
|
||||
$qb->setValue('federated_address', $qb->createNamedParameter($telegram_user_metadata->getFederatedAddress()));
|
||||
$qb->setValue('updated_timestamp', $qb->createNamedParameter(time(), ParameterType::INTEGER));
|
||||
$qb->setValue('updated_client', $qb->createNamedParameter($client_uuid));
|
||||
|
||||
foreach($telegram_user_metadata->toArray() as $key => $value)
|
||||
{
|
||||
switch(gettype($value))
|
||||
{
|
||||
case 'array':
|
||||
$qb->setValue($key, $qb->createNamedParameter(implode(',', $value)));
|
||||
break;
|
||||
case 'NULL':
|
||||
$qb->setValue($key, $qb->createNamedParameter(null, ParameterType::NULL));
|
||||
break;
|
||||
case 'boolean':
|
||||
$qb->setValue($key, $qb->createNamedParameter((int)$value, ParameterType::INTEGER));
|
||||
break;
|
||||
case 'integer':
|
||||
$qb->setValue($key, $qb->createNamedParameter($value, ParameterType::INTEGER));
|
||||
break;
|
||||
|
||||
default:
|
||||
$qb->setValue($key, $qb->createNamedParameter($value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$qb->executeQuery();
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
throw new DatabaseException(sprintf('There was a database error while trying to register peer metadata: %s', $e->getMessage()), $e);
|
||||
}
|
||||
|
||||
return $telegram_user_metadata->getFederatedAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Peer|string $federated_address
|
||||
* @throws PeerMetadataNotFoundException
|
||||
* @throws DatabaseException
|
||||
* @return TelegramUserMetadata
|
||||
*/
|
||||
public function getMetadata(Peer|string $federated_address): TelegramUserMetadata
|
||||
{
|
||||
if($federated_address instanceof Peer)
|
||||
{
|
||||
$federated_address = $federated_address->getFederatedAddress();
|
||||
}
|
||||
|
||||
if(Configuration::isCacheSystemEnabled() && Configuration::getObjectCacheEnabled('peer_objects'))
|
||||
{
|
||||
try
|
||||
{
|
||||
$redis = RedisConnectionManager::getConnectionFromConfig('peer_objects');
|
||||
$key = sprintf('telegram_user_metadata:%s', $federated_address);
|
||||
|
||||
if($redis->exists($key))
|
||||
{
|
||||
$telegram_user_metadata = TelegramUserMetadata::fromArray($redis->hGetAll($key), true);
|
||||
|
||||
if(Configuration::getObjectCacheTTL('peer_objects') > 0)
|
||||
{
|
||||
$redis->expire($key, Configuration::getObjectCacheTTL('peer_objects'));
|
||||
}
|
||||
|
||||
Log::debug(Misc::FEDERATIONLIB, sprintf('Loaded peer metadata object %s from cache', $federated_address));
|
||||
return $telegram_user_metadata;
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
Log::warning(Misc::FEDERATIONLIB, sprintf('Failed to load peer metadata object %s from cache: %s', $federated_address, $e->getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
$qb = Database::getConnection()->createQueryBuilder();
|
||||
$qb->select(
|
||||
'id',
|
||||
'type',
|
||||
'title',
|
||||
'username',
|
||||
'first_name',
|
||||
'last_name',
|
||||
'is_forum',
|
||||
'updated_timestamp',
|
||||
'updated_client'
|
||||
);
|
||||
$qb->from(DatabaseTables::PEERS_TELEGRAM_USER);
|
||||
$qb->where('federated_address = :federated_address');
|
||||
$qb->setParameter('federated_address', $federated_address);
|
||||
$qb->setMaxResults(1);
|
||||
|
||||
try
|
||||
{
|
||||
$result = $qb->executeQuery();
|
||||
|
||||
if($result->rowCount() === 0)
|
||||
{
|
||||
throw new PeerMetadataNotFoundException(sprintf('Peer metadata not found for federated address %s', $federated_address));
|
||||
}
|
||||
|
||||
$telegram_user_metadata = TelegramUserMetadata::fromArray($result->fetchAssociative(), true);
|
||||
}
|
||||
catch(PeerMetadataNotFoundException $e)
|
||||
{
|
||||
throw $e;
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
throw new DatabaseException(sprintf('Failed to get peer metadata for federated address %s', $federated_address), $e);
|
||||
}
|
||||
|
||||
if(Configuration::isCacheSystemEnabled() && Configuration::getObjectCacheEnabled('peer_objects'))
|
||||
{
|
||||
try
|
||||
{
|
||||
$redis = RedisConnectionManager::getConnectionFromConfig('peer_objects');
|
||||
|
||||
$key = sprintf('telegram_user_metadata:%s', $federated_address);
|
||||
$redis->hMSet($key, $telegram_user_metadata->toArray());
|
||||
|
||||
if(Configuration::getObjectCacheTTL('peer_objects') > 0)
|
||||
{
|
||||
$redis->expire($key, Configuration::getObjectCacheTTL('peer_objects'));
|
||||
}
|
||||
|
||||
Log::debug(Misc::FEDERATIONLIB, sprintf('Cached peer metadata object %s', $federated_address));
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
Log::warning(Misc::FEDERATIONLIB, sprintf('Failed to cache peer metadata object %s: %s', $federated_address, $e->getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
return $telegram_user_metadata;
|
||||
}
|
||||
}
|
|
@ -2,14 +2,22 @@
|
|||
|
||||
namespace FederationLib\Managers;
|
||||
|
||||
use FederationLib\Enums\Standard\UserPeerType;
|
||||
use FederationLib\FederationLib;
|
||||
use FederationLib\Interfaces\PeerMetadataManagerInterface;
|
||||
use FederationLib\Objects\Standard\PeerMetadata\TelegramUserMetadata;
|
||||
|
||||
class PeerManager
|
||||
{
|
||||
/**
|
||||
* @var FederationLib
|
||||
*/
|
||||
private FederationLib $federationLib;
|
||||
private $federationLib;
|
||||
|
||||
/**
|
||||
* @var PeerMetadataManagerInterface[]
|
||||
*/
|
||||
private $metadata_managers;
|
||||
|
||||
/**
|
||||
* PeerManager constructor.
|
||||
|
@ -19,5 +27,6 @@
|
|||
public function __construct(FederationLib $federationLib)
|
||||
{
|
||||
$this->federationLib = $federationLib;
|
||||
$this->metadata_managers[UserPeerType::TELEGRAM_USER] = new TelegramUserMetadata();
|
||||
}
|
||||
}
|
|
@ -17,6 +17,19 @@
|
|||
*/
|
||||
private static $connections;
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return \Redis
|
||||
* @throws CacheConnectionException
|
||||
*/
|
||||
public static function getConnectionFromConfig(string $name): \Redis
|
||||
{
|
||||
return self::getConnection(
|
||||
Configuration::getObjectCacheServerPreference($name),
|
||||
Configuration::getObjectCacheServerFallback($name)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the requested redis connection to use
|
||||
*
|
||||
|
|
|
@ -0,0 +1,315 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpUnused */
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace FederationLib\Objects\Standard\PeerMetadata;
|
||||
|
||||
use FederationLib\Enums\Standard\UserPeerType;
|
||||
use FederationLib\Exceptions\Standard\InvalidPeerMetadataException;
|
||||
use FederationLib\Interfaces\PeerMetadataInterface;
|
||||
|
||||
class TelegramUserMetadata implements PeerMetadataInterface
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $is_bot;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $first_name;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $last_name;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $username;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $language_code;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $is_premium;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
private $updated_timestamp;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $updated_client;
|
||||
|
||||
/**
|
||||
* Validates the given metadata and throws an exception if the metadata is invalid
|
||||
*
|
||||
* @throws InvalidPeerMetadataException
|
||||
*/
|
||||
public function validate(): void
|
||||
{
|
||||
if($this->id === null)
|
||||
{
|
||||
throw new InvalidPeerMetadataException(sprintf('The property "id" is required in the metadata for peer type %s', UserPeerType::TELEGRAM_USER));
|
||||
}
|
||||
|
||||
if(!is_int($this->id))
|
||||
{
|
||||
throw new InvalidPeerMetadataException(sprintf('The property "id" must be an integer in metadata for peer type %s, got %s', UserPeerType::TELEGRAM_USER, gettype($this->id)));
|
||||
}
|
||||
|
||||
if(!is_bool($this->is_bot))
|
||||
{
|
||||
throw new InvalidPeerMetadataException(sprintf('The property "is_bot" must be a boolean in metadata for peer type %s, got %s', UserPeerType::TELEGRAM_USER, gettype($this->is_bot)));
|
||||
}
|
||||
|
||||
if($this->first_name === null)
|
||||
{
|
||||
throw new InvalidPeerMetadataException(sprintf('The property "first_name" is required in the metadata for peer type %s', UserPeerType::TELEGRAM_USER));
|
||||
}
|
||||
|
||||
if(!is_string($this->first_name))
|
||||
{
|
||||
throw new InvalidPeerMetadataException(sprintf('The property "first_name" must be a string in metadata for peer type %s, got %s', UserPeerType::TELEGRAM_USER, gettype($this->first_name)));
|
||||
}
|
||||
|
||||
if($this->last_name !== null && !is_string($this->last_name))
|
||||
{
|
||||
throw new InvalidPeerMetadataException(sprintf('The property "last_name" must be a string in metadata for peer type %s, got %s', UserPeerType::TELEGRAM_USER, gettype($this->last_name)));
|
||||
}
|
||||
|
||||
if($this->username !== null && !is_string($this->username))
|
||||
{
|
||||
throw new InvalidPeerMetadataException(sprintf('The property "username" must be a string in metadata for peer type %s, got %s', UserPeerType::TELEGRAM_USER, gettype($this->username)));
|
||||
}
|
||||
|
||||
if($this->language_code !== null && !is_string($this->language_code))
|
||||
{
|
||||
throw new InvalidPeerMetadataException(sprintf('The property "language_code" must be a string in metadata for peer type %s, got %s', UserPeerType::TELEGRAM_USER, gettype($this->language_code)));
|
||||
}
|
||||
|
||||
if(!is_bool($this->is_premium))
|
||||
{
|
||||
throw new InvalidPeerMetadataException(sprintf('The property "is_premium" must be a boolean in metadata for peer type %s, got %s', UserPeerType::TELEGRAM_USER, gettype($this->is_premium)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns True if the peer is a bot, False otherwise
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isAutomated(): bool
|
||||
{
|
||||
return $this->is_bot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the platform-specific ID of the peer
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPlatformId(): string
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the standard federated address of the peer
|
||||
* Format: telegram.user:<id>
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFederatedAddress(): string
|
||||
{
|
||||
return sprintf('%s:%s', UserPeerType::TELEGRAM_USER, $this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the client UUID that last updated the record
|
||||
*
|
||||
* @param string|null $client
|
||||
* @return void
|
||||
*/
|
||||
public function setUpdatedClient(?string $client): void
|
||||
{
|
||||
$this->updated_client = $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Timestamp for when the record was last updated
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getLastUpdatedTimestamp(): int
|
||||
{
|
||||
return $this->updated_timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Timestamp for when the record was last updated
|
||||
*
|
||||
* @param int|null $timestamp
|
||||
* @return void
|
||||
*/
|
||||
public function setLastUpdatedTimestamp(?int $timestamp): void
|
||||
{
|
||||
$this->updated_timestamp = $timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Client UUID that last updated the record
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public function getUpdatedClient(): ?string
|
||||
{
|
||||
return $this->updated_client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unique identifier for this user or bot. This number may have more than 32 significant bits and some
|
||||
* programming languages may have difficulty/silent defects in interpreting it. But it has at most 52
|
||||
* significant bits, so a 64-bit integer or double-precision float type are safe for storing this identifier.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* True, if this user is a bot
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isBot(): bool
|
||||
{
|
||||
return $this->is_bot;
|
||||
}
|
||||
|
||||
/**
|
||||
* User's or bot's first name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFirstName(): string
|
||||
{
|
||||
return $this->first_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional. User's or bot's last name
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getLastName(): ?string
|
||||
{
|
||||
return $this->last_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional. User's or bot's username
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getUsername(): ?string
|
||||
{
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional. IETF language tag of the user's language
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getLanguageCode(): ?string
|
||||
{
|
||||
return $this->language_code;
|
||||
}
|
||||
|
||||
/**
|
||||
* True, if this user is a Telegram Premium user
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isPremium(): bool
|
||||
{
|
||||
return $this->is_premium;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array representation of the object.
|
||||
*
|
||||
* @param bool $raw
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(bool $raw = false): array
|
||||
{
|
||||
$return = [
|
||||
'id' => $this->id,
|
||||
'is_bot' => $this->is_bot,
|
||||
'first_name' => $this->first_name,
|
||||
'last_name' => $this->last_name,
|
||||
'username' => $this->username,
|
||||
'language_code' => $this->language_code,
|
||||
'is_premium' => $this->is_premium
|
||||
];
|
||||
|
||||
if(!$raw)
|
||||
{
|
||||
return $return;
|
||||
}
|
||||
|
||||
return array_merge($return, [
|
||||
'updated_timestamp' => $this->updated_timestamp,
|
||||
'updated_client' => $this->updated_client
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs object from an array representation.
|
||||
*
|
||||
* @param array $array
|
||||
* @param bool $raw
|
||||
* @return TelegramUserMetadata
|
||||
*/
|
||||
public static function fromArray(array $array, bool $raw = false): TelegramUserMetadata
|
||||
{
|
||||
$object = new self();
|
||||
|
||||
$object->id = $array['id'];
|
||||
$object->is_bot = $array['is_bot'] ?? false;
|
||||
$object->first_name = $array['first_name'];
|
||||
$object->last_name = $array['last_name'] ?? null;
|
||||
$object->username = $array['username'] ?? null;
|
||||
$object->language_code = $array['language_code'] ?? null;
|
||||
$object->is_premium = $array['is_premium'] ?? false;
|
||||
|
||||
if(!$raw)
|
||||
{
|
||||
return $object;
|
||||
}
|
||||
|
||||
$object->updated_timestamp = $array['updated_timestamp'] ?? null;
|
||||
$object->updated_client = $array['updated_client'] ?? null;
|
||||
|
||||
return $object;
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue