diff --git a/src/Socialbox/Classes/Configuration.php b/src/Socialbox/Classes/Configuration.php index 8ec6a5e..e0823f9 100644 --- a/src/Socialbox/Classes/Configuration.php +++ b/src/Socialbox/Classes/Configuration.php @@ -157,6 +157,10 @@ // When a peer's external address is resolved, it is cached for this amount of time before resolving again. // This reduces the amount of times a resolution request is made to the external server. $config->setDefault('policies.peer_sync_interval', 3600); + // The maximum number of contacts a peer can retrieve from the server at once, if the client puts a + // value that exceeds this limit, the server will use this limit instead. + // recommendation: 100 + $config->setDefault('policies.get_contacts_limit', 100); // Storage configuration $config->setDefault('storage.path', '/etc/socialbox'); // The main path for file storage diff --git a/src/Socialbox/Classes/Configuration/PoliciesConfiguration.php b/src/Socialbox/Classes/Configuration/PoliciesConfiguration.php index 8216907..05abe8f 100644 --- a/src/Socialbox/Classes/Configuration/PoliciesConfiguration.php +++ b/src/Socialbox/Classes/Configuration/PoliciesConfiguration.php @@ -8,6 +8,7 @@ private int $sessionInactivityExpires; private int $imageCaptchaExpires; private int $peerSyncInterval; + private int $getContactsLimit; public function __construct(array $data) { @@ -15,6 +16,7 @@ $this->sessionInactivityExpires = $data['session_inactivity_expires']; $this->imageCaptchaExpires = $data['image_captcha_expires']; $this->peerSyncInterval = $data['peer_sync_interval']; + $this->getContactsLimit = $data['get_contacts_limit']; } /** @@ -58,4 +60,14 @@ { return $this->peerSyncInterval; } + + /** + * Returns the maximum amount of contacts that can be retrieved in a single request + * + * @return int + */ + public function getGetContactsLimit(): int + { + return $this->getContactsLimit; + } } \ No newline at end of file diff --git a/src/Socialbox/Classes/StandardMethods/AddressBookGetContacts.php b/src/Socialbox/Classes/StandardMethods/AddressBookGetContacts.php new file mode 100644 index 0000000..46122ab --- /dev/null +++ b/src/Socialbox/Classes/StandardMethods/AddressBookGetContacts.php @@ -0,0 +1,63 @@ +getGetContactsLimit(); + if($rpcRequest->containsParameter('limit')) + { + $limit = (int)$rpcRequest->getParameter('limit'); + if($limit < 0) + { + return $rpcRequest->produceError(StandardError::RPC_INVALID_ARGUMENTS, 'Invalid limit'); + } + + $limit = min($limit, Configuration::getPoliciesConfiguration()->getGetContactsLimit()); + } + + $page = 0; + if($rpcRequest->containsParameter('page')) + { + $page = (int)$rpcRequest->getParameter('page'); + if($page < 0) + { + return $rpcRequest->produceError(StandardError::RPC_INVALID_ARGUMENTS, 'Invalid page'); + } + + $page = max($page, 0); + } + + try + { + $contacts = ContactManager::getContacts($request->getPeer(), $limit, $page); + } + catch(DatabaseOperationException $e) + { + throw new StandardException('Failed to get contacts', StandardError::INTERNAL_SERVER_ERROR, $e); + } + + $results = []; + foreach($contacts as $contact) + { + $results[] = $contact->toStandard(); + } + + return $rpcRequest->produceResponse($results); + } + } \ No newline at end of file diff --git a/src/Socialbox/Enums/StandardMethods.php b/src/Socialbox/Enums/StandardMethods.php index e54e3e8..7cf47fa 100644 --- a/src/Socialbox/Enums/StandardMethods.php +++ b/src/Socialbox/Enums/StandardMethods.php @@ -8,6 +8,7 @@ use Socialbox\Classes\StandardMethods\AcceptTermsOfService; use Socialbox\Classes\StandardMethods\AddressBookAddContact; use Socialbox\Classes\StandardMethods\AddressBookDeleteContact; + use Socialbox\Classes\StandardMethods\AddressBookGetContacts; use Socialbox\Classes\StandardMethods\Authenticate; use Socialbox\Classes\StandardMethods\GetAllowedMethods; use Socialbox\Classes\StandardMethods\GetCommunityGuidelines; @@ -100,6 +101,7 @@ case ADDRESS_BOOK_ADD_CONTACT = 'addressBookAddContact'; case ADDRESS_BOOK_DELETE_CONTACT = 'addressBookDeleteContact'; + case ADDRESS_BOOK_GET_CONTACTS = 'addressBookGetContacts'; case AUTHENTICATE = 'authenticate'; case RESOLVE_PEER = 'resolvePeer'; @@ -152,6 +154,7 @@ self::ADDRESS_BOOK_ADD_CONTACT => AddressBookAddContact::execute($request, $rpcRequest), self::ADDRESS_BOOK_DELETE_CONTACT => AddressBookDeleteContact::execute($request, $rpcRequest), + self::ADDRESS_BOOK_GET_CONTACTS => AddressBookGetContacts::execute($request, $rpcRequest), self::AUTHENTICATE => Authenticate::execute($request, $rpcRequest), self::RESOLVE_PEER => ResolvePeer::execute($request, $rpcRequest), @@ -286,6 +289,7 @@ self::ADDRESS_BOOK_ADD_CONTACT, self::ADDRESS_BOOK_DELETE_CONTACT, + self::ADDRESS_BOOK_GET_CONTACTS, ]; // Prevent the user from deleting their display name if it is required diff --git a/src/Socialbox/Managers/ContactManager.php b/src/Socialbox/Managers/ContactManager.php index dc00f46..39339dc 100644 --- a/src/Socialbox/Managers/ContactManager.php +++ b/src/Socialbox/Managers/ContactManager.php @@ -8,7 +8,7 @@ use Socialbox\Classes\Database; use Socialbox\Enums\Types\ContactRelationshipType; use Socialbox\Exceptions\DatabaseOperationException; - use Socialbox\Objects\Database\ContactRecord; + use Socialbox\Objects\Database\ContactDatabaseRecord; use Socialbox\Objects\PeerAddress; class ContactManager @@ -109,10 +109,10 @@ * * @param string $peerUuid The unique identifier for the peer whose contact is to be retrieved. * @param string|PeerAddress $contactAddress The address of the contact, either as a string or a PeerAddress object. - * @return ContactRecord|null The retrieved ContactRecord instance if found, or null if no matching contact exists. + * @return ContactDatabaseRecord|null The retrieved ContactRecord instance if found, or null if no matching contact exists. * @throws DatabaseOperationException If the database query fails. */ - public static function getContact(string $peerUuid, string|PeerAddress $contactAddress): ?ContactRecord + public static function getContact(string $peerUuid, string|PeerAddress $contactAddress): ?ContactDatabaseRecord { if($contactAddress instanceof PeerAddress) { @@ -138,7 +138,7 @@ return null; } - return ContactRecord::fromArray($result); + return ContactDatabaseRecord::fromArray($result); } /** @@ -204,10 +204,10 @@ * Retrieves a contact by its unique identifier. * * @param string $uuid The unique identifier of the contact to retrieve. - * @return ContactRecord|null A ContactRecord instance if the contact is found, or null if no contact exists with the provided UUID. + * @return ContactDatabaseRecord|null A ContactRecord instance if the contact is found, or null if no contact exists with the provided UUID. * @throws DatabaseOperationException If the database query fails. */ - public static function getContactByUuid(string $uuid): ?ContactRecord + public static function getContactByUuid(string $uuid): ?ContactDatabaseRecord { try { @@ -227,7 +227,7 @@ return null; } - return ContactRecord::fromArray($result); + return ContactDatabaseRecord::fromArray($result); } /** @@ -236,7 +236,7 @@ * @param string $peerUuid The unique identifier for the peer whose contacts are to be retrieved. * @param int $limit The maximum number of contacts to retrieve per page. Defaults to 100. * @param int $page The page number to retrieve. Defaults to 1. - * @return array An array of ContactRecord instances representing the contacts for the given peer. + * @return ContactDatabaseRecord[] An array of ContactRecord instances representing the contacts for the given peer. * @throws DatabaseOperationException If the database query fails. */ public static function getContacts(string $peerUuid, int $limit=100, int $page=1): array @@ -268,7 +268,7 @@ // Convert results to ContactRecord instances foreach ($results as $result) { - $contacts[] = ContactRecord::fromArray($result); + $contacts[] = ContactDatabaseRecord::fromArray($result); } } catch (PDOException $e) diff --git a/src/Socialbox/Objects/Database/ContactRecord.php b/src/Socialbox/Objects/Database/ContactDatabaseRecord.php similarity index 86% rename from src/Socialbox/Objects/Database/ContactRecord.php rename to src/Socialbox/Objects/Database/ContactDatabaseRecord.php index 3900920..47551a0 100644 --- a/src/Socialbox/Objects/Database/ContactRecord.php +++ b/src/Socialbox/Objects/Database/ContactDatabaseRecord.php @@ -7,8 +7,9 @@ use InvalidArgumentException; use Socialbox\Enums\Types\ContactRelationshipType; use Socialbox\Interfaces\SerializableInterface; + use Socialbox\Objects\Standard\ContactRecord; - class ContactRecord implements SerializableInterface + class ContactDatabaseRecord implements SerializableInterface { private string $uuid; private string $peerUuid; @@ -117,11 +118,25 @@ /** * @inheritDoc */ - public static function fromArray(array $data): ContactRecord + public static function fromArray(array $data): ContactDatabaseRecord { return new self($data); } + /** + * Converts the object to a standard contact record. + * + * @return ContactRecord The standard contact record. + */ + public function toStandard(): ContactRecord + { + return new ContactRecord([ + 'address' => $this->contactPeerAddress, + 'relationship' => $this->relationship, + 'added_timestamp' => $this->created->getTimestamp() + ]); + } + /** * @inheritDoc */ diff --git a/src/Socialbox/Objects/Standard/ContactRecord.php b/src/Socialbox/Objects/Standard/ContactRecord.php new file mode 100644 index 0000000..919efb0 --- /dev/null +++ b/src/Socialbox/Objects/Standard/ContactRecord.php @@ -0,0 +1,76 @@ +address = PeerAddress::fromAddress($data['address']); + $this->relationship = ContactRelationshipType::tryFrom($data['relationship']) ?? ContactRelationshipType::MUTUAL; + $this->addedTimestamp = $data['added_timestamp']; + } + + /** + * Retrieves the address of the contact. + * + * @return PeerAddress Returns the address of the contact. + */ + public function getAddress(): PeerAddress + { + return $this->address; + } + + /** + * Retrieves the relationship of the contact. + * + * @return ContactRelationshipType Returns the relationship of the contact. + */ + public function getRelationship(): ContactRelationshipType + { + return $this->relationship; + } + + /** + * Retrieves the timestamp when the contact was added. + * + * @return int Returns the timestamp when the contact was added. + */ + public function getAddedTimestamp(): int + { + return $this->addedTimestamp; + } + + /** + * @inheritDoc + */ + public static function fromArray(array $data): object + { + return new self($data); + } + + /** + * @inheritDoc + */ + public function toArray(): array + { + return [ + 'address' => $this->address->getAddress(), + 'relationship' => $this->relationship->value, + 'added_timestamp' => $this->addedTimestamp + ]; + } + } \ No newline at end of file