diff --git a/.phan/config.php b/.phan/config.php deleted file mode 100644 index 423347d7..00000000 --- a/.phan/config.php +++ /dev/null @@ -1,356 +0,0 @@ -=7.4.0" - 'target_php_version' => '7.4', - - // If enabled, missing properties will be created when - // they are first seen. If false, we'll report an - // error message if there is an attempt to write - // to a class property that wasn't explicitly - // defined. - 'allow_missing_properties' => false, - - // If enabled, null can be cast to any type and any - // type can be cast to null. Setting this to true - // will cut down on false positives. - 'null_casts_as_any_type' => false, - - // If enabled, allow null to be cast as any array-like type. - // - // This is an incremental step in migrating away from `null_casts_as_any_type`. - // If `null_casts_as_any_type` is true, this has no effect. - 'null_casts_as_array' => true, - - // If enabled, allow any array-like type to be cast to null. - // This is an incremental step in migrating away from `null_casts_as_any_type`. - // If `null_casts_as_any_type` is true, this has no effect. - 'array_casts_as_null' => true, - - // If enabled, scalars (int, float, bool, string, null) - // are treated as if they can cast to each other. - // This does not affect checks of array keys. See `scalar_array_key_cast`. - 'scalar_implicit_cast' => false, - - // If enabled, any scalar array keys (int, string) - // are treated as if they can cast to each other. - // E.g. `array` can cast to `array` and vice versa. - // Normally, a scalar type such as int could only cast to/from int and mixed. - 'scalar_array_key_cast' => true, - - // If this has entries, scalars (int, float, bool, string, null) - // are allowed to perform the casts listed. - // - // E.g. `['int' => ['float', 'string'], 'float' => ['int'], 'string' => ['int'], 'null' => ['string']]` - // allows casting null to a string, but not vice versa. - // (subset of `scalar_implicit_cast`) - 'scalar_implicit_partial' => [], - - // If enabled, Phan will warn if **any** type in a method invocation's object - // is definitely not an object, - // or if **any** type in an invoked expression is not a callable. - // Setting this to true will introduce numerous false positives - // (and reveal some bugs). - 'strict_method_checking' => false, - - // If enabled, Phan will warn if **any** type of the object expression for a property access - // does not contain that property. - 'strict_object_checking' => false, - - // If enabled, Phan will warn if **any** type in the argument's union type - // cannot be cast to a type in the parameter's expected union type. - // Setting this to true will introduce numerous false positives - // (and reveal some bugs). - 'strict_param_checking' => false, - - // If enabled, Phan will warn if **any** type in a property assignment's union type - // cannot be cast to a type in the property's declared union type. - // Setting this to true will introduce numerous false positives - // (and reveal some bugs). - 'strict_property_checking' => false, - - // If enabled, Phan will warn if **any** type in a returned value's union type - // cannot be cast to the declared return type. - // Setting this to true will introduce numerous false positives - // (and reveal some bugs). - 'strict_return_checking' => false, - - // If true, seemingly undeclared variables in the global - // scope will be ignored. - // - // This is useful for projects with complicated cross-file - // globals that you have no hope of fixing. - 'ignore_undeclared_variables_in_global_scope' => true, - - // Set this to false to emit `PhanUndeclaredFunction` issues for internal functions that Phan has signatures for, - // but aren't available in the codebase, or from Reflection. - // (may lead to false positives if an extension isn't loaded) - // - // If this is true(default), then Phan will not warn. - // - // Even when this is false, Phan will still infer return values and check parameters of internal functions - // if Phan has the signatures. - 'ignore_undeclared_functions_with_known_signatures' => true, - - // Backwards Compatibility Checking. This is slow - // and expensive, but you should consider running - // it before upgrading your version of PHP to a - // new version that has backward compatibility - // breaks. - // - // If you are migrating from PHP 5 to PHP 7, - // you should also look into using - // [php7cc (no longer maintained)](https://github.com/sstalle/php7cc) - // and [php7mar](https://github.com/Alexia/php7mar), - // which have different backwards compatibility checks. - 'backward_compatibility_checks' => false, - - // If true, check to make sure the return type declared - // in the doc-block (if any) matches the return type - // declared in the method signature. - 'check_docblock_signature_return_type_match' => false, - - // This setting maps case-insensitive strings to union types. - // - // This is useful if a project uses phpdoc that differs from the phpdoc2 standard. - // - // If the corresponding value is the empty string, - // then Phan will ignore that union type (E.g. can ignore 'the' in `@return the value`) - // - // If the corresponding value is not empty, - // then Phan will act as though it saw the corresponding UnionTypes(s) - // when the keys show up in a UnionType of `@param`, `@return`, `@var`, `@property`, etc. - // - // This matches the **entire string**, not parts of the string. - // (E.g. `@return the|null` will still look for a class with the name `the`, but `@return the` will be ignored with the below setting) - // - // (These are not aliases, this setting is ignored outside of doc comments). - // (Phan does not check if classes with these names exist) - // - // Example setting: `['unknown' => '', 'number' => 'int|float', 'char' => 'string', 'long' => 'int', 'the' => '']` - 'phpdoc_type_mapping' => [], - - // Set to true in order to attempt to detect dead - // (unreferenced) code. Keep in mind that the - // results will only be a guess given that classes, - // properties, constants and methods can be referenced - // as variables (like `$class->$property` or - // `$class->$method()`) in ways that we're unable - // to make sense of. - 'dead_code_detection' => false, - - // Set to true in order to attempt to detect unused variables. - // `dead_code_detection` will also enable unused variable detection. - // - // This has a few known false positives, e.g. for loops or branches. - 'unused_variable_detection' => false, - - // Set to true in order to attempt to detect redundant and impossible conditions. - // - // This has some false positives involving loops, - // variables set in branches of loops, and global variables. - 'redundant_condition_detection' => false, - - // If enabled, Phan will act as though it's certain of real return types of a subset of internal functions, - // even if those return types aren't available in reflection (real types were taken from php 7.3 or 8.0-dev, depending on target_php_version). - // - // Note that with php 7 and earlier, php would return null or false for many internal functions if the argument types or counts were incorrect. - // As a result, enabling this setting with target_php_version 8.0 may result in false positives for `--redundant-condition-detection` when codebases also support php 7.x. - 'assume_real_types_for_internal_functions' => false, - - // If true, this runs a quick version of checks that takes less - // time at the cost of not running as thorough - // of an analysis. You should consider setting this - // to true only when you wish you had more **undiagnosed** issues - // to fix in your code base. - // - // In quick-mode the scanner doesn't rescan a function - // or a method's code block every time a call is seen. - // This means that the problem here won't be detected: - // - // ```php - // false, - - // Override to hardcode existence and types of (non-builtin) globals in the global scope. - // Class names should be prefixed with `\`. - // - // (E.g. `['_FOO' => '\FooClass', 'page' => '\PageClass', 'userId' => 'int']`) - 'globals_type_map' => [], - - // The minimum severity level to report on. This can be - // set to `Issue::SEVERITY_LOW`, `Issue::SEVERITY_NORMAL` or - // `Issue::SEVERITY_CRITICAL`. Setting it to only - // critical issues is a good place to start on a big - // sloppy mature code base. - 'minimum_severity' => Issue::SEVERITY_LOW, - - // Add any issue types (such as `'PhanUndeclaredMethod'`) - // to this black-list to inhibit them from being reported. - 'suppress_issue_types' => [], - - // A regular expression to match files to be excluded - // from parsing and analysis and will not be read at all. - // - // This is useful for excluding groups of test or example - // directories/files, unanalyzable files, or files that - // can't be removed for whatever reason. - // (e.g. `'@Test\.php$@'`, or `'@vendor/.*/(tests|Tests)/@'`) - 'exclude_file_regex' => '@^vendor/.*/(tests?|Tests?)/@', - - // A list of files that will be excluded from parsing and analysis - // and will not be read at all. - // - // This is useful for excluding hopelessly unanalyzable - // files that can't be removed for whatever reason. - 'exclude_file_list' => [], - - // A directory list that defines files that will be excluded - // from static analysis, but whose class and method - // information should be included. - // - // Generally, you'll want to include the directories for - // third-party code (such as "vendor/") in this list. - // - // n.b.: If you'd like to parse but not analyze 3rd - // party code, directories containing that code - // should be added to the `directory_list` as well as - // to `exclude_analysis_directory_list`. - 'exclude_analysis_directory_list' => [ - 'vendor/', - ], - - // Enable this to enable checks of require/include statements referring to valid paths. - // The settings `include_paths` and `warn_about_relative_include_statement` affect the checks. - 'enable_include_path_checks' => true, - - // The number of processes to fork off during the analysis - // phase. - 'processes' => 1, - - // List of case-insensitive file extensions supported by Phan. - // (e.g. `['php', 'html', 'htm']`) - 'analyzed_file_extensions' => [ - 'php', - ], - - // You can put paths to stubs of internal extensions in this config option. - // If the corresponding extension is **not** loaded, then Phan will use the stubs instead. - // Phan will continue using its detailed type annotations, - // but load the constants, classes, functions, and classes (and their Reflection types) - // from these stub files (doubling as valid php files). - // Use a different extension from php to avoid accidentally loading these. - // The `tools/make_stubs` script can be used to generate your own stubs (compatible with php 7.0+ right now) - // - // (e.g. `['xdebug' => '.phan/internal_stubs/xdebug.phan_php']`) - 'autoload_internal_extension_signatures' => [], - - // A list of plugin files to execute. - // - // Plugins which are bundled with Phan can be added here by providing their name (e.g. `'AlwaysReturnPlugin'`) - // - // Documentation about available bundled plugins can be found [here](https://github.com/phan/phan/tree/master/.phan/plugins). - // - // Alternately, you can pass in the full path to a PHP file with the plugin's implementation (e.g. `'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php'`) - 'plugins' => [ - 'AlwaysReturnPlugin', - 'PregRegexCheckerPlugin', - 'UnreachableCodePlugin', - ], - - // A list of directories that should be parsed for class and - // method information. After excluding the directories - // defined in `exclude_analysis_directory_list`, the remaining - // files will be statically analyzed for errors. - // - // Thus, both first-party and third-party code being used by - // your application should be included in this list. - 'directory_list' => [ - 'src/danog/MadelineProto', - 'vendor/amphp/amp/lib', - 'vendor/amphp/byte-stream/lib', - 'vendor/amphp/dns/lib', - 'vendor/amphp/file/src', - 'vendor/amphp/http-client-cookies/src', - 'vendor/amphp/http-client/src', - 'vendor/amphp/http-server/src', - 'vendor/amphp/http/src', - 'vendor/amphp/php-cs-fixer-config/src', - 'vendor/amphp/socket/src', - 'vendor/amphp/websocket-client/src', - 'vendor/amphp/websocket/src', - 'vendor/danog/7to5/src', - 'vendor/danog/7to70/src', - 'vendor/danog/dns-over-https/lib', - 'vendor/danog/ipc/lib', - 'vendor/danog/magicalserializer/src', - 'vendor/danog/primemodule/lib', - 'vendor/danog/tg-file-decoder/src', - 'vendor/danog/tgseclib/phpseclib', - 'vendor/erusev/parsedown', - 'vendor/league/uri/src' - ], - - // A list of individual files to include in analysis - // with a path relative to the root directory of the - // project. - 'file_list' => [], -]; diff --git a/src/danog/MadelineProto/Loop/Connection/ReadLoop.php b/src/danog/MadelineProto/Loop/Connection/ReadLoop.php index e03eddd9..dc1ccea7 100644 --- a/src/danog/MadelineProto/Loop/Connection/ReadLoop.php +++ b/src/danog/MadelineProto/Loop/Connection/ReadLoop.php @@ -196,7 +196,7 @@ class ReadLoop extends SignalLoop $API->logger->logger('Got unknown auth_key id', Logger::ERROR); return -404; } - $deserialized = $API->getTL()->deserialize($message_data, ['type' => '', 'connection' => $connection]); + $deserialized = yield from $API->getTL()->deserialize($message_data, ['type' => '', 'connection' => $connection]); if (isset($API->referenceDatabase)) { $API->referenceDatabase->reset(); } diff --git a/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php b/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php index cb8ce96f..08c32b0b 100644 --- a/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php @@ -237,7 +237,7 @@ trait AuthKeyHandler * int $server_time * ] */ - $server_DH_inner_data = $this->TL->deserialize($answer, ['type' => '']); + $server_DH_inner_data = yield from $this->TL->deserialize($answer, ['type' => '']); /* * *********************************************************************** * Do some checks diff --git a/src/danog/MadelineProto/SecretChats/MessageHandler.php b/src/danog/MadelineProto/SecretChats/MessageHandler.php index 8224316b..e39b1037 100644 --- a/src/danog/MadelineProto/SecretChats/MessageHandler.php +++ b/src/danog/MadelineProto/SecretChats/MessageHandler.php @@ -115,7 +115,7 @@ trait MessageHandler $this->secret_chats[$message['message']['chat_id']]['mtproto'] = 2; } } - $deserialized = $this->TL->deserialize($message_data, ['type' => '']); + $deserialized = yield from $this->TL->deserialize($message_data, ['type' => '']); $this->secret_chats[$message['message']['chat_id']]['ttr']--; if (($this->secret_chats[$message['message']['chat_id']]['ttr'] <= 0 || \time() - $this->secret_chats[$message['message']['chat_id']]['updated'] > 7 * 24 * 60 * 60) && $this->secret_chats[$message['message']['chat_id']]['rekeying'][0] === 0) { yield from $this->rekey($message['message']['chat_id']); diff --git a/src/danog/MadelineProto/TL/TL.php b/src/danog/MadelineProto/TL/TL.php index cf0edc03..186f6141 100644 --- a/src/danog/MadelineProto/TL/TL.php +++ b/src/danog/MadelineProto/TL/TL.php @@ -19,6 +19,7 @@ namespace danog\MadelineProto\TL; +use Amp\Promise; use danog\MadelineProto\MTProto; use danog\MadelineProto\Tools; @@ -788,7 +789,8 @@ class TL } elseif (!\is_resource($stream)) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['stream_handle_invalid']); } - $this->deserialize($stream, $type); + $promises = []; + $this->deserializeInternal($stream, $promises, $type); return \ftell($stream); } /** @@ -797,9 +799,28 @@ class TL * @param string|resource $stream Stream * @param array $type Type identifier * + * @return \Generator + */ + public function deserialize($stream, $type = ['type' => '']): \Generator + { + $promises = []; + $result = $this->deserializeInternal($stream, $promises, $type); + if ($promises) { + yield $promises; + } + return $result; + } + + /** + * Deserialize TL object. + * + * @param string|resource $stream Stream + * @param Promise[] &$promises Promise array + * @param array $type Type identifier + * * @return mixed */ - public function deserialize($stream, $type = ['type' => '']) + private function deserializeInternal($stream, array &$promises, array $type) { if (\is_string($stream)) { $res = \fopen('php://memory', 'rw+b'); @@ -865,7 +886,17 @@ class TL } switch ($constructorData['predicate']) { case 'gzip_packed': - return $this->deserialize(\gzdecode($this->deserialize($stream, ['type' => 'bytes', 'connection' => $type['connection']])), ['type' => '', 'connection' => $type['connection']]); + return $this->deserializeInternal( + \gzdecode( + $this->deserializeInternal( + $stream, + $promises, + ['type' => 'bytes', 'connection' => $type['connection']] + ) + ), + $promises, + ['type' => '', 'connection' => $type['connection']] + ); case 'Vector t': case 'vector': break; @@ -878,7 +909,7 @@ class TL $result = []; $type['type'] = $type['subtype']; for ($i = 0; $i < $count; $i++) { - $result[] = $this->deserialize($stream, $type); + $result[] = $this->deserializeInternal($stream, $promises, $type); } return $result; } @@ -907,13 +938,23 @@ class TL if (!isset($type['subtype'])) { $type['subtype'] = ''; } - return $this->deserialize(\gzdecode($this->deserialize($stream, ['type' => 'bytes'])), ['type' => '', 'connection' => $type['connection'], 'subtype' => $type['subtype']]); + return $this->deserializeInternal( + \gzdecode( + $this->deserializeInternal( + $stream, + $promises, + ['type' => 'bytes'] + ) + ), + $promises, + ['type' => '', 'connection' => $type['connection'], 'subtype' => $type['subtype']] + ); } if ($constructorData['type'] === 'Vector t') { $constructorData['connection'] = $type['connection']; $constructorData['subtype'] = $type['subtype'] ?? ''; $constructorData['type'] = 'vector'; - return $this->deserialize($stream, $constructorData); + return $this->deserializeInternal($stream, $promises, $constructorData); } if ($constructorData['predicate'] === 'boolTrue') { return true; @@ -968,7 +1009,7 @@ class TL if (isset($type['connection'])) { $arg['connection'] = $type['connection']; } - $x[$arg['name']] = $this->deserialize($stream, $arg); + $x[$arg['name']] = $this->deserializeInternal($stream, $promises, $arg); if ($arg['name'] === 'random_bytes') { if (\strlen($x[$arg['name']]) < 15) { throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['rand_bytes_too_small']); @@ -1000,7 +1041,10 @@ class TL } if (isset($this->callbacks[TLCallback::CONSTRUCTOR_CALLBACK][$x['_']])) { foreach ($this->callbacks[TLCallback::CONSTRUCTOR_CALLBACK][$x['_']] as $callback) { - \danog\MadelineProto\Tools::callFork($callback($x)); + $promise = \danog\MadelineProto\Tools::callFork($callback($x)); + if ($promise instanceof Promise) { + $promises []= $promise; + } } } elseif ($x['_'] === 'rpc_result' && isset($type['connection']->outgoing_messages[$x['req_msg_id']]['_']) && isset($this->callbacks[TLCallback::METHOD_CALLBACK][$type['connection']->outgoing_messages[$x['req_msg_id']]['_']])) { foreach ($this->callbacks[TLCallback::METHOD_CALLBACK][$type['connection']->outgoing_messages[$x['req_msg_id']]['_']] as $callback) { diff --git a/src/danog/MadelineProto/TON/ADNLConnection.php b/src/danog/MadelineProto/TON/ADNLConnection.php index 94134e89..e234e0b5 100644 --- a/src/danog/MadelineProto/TON/ADNLConnection.php +++ b/src/danog/MadelineProto/TON/ADNLConnection.php @@ -132,11 +132,11 @@ class ADNLConnection $buffer = yield $this->stream->getReadBuffer($length); if ($length) { $data = yield $buffer->bufferRead($length); - $data = $this->TL->deserialize($data); + $data = yield from $this->TL->deserialize($data); if ($data['_'] !== 'adnl.message.answer') { throw new Exception('Wrong answer type: '.$data['_']); } - $this->requests[$data['query_id']]->resolve($this->TL->deserialize((string) $data['answer'])); + $this->requests[$data['query_id']]->resolve(yield from $this->TL->deserialize((string) $data['answer'])); } } })()); diff --git a/src/danog/MadelineProto/TON/Lite.php b/src/danog/MadelineProto/TON/Lite.php index f7550bf8..09b7c792 100644 --- a/src/danog/MadelineProto/TON/Lite.php +++ b/src/danog/MadelineProto/TON/Lite.php @@ -84,7 +84,7 @@ class Lite $config['_'] = 'liteclient.config.global'; $config = Tools::convertJsonTL($config); $config['validator']['init_block'] = $config['validator']['init_block'] ?? $config['validator']['zero_state']; - $this->config = $this->TL->deserialize(yield from $this->TL->serializeObject(['type' => ''], $config, 'cleanup')); + $this->config = yield from $this->TL->deserialize(yield from $this->TL->serializeObject(['type' => ''], $config, 'cleanup')); foreach ($this->config['liteservers'] as $lite) { $this->connections[] = $connection = new ADNLConnection($this->TL); yield from $connection->connect($lite);