diff --git a/composer.json b/composer.json index 82134254..4d105a3e 100644 --- a/composer.json +++ b/composer.json @@ -66,12 +66,17 @@ } ], "scripts": { + "build": [ + "@docs", + "@cs-fix" + ], "check": [ "@cs", "@test" ], "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" } } diff --git a/src/danog/MadelineProto/DocsBuilder/Constructors.php b/src/danog/MadelineProto/DocsBuilder/Constructors.php index 25d9f4b2..2b3bf675 100644 --- a/src/danog/MadelineProto/DocsBuilder/Constructors.php +++ b/src/danog/MadelineProto/DocsBuilder/Constructors.php @@ -19,6 +19,8 @@ namespace danog\MadelineProto\DocsBuilder; +use danog\MadelineProto\Tools; + trait Constructors { public function mkConstructors() @@ -64,7 +66,7 @@ trait Constructors $param['type'] = 'DecryptedMessage'; } $type_or_subtype = isset($param['subtype']) ? 'subtype' : 'type'; - $type_or_bare_type = \ctype_upper($this->end(\explode('.', $param[$type_or_subtype]))[0]) || \in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int53', 'int', 'long', 'int128', 'int256', 'int512']) ? 'types' : 'constructors'; + $type_or_bare_type = \ctype_upper(Tools::end(\explode('.', $param[$type_or_subtype]))[0]) || \in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int53', 'int', 'long', 'int128', 'int256', 'int512']) ? 'types' : 'constructors'; $param[$type_or_subtype] = \str_replace(['.', 'true', 'false'], ['_', 'Bool', 'Bool'], $param[$type_or_subtype]); if (\preg_match('/%/', $param[$type_or_subtype])) { $param[$type_or_subtype] = $this->constructors->findByType(\str_replace('%', '', $param[$type_or_subtype]))['predicate']; @@ -73,7 +75,7 @@ trait Constructors $param[$type_or_subtype] = \substr($param[$type_or_subtype], 0, -1); } $params .= "'".$param['name']."' => "; - $param[$type_or_subtype] = '['.$this->escape($param[$type_or_subtype]).'](../'.$type_or_bare_type.'/'.$param[$type_or_subtype].'.md)'; + $param[$type_or_subtype] = '['.Tools::markdownEscape($param[$type_or_subtype]).'](../'.$type_or_bare_type.'/'.$param[$type_or_subtype].'.md)'; $params .= (isset($param['subtype']) ? '\\['.$param[$type_or_subtype].'\\]' : $param[$type_or_subtype]).', '; } $md_constructor = \str_replace('_', '\\_', $constructor.$layer); @@ -126,7 +128,7 @@ trait Constructors if (\preg_match('/%/', $ptype)) { $ptype = $this->constructors->findByType(\str_replace('%', '', $ptype))['predicate']; } - $type_or_bare_type = (\ctype_upper($this->end(\explode('_', $ptype))[0]) || \in_array($ptype, ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int53', 'int', 'long', 'int128', 'int256', 'int512'])) && $ptype !== 'MTmessage' ? 'types' : 'constructors'; + $type_or_bare_type = (\ctype_upper(Tools::end(\explode('_', $ptype))[0]) || \in_array($ptype, ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int53', 'int', 'long', 'int128', 'int256', 'int512'])) && $ptype !== 'MTmessage' ? 'types' : 'constructors'; if (\substr($ptype, -1) === '>') { $ptype = \substr($ptype, 0, -1); } diff --git a/src/danog/MadelineProto/DocsBuilder/Methods.php b/src/danog/MadelineProto/DocsBuilder/Methods.php index 54078000..4dac7360 100644 --- a/src/danog/MadelineProto/DocsBuilder/Methods.php +++ b/src/danog/MadelineProto/DocsBuilder/Methods.php @@ -19,6 +19,8 @@ namespace danog\MadelineProto\DocsBuilder; +use danog\MadelineProto\Tools; + trait Methods { public function mkMethods() @@ -76,9 +78,9 @@ trait Methods $param['type'] = 'InputPeer'; } $type_or_subtype = isset($param['subtype']) ? 'subtype' : 'type'; - $type_or_bare_type = \ctype_upper($this->end(\explode('.', $param[$type_or_subtype]))[0]) || \in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int', 'long', 'int128', 'int256', 'int512', 'int53']) ? 'types' : 'constructors'; + $type_or_bare_type = \ctype_upper(Tools::end(\explode('.', $param[$type_or_subtype]))[0]) || \in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int', 'long', 'int128', 'int256', 'int512', 'int53']) ? 'types' : 'constructors'; $param[$type_or_subtype] = \str_replace(['true', 'false'], ['Bool', 'Bool'], $param[$type_or_subtype]); - $param[$type_or_subtype] = '['.$this->escape($param[$type_or_subtype]).'](../'.$type_or_bare_type.'/'.$param[$type_or_subtype].'.md)'; + $param[$type_or_subtype] = '['.Tools::markdownEscape($param[$type_or_subtype]).'](../'.$type_or_bare_type.'/'.$param[$type_or_subtype].'.md)'; $params .= "'".$param['name']."' => ".(isset($param['subtype']) ? '\\['.$param[$type_or_subtype].'\\]' : $param[$type_or_subtype]).', '; } if (!isset($this->td_descriptions['methods'][$data['method']])) { @@ -159,7 +161,7 @@ trait Methods if (\in_array($ptype, ['InputEncryptedFile']) && !isset($this->settings['td'])) { $human_ptype = 'File path or '.$ptype; } - $type_or_bare_type = \ctype_upper($this->end(\explode('.', $param[$type_or_subtype]))[0]) || \in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int', 'long', 'int128', 'int256', 'int512', 'int53']) ? 'types' : 'constructors'; + $type_or_bare_type = \ctype_upper(Tools::end(\explode('.', $param[$type_or_subtype]))[0]) || \in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int', 'long', 'int128', 'int256', 'int512', 'int53']) ? 'types' : 'constructors'; if (!isset($this->td_descriptions['methods'][$data['method']]['params'][$param['name']])) { $this->addToLang('method_'.$data['method'].'_param_'.$param['name'].'_type_'.$param['type']); if (isset($this->td_descriptions['methods'][$data['method']]['description'])) { diff --git a/src/danog/MadelineProto/EventHandler.php b/src/danog/MadelineProto/EventHandler.php index 6f153ff7..8c478f0f 100644 --- a/src/danog/MadelineProto/EventHandler.php +++ b/src/danog/MadelineProto/EventHandler.php @@ -19,9 +19,17 @@ namespace danog\MadelineProto; +/** + * Event handler + */ class EventHandler extends InternalDoc { - public function __construct($MadelineProto) + /** + * Constructor + * + * @param API|null $MadelineProto MadelineProto instance + */ + public function __construct(?API $MadelineProto) { if (!$MadelineProto) { return; diff --git a/src/danog/MadelineProto/InternalDoc.php b/src/danog/MadelineProto/InternalDoc.php index 7375addf..e60e275d 100644 --- a/src/danog/MadelineProto/InternalDoc.php +++ b/src/danog/MadelineProto/InternalDoc.php @@ -4018,40 +4018,57 @@ interface folders class InternalDoc extends APIFactory { - public function logger($param, $level = \danog\MadelineProto\Logger::NOTICE, $file = null, array $extra = []) + /** + * Cleanup memory and session file. + * + * @return void + */ + public function cleanup(array $extra = []) + { + return $this->__call(__FUNCTION__, [$extra]); + } + /** + * Logger. + * + * @param string $param Parameter + * @param int $level Logging level + * @param string $file File where the message originated + * + * @return void + */ + public function logger($param, int $level = \danog\MadelineProto\Logger::NOTICE, string $file = '', array $extra = []) { return $this->__call(__FUNCTION__, [$param, $level, $file, $extra]); } - - public function isAltervista(array $extra = []) + /** + * Get async HTTP client. + * + * @return \Amp\Artax\Client + */ + public function getHTTPClient(array $extra = []): Amp\Artax\Client { return $this->__call(__FUNCTION__, [$extra]); } - - public function isInitingAuthorization(array $extra = []) + /** + * Get async DNS client. + * + * @return \Amp\Dns\Resolver + */ + public function getDNSClient(array $extra = []): Amp\Dns\Resolver { return $this->__call(__FUNCTION__, [$extra]); } - - public function getHTTPClient(array $extra = []) - { - return $this->__call(__FUNCTION__, [$extra]); - } - - public function getDNSClient(array $extra = []) - { - return $this->__call(__FUNCTION__, [$extra]); - } - - public function fileGetContents($url, array $extra = []) + /** + * Get contents of remote file asynchronously. + * + * @param string $url URL + * + * @return \Generator + */ + public function fileGetContents(string $url, array $extra = []) { return $this->__call(__FUNCTION__, [$url, $extra]); } - - public function testing(callable $a, ?string $b = null, $c = null, $d = 2, $e = \danog\MadelineProto\MTProto::METHOD_BEFORE_CALLBACK, array $extra = []): ?string - { - return $this->__call(__FUNCTION__, [$a, $b, $c, $d, $e, $extra]); - } /** * Get all datacenter connections. * @@ -4062,32 +4079,39 @@ class InternalDoc extends APIFactory return $this->__call(__FUNCTION__, [$extra]); } - public function hasAllAuth(array $extra = []) + public function hasAllAuth(array $extra = []): bool { return $this->__call(__FUNCTION__, [$extra]); } - - public function startLoops(array $extra = []) - { - return $this->__call(__FUNCTION__, [$extra]); - } - - public function stopLoops(array $extra = []) - { - return $this->__call(__FUNCTION__, [$extra]); - } - - public function getSettings($settings, $previousSettings = [ - ], array $extra = []) + /** + * Get correct settings array for the latest version. + * + * @param array $settings Current settings array + * @param array $previousSettings Previous settings array + * + * @return array + */ + public function getSettings(array $settings, array $previousSettings = [ + ], array $extra = []): array { return $this->__call(__FUNCTION__, [$settings, $previousSettings, $extra]); } - - public function parseSettings($settings, array $extra = []) + /** + * Parse and store settings. + * + * @param array $settings Settings + * + * @return void + */ + public function parseSettings(array $settings, array $extra = []) { return $this->__call(__FUNCTION__, [$settings, $extra]); } - + /** + * Setup logger. + * + * @return void + */ public function setupLogger(array $extra = []) { return $this->__call(__FUNCTION__, [$extra]); @@ -4111,63 +4135,105 @@ class InternalDoc extends APIFactory * * @return boolean */ - public function isHttp(string $datacenter, array $extra = []) + public function isHttp(string $datacenter, array $extra = []): bool { return $this->__call(__FUNCTION__, [$datacenter, $extra]); } + public function isInitingAuthorization(array $extra = []) + { + return $this->__call(__FUNCTION__, [$extra]); + } + /** + * Connects to all datacenters and if necessary creates authorization keys, binds them and writes client info. + * + * @param boolean $reconnectAll Whether to reconnect to all DCs + * + * @return \Generator + */ public function connectToAllDcs(bool $reconnectAll = true, array $extra = []) { return $this->__call(__FUNCTION__, [$reconnectAll, $extra]); } - + /** + * Clean up MadelineProto session after logout. + * + * @return void + */ public function resetSession(array $extra = []) { return $this->__call(__FUNCTION__, [$extra]); } - + /** + * Reset the update state and fetch all updates from the beginning. + * + * @return void + */ public function resetUpdateState(array $extra = []) { return $this->__call(__FUNCTION__, [$extra]); } - + /** + * Start the update system. + * + * @param boolean $anyway Force start update system? + * + * @return void + */ public function startUpdateSystem($anyway = false, array $extra = []) { return $this->__call(__FUNCTION__, [$anyway, $extra]); } - + /** + * Store shared phone config. + * + * @param mixed $watcherId Watcher ID + * + * @return void + */ public function getPhoneConfig($watcherId = null, array $extra = []) { return $this->__call(__FUNCTION__, [$watcherId, $extra]); } - - public function getCdnConfig($datacenter, array $extra = []) + /** + * Store RSA keys for CDN datacenters. + * + * @param string $datacenter DC ID + * + * @return \Generator + */ + public function getCdnConfig(string $datacenter, array $extra = []) { return $this->__call(__FUNCTION__, [$datacenter, $extra]); } - - public function getCachedConfig(array $extra = []) + /** + * Get cached server-side config. + * + * @return array + */ + public function getCachedConfig(array $extra = []): array { return $this->__call(__FUNCTION__, [$extra]); } - - public function getConfig($config = [ - ], $options = [ + /** + * Get cached (or eventually re-fetch) server-side config. + * + * @param array $config Current config + * @param array $options Options for method call + * + * @return \Generator + */ + public function getConfig(array $config = [ + ], array $options = [ ], array $extra = []) { return $this->__call(__FUNCTION__, [$config, $options, $extra]); } - - public function parseConfig(array $extra = []) - { - return $this->__call(__FUNCTION__, [$extra]); - } - - public function parseDcOptions($dc_options, array $extra = []) - { - return $this->__call(__FUNCTION__, [$dc_options, $extra]); - } - + /** + * Get info about the logged-in user. + * + * @return \Generator + */ public function getSelf(array $extra = []) { return $this->__call(__FUNCTION__, [$extra]); @@ -4990,82 +5056,186 @@ class InternalDoc extends APIFactory { return $this->__call(__FUNCTION__, [$value, $extra]); } - - public function packSignedInt($value, array $extra = []) + /** + * Convert integer to base256 signed int. + * + * @param integer $value Value to convert + * + * @return string + */ + public function packSignedInt(int $value, array $extra = []): string { return $this->__call(__FUNCTION__, [$value, $extra]); } - - public function packSignedLong($value, array $extra = []) + /** + * Convert integer to base256 long. + * + * @param int $value Value to convert + * + * @return string + */ + public function packSignedLong(int $value, array $extra = []): string { return $this->__call(__FUNCTION__, [$value, $extra]); } - - public function packUnsignedInt($value, array $extra = []) + /** + * Convert value to unsigned base256 int. + * + * @param int $value Value + * + * @return string + */ + public function packUnsignedInt(int $value, array $extra = []): string { return $this->__call(__FUNCTION__, [$value, $extra]); } - - public function packDouble($value, array $extra = []) + /** + * Convert double to binary version. + * + * @param double $value Value to convert + * + * @return string + */ + public function packDouble(\danog\MadelineProto\double $value, array $extra = []): string { return $this->__call(__FUNCTION__, [$value, $extra]); } - - public function unpackDouble($value, array $extra = []) + /** + * Unpack binary double. + * + * @param string $value Value to unpack + * + * @return double + */ + public function unpackDouble(string $value, array $extra = []): danog\MadelineProto\double { return $this->__call(__FUNCTION__, [$value, $extra]); } - + /** + * Synchronously wait for a promise|generator. + * + * @param \Generator|Promise $promise The promise to wait for + * @param boolean $ignoreSignal Whether to ignore shutdown signals + * + * @return mixed + */ public function wait($promise, $ignoreSignal = false, array $extra = []) { return $this->__call(__FUNCTION__, [$promise, $ignoreSignal, $extra]); } - - public function all($promises, array $extra = []) + /** + * Returns a promise that succeeds when all promises succeed, and fails if any promise fails. + * Returned promise succeeds with an array of values used to succeed each contained promise, with keys corresponding to the array of promises. + * + * @param array<\Generator|Promise> $promises Promises + * + * @return Promise + */ + public function all(array $promises, array $extra = []) { return $this->__call(__FUNCTION__, [$promises, $extra]); } - - public function any($promises, array $extra = []) + /** + * Returns a promise that is resolved when all promises are resolved. The returned promise will not fail. + * + * @param array $promises Promises + * + * @return Promise + */ + public function any(array $promises, array $extra = []) { return $this->__call(__FUNCTION__, [$promises, $extra]); } - - public function some($promises, array $extra = []) + /** + * Resolves with a two-item array delineating successful and failed Promise results. + * The returned promise will only fail if the given number of required promises fail. + * + * @param array $promises Promises + * + * @return Promise + */ + public function some(array $promises, array $extra = []) { return $this->__call(__FUNCTION__, [$promises, $extra]); } - - public function first($promises, array $extra = []) + /** + * Returns a promise that succeeds when the first promise succeeds, and fails only if all promises fail. + * + * @param array $promises Promises + * + * @return Promise + */ + public function first(array $promises, array $extra = []) { return $this->__call(__FUNCTION__, [$promises, $extra]); } - - public function timeout($promise, $timeout, array $extra = []) + /** + * Create an artificial timeout for any \Generator or Promise. + * + * @param \Generator|Promise $promise + * @param integer $timeout + * + * @return Promise + */ + public function timeout($promise, int $timeout, array $extra = []) { return $this->__call(__FUNCTION__, [$promise, $timeout, $extra]); } - + /** + * Convert generator, promise or any other value to a promise. + * + * @param \Generator|Promise|mixed $promise + * + * @return Promise + */ public function call($promise, array $extra = []) { return $this->__call(__FUNCTION__, [$promise, $extra]); } - + /** + * Call promise in background. + * + * @param \Generator|Promise $promise Promise to resolve + * @param ?\Generator|Promise $actual Promise to resolve instead of $promise + * @param string $file File + * + * @return void + */ public function callFork($promise, $actual = null, $file = '', array $extra = []) { return $this->__call(__FUNCTION__, [$promise, $actual, $file, $extra]); } - + /** + * Call promise in background, deferring execution. + * + * @param \Generator|Promise $promise Promise to resolve + * + * @return void + */ public function callForkDefer($promise, array $extra = []) { return $this->__call(__FUNCTION__, [$promise, $extra]); } - - public function rethrow($e, $file = '', array $extra = []) + /** + * Rethrow error catched in strand. + * + * @param \Throwable $e Exception + * @param string $file File where the strand started + * + * @return void + */ + public function rethrow(\Throwable $e, $file = '', array $extra = []) { return $this->__call(__FUNCTION__, [$e, $file, $extra]); } - + /** + * Call promise $b after promise $a. + * + * @param \Generator|Promise $a Promise A + * @param \Generator|Promise $b Promise B + * + * @return Promise + */ public function after($a, $b, array $extra = []) { return $this->__call(__FUNCTION__, [$a, $b, $extra]); @@ -5241,6 +5411,37 @@ class InternalDoc extends APIFactory { return $this->__call(__FUNCTION__, [$string, $extra]); } + /** + * Get final element of array. + * + * @param array $what Array + * + * @return mixed + */ + public function end(array $what, array $extra = []) + { + return $this->__call(__FUNCTION__, [$what, $extra]); + } + /** + * Escape string for markdown. + * + * @param string $hwat String to escape + * + * @return void + */ + public function markdownEscape(string $hwat, array $extra = []): string + { + return $this->__call(__FUNCTION__, [$hwat, $extra]); + } + /** + * Whether this is altervista. + * + * @return boolean + */ + public function isAltervista(array $extra = []): bool + { + return $this->__call(__FUNCTION__, [$extra]); + } public function requestCall($user, array $extra = []) { diff --git a/src/danog/MadelineProto/Logger.php b/src/danog/MadelineProto/Logger.php index 2e5576a8..3bf39904 100644 --- a/src/danog/MadelineProto/Logger.php +++ b/src/danog/MadelineProto/Logger.php @@ -25,7 +25,7 @@ use function Amp\ByteStream\getStderr; use function Amp\ByteStream\getStdout; /** - * Logger class + * Logger class. */ class Logger { @@ -37,50 +37,50 @@ class Logger const RESET = ['all' => 0, 'bold' => 21, 'dim' => 22, 'underlined' => 24, 'blink' => 25, 'reverse' => 26, 'hidden' => 28]; /** - * Logging mode + * Logging mode. * * @var integer */ public $mode = 0; /** - * Optional logger parameter + * Optional logger parameter. * * @var mixed */ public $optional = null; /** - * Logger prefix + * Logger prefix. * * @var string */ public $prefix = ''; /** - * Logging level + * Logging level. * * @var integer */ public $level = self::NOTICE; /** - * Logging colors + * Logging colors. * * @var array */ public $colors = []; /** - * Newline + * Newline. * * @var string */ public $newline = "\n"; /** - * Default logger instance + * Default logger instance. * * @var self */ public static $default; /** - * Whether the AGPL notice was printed + * Whether the AGPL notice was printed. * * @var boolean */ @@ -103,7 +103,7 @@ class Logger * Construct global static logger from MadelineProto settings. * * @param array $settings Settings array - * + * * @return void */ public static function constructorFromSettings(array $settings) @@ -118,7 +118,7 @@ class Logger * * @param array $settings Settings array * @param string $prefix Optional prefix for log messages - * + * * @return self */ public static function getLoggerFromSettings(array $settings, string $prefix = ''): self @@ -159,11 +159,11 @@ class Logger * Construct global logger. * * @param int $mode One of the logger constants - * @param mixed $optional Optional parameter for logger + * @param mixed $optional Optional parameter for logger * @param string $prefix Prefix for log messages * @param int $level Default logging level * @param int $max_size Maximum size for logfile - * + * * @return void */ public static function constructor(int $mode, $optional = null, string $prefix = '', int $level = self::NOTICE, int $max_size = 100 * 1024 * 1024) @@ -175,11 +175,11 @@ class Logger * Construct global logger. * * @param int $mode One of the logger constants - * @param mixed $optional Optional parameter for logger + * @param mixed $optional Optional parameter for logger * @param string $prefix Prefix for log messages * @param int $level Default logging level * @param int $max_size Maximum size for logfile - * + * * @return void */ public function __construct(int $mode, $optional = null, string $prefix = '', int $level = self::NOTICE, int $max_size = 100 * 1024 * 1024) @@ -232,11 +232,11 @@ class Logger } /** - * Log a message + * Log a message. * * @param mixed $param Message * @param int $level Logging level - * + * * @return void */ public static function log($param, int $level = self::NOTICE) @@ -249,12 +249,12 @@ class Logger } /** - * Log a message + * Log a message. * * @param mixed $param Message to log - * @param int $level Logging level + * @param int $level Logging level * @param string $file File that originated the message - * + * * @return void */ public function logger($param, int $level = self::NOTICE, string $file = '') diff --git a/src/danog/MadelineProto/MTProto.php b/src/danog/MadelineProto/MTProto.php index c91fb73c..29a6c4a0 100644 --- a/src/danog/MadelineProto/MTProto.php +++ b/src/danog/MadelineProto/MTProto.php @@ -244,7 +244,7 @@ class MTProto extends AsyncConstruct implements TLCallback /** * Authorization info (User). * - * @var [type] + * @var array|null */ public $authorization = null; /** @@ -413,7 +413,7 @@ class MTProto extends AsyncConstruct implements TLCallback public $datacenter; /** - * Logger instance + * Logger instance. * * @var Logger */ @@ -440,32 +440,13 @@ class MTProto extends AsyncConstruct implements TLCallback */ public function __construct_async($settings = []) { - \danog\MadelineProto\Magic::classExists(); - // Parse settings + Magic::classExists(); + // Parse and store settings $this->parseSettings($settings); - // Connect to servers - $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['inst_dc'], Logger::ULTRA_VERBOSE); - if (!($this->channels_state instanceof CombinedUpdatesState)) { - $this->channels_state = new CombinedUpdatesState($this->channels_state); - } - if (isset($this->updates_state)) { - if (!($this->updates_state instanceof UpdatesState)) { - $this->updates_state = new UpdatesState($this->updates_state); - } - $this->channels_state->__construct([false => $this->updates_state]); - unset($this->updates_state); - } - if (!isset($this->datacenter)) { - $this->datacenter = new DataCenter($this, $this->settings['connection'], $this->settings['connection_settings']); - } - if (!isset($this->referenceDatabase)) { - $this->referenceDatabase = new ReferenceDatabase($this); - } - if (!isset($this->minDatabase)) { - $this->minDatabase = new MinDatabase($this); - } + $this->logger->logger(Lang::$current_lang['inst_dc'], Logger::ULTRA_VERBOSE); + $this->cleanupProperties(); // Load rsa keys - $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['load_rsa'], Logger::ULTRA_VERBOSE); + $this->logger->logger(Lang::$current_lang['load_rsa'], Logger::ULTRA_VERBOSE); $this->rsa_keys = []; foreach ($this->settings['authorization']['rsa_keys'] as $key) { $key = yield (new RSA())->load($key); @@ -475,7 +456,7 @@ class MTProto extends AsyncConstruct implements TLCallback * *********************************************************************** * Define some needed numbers for BigInteger */ - $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['TL_translation'], Logger::ULTRA_VERBOSE); + $this->logger->logger(Lang::$current_lang['TL_translation'], Logger::ULTRA_VERBOSE); $callbacks = [$this, $this->referenceDatabase]; if (!($this->authorization['user']['bot'] ?? false)) { $callbacks []= $this->minDatabase; @@ -487,7 +468,7 @@ class MTProto extends AsyncConstruct implements TLCallback if ((!isset($this->authorization['user']['bot']) || !$this->authorization['user']['bot']) && $this->datacenter->getDataCenterConnection($this->datacenter->curdc)->hasTempAuthKey()) { try { $nearest_dc = yield $this->methodCallAsyncRead('help.getNearestDc', [], ['datacenter' => $this->datacenter->curdc]); - $this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['nearest_dc'], $nearest_dc['country'], $nearest_dc['nearest_dc']), Logger::NOTICE); + $this->logger->logger(\sprintf(Lang::$current_lang['nearest_dc'], $nearest_dc['country'], $nearest_dc['nearest_dc']), Logger::NOTICE); if ($nearest_dc['nearest_dc'] != $nearest_dc['this_dc']) { $this->settings['connection_settings']['default_dc'] = $this->datacenter->curdc = (int) $nearest_dc['nearest_dc']; } @@ -503,7 +484,7 @@ class MTProto extends AsyncConstruct implements TLCallback } /** - * Sleep function + * Sleep function. * * @return array */ @@ -512,7 +493,74 @@ class MTProto extends AsyncConstruct implements TLCallback if ($this->settings['serialization']['cleanup_before_serialization']) { $this->cleanup(); } - return ['supportUser', 'referenceDatabase', 'minDatabase', 'channel_participants', 'event_handler', 'event_handler_instance', 'loop_callback', 'web_template', 'encrypted_layer', 'settings', 'config', 'authorization', 'authorized', 'rsa_keys', 'dh_config', 'chats', 'last_stored', 'qres', 'got_state', 'channels_state', 'updates', 'updates_key', 'full_chats', 'msg_ids', 'dialog_params', 'datacenter', 'v', 'constructors', 'td_constructors', 'methods', 'td_methods', 'td_descriptions', 'tl_callbacks', 'temp_requested_secret_chats', 'temp_rekeyed_secret_chats', 'secret_chats', 'hook_url', 'storage', 'authorized_dc', 'tos']; + return [ + // Databases + 'chats', + 'full_chats', + 'referenceDatabase', + 'minDatabase', + 'channel_participants', + + // Misc caching + 'dialog_params', + 'last_stored', + 'qres', + 'supportUser', + 'tos', + + // Event handler + 'event_handler', + 'event_handler_instance', + 'loop_callback', + 'updates', + 'updates_key', + + 'hook_url', + + // Web login template + 'web_template', + + // Settings + 'settings', + 'config', + + // Authorization keys + 'datacenter', + + // Authorization state + 'authorization', + 'authorized', + 'authorized_dc', + + // Authorization cache + 'rsa_keys', + 'dh_config', + + // Update state + 'got_state', + 'channels_state', + 'msg_ids', + + // Version + 'v', + + // TL (we don't need this) + 'constructors', + 'td_constructors', + 'methods', + 'td_methods', + 'td_descriptions', + 'tl_callbacks', + + // Secret chats + 'secret_chats', + 'encrypted_layer', + 'temp_requested_secret_chats', + 'temp_rekeyed_secret_chats', + + // Object storage + 'storage', + ]; } @@ -533,12 +581,12 @@ class MTProto extends AsyncConstruct implements TLCallback } /** - * Logger + * Logger. * * @param string $param Parameter - * @param int $level Logging level + * @param int $level Logging level * @param string $file File where the message originated - * + * * @return void */ public function logger($param, int $level = Logger::NOTICE, string $file = '') @@ -551,7 +599,7 @@ class MTProto extends AsyncConstruct implements TLCallback } /** - * Get async HTTP client + * Get async HTTP client. * * @return \Amp\Artax\Client */ @@ -561,7 +609,7 @@ class MTProto extends AsyncConstruct implements TLCallback } /** - * Get async DNS client + * Get async DNS client. * * @return \Amp\Dns\Resolver */ @@ -571,10 +619,10 @@ class MTProto extends AsyncConstruct implements TLCallback } /** - * Get contents of remote file asynchronously + * Get contents of remote file asynchronously. * * @param string $url URL - * + * * @return \Generator */ public function fileGetContents(string $url): \Generator @@ -592,22 +640,8 @@ class MTProto extends AsyncConstruct implements TLCallback return $this->datacenter->getDataCenterConnections(); } - public function hasAllAuth(): bool - { - if ($this->isInitingAuthorization()) { - return false; - } - - foreach ($this->datacenter->getDataCenterConnections() as $dc) { - if (!$dc->isAuthorized() || !$dc->hasTempAuthKey()) { - return false; - } - } - - return true; - } /** - * Prompt serialization of instance + * Prompt serialization of instance. * * @return void */ @@ -619,7 +653,7 @@ class MTProto extends AsyncConstruct implements TLCallback } } /** - * Start all internal loops + * Start all internal loops. * * @return void */ @@ -648,7 +682,7 @@ class MTProto extends AsyncConstruct implements TLCallback $this->checkTosLoop->start(); } /** - * Stop all internal loops + * Stop all internal loops. * * @return void */ @@ -677,63 +711,12 @@ class MTProto extends AsyncConstruct implements TLCallback } /** - * Wakeup function - */ - public function __wakeup() - { - $backtrace = \debug_backtrace(0, 3); - $this->asyncInitPromise = true; - $this->setInitPromise($this->__wakeup_async($backtrace)); - } - - /** - * Async wakeup function + * Clean up properties from previous versions of MadelineProto. * - * @param array $backtrace Stack trace - * - * @return \Generator + * @return void */ - public function __wakeup_async(array $backtrace): \Generator + private function cleanupProperties() { - \set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']); - $this->setupLogger(); - if (\danog\MadelineProto\Magic::$has_thread && \is_object(\Thread::getCurrentThread())) { - return; - } - Lang::$current_lang = &Lang::$lang['en']; - if (isset($this->settings['app_info']['lang_code']) && isset(Lang::$lang[$this->settings['app_info']['lang_code']])) { - Lang::$current_lang = &Lang::$lang[$this->settings['app_info']['lang_code']]; - } - if (!isset($this->referenceDatabase)) { - $this->referenceDatabase = new ReferenceDatabase($this); - } - if (!isset($this->minDatabase)) { - $this->minDatabase = new MinDatabase($this); - } - $callbacks = [$this, $this->referenceDatabase]; - if (!($this->authorization['user']['bot'] ?? false)) { - $callbacks []= $this->minDatabase; - } - $this->updateCallbacks($callbacks); - - $this->settings['connection_settings']['all']['ipv6'] = \danog\MadelineProto\Magic::$ipv6; - /*if (isset($this->settings['pwr']['updateHandler']) && $this->settings['pwr']['updateHandler'] === $this->settings['updates']['callback']) { - unset($this->settings['pwr']['updateHandler']); - $this->updates = []; - }*/ - /*$keys = array_keys((array) get_object_vars($this)); - if (count($keys) !== count(array_unique($keys))) { - throw new Bug74586Exception(); - } - if (isset($this->data)) { - foreach ($this->data as $k => $v) { - $this->{$k} = $v; - } - unset($this->data); - }*/ - if ($this->authorized === true) { - $this->authorized = self::LOGGED_IN; - } if (!($this->channels_state instanceof CombinedUpdatesState)) { $this->channels_state = new CombinedUpdatesState($this->channels_state); } @@ -744,9 +727,147 @@ class MTProto extends AsyncConstruct implements TLCallback $this->channels_state->__construct([false => $this->updates_state]); unset($this->updates_state); } + if (!isset($this->datacenter)) { + $this->datacenter = new DataCenter($this, $this->settings['connection'], $this->settings['connection_settings']); + } + if (!isset($this->referenceDatabase)) { + $this->referenceDatabase = new ReferenceDatabase($this); + } + if (!isset($this->minDatabase)) { + $this->minDatabase = new MinDatabase($this); + } + } + /** + * Upgrade MadelineProto instance + * + * @return \Generator + */ + private function upgradeMadelineProto(): \Generator + { + $this->logger->logger(Lang::$current_lang['serialization_ofd'], Logger::WARNING); + foreach ($this->datacenter->getDataCenterConnections() as $dc_id => $socket) { + if ($this->authorized === self::LOGGED_IN && \strpos($dc_id, '_') === false && $socket->hasPermAuthKey() && $socket->hasTempAuthKey()) { + $socket->bind(); + $socket->authorized(true); + } + } + $settings = $this->settings; + if (isset($settings['updates']['callback'][0]) && $settings['updates']['callback'][0] === $this) { + $settings['updates']['callback'] = 'getUpdatesUpdateHandler'; + } + if (isset($settings['updates']['getdifference_interval']) && $settings['updates']['getdifference_interval'] === -1) { + unset($settings['updates']['getdifference_interval']); + } + unset($settings['tl_schema']); + if (isset($settings['authorization']['rsa_key'])) { + unset($settings['authorization']['rsa_key']); + } + if (!isset($this->full_chats)) { + $this->full_chats = []; + } + if (!isset($this->secret_chats)) { + $this->secret_chats = []; + } - if ($this->event_handler && \class_exists($this->event_handler) && \is_subclass_of($this->event_handler, '\danog\MadelineProto\EventHandler')) { - $this->setEventHandler($this->event_handler); + foreach ($this->full_chats as $id => $full) { + if (isset($full['full'], $full['last_update'])) { + $this->full_chats[$id] = ['full' => $full['full'], 'last_update' => $full['last_update']]; + } + } + foreach ($this->secret_chats as $key => &$chat) { + if (!\is_array($chat)) { + unset($this->secret_chats[$key]); + continue; + } + if ($chat['layer'] >= 73) { + $chat['mtproto'] = 2; + } else { + $chat['mtproto'] = 1; + } + } + foreach ($settings['connection_settings'] as $key => &$connection) { + if (\in_array($key, ['default_dc', 'media_socket_count', 'robin_period'])) { + continue; + } + if (!\is_array($connection)) { + unset($settings['connection_settings'][$key]); + continue; + } + if (!isset($connection['proxy'])) { + $connection['proxy'] = '\\Socket'; + } + if (!isset($connection['proxy_extra'])) { + $connection['proxy_extra'] = []; + } + if (!isset($connection['pfs'])) { + $connection['pfs'] = \extension_loaded('gmp'); + } + if ($connection['protocol'] === 'obfuscated2') { + $connection['protocol'] = 'tcp_intermediate_padded'; + $connection['obfuscated'] = true; + } + } + if ($settings['app_info']['api_id'] === 6) { + unset($settings['app_info']); + } + $this->resetMTProtoSession(true, true); + $this->config = ['expires' => -1]; + $this->dh_config = ['version' => 0]; + yield $this->__construct_async($settings); + foreach ($this->secret_chats as $chat => $data) { + try { + if (isset($this->secret_chats[$chat]) && $this->secret_chats[$chat]['InputEncryptedChat'] !== null) { + yield $this->notifyLayer($chat); + } + } catch (\danog\MadelineProto\RPCErrorException $e) { + } + } + } + /** + * Wakeup function. + */ + public function __wakeup() + { + $backtrace = \debug_backtrace(0, 3); + $this->asyncInitPromise = true; + $this->setInitPromise($this->__wakeup_async($backtrace)); + } + + /** + * Async wakeup function. + * + * @param array $backtrace Stack trace + * + * @return \Generator + */ + public function __wakeup_async(array $backtrace): \Generator + { + // Setup one-time stuffs + Magic::classExists(); + // Setup logger + $this->setupLogger(); + // We don't like threads + if (Magic::$has_thread && \is_object(\Thread::getCurrentThread())) { + return; + } + // Setup language + Lang::$current_lang = &Lang::$lang['en']; + if (Lang::$lang[$this->settings['app_info']['lang_code'] ?? 'en'] ?? false) { + Lang::$current_lang = &Lang::$lang[$this->settings['app_info']['lang_code']]; + } + // Cleanup old properties, init new stuffs + $this->cleanupProperties(); + + // Update TL callbacks + $callbacks = [$this, $this->referenceDatabase]; + if (!($this->authorization['user']['bot'] ?? false)) { + $callbacks []= $this->minDatabase; + } + $this->updateCallbacks($callbacks); + + $this->settings['connection_settings']['all']['ipv6'] = Magic::$ipv6; + if ($this->authorized === true) { + $this->authorized = self::LOGGED_IN; } $force = false; $this->resetMTProtoSession(); @@ -756,97 +877,19 @@ class MTProto extends AsyncConstruct implements TLCallback } } - if (isset($this->settings['tl_schema']['src']['botAPI']) && $this->settings['tl_schema']['src']['botAPI'] !== __DIR__.'/TL_botAPI.tl') { + if ($this->event_handler && \class_exists($this->event_handler) && \is_subclass_of($this->event_handler, EventHandler::class)) { + $this->setEventHandler($this->event_handler); + } + + if (($this->settings['tl_schema']['src']['botAPI'] ?? '') !== __DIR__.'/TL_botAPI.tl') { unset($this->v); } if (!isset($this->v) || $this->v !== self::V) { - $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['serialization_ofd'], Logger::WARNING); - foreach ($this->datacenter->getDataCenterConnections() as $dc_id => $socket) { - if ($this->authorized === self::LOGGED_IN && \strpos($dc_id, '_') === false && $socket->hasPermAuthKey() && $socket->hasTempAuthKey()) { - $socket->bind(); - $socket->authorized(true); - } - } - $settings = $this->settings; - if (isset($settings['updates']['callback'][0]) && $settings['updates']['callback'][0] === $this) { - $settings['updates']['callback'] = 'getUpdatesUpdateHandler'; - } - if (isset($settings['updates']['getdifference_interval']) && $settings['updates']['getdifference_interval'] === -1) { - unset($settings['updates']['getdifference_interval']); - } - unset($settings['tl_schema']); - if (isset($settings['authorization']['rsa_key'])) { - unset($settings['authorization']['rsa_key']); - } - if (!isset($this->full_chats)) { - $this->full_chats = []; - } - if (!isset($this->secret_chats)) { - $this->secret_chats = []; - } - - foreach ($this->full_chats as $id => $full) { - if (isset($full['full'], $full['last_update'])) { - $this->full_chats[$id] = ['full' => $full['full'], 'last_update' => $full['last_update']]; - } - } - foreach ($this->secret_chats as $key => &$chat) { - if (!\is_array($chat)) { - unset($this->secret_chats[$key]); - continue; - } - if ($chat['layer'] >= 73) { - $chat['mtproto'] = 2; - } else { - $chat['mtproto'] = 1; - } - } - foreach ($settings['connection_settings'] as $key => &$connection) { - if (\in_array($key, ['default_dc', 'media_socket_count', 'robin_period'])) { - continue; - } - if (!\is_array($connection)) { - unset($settings['connection_settings'][$key]); - continue; - } - if (!isset($connection['proxy'])) { - $connection['proxy'] = '\\Socket'; - } - if (!isset($connection['proxy_extra'])) { - $connection['proxy_extra'] = []; - } - if (!isset($connection['pfs'])) { - $connection['pfs'] = \extension_loaded('gmp'); - } - if ($connection['protocol'] === 'obfuscated2') { - $connection['protocol'] = 'tcp_intermediate_padded'; - $connection['obfuscated'] = true; - } - } - if ($settings['app_info']['api_id'] === 6) { - unset($settings['app_info']); - } - $this->resetMTProtoSession(true, true); - $this->config = ['expires' => -1]; - $this->dh_config = ['version' => 0]; - yield $this->__construct_async($settings); + yield $this->upgradeMadelineProto(); $force = true; - foreach ($this->secret_chats as $chat => $data) { - try { - if (isset($this->secret_chats[$chat]) && $this->secret_chats[$chat]['InputEncryptedChat'] !== null) { - yield $this->notifyLayer($chat); - } - } catch (\danog\MadelineProto\RPCErrorException $e) { - } - } } - /*if (!$this->settings['updates']['handle_old_updates']) { - $this->channels_state = new CombinedUpdatesState(); - $this->msg_ids = []; - $this->got_state = false; - }*/ yield $this->connectToAllDcs(); foreach ($this->calls as $id => $controller) { if (!\is_object($controller)) { @@ -872,14 +915,14 @@ class MTProto extends AsyncConstruct implements TLCallback yield $this->getDialogs($force); } if ($this->authorized === self::LOGGED_IN && $this->settings['updates']['handle_updates']) { - $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['getupdates_deserialization'], Logger::NOTICE); + $this->logger->logger(Lang::$current_lang['getupdates_deserialization'], Logger::NOTICE); yield $this->updaters[false]->resume(); } $this->updaters[false]->start(); } /** - * Destructor + * Destructor. */ public function __destruct() { @@ -907,11 +950,11 @@ class MTProto extends AsyncConstruct implements TLCallback } /** - * Get correct settings array for the latest version + * Get correct settings array for the latest version. * * @param array $settings Current settings array * @param array $previousSettings Previous settings array - * + * * @return array */ public static function getSettings(array $settings, array $previousSettings = []): array @@ -1097,7 +1140,7 @@ class MTProto extends AsyncConstruct implements TLCallback // can be tcp_full, tcp_abridged, tcp_intermediate, http, https, obfuscated2, udp (unsupported) 'test_mode' => false, // decides whether to connect to the main telegram servers or to the testing servers (deep telegram) - 'ipv6' => \danog\MadelineProto\Magic::$ipv6, + 'ipv6' => Magic::$ipv6, // decides whether to use ipv6, ipv6 attribute of API attribute of API class contains autodetected boolean 'timeout' => 2, // timeout for sockets @@ -1242,17 +1285,17 @@ class MTProto extends AsyncConstruct implements TLCallback return $settings; } /** - * Parse and store settings + * Parse and store settings. * * @param array $settings Settings - * + * * @return void */ public function parseSettings(array $settings) { $settings = self::getSettings($settings, $this->settings); if ($settings['app_info'] === null) { - throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['api_not_set'], 0, null, 'MadelineProto', 1); + throw new \danog\MadelineProto\Exception(Lang::$current_lang['api_not_set'], 0, null, 'MadelineProto', 1); } $this->settings = $settings; if (!$this->settings['updates']['handle_updates']) { @@ -1263,7 +1306,7 @@ class MTProto extends AsyncConstruct implements TLCallback } /** - * Setup logger + * Setup logger. * * @return void */ @@ -1283,7 +1326,7 @@ class MTProto extends AsyncConstruct implements TLCallback public function resetMTProtoSession(bool $de = true, bool $auth_key = false) { if (!\is_object($this->datacenter)) { - throw new Exception(\danog\MadelineProto\Lang::$current_lang['session_corrupted']); + throw new Exception(Lang::$current_lang['session_corrupted']); } foreach ($this->datacenter->getDataCenterConnections() as $id => $socket) { if ($de) { @@ -1307,6 +1350,20 @@ class MTProto extends AsyncConstruct implements TLCallback return $this->datacenter->isHttp($datacenter); } + public function hasAllAuth(): bool + { + if ($this->isInitingAuthorization()) { + return false; + } + + foreach ($this->datacenter->getDataCenterConnections() as $dc) { + if (!$dc->isAuthorized() || !$dc->hasTempAuthKey()) { + return false; + } + } + + return true; + } public function isInitingAuthorization() { @@ -1314,10 +1371,10 @@ class MTProto extends AsyncConstruct implements TLCallback } /** - * Connects to all datacenters and if necessary creates authorization keys, binds them and writes client info + * Connects to all datacenters and if necessary creates authorization keys, binds them and writes client info. * * @param boolean $reconnectAll Whether to reconnect to all DCs - * + * * @return \Generator */ public function connectToAllDcs(bool $reconnectAll = true): \Generator @@ -1355,7 +1412,7 @@ class MTProto extends AsyncConstruct implements TLCallback yield $this->getPhoneConfig(); } /** - * Clean up MadelineProto session after logout + * Clean up MadelineProto session after logout. * * @return void */ @@ -1401,7 +1458,7 @@ class MTProto extends AsyncConstruct implements TLCallback $this->full_chats = []; } /** - * Reset the update state and fetch all updates from the beginning + * Reset the update state and fetch all updates from the beginning. * * @return void */ @@ -1433,10 +1490,10 @@ class MTProto extends AsyncConstruct implements TLCallback } /** - * Start the update system + * Start the update system. * * @param boolean $anyway Force start update system? - * + * * @return void */ public function startUpdateSystem($anyway = false) @@ -1479,10 +1536,10 @@ class MTProto extends AsyncConstruct implements TLCallback } /** - * Store shared phone config + * Store shared phone config. * * @param mixed $watcherId Watcher ID - * + * * @return void */ public function getPhoneConfig($watcherId = null) @@ -1496,10 +1553,10 @@ class MTProto extends AsyncConstruct implements TLCallback } /** - * Store RSA keys for CDN datacenters + * Store RSA keys for CDN datacenters. * * @param string $datacenter DC ID - * + * * @return \Generator */ public function getCdnConfig(string $datacenter): \Generator @@ -1515,7 +1572,7 @@ class MTProto extends AsyncConstruct implements TLCallback } /** - * Get cached server-side config + * Get cached server-side config. * * @return array */ @@ -1525,11 +1582,11 @@ class MTProto extends AsyncConstruct implements TLCallback } /** - * Get cached (or eventually re-fetch) server-side config + * Get cached (or eventually re-fetch) server-side config. * * @param array $config Current config * @param array $options Options for method call - * + * * @return \Generator */ public function getConfig(array $config = [], array $options = []): \Generator @@ -1544,7 +1601,7 @@ class MTProto extends AsyncConstruct implements TLCallback } /** - * Parse cached config + * Parse cached config. * * @return \Generator */ @@ -1555,15 +1612,15 @@ class MTProto extends AsyncConstruct implements TLCallback unset($this->config['dc_options']); yield $this->parseDcOptions($options); } - $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['config_updated'], Logger::NOTICE); + $this->logger->logger(Lang::$current_lang['config_updated'], Logger::NOTICE); $this->logger->logger($this->config, Logger::NOTICE); } /** - * Parse DC options from config + * Parse DC options from config. * * @param array $dc_options DC options - * + * * @return \Generator */ private function parseDcOptions(array $dc_options): \Generator @@ -1596,7 +1653,7 @@ class MTProto extends AsyncConstruct implements TLCallback } /** - * Get info about the logged-in user + * Get info about the logged-in user. * * @return \Generator */ @@ -1653,7 +1710,7 @@ class MTProto extends AsyncConstruct implements TLCallback /** - * Get debug information for var_dump + * Get debug information for var_dump. * * @return array */ diff --git a/src/danog/MadelineProto/MTProtoTools/CombinedUpdatesState.php b/src/danog/MadelineProto/MTProtoTools/CombinedUpdatesState.php index 56a0b41f..f391b0df 100644 --- a/src/danog/MadelineProto/MTProtoTools/CombinedUpdatesState.php +++ b/src/danog/MadelineProto/MTProtoTools/CombinedUpdatesState.php @@ -20,12 +20,22 @@ namespace danog\MadelineProto\MTProtoTools; /** - * Stores multiple states. + * Stores multiple update states. */ class CombinedUpdatesState { + /** + * Update states. + * + * @var array + */ private $states = []; + /** + * Constructor function. + * + * @param array $init Initial array of states + */ public function __construct($init = []) { $this->states[false] = new UpdatesState(); @@ -41,14 +51,14 @@ class CombinedUpdatesState } /** - * Update multiple parameters. + * Get or update multiple parameters. * - * @param array|null $init - * @param int $channel + * @param int $channel Channel to get info about (optional, if not provided returns the entire info array) + * @param array $init Parameters to update * - * @return UpdatesState + * @return UpdatesState|UpdatesState[] */ - public function get($channel = null, $init = []) + public function get(int $channel = null, array $init = []) { if ($channel === null) { return $this->states; @@ -63,11 +73,11 @@ class CombinedUpdatesState /** * Remove update state. * - * @param int $channel + * @param int $channel Channel whose state should be removed * * @return void */ - public function remove($channel) + public function remove(int $channel) { if (isset($this->states[$channel])) { unset($this->states[$channel]); @@ -77,11 +87,11 @@ class CombinedUpdatesState /** * Check if update state is present. * - * @param int $channel + * @param int $channel Channel ID * - * @return void + * @return bool */ - public function has($channel) + public function has(int $channel): bool { return isset($this->states[$channel]); } @@ -89,12 +99,12 @@ class CombinedUpdatesState /** * Are we currently busy? * - * @param int $channel - * @param bool|null $set + * @param int $channel Channel to get info about + * @param bool|null $set Busy flag to set before returning * * @return bool */ - public function syncLoading($channel, $set = null) + public function syncLoading(int $channel, bool $set = null): bool { return $this->get($channel)->syncLoading($set); } diff --git a/src/danog/MadelineProto/MTProtoTools/UpdatesState.php b/src/danog/MadelineProto/MTProtoTools/UpdatesState.php index ed6868ee..d7a86bc2 100644 --- a/src/danog/MadelineProto/MTProtoTools/UpdatesState.php +++ b/src/danog/MadelineProto/MTProtoTools/UpdatesState.php @@ -90,7 +90,7 @@ class UpdatesState * * @return bool */ - public function isChannel() + public function isChannel(): bool { return (bool) $this->channelId; } @@ -108,11 +108,11 @@ class UpdatesState /** * Are we currently busy? * - * @param bool|null $set + * @param bool|null $set Update the currently busy flag * * @return bool */ - public function syncLoading($set = null) + public function syncLoading(bool $set = null): bool { if ($set !== null) { $this->syncLoading = $set; @@ -124,11 +124,11 @@ class UpdatesState /** * Update multiple parameters. * - * @param array $init + * @param array $init Parameters to update * * @return self */ - public function update($init) + public function update(array $init): self { foreach ($this->channelId ? ['pts'] : ['pts', 'qts', 'seq', 'date'] as $param) { if (isset($init[$param])) { @@ -142,11 +142,11 @@ class UpdatesState /** * Get/set PTS. * - * @param int $set + * @param int $set PTS to set * - * @return int + * @return int PTS */ - public function pts($set = 0) + public function pts(int $set = 0): int { if ($set !== 0 && $set > $this->pts) { $this->pts = $set; @@ -158,11 +158,11 @@ class UpdatesState /** * Get/set QTS. * - * @param int $set + * @param int $set QTS to set * - * @return int + * @return int QTS */ - public function qts($set = 0) + public function qts(int $set = 0): int { if ($set !== 0 && $set > $this->qts) { $this->qts = $set; @@ -174,11 +174,11 @@ class UpdatesState /** * Get/set seq. * - * @param int $set + * @param int $set Seq to set * - * @return int + * @return int seq */ - public function seq($set = 0) + public function seq(int $set = 0): int { if ($set !== 0 && $set > $this->seq) { $this->seq = $set; @@ -190,11 +190,11 @@ class UpdatesState /** * Get/set date. * - * @param int $set + * @param int $set Date to set * - * @return int + * @return int Date */ - public function date($set = 0) + public function date(int $set = 0): int { if ($set !== 0 && $set > $this->date) { $this->date = $set; @@ -206,11 +206,11 @@ class UpdatesState /** * Check validity of PTS contained in update. * - * @param array $update + * @param array $update Update * * @return int -1 if it's too old, 0 if it's ok, 1 if it's too new */ - public function checkPts($update) + public function checkPts(array $update): int { return $update['pts'] - ($this->pts + $update['pts_count']); } @@ -218,11 +218,11 @@ class UpdatesState /** * Check validity of seq contained in update. * - * @param int $seq + * @param int $seq Seq * * @return int -1 if it's too old, 0 if it's ok, 1 if it's too new */ - public function checkSeq($seq) + public function checkSeq(int $seq): int { return $seq ? $seq - ($this->seq + 1) : $seq; } diff --git a/src/danog/MadelineProto/Magic.php b/src/danog/MadelineProto/Magic.php index 48678753..756f1778 100644 --- a/src/danog/MadelineProto/Magic.php +++ b/src/danog/MadelineProto/Magic.php @@ -74,7 +74,7 @@ class Magic const JSON_EMOJIS = '["\\ud83d\\ude09","\\ud83d\\ude0d","\\ud83d\\ude1b","\\ud83d\\ude2d","\\ud83d\\ude31","\\ud83d\\ude21","\\ud83d\\ude0e","\\ud83d\\ude34","\\ud83d\\ude35","\\ud83d\\ude08","\\ud83d\\ude2c","\\ud83d\\ude07","\\ud83d\\ude0f","\\ud83d\\udc6e","\\ud83d\\udc77","\\ud83d\\udc82","\\ud83d\\udc76","\\ud83d\\udc68","\\ud83d\\udc69","\\ud83d\\udc74","\\ud83d\\udc75","\\ud83d\\ude3b","\\ud83d\\ude3d","\\ud83d\\ude40","\\ud83d\\udc7a","\\ud83d\\ude48","\\ud83d\\ude49","\\ud83d\\ude4a","\\ud83d\\udc80","\\ud83d\\udc7d","\\ud83d\\udca9","\\ud83d\\udd25","\\ud83d\\udca5","\\ud83d\\udca4","\\ud83d\\udc42","\\ud83d\\udc40","\\ud83d\\udc43","\\ud83d\\udc45","\\ud83d\\udc44","\\ud83d\\udc4d","\\ud83d\\udc4e","\\ud83d\\udc4c","\\ud83d\\udc4a","\\u270c","\\u270b","\\ud83d\\udc50","\\ud83d\\udc46","\\ud83d\\udc47","\\ud83d\\udc49","\\ud83d\\udc48","\\ud83d\\ude4f","\\ud83d\\udc4f","\\ud83d\\udcaa","\\ud83d\\udeb6","\\ud83c\\udfc3","\\ud83d\\udc83","\\ud83d\\udc6b","\\ud83d\\udc6a","\\ud83d\\udc6c","\\ud83d\\udc6d","\\ud83d\\udc85","\\ud83c\\udfa9","\\ud83d\\udc51","\\ud83d\\udc52","\\ud83d\\udc5f","\\ud83d\\udc5e","\\ud83d\\udc60","\\ud83d\\udc55","\\ud83d\\udc57","\\ud83d\\udc56","\\ud83d\\udc59","\\ud83d\\udc5c","\\ud83d\\udc53","\\ud83c\\udf80","\\ud83d\\udc84","\\ud83d\\udc9b","\\ud83d\\udc99","\\ud83d\\udc9c","\\ud83d\\udc9a","\\ud83d\\udc8d","\\ud83d\\udc8e","\\ud83d\\udc36","\\ud83d\\udc3a","\\ud83d\\udc31","\\ud83d\\udc2d","\\ud83d\\udc39","\\ud83d\\udc30","\\ud83d\\udc38","\\ud83d\\udc2f","\\ud83d\\udc28","\\ud83d\\udc3b","\\ud83d\\udc37","\\ud83d\\udc2e","\\ud83d\\udc17","\\ud83d\\udc34","\\ud83d\\udc11","\\ud83d\\udc18","\\ud83d\\udc3c","\\ud83d\\udc27","\\ud83d\\udc25","\\ud83d\\udc14","\\ud83d\\udc0d","\\ud83d\\udc22","\\ud83d\\udc1b","\\ud83d\\udc1d","\\ud83d\\udc1c","\\ud83d\\udc1e","\\ud83d\\udc0c","\\ud83d\\udc19","\\ud83d\\udc1a","\\ud83d\\udc1f","\\ud83d\\udc2c","\\ud83d\\udc0b","\\ud83d\\udc10","\\ud83d\\udc0a","\\ud83d\\udc2b","\\ud83c\\udf40","\\ud83c\\udf39","\\ud83c\\udf3b","\\ud83c\\udf41","\\ud83c\\udf3e","\\ud83c\\udf44","\\ud83c\\udf35","\\ud83c\\udf34","\\ud83c\\udf33","\\ud83c\\udf1e","\\ud83c\\udf1a","\\ud83c\\udf19","\\ud83c\\udf0e","\\ud83c\\udf0b","\\u26a1","\\u2614","\\u2744","\\u26c4","\\ud83c\\udf00","\\ud83c\\udf08","\\ud83c\\udf0a","\\ud83c\\udf93","\\ud83c\\udf86","\\ud83c\\udf83","\\ud83d\\udc7b","\\ud83c\\udf85","\\ud83c\\udf84","\\ud83c\\udf81","\\ud83c\\udf88","\\ud83d\\udd2e","\\ud83c\\udfa5","\\ud83d\\udcf7","\\ud83d\\udcbf","\\ud83d\\udcbb","\\u260e","\\ud83d\\udce1","\\ud83d\\udcfa","\\ud83d\\udcfb","\\ud83d\\udd09","\\ud83d\\udd14","\\u23f3","\\u23f0","\\u231a","\\ud83d\\udd12","\\ud83d\\udd11","\\ud83d\\udd0e","\\ud83d\\udca1","\\ud83d\\udd26","\\ud83d\\udd0c","\\ud83d\\udd0b","\\ud83d\\udebf","\\ud83d\\udebd","\\ud83d\\udd27","\\ud83d\\udd28","\\ud83d\\udeaa","\\ud83d\\udeac","\\ud83d\\udca3","\\ud83d\\udd2b","\\ud83d\\udd2a","\\ud83d\\udc8a","\\ud83d\\udc89","\\ud83d\\udcb0","\\ud83d\\udcb5","\\ud83d\\udcb3","\\u2709","\\ud83d\\udceb","\\ud83d\\udce6","\\ud83d\\udcc5","\\ud83d\\udcc1","\\u2702","\\ud83d\\udccc","\\ud83d\\udcce","\\u2712","\\u270f","\\ud83d\\udcd0","\\ud83d\\udcda","\\ud83d\\udd2c","\\ud83d\\udd2d","\\ud83c\\udfa8","\\ud83c\\udfac","\\ud83c\\udfa4","\\ud83c\\udfa7","\\ud83c\\udfb5","\\ud83c\\udfb9","\\ud83c\\udfbb","\\ud83c\\udfba","\\ud83c\\udfb8","\\ud83d\\udc7e","\\ud83c\\udfae","\\ud83c\\udccf","\\ud83c\\udfb2","\\ud83c\\udfaf","\\ud83c\\udfc8","\\ud83c\\udfc0","\\u26bd","\\u26be","\\ud83c\\udfbe","\\ud83c\\udfb1","\\ud83c\\udfc9","\\ud83c\\udfb3","\\ud83c\\udfc1","\\ud83c\\udfc7","\\ud83c\\udfc6","\\ud83c\\udfca","\\ud83c\\udfc4","\\u2615","\\ud83c\\udf7c","\\ud83c\\udf7a","\\ud83c\\udf77","\\ud83c\\udf74","\\ud83c\\udf55","\\ud83c\\udf54","\\ud83c\\udf5f","\\ud83c\\udf57","\\ud83c\\udf71","\\ud83c\\udf5a","\\ud83c\\udf5c","\\ud83c\\udf61","\\ud83c\\udf73","\\ud83c\\udf5e","\\ud83c\\udf69","\\ud83c\\udf66","\\ud83c\\udf82","\\ud83c\\udf70","\\ud83c\\udf6a","\\ud83c\\udf6b","\\ud83c\\udf6d","\\ud83c\\udf6f","\\ud83c\\udf4e","\\ud83c\\udf4f","\\ud83c\\udf4a","\\ud83c\\udf4b","\\ud83c\\udf52","\\ud83c\\udf47","\\ud83c\\udf49","\\ud83c\\udf53","\\ud83c\\udf51","\\ud83c\\udf4c","\\ud83c\\udf50","\\ud83c\\udf4d","\\ud83c\\udf46","\\ud83c\\udf45","\\ud83c\\udf3d","\\ud83c\\udfe1","\\ud83c\\udfe5","\\ud83c\\udfe6","\\u26ea","\\ud83c\\udff0","\\u26fa","\\ud83c\\udfed","\\ud83d\\uddfb","\\ud83d\\uddfd","\\ud83c\\udfa0","\\ud83c\\udfa1","\\u26f2","\\ud83c\\udfa2","\\ud83d\\udea2","\\ud83d\\udea4","\\u2693","\\ud83d\\ude80","\\u2708","\\ud83d\\ude81","\\ud83d\\ude82","\\ud83d\\ude8b","\\ud83d\\ude8e","\\ud83d\\ude8c","\\ud83d\\ude99","\\ud83d\\ude97","\\ud83d\\ude95","\\ud83d\\ude9b","\\ud83d\\udea8","\\ud83d\\ude94","\\ud83d\\ude92","\\ud83d\\ude91","\\ud83d\\udeb2","\\ud83d\\udea0","\\ud83d\\ude9c","\\ud83d\\udea6","\\u26a0","\\ud83d\\udea7","\\u26fd","\\ud83c\\udfb0","\\ud83d\\uddff","\\ud83c\\udfaa","\\ud83c\\udfad","\\ud83c\\uddef\\ud83c\\uddf5","\\ud83c\\uddf0\\ud83c\\uddf7","\\ud83c\\udde9\\ud83c\\uddea","\\ud83c\\udde8\\ud83c\\uddf3","\\ud83c\\uddfa\\ud83c\\uddf8","\\ud83c\\uddeb\\ud83c\\uddf7","\\ud83c\\uddea\\ud83c\\uddf8","\\ud83c\\uddee\\ud83c\\uddf9","\\ud83c\\uddf7\\ud83c\\uddfa","\\ud83c\\uddec\\ud83c\\udde7","1\\u20e3","2\\u20e3","3\\u20e3","4\\u20e3","5\\u20e3","6\\u20e3","7\\u20e3","8\\u20e3","9\\u20e3","0\\u20e3","\\ud83d\\udd1f","\\u2757","\\u2753","\\u2665","\\u2666","\\ud83d\\udcaf","\\ud83d\\udd17","\\ud83d\\udd31","\\ud83d\\udd34","\\ud83d\\udd35","\\ud83d\\udd36","\\ud83d\\udd37"]'; /** - * Initialize magic constants + * Initialize magic constants. * * @return void */ @@ -206,7 +206,7 @@ class Magic } /** - * Check if this is a POSIX fork of the main PHP process + * Check if this is a POSIX fork of the main PHP process. * * @return boolean */ @@ -231,7 +231,7 @@ class Magic } /** - * Get current working directory + * Get current working directory. * * @return string */ diff --git a/src/danog/MadelineProto/RSA.php b/src/danog/MadelineProto/RSA.php index ca58dd94..5ff72b47 100644 --- a/src/danog/MadelineProto/RSA.php +++ b/src/danog/MadelineProto/RSA.php @@ -18,52 +18,74 @@ namespace danog\MadelineProto; +/** + * RSA class + */ class RSA { use \danog\MadelineProto\TL\TL; use \danog\MadelineProto\Tools; use \danog\Serializable; + /** + * Exponent + * + * @var \phpseclib\Math\BigInteger + */ public $e; + /** + * Modulus + * + * @var \phpseclib\Math\BigInteger + */ public $n; + /** + * Fingerprint + * + * @var string + */ public $fp; - public function load($rsa_key) + /** + * Load RSA key + * + * @param string $rsa_key RSA key + * + * @return \Generator + */ + public function load(string $rsa_key): \Generator { \danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['rsa_init'], Logger::ULTRA_VERBOSE); \danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['loading_key'], Logger::ULTRA_VERBOSE); $key = \phpseclib\Crypt\RSA::load($rsa_key); - $this->n = self::getVar($key, 'modulus'); - $this->e = self::getVar($key, 'exponent'); + $this->n = Tools::getVar($key, 'modulus'); + $this->e = Tools::getVar($key, 'exponent'); \danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['computing_fingerprint'], Logger::ULTRA_VERBOSE); $this->fp = \substr(\sha1((yield $this->serializeObject(['type' => 'bytes'], $this->n->toBytes(), 'key')).(yield $this->serializeObject(['type' => 'bytes'], $this->e->toBytes(), 'key')), true), -8); return $this; } - public function __sleep() + /** + * Sleep function + * + * @return array + */ + public function __sleep(): array { return ['e', 'n', 'fp']; } - public function encrypt($data) + /** + * Encrypt data + * + * @param string $data Data to encrypt + * + * @return string + */ + public function encrypt($data): string { \danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['rsa_encrypting'], Logger::VERBOSE); return (new \phpseclib\Math\BigInteger((string) $data, 256))->powMod($this->e, $this->n)->toBytes(); } - /** - * Accesses a private variable from an object. - * - * @param object $obj - * @param string $var - * @return mixed - * @access public - */ - public static function getVar($obj, $var) - { - $reflection = new \ReflectionClass(\get_class($obj)); - $prop = $reflection->getProperty($var); - $prop->setAccessible(true); - return $prop->getValue($obj); - } } diff --git a/src/danog/MadelineProto/TL/TL.php b/src/danog/MadelineProto/TL/TL.php index 41305075..5cd09a63 100644 --- a/src/danog/MadelineProto/TL/TL.php +++ b/src/danog/MadelineProto/TL/TL.php @@ -19,16 +19,66 @@ namespace danog\MadelineProto\TL; +use danog\MadelineProto\MTProto; + trait TL { + /** + * Highest available secret chat layer version + * + * @var integer + */ public $encrypted_layer = -1; + /** + * Constructors + * + * @var TLConstructor + */ public $constructors; + /** + * Methods + * + * @var TLMethods + */ public $methods; + /** + * TD Constructors + * + * @var TLConstructors + */ public $td_constructors; + /** + * TD Methods + * + * @var TLMethods + */ public $td_methods; + /** + * Descriptions + * + * @var array + */ public $td_descriptions; + /** + * TL callbacks + * + * @var array + */ public $tl_callbacks = []; - + /** + * API instance + * + * @var \danog\MadelineProto\MTProto + */ + private $API; + /** + * Constructor function + * + * @param MTProto $API API instance + */ + public function __construct(MTProto $API) { + $this->API = $API; + } public function constructTL($files, $objects = []) { $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['TL_loading'], \danog\MadelineProto\Logger::VERBOSE); diff --git a/src/danog/MadelineProto/Tools.php b/src/danog/MadelineProto/Tools.php index d742a058..e8c4f21a 100644 --- a/src/danog/MadelineProto/Tools.php +++ b/src/danog/MadelineProto/Tools.php @@ -819,4 +819,22 @@ trait Tools { return Magic::$altervista; } + + + /** + * Accesses a private variable from an object. + * + * @param object $obj Object + * @param string $var Attribute name + * + * @return mixed + * @access public + */ + public static function getVar($obj, string $var) + { + $reflection = new \ReflectionClass(\get_class($obj)); + $prop = $reflection->getProperty($var); + $prop->setAccessible(true); + return $prop->getValue($obj); + } } diff --git a/src/danog/MadelineProto/Wrappers/DialogHandler.php b/src/danog/MadelineProto/Wrappers/DialogHandler.php index 1f2ce010..67afcc7a 100644 --- a/src/danog/MadelineProto/Wrappers/DialogHandler.php +++ b/src/danog/MadelineProto/Wrappers/DialogHandler.php @@ -21,7 +21,14 @@ namespace danog\MadelineProto\Wrappers; trait DialogHandler { - public function getDialogs($force = true) + /** + * Get dialog peers + * + * @param boolean $force Whether to refetch all dialogs ignoring cache + * + * @return \Generator> + */ + public function getDialogs($force = true): \Generator { if ($this->authorization['user']['bot']) { $res = []; @@ -39,7 +46,14 @@ trait DialogHandler return $res; } - public function getFullDialogs($force = true) + /** + * Get full info of all dialogs + * + * @param boolean $force Whether to refetch all dialogs ignoring cache + * + * @return \Generator + */ + public function getFullDialogs($force = true): \Generator { if ($force || !isset($this->dialog_params['offset_date']) || \is_null($this->dialog_params['offset_date']) || !isset($this->dialog_params['offset_id']) || \is_null($this->dialog_params['offset_id']) || !isset($this->dialog_params['offset_peer']) || \is_null($this->dialog_params['offset_peer']) || !isset($this->dialog_params['count']) || \is_null($this->dialog_params['count'])) { $this->dialog_params = ['limit' => 100, 'offset_date' => 0, 'offset_id' => 0, 'offset_peer' => ['_' => 'inputPeerEmpty'], 'count' => 0, 'hash' => 0]; diff --git a/src/danog/MadelineProto/Wrappers/Events.php b/src/danog/MadelineProto/Wrappers/Events.php index 4afb0511..88406dce 100644 --- a/src/danog/MadelineProto/Wrappers/Events.php +++ b/src/danog/MadelineProto/Wrappers/Events.php @@ -19,15 +19,39 @@ namespace danog\MadelineProto\Wrappers; +use EventHandler; + /** - * Manages logging in and out. + * Event handler */ trait Events { + /** + * Event handler class name + * + * @var string + */ public $event_handler; + /** + * Event handler instance + * + * @var \danog\MadelineProto\EventHandler + */ private $event_handler_instance; + /** + * Event handler method list + * + * @var array + */ private $event_handler_methods = []; + /** + * Set event handler + * + * @param string|EventHandler $event_handler Event handler + * + * @return void + */ public function setEventHandler($event_handler) { if (!\class_exists($event_handler) || !\is_subclass_of($event_handler, '\danog\MadelineProto\EventHandler')) { @@ -66,12 +90,26 @@ trait Events } } - public function getEventHandler() + /** + * Get event handler + * + * @return EventHandler + */ + public function getEventHandler(): EventHandler { return $this->event_handler_instance; } - public function eventUpdateHandler($update) + /** + * Event update handler + * + * @param array $update Update + * + * @return void + * + * @internal Internal event handler + */ + public function eventUpdateHandler(array $update) { if (isset($this->event_handler_methods[$update['_']])) { return $this->event_handler_methods[$update['_']]($update); diff --git a/src/danog/MadelineProto/Wrappers/TOS.php b/src/danog/MadelineProto/Wrappers/TOS.php index 7d0b8503..fc043b29 100644 --- a/src/danog/MadelineProto/Wrappers/TOS.php +++ b/src/danog/MadelineProto/Wrappers/TOS.php @@ -24,7 +24,12 @@ namespace danog\MadelineProto\Wrappers; */ trait TOS { - public function checkTos() + /** + * Check for terms of service update + * + * @return \Generator + */ + public function checkTos(): \Generator { if ($this->authorized === self::LOGGED_IN && !$this->authorization['user']['bot']) { if ($this->tos['expires'] < \time()) { @@ -46,7 +51,12 @@ trait TOS } } - public function acceptTos() + /** + * Accept terms of service update + * + * @return \Generator + */ + public function acceptTos(): \Generator { $this->tos['accepted'] = yield $this->methodCallAsyncRead('help.acceptTermsOfService', ['id' => $this->tos['terms_of_service']['id']], ['datacenter' => $this->datacenter->curdc]); if ($this->tos['accepted']) { @@ -56,7 +66,14 @@ trait TOS } } - public function declineTos() + /** + * Decline terms of service update + * + * THIS WILL DELETE YOUR ACCOUNT! + * + * @return \Generator + */ + public function declineTos(): \Generator { yield $this->methodCallAsyncRead('account.deleteAccount', ['reason' => 'Decline ToS update'], ['datacenter' => $this->datacenter->curdc]); yield $this->logout();