diff --git a/.gitignore b/.gitignore index 4176aad..f8ce80d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,6 @@ tmp/ config.php vendor/ -composer.lock \ No newline at end of file +composer.lock + +.*.swp diff --git a/src/Models/BaseMessage.php b/src/Models/BaseMessage.php index 7910b60..cdd75ad 100644 --- a/src/Models/BaseMessage.php +++ b/src/Models/BaseMessage.php @@ -95,6 +95,42 @@ public function fromJSON( $json, $keepOriginal = false ) { $this->decode(); } + /** + * Creates and returns a new message from the given encoded message like object + * @param stdClass $obj Message-like object + * @param CipherParams|null $cipherParams + */ + public static function fromEncoded( $obj, CipherParams $cipherParams = null ) { + $class = get_called_class(); + + $msg = new $class(); + if ($cipherParams != null) { + $msg->setCipherParams( $cipherParams ); + } + + foreach ($obj as $key => $value) { + if (property_exists( $class, $key )) { + $msg->$key = $value; + } + } + + $msg->decode(); + + return $msg; + } + + /** + * Creates and returns a new message from the given encoded message like object + * @param array $objs Array of Message-Like objects + * @param CipherParams|null $cipherParams + */ + public static function fromEncodedArray( $objs, CipherParams $cipherParams = null ) { + return array_map( + function( $obj ) use ($cipherParams) { return static::fromEncoded($obj, $cipherParams); }, + $objs + ); + } + /** * Returns an encoded message as a stdClass ready for stringifying */ @@ -224,4 +260,4 @@ protected function clearFields() { public function setCipherParams( CipherParams $cipherParams ) { $this->cipherParams = $cipherParams; } -} \ No newline at end of file +} diff --git a/src/Models/ClientOptions.php b/src/Models/ClientOptions.php index 9ca01ee..e3f52c1 100644 --- a/src/Models/ClientOptions.php +++ b/src/Models/ClientOptions.php @@ -75,13 +75,18 @@ class ClientOptions extends AuthOptions { /** * @var integer connection timeout after which a next fallback host is used */ - public $httpRequestTimeout = 15000; + public $httpRequestTimeout = 10000; /** * @var integer Max number of fallback host retries for HTTP requests that fail due to network issues or server problems */ public $httpMaxRetryCount = 3; + /** + * @var integer Max elapsed time in which fallback host retries for HTTP requests will be attempted + */ + public $httpMaxRetryDuration = 15000; + /** * @var string a class that should be used for making HTTP connections * To allow mocking in tests. @@ -126,4 +131,4 @@ public function __construct( $options = [] ) { $this->restHost = $this->environment . '-' . $this->restHost; } } -} \ No newline at end of file +} diff --git a/src/Models/Message.php b/src/Models/Message.php index d73d1aa..045fb53 100644 --- a/src/Models/Message.php +++ b/src/Models/Message.php @@ -27,4 +27,5 @@ protected function encode() { return $msg; } + } diff --git a/tests/ChannelMessagesTest.php b/tests/ChannelMessagesTest.php index 46c35f0..e0ec5c2 100644 --- a/tests/ChannelMessagesTest.php +++ b/tests/ChannelMessagesTest.php @@ -269,7 +269,7 @@ public function testPublishConnectionKey() { $msg = new Message(); $msg->name = 'delegatedMsg'; $msg->data = 'test payload'; - $msg->connectionKey = 'fake!realtime_key'; + $msg->connectionKey = 'fake.realtime_key'; // publishing the message with an invalid key must fail $this->setExpectedException( 'Ably\Exceptions\AblyException', '', 40006 ); diff --git a/tests/CryptoTest.php b/tests/CryptoTest.php index 22f0bba..8f827ee 100644 --- a/tests/CryptoTest.php +++ b/tests/CryptoTest.php @@ -128,11 +128,44 @@ public function testMessageEncryptionAgainstFixture( $filename ) { $decryptedExample->setCipherParams( $cipherParams ); $decryptedExample->fromJSON( $example->encrypted ); - $this->assertEquals( $decodedExample->data, $decryptedExample->data, 'Expected unencrypted and decrypted message\'s contents to match' ); + $this->assertEquals( $decodedExample->data, $decryptedExample->data, + 'Expected unencrypted and decrypted message\'s contents to match' ); $decodedExample->setCipherParams( $cipherParams ); $encryptedJSON = json_decode( $decodedExample->toJSON() ); - $this->assertEquals( $example->encrypted->data, $encryptedJSON->data, 'Expected encrypted and example encrypted message\'s contents to match' ); + $this->assertEquals( $example->encrypted->data, $encryptedJSON->data, + 'Expected encrypted and example encrypted message\'s contents to match' ); + } + } + + /** + * Tests Message:fromEncodedArray + * + * @dataProvider filenameProvider + */ + public function testMessageFromEncodedArray( $filename ) { + $fixture = json_decode( file_get_contents( $filename ) ); + + $cipherParams = Crypto::getDefaultParams([ + 'key' => $fixture->key, + 'algorithm' => $fixture->algorithm, + 'keyLength' => $fixture->keylength, + 'mode' => $fixture->mode, + 'iv' => $fixture->iv, + 'base64Key' => true, + 'base64Iv' => true, + ]); + + $encrypted = array_map( function ( $x ) { return $x->encrypted ; }, $fixture->items ); + $encoded = array_map( function ( $x ) { return $x->encoded ; }, $fixture->items ); + + $encrypted = Message::fromEncodedArray( $encrypted, $cipherParams ); + $encoded = Message::fromEncodedArray( $encoded ); + + foreach ($encrypted as $i => $decryptedExample) { + $decodedExample = $encoded[$i]; + $this->assertEquals( $decodedExample->data, $decryptedExample->data, + 'Expected unencrypted and decrypted message\'s contents to match' ); } } @@ -166,11 +199,44 @@ public function testPresenceMessageEncryptionAgainstFixture( $filename ) { $decryptedExample->setCipherParams( $cipherParams ); $decryptedExample->fromJSON( $example->encrypted ); - $this->assertEquals( $decodedExample->data, $decryptedExample->data, 'Expected unencrypted and decrypted message\'s contents to match' ); + $this->assertEquals( $decodedExample->data, $decryptedExample->data, + 'Expected unencrypted and decrypted message\'s contents to match' ); $decodedExample->setCipherParams( $cipherParams ); $encryptedJSON = json_decode( $decodedExample->toJSON() ); - $this->assertEquals( $example->encrypted->data, $encryptedJSON->data, 'Expected encrypted and example encrypted message\'s contents to match' ); + $this->assertEquals( $example->encrypted->data, $encryptedJSON->data, + 'Expected encrypted and example encrypted message\'s contents to match' ); + } + } + + /** + * Tests PresenceMessage:fromEncodedArray + * + * @dataProvider filenameProvider + */ + public function testPresenceMessageFromEncodedArray( $filename ) { + $fixture = json_decode( file_get_contents( $filename ) ); + + $cipherParams = Crypto::getDefaultParams([ + 'key' => $fixture->key, + 'algorithm' => $fixture->algorithm, + 'keyLength' => $fixture->keylength, + 'mode' => $fixture->mode, + 'iv' => $fixture->iv, + 'base64Key' => true, + 'base64Iv' => true, + ]); + + $encrypted = array_map( function ( $x ) { return $x->encrypted ; }, $fixture->items ); + $encoded = array_map( function ( $x ) { return $x->encoded ; }, $fixture->items ); + + $encrypted = PresenceMessage::fromEncodedArray( $encrypted, $cipherParams ); + $encoded = PresenceMessage::fromEncodedArray( $encoded ); + + foreach ($encrypted as $i => $decryptedExample) { + $decodedExample = $encoded[$i]; + $this->assertEquals( $decodedExample->data, $decryptedExample->data, + 'Expected unencrypted and decrypted message\'s contents to match' ); } } @@ -180,4 +246,4 @@ public function filenameProvider() { [ __DIR__ . '/../ably-common/test-resources/crypto-data-256.json'], ]; } -} \ No newline at end of file +} diff --git a/tests/TypesTest.php b/tests/TypesTest.php index dea6045..4fc8b56 100644 --- a/tests/TypesTest.php +++ b/tests/TypesTest.php @@ -150,8 +150,9 @@ public function testClientOptionsType() { $co = new \Ably\Models\ClientOptions(); $this->assertEquals( 4000, $co->httpOpenTimeout ); - $this->assertEquals( 15000, $co->httpRequestTimeout ); + $this->assertEquals( 10000, $co->httpRequestTimeout ); $this->assertEquals( 3, $co->httpMaxRetryCount ); + $this->assertEquals( 15000, $co->httpMaxRetryDuration ); } public function testAuthOptionsType() { @@ -261,4 +262,4 @@ public function testHttpPaginatedResponseType() { 'headers', ] ); } -} \ No newline at end of file +}