diff --git a/composer.json b/composer.json index 227ca73e..6cf0763a 100644 --- a/composer.json +++ b/composer.json @@ -40,6 +40,8 @@ "phpunit/phpunit": "^8", "amphp/php-cs-fixer-config": "dev-master", "haydenpierce/class-finder": "^0.4", + "amphp/websocket-client": "dev-master as 1", + "amphp/websocket": "dev-master as 1", "ext-ctype": "*", "danog/7to70": "^1", "danog/7to5": "^1" @@ -62,6 +64,11 @@ "src/polyfill.php" ] }, + "autoload-dev": { + "psr-4": { + "danog\\MadelineProto\\Test\\": "tests/danog/" + } + }, "repositories": [{ "type": "git", "url": "https://github.com/danog/dns" @@ -80,6 +87,6 @@ "cs": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix -v --diff --dry-run", "cs-fix": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix -v --diff", "docs": "php tools/build_docs.php", - "test": "@php -dzend.assertions=1 -dassert.exception=1 ./vendor/bin/phpunit --coverage-text" + "test": "@php -dzend.assertions=1 -dassert.exception=1 ./vendor/bin/phpunit --coverage-text --config tests/phpunit.xml" } } diff --git a/src/danog/MadelineProto/Connection.php b/src/danog/MadelineProto/Connection.php index 5ec53e7e..1d73927e 100644 --- a/src/danog/MadelineProto/Connection.php +++ b/src/danog/MadelineProto/Connection.php @@ -466,7 +466,7 @@ class Connection extends Session * * @return void */ - public function setExtra(DataCenterConnection $extra, int $id) + public function setExtra($extra, int $id) { $this->shared = $extra; $this->id = $id; @@ -478,7 +478,7 @@ class Connection extends Session * * @return MTProto */ - public function getExtra(): MTProto + public function getExtra() { return $this->API; } diff --git a/src/danog/MadelineProto/DataCenterConnection.php b/src/danog/MadelineProto/DataCenterConnection.php index 9276f66b..2e1c915a 100644 --- a/src/danog/MadelineProto/DataCenterConnection.php +++ b/src/danog/MadelineProto/DataCenterConnection.php @@ -597,7 +597,7 @@ class DataCenterConnection implements JsonSerializable * * @return void */ - public function setExtra(MTProto $API) + public function setExtra($API) { $this->API = $API; } @@ -606,7 +606,7 @@ class DataCenterConnection implements JsonSerializable * * @return MTProto */ - public function getExtra(): MTProto + public function getExtra() { return $this->API; } diff --git a/src/danog/MadelineProto/MTProtoSession/CallHandler.php b/src/danog/MadelineProto/MTProtoSession/CallHandler.php index 6edb2f30..b91f987c 100644 --- a/src/danog/MadelineProto/MTProtoSession/CallHandler.php +++ b/src/danog/MadelineProto/MTProtoSession/CallHandler.php @@ -87,20 +87,21 @@ trait CallHandler public function methodCallAsyncRead(string $method, $args = [], array $aargs = ['msg_id' => null]): Promise { $deferred = new Deferred(); - $this->methodCallAsyncWrite($method, $args, $aargs)->onResolve(function ($e, $read_deferred) use ($deferred) { - if ($e) { - $deferred->fail($e); - } else { - if (\is_array($read_deferred)) { - $read_deferred = \array_map(function ($value) { - return $value->promise(); - }, $read_deferred); - $deferred->resolve(all($read_deferred)); + $this->methodCallAsyncWrite($method, $args, $aargs)->onResolve( + static function (\Throwable $e, $readDeferred) use ($deferred): void { + if ($e) { + $deferred->fail($e); } else { - $deferred->resolve($read_deferred->promise()); + if (\is_array($readDeferred)) { + $readDeferred = \array_map(fn (Deferred $value) => $value->promise(), $readDeferred); + $deferred->resolve(all($readDeferred)); + } else { + $readDeferred->promise()->onResolve(fn(\Throwable $e, $res) => var_dump($e, $res)); + $deferred->resolve($readDeferred->promise()); + } } } - }); + ); return $aargs['noResponse'] ?? false ? new Success() : $deferred->promise(); } /** diff --git a/src/danog/MadelineProto/Stream/MTProtoTransport/FullStream.php b/src/danog/MadelineProto/Stream/MTProtoTransport/FullStream.php index a92178d6..6aa2adee 100644 --- a/src/danog/MadelineProto/Stream/MTProtoTransport/FullStream.php +++ b/src/danog/MadelineProto/Stream/MTProtoTransport/FullStream.php @@ -46,9 +46,9 @@ class FullStream implements BufferedStreamInterface, MTProtoBufferInterface * * @param ConnectionContext $ctx * - * @return Promise + * @return \Generator */ - public function connect(ConnectionContext $ctx, string $header = ''): Promise + public function connect(ConnectionContext $ctx, string $header = ''): \Generator { $this->in_seq_no = -1; $this->out_seq_no = -1; diff --git a/src/danog/MadelineProto/Stream/Transport/WsStream.php b/src/danog/MadelineProto/Stream/Transport/WsStream.php index d22c6996..217c4ba9 100644 --- a/src/danog/MadelineProto/Stream/Transport/WsStream.php +++ b/src/danog/MadelineProto/Stream/Transport/WsStream.php @@ -64,7 +64,7 @@ class WsStream implements RawStreamInterface, ProxyStreamInterface */ public function connect(ConnectionContext $ctx, string $header = ''): \Generator { - if (!\class_exists(Connector::class)) { + if (!\class_exists(Handshake::class)) { throw new \danog\MadelineProto\Exception('Please install amphp/websocket-client by running "composer require amphp/websocket-client:dev-master"'); } $this->dc = $ctx->getIntDc(); diff --git a/src/danog/MadelineProto/TL/Conversion/BotAPIFiles.php b/src/danog/MadelineProto/TL/Conversion/BotAPIFiles.php index 3c058625..1de8a07f 100644 --- a/src/danog/MadelineProto/TL/Conversion/BotAPIFiles.php +++ b/src/danog/MadelineProto/TL/Conversion/BotAPIFiles.php @@ -111,7 +111,7 @@ trait BotAPIFiles return $res; case THUMBNAIL: $res['InputFileLocation'] = [ - '_' => $photoSize->getThumbFileType() <= PHOTO ? 'inputPhotoFileLocation' : 'inputDocumentFileLocation', + '_' => $photoSize->getThumbFileType() <= PHOTO ? 'inputDocumentFileLocation' : 'inputPhotoFileLocation', 'id' => $fileId->getId(), 'access_hash' => $fileId->getAccessHash(), 'file_reference' => $fileId->getFileReference(), @@ -204,7 +204,7 @@ trait BotAPIFiles 'file_reference' => $fileId->getFileReference(), 'dc_id' => $fileId->getDcId(), 'mime_type' => '', - 'attributes' => [$attribute] + 'attributes' => $attribute ? [$attribute] : [] ]; $res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => '']; return $res; diff --git a/tests/danog/MadelineProto/API.php b/tests/danog/MadelineProto/API.php deleted file mode 100644 index 1f1fb330..00000000 --- a/tests/danog/MadelineProto/API.php +++ /dev/null @@ -1,59 +0,0 @@ - \random_int(PHP_INT_MIN, PHP_INT_MAX)]; - $MadelineProto = new \danog\MadelineProto\API( - [ - 'app_info' => [ - 'api_id' => 25628, - 'api_hash' => '1fe17cda7d355166cdaa71f04122873c', - ], - 'connection_settings' => [ - 'all' => [ - 'ipv6' => $ipv6, - 'test_mode' => $test_mode, - 'protocol' => $protocol, - 'obfuscated' => $obfuscated, - 'transport' => $transport, - ], - ], - ] - ); - $pong = $MadelineProto->ping($ping); - $this->assertContainsEquals('_', $pong, 'pong'); - $this->assertContainsEquals('ping_id', $pong, $ping['ping_id']); - } - - public function protocolProvider(): \Generator - { - foreach ([false, true] as $test_mode) { - foreach ([false, true] as $ipv6) { - foreach (['tcp', 'ws', 'wss'] as $transport) { - foreach ([true, false] as $obfuscated) { - if ($transport !== 'tcp' && !$obfuscated) { - continue; - } - foreach (['tcp_abridged', 'tcp_intermediate', 'tcp_intermediate_padded', 'tcp_full'] as $protocol) { - if ($protocol === 'tcp_full' && $obfuscated) { - continue; - } - yield [$transport, $obfuscated, $protocol, $test_mode, $ipv6]; - } - } - } - yield ['tcp', false, 'http', $test_mode, $ipv6]; - yield ['tcp', false, 'https', $test_mode, $ipv6]; - } - } - } -} diff --git a/tests/danog/MadelineProto/DataCenterTest.php b/tests/danog/MadelineProto/DataCenterTest.php new file mode 100644 index 00000000..39c9d731 --- /dev/null +++ b/tests/danog/MadelineProto/DataCenterTest.php @@ -0,0 +1,94 @@ + [ + 'all' => [ + 'ipv6' => $ipv6, + 'test_mode' => $test_mode, + 'protocol' => $protocol, + 'obfuscated' => $obfuscated, + 'transport' => $transport + ], + ] + ] + ); + $datacenter = new DataCenter( + new class($settings) { + /** + * Constructor. + * + * @param array $settings Logger settings + */ + public function __construct(array $settings) + { + $this->logger = Logger::getLoggerFromSettings($settings); + $this->settings = $settings; + } + /** + * Get logger. + * + * @return Logger + */ + public function getLogger(): Logger + { + return $this->logger; + } + }, + $settings['connection'], + $settings['connection_settings'], + ); + + Tools::wait($datacenter->dcConnect(2)); + $this->assertTrue(true); + } + + public function protocolProvider(): \Generator + { + foreach ([false, true] as $test_mode) { + foreach ([false, true] as $ipv6) { + foreach (['tcp', 'ws', 'wss'] as $transport) { + foreach ([true, false] as $obfuscated) { + if ($transport !== 'tcp' && !$obfuscated) { + continue; + } + foreach (['abridged', 'intermediate', 'intermediate_padded', 'full'] as $protocol) { + if ($protocol === 'full' && $obfuscated) { + continue; + } + yield [$transport, $obfuscated, $protocol, $test_mode, $ipv6]; + } + } + } + yield ['tcp', false, 'http', $test_mode, $ipv6]; + yield ['tcp', false, 'https', $test_mode, $ipv6]; + } + } + } +} diff --git a/tests/danog/MadelineProto/FileIdTest.php b/tests/danog/MadelineProto/FileIdTest.php new file mode 100644 index 00000000..2888a5c6 --- /dev/null +++ b/tests/danog/MadelineProto/FileIdTest.php @@ -0,0 +1,140 @@ + [ + 'api_id' => \getenv('API_ID'), + 'api_hash' => \getenv('API_HASH'), + ], + 'logger' => [ + 'logger' => Logger::ECHO_LOGGER, + 'logger_level' => Logger::ULTRA_VERBOSE + ] + ] + ); + self::$MadelineProto->botLogin(\getenv('BOT_TOKEN')); + } + + /** + * @param string $fileId File ID + * @param string $type Expected type + * + * @dataProvider provideFileIdsAndType + */ + public function testDownload(string $type, string $fileIdStr, string $uniqueFileIdStr) + { + self::$MadelineProto->downloadToFile($fileIdStr, '/dev/null'); + } + /** + * @param string $fileId File ID + * @param string $type Expected type + * + * @dataProvider provideFileIdsAndType + */ + public function testResend(string $type, string $fileIdStr, string $uniqueFileIdStr) + { + self::$MadelineProto->messages->sendMedia( + [ + 'peer' => \getenv('DEST'), + 'media' => $fileIdStr + ] + ); + } + + public function provideFileIdsAndType(): \Generator + { + $dest = \getenv('DEST'); + $token = \getenv('BOT_TOKEN'); + foreach ($this->provideChats() as $chat) { + $result = \json_decode(\file_get_contents("https://api.telegram.org/bot$token/getChat?chat_id=$chat"), true)['result']['photo']; + yield [ + 'profile_photo', + $result['small_file_id'], + $result['small_file_unique_id'], + ]; + yield [ + 'profile_photo', + $result['big_file_id'], + $result['big_file_unique_id'], + ]; + } + foreach ($this->provideUrls() as $type => $url) { + if ($type === 'video_note') { + \copy($url, \basename($url)); + + $handle = \curl_init("https://api.telegram.org/bot$token/sendVideoNote?chat_id=$dest"); + \curl_setopt($handle, CURLOPT_POST, true); + \curl_setopt($handle, CURLOPT_POSTFIELDS, [ + $type => new CURLFile(\basename($url)) + ]); + \curl_setopt($handle, CURLOPT_RETURNTRANSFER, true); + $botResult = \json_decode(\curl_exec($handle), true); + \curl_close($handle); + + \unlink(\basename($url)); + } else { + $botResult = \json_decode(\file_get_contents("https://api.telegram.org/bot$token/send$type?chat_id=$dest&$type=$url"), true); + } + $botResult = $botResult['result'][$type]; + if ($type !== 'photo') { + $botResult = [$botResult]; + } + foreach ($botResult as $subResult) { + yield [ + $type, + $subResult['file_id'], + $subResult['file_unique_id'] + ]; + if (isset($subResult['thumb'])) { + yield [ + 'thumbnail', + $subResult['thumb']['file_id'], + $subResult['thumb']['file_unique_id'] + ]; + } + } + } + return $result; + } + public function provideChats(): array + { + return [\getenv('DEST'), '@MadelineProto']; + } + public function provideUrls(): array + { + return [ + 'sticker' => 'https://github.com/danog/MadelineProto/blob/master/tests/lel.webp?raw=true', + 'photo' => 'https://github.com/danog/MadelineProto/blob/master/tests/faust.jpg', + 'audio' => 'https://github.com/danog/MadelineProto/blob/master/tests/mosconi.mp3?raw=true', + 'video' => 'https://github.com/danog/MadelineProto/blob/master/tests/swing.mp4?raw=true', + 'animation' => 'https://github.com/danog/MadelineProto/blob/master/tests/pony.mp4?raw=true', + 'document' => 'https://github.com/danog/danog.github.io/raw/master/lol/index_htm_files/0.gif', + 'voice' => 'https://daniil.it/audio_2020-02-01_18-09-08.ogg', + //'video_note' => 'https://daniil.it/round.mp4' + ]; + } +} diff --git a/tests/phpunit.xml b/tests/phpunit.xml index a7acb4db..88cb5382 100644 --- a/tests/phpunit.xml +++ b/tests/phpunit.xml @@ -1,7 +1,20 @@ - - - - - - + + + + ../tests + + +