diff --git a/src/BigIntegor.php b/src/BigIntegor.php index 077a0d91..ff042918 100644 --- a/src/BigIntegor.php +++ b/src/BigIntegor.php @@ -19,7 +19,7 @@ namespace phpseclib\Math; -if (PHP_MAJOR_VERSION < 7 && !((\class_exists(\Phar::class) && \Phar::running()) || \defined('TESTING_VERSIONS'))) { +if (PHP_MAJOR_VERSION < 7 && !(\class_exists(\Phar::class) && \Phar::running() || \defined('TESTING_VERSIONS'))) { throw new \Exception('MadelineProto requires php 7 to run natively, use phar.madelineproto.xyz to run on PHP 5.6'); } if (\defined('HHVM_VERSION')) { @@ -32,7 +32,6 @@ if (\defined('HHVM_VERSION')) { } } } - class BigIntegor { } diff --git a/src/ReflectionGenerator.php b/src/ReflectionGenerator.php index 6ffb0526..3daffefd 100644 --- a/src/ReflectionGenerator.php +++ b/src/ReflectionGenerator.php @@ -22,7 +22,8 @@ if (!\class_exists('ReflectionGenerator')) { } public function getFunction(): ReflectionFunctionAbstract { - return new ReflectionFunction(function () {}); + return new ReflectionFunction(function () { + }); } public function getThis(): object { diff --git a/src/YieldReturnValue.php b/src/YieldReturnValue.php index 7ec0e9ee..240552f9 100644 --- a/src/YieldReturnValue.php +++ b/src/YieldReturnValue.php @@ -1,4 +1,5 @@ value = $value; } - public function getReturn() { return $this->value; diff --git a/src/danog/MadelineProto/API.php b/src/danog/MadelineProto/API.php index 8492f581..cdbf2e86 100644 --- a/src/danog/MadelineProto/API.php +++ b/src/danog/MadelineProto/API.php @@ -21,7 +21,6 @@ namespace danog\MadelineProto; use Amp\Deferred; use Amp\Promise; - use function Amp\File\exists; use function Amp\File\get; use function Amp\File\put; @@ -67,7 +66,6 @@ class API extends InternalDoc public $asyncAPIPromise; private $oldInstance = false; private $destructing = false; - /** * Magic constructor function. * @@ -94,7 +92,6 @@ class API extends InternalDoc } } } - /** * Async constructor function. * @@ -108,29 +105,25 @@ class API extends InternalDoc { if (\is_string($params)) { Logger::constructorFromSettings($settings); - $realpaths = Serialization::realpaths($params); $this->session = $realpaths['file']; - if (yield exists($realpaths['file'])) { Logger::log('Waiting for shared lock of serialization lockfile...'); $unlock = yield Tools::flock($realpaths['lockfile'], LOCK_SH); Logger::log('Shared lock acquired, deserializing...'); - try { $tounserialize = yield get($realpaths['file']); } finally { $unlock(); } \danog\MadelineProto\Magic::classExists(); - try { $unserialized = \unserialize($tounserialize); } catch (\danog\MadelineProto\Bug74586Exception $e) { \class_exists('\\Volatile'); $tounserialize = \str_replace('O:26:"danog\\MadelineProto\\Button":', 'O:35:"danog\\MadelineProto\\TL\\Types\\Button":', $tounserialize); foreach (['RSA', 'TL\\TLMethods', 'TL\\TLConstructors', 'MTProto', 'API', 'DataCenter', 'Connection', 'TL\\Types\\Button', 'TL\\Types\\Bytes', 'APIFactory'] as $class) { - \class_exists('\\danog\\MadelineProto\\'.$class); + \class_exists('\\danog\\MadelineProto\\' . $class); } $unserialized = \danog\Serialization::unserialize($tounserialize); } catch (\danog\MadelineProto\Exception $e) { @@ -142,7 +135,7 @@ class API extends InternalDoc } \class_exists('\\Volatile'); foreach (['RSA', 'TL\\TLMethods', 'TL\\TLConstructors', 'MTProto', 'API', 'DataCenter', 'Connection', 'TL\\Types\\Button', 'TL\\Types\\Bytes', 'APIFactory'] as $class) { - \class_exists('\\danog\\MadelineProto\\'.$class); + \class_exists('\\danog\\MadelineProto\\' . $class); } $changed = false; if (\strpos($tounserialize, 'O:26:"danog\\MadelineProto\\Button":') !== false) { @@ -165,12 +158,10 @@ class API extends InternalDoc $tounserialize = \str_replace('C:26:"phpseclib3\\Math\\BigInteger"', 'C:24:"tgseclib\\Math\\BigInteger"', $tounserialize); $changed = true; } - Logger::log((string) $e, Logger::ERROR); if (!$changed) { throw $e; } - try { $unserialized = \danog\Serialization::unserialize($tounserialize); } catch (\Throwable $e) { @@ -189,7 +180,6 @@ class API extends InternalDoc $this->web_api_template = $unserialized->web_api_template; $this->my_telegram_org_wrapper = $unserialized->my_telegram_org_wrapper; $this->getting_api_id = $unserialized->getting_api_id; - if (isset($unserialized->API)) { $this->API = $unserialized->API; $this->APIFactory(); @@ -208,7 +198,6 @@ class API extends InternalDoc $params = $settings; } Logger::constructorFromSettings($settings); - if (!isset($params['app_info']['api_id']) || !$params['app_info']['api_id']) { $app = yield $this->APIStart($params); $params['app_info']['api_id'] = $app['api_id']; @@ -226,7 +215,6 @@ class API extends InternalDoc //\danog\MadelineProto\Logger::log('Pong: '.$pong['ping_id'], Logger::ULTRA_VERBOSE); \danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['madelineproto_ready'], Logger::NOTICE); } - /** * Enable or disable async. * @@ -237,14 +225,12 @@ class API extends InternalDoc public function async(bool $async): void { $this->async = $async; - if ($this->API) { - if ($this->API->event_handler && \class_exists($this->API->event_handler) && \is_subclass_of($this->API->event_handler, '\danog\MadelineProto\EventHandler')) { + if ($this->API->event_handler && \class_exists($this->API->event_handler) && \is_subclass_of($this->API->event_handler, '\\danog\\MadelineProto\\EventHandler')) { $this->API->setEventHandler($this->API->event_handler); } } } - /** * Destruct function. * @@ -270,7 +256,6 @@ class API extends InternalDoc } //restore_error_handler(); } - /** * Sleep function. * @@ -282,8 +267,6 @@ class API extends InternalDoc { return ['API', 'web_api_template', 'getting_api_id', 'my_telegram_org_wrapper']; } - - /** * Custom fast getSelf. * @@ -295,7 +278,6 @@ class API extends InternalDoc { return isset($this->API) && isset($this->API->authorization['user']) ? $this->API->authorization['user'] : false; } - /** * Init API wrapper. * @@ -322,7 +304,6 @@ class API extends InternalDoc $this->methods = []; foreach ($methods as $method) { $actual_method = $method; - if ($method == 'methodCallAsyncRead') { $method = 'methodCall'; } elseif (\stripos($method, 'async') !== false) { @@ -340,14 +321,12 @@ class API extends InternalDoc $this->methods[\strtolower(Tools::fromCamelCase($method))] = $actual_method; } } - $this->API->wrapper = $this; - if ($this->API->event_handler && \class_exists($this->API->event_handler) && \is_subclass_of($this->API->event_handler, '\danog\MadelineProto\EventHandler')) { + if ($this->API->event_handler && \class_exists($this->API->event_handler) && \is_subclass_of($this->API->event_handler, '\\danog\\MadelineProto\\EventHandler')) { $this->API->setEventHandler($this->API->event_handler); } } } - /** * Get full list of MTProto and API methods. * @@ -362,10 +341,8 @@ class API extends InternalDoc foreach ($this->API->methods->by_id as $method) { $methods[] = $method['method']; } - return \array_merge($methods, \get_class_methods($this->API)); } - /** * Serialize session. * @@ -377,12 +354,11 @@ class API extends InternalDoc */ public function serialize(string $filename = ''): Promise { - return Tools::callFork((function () use ($filename) { + return Tools::callFork((function () use ($filename): \Generator { if (empty($filename)) { $filename = $this->session; } //Logger::log(\danog\MadelineProto\Lang::$current_lang['serializing_madelineproto']); - if ($filename == '') { return; } @@ -399,11 +375,8 @@ class API extends InternalDoc $this->serialized = \time(); $realpaths = Serialization::realpaths($filename); //Logger::log('Waiting for exclusive lock of serialization lockfile...'); - $unlock = yield Tools::flock($realpaths['lockfile'], LOCK_EX); - //Logger::log('Lock acquired, serializing'); - try { if (!$this->getting_api_id) { $update_closure = $this->API->settings['updates']['callback']; @@ -425,7 +398,6 @@ class API extends InternalDoc $unlock(); } //Logger::log('Done serializing'); - return $wrote; })()); } diff --git a/src/danog/MadelineProto/Absolute.php b/src/danog/MadelineProto/Absolute.php index 18483329..569eab69 100644 --- a/src/danog/MadelineProto/Absolute.php +++ b/src/danog/MadelineProto/Absolute.php @@ -26,10 +26,9 @@ class Absolute { public static function absolute($file) { - if (($file[0] !== '/') && ($file[1] !== ':') && !\in_array(\substr($file, 0, 4), ['phar', 'http'])) { - $file = Magic::getcwd().'/'.$file; + if ($file[0] !== '/' && $file[1] !== ':' && !\in_array(\substr($file, 0, 4), ['phar', 'http'])) { + $file = Magic::getcwd() . '/' . $file; } - return $file; } } diff --git a/src/danog/MadelineProto/AbstractAPIFactory.php b/src/danog/MadelineProto/AbstractAPIFactory.php index 5aa4cb1c..af18bd49 100644 --- a/src/danog/MadelineProto/AbstractAPIFactory.php +++ b/src/danog/MadelineProto/AbstractAPIFactory.php @@ -61,21 +61,18 @@ abstract class AbstractAPIFactory extends AsyncConstruct * @var Promise */ public $asyncAPIPromise; - /** * Method list. * * @var string[] */ protected $methods = []; - public function __construct($namespace, &$API, &$async) { - $this->namespace = $namespace.'.'; - $this->API = &$API; - $this->async = &$async; + $this->namespace = $namespace . '.'; + $this->API =& $API; + $this->async =& $async; } - /** * Enable or disable async. * @@ -87,7 +84,6 @@ abstract class AbstractAPIFactory extends AsyncConstruct { $this->async = $async; } - /** * Call async wrapper function. * @@ -101,25 +97,21 @@ abstract class AbstractAPIFactory extends AsyncConstruct public function __call(string $name, array $arguments) { $yielded = Tools::call($this->__call_async($name, $arguments)); - $async = $this->lua === false && (\is_array(\end($arguments)) && isset(\end($arguments)['async']) ? \end($arguments)['async'] : ($this->async && $name !== 'loop')); - + $async = $this->lua === false && (\is_array(\end($arguments)) && isset(\end($arguments)['async']) ? \end($arguments)['async'] : $this->async && $name !== 'loop'); if ($async) { return $yielded; } if (!$this->lua) { return Tools::wait($yielded); } - try { $yielded = Tools::wait($yielded); Lua::convertObjects($yielded); - return $yielded; } catch (\Throwable $e) { return ['error_code' => $e->getCode(), 'error' => $e->getMessage()]; } } - /** * Call async wrapper function. * @@ -159,20 +151,17 @@ abstract class AbstractAPIFactory extends AsyncConstruct yield $this->API->initAsynchronously(); $this->API->logger->logger('Finished init asynchronously'); } - $lower_name = \strtolower($name); if ($this->namespace !== '' || !isset($this->methods[$lower_name])) { - $name = $this->namespace.$name; + $name = $this->namespace . $name; $aargs = isset($arguments[1]) && \is_array($arguments[1]) ? $arguments[1] : []; $aargs['apifactory'] = true; $aargs['datacenter'] = $this->API->datacenter->curdc; $args = isset($arguments[0]) && \is_array($arguments[0]) ? $arguments[0] : []; - return yield $this->API->methodCallAsyncRead($name, $args, $aargs); } return yield $this->methods[$lower_name](...$arguments); } - /** * Get attribute. * @@ -189,16 +178,13 @@ abstract class AbstractAPIFactory extends AsyncConstruct } if ($name === 'settings') { $this->API->flushSettings = true; - return $this->API->settings; } if ($name === 'logger') { return $this->API->logger; } - return $this->API->storage[$name]; } - /** * Set an attribute. * @@ -218,13 +204,10 @@ abstract class AbstractAPIFactory extends AsyncConstruct if ($this->API->asyncInitPromise) { $this->API->init(); } - return $this->API->__construct(\array_replace_recursive($this->API->settings, $value)); } - return $this->API->storage[$name] = $value; } - /** * Whether an attribute exists. * @@ -237,10 +220,8 @@ abstract class AbstractAPIFactory extends AsyncConstruct if ($this->asyncAPIPromise) { Tools::wait($this->asyncAPIPromise); } - return isset($this->API->storage[$name]); } - /** * Unset attribute. * diff --git a/src/danog/MadelineProto/AnnotationsBuilder.php b/src/danog/MadelineProto/AnnotationsBuilder.php index 9f83d57a..f682fb7b 100644 --- a/src/danog/MadelineProto/AnnotationsBuilder.php +++ b/src/danog/MadelineProto/AnnotationsBuilder.php @@ -27,7 +27,6 @@ use phpDocumentor\Reflection\DocBlockFactory; class AnnotationsBuilder { use Tools; - public function __construct(Logger $logger, array $settings, string $output, array $reflectionClasses, string $namespace) { $this->reflectionClasses = $reflectionClasses; @@ -43,14 +42,12 @@ class AnnotationsBuilder $this->settings = $settings; $this->output = $output; } - public function mkAnnotations() { \danog\MadelineProto\Logger::log('Generating annotations...', \danog\MadelineProto\Logger::NOTICE); $this->setProperties(); $this->createInternalClasses(); } - /** * Open file of class APIFactory * Insert properties @@ -68,16 +65,15 @@ class AnnotationsBuilder if ($raw_docblock = $property->getDocComment()) { $docblock = $fixture->create($raw_docblock); if ($docblock->hasTag('internal')) { - $content = \str_replace("\n ".$raw_docblock."\n public \$".$property->getName().';', '', $content); + $content = \str_replace("\n " . $raw_docblock . "\n public \$" . $property->getName() . ';', '', $content); } } } foreach ($this->TL->getMethodNamespaces() as $namespace) { - $content = \preg_replace('/(class( \\w+[,]?){0,}\\n{\\n)/', '${1}'." /**\n"." * @internal this is a internal property generated by build_docs.php, don't change manually\n"." *\n"." * @var {$namespace}\n"." */\n"." public \${$namespace};\n", $content); + $content = \preg_replace('/(class( \\w+[,]?){0,}\\n{\\n)/', '${1}' . " /**\n" . " * @internal this is a internal property generated by build_docs.php, don't change manually\n" . " *\n" . " * @var {$namespace}\n" . " */\n" . " public \${$namespace};\n", $content); } \file_put_contents($filename, $content); } - /** * Create internalDoc. * @@ -88,23 +84,19 @@ class AnnotationsBuilder \danog\MadelineProto\Logger::log('Creating internal classes...', \danog\MadelineProto\Logger::NOTICE); $handle = \fopen($this->output, 'w'); \fwrite($handle, "namespace}; class InternalDoc extends APIFactory {}"); - $class = new \ReflectionClass($this->reflectionClasses['API']); $methods = $class->getMethods(\ReflectionMethod::IS_STATIC | \ReflectionMethod::IS_PUBLIC); $ignoreMethods = ['fetchserializableobject']; foreach ($methods as $method) { $ignoreMethods[$method->getName()] = $method->getName(); } - $class = new \ReflectionClass(TLCallback::class); $methods = $class->getMethods(\ReflectionMethod::IS_STATIC | \ReflectionMethod::IS_PUBLIC); foreach ($methods as $method) { $ignoreMethods[$method->getName()] = $method->getName(); } - \fclose($handle); $handle = \fopen($this->output, 'w'); - $internalDoc = []; foreach ($this->TL->getMethods()->by_id as $id => $data) { if (!\strpos($data['method'], '.')) { @@ -115,7 +107,6 @@ class AnnotationsBuilder continue; } $internalDoc[$namespace][$method]['title'] = \str_replace(['](../', '.md'], ['](https://docs.madelineproto.xyz/API_docs/', '.html'], Lang::$current_lang["method_{$data['method']}"] ?? ''); - $type = \str_ireplace(['vector<', '>'], [' of ', '[]'], $data['type']); foreach ($data['params'] as $param) { if (\in_array($param['name'], ['flags', 'random_id', 'random_bytes'])) { @@ -133,31 +124,25 @@ class AnnotationsBuilder $param['type'] = 'Vector t'; $param['subtype'] = 'int'; } - $stype = 'type'; if (isset($param['subtype'])) { $stype = 'subtype'; } - $ptype = $param[$stype]; switch ($ptype) { case 'true': case 'false': $ptype = 'boolean'; } - $ptype = $stype === 'type' ? $ptype : "[$ptype]"; - $opt = ($param['pow'] ?? false) ? 'Optional: ' : ''; - $internalDoc[$namespace][$method]['attr'][$param['name']] = [ - 'type' => $ptype, - 'description' => \str_replace(['](../', '.md'], ['](https://docs.madelineproto.xyz/API_docs/', '.html'], $opt.(Lang::$current_lang["method_{$data['method']}_param_{$param['name']}_type_{$param['type']}"] ?? '')) - ]; + $ptype = $stype === 'type' ? $ptype : "[{$ptype}]"; + $opt = $param['pow'] ?? false ? 'Optional: ' : ''; + $internalDoc[$namespace][$method]['attr'][$param['name']] = ['type' => $ptype, 'description' => \str_replace(['](../', '.md'], ['](https://docs.madelineproto.xyz/API_docs/', '.html'], $opt . (Lang::$current_lang["method_{$data['method']}_param_{$param['name']}_type_{$param['type']}"] ?? ''))]; } if ($type === 'Bool') { $type = \strtolower($type); } $internalDoc[$namespace][$method]['return'] = $type; } - $class = new \ReflectionClass($this->reflectionClasses['MTProto']); $methods = $class->getMethods(\ReflectionMethod::IS_STATIC | \ReflectionMethod::IS_PUBLIC); foreach ($methods as $key => $method) { @@ -183,15 +168,13 @@ class AnnotationsBuilder continue; } $static = $method->isStatic(); - if (!$static) { $code = \file_get_contents($method->getFileName()); $code = \implode("\n", \array_slice(\explode("\n", $code), $method->getStartLine(), $method->getEndLine() - $method->getStartLine())); if (\strpos($code, '$this') === false) { - Logger::log("$name should be STATIC!", Logger::FATAL_ERROR); + Logger::log("{$name} should be STATIC!", Logger::FATAL_ERROR); } } - if ($name == 'methodCallAsyncRead') { $name = 'methodCall'; } elseif (\stripos($name, 'async') !== false) { @@ -203,10 +186,8 @@ class AnnotationsBuilder } $name = Tools::fromSnakeCase($name); $name = \str_ireplace(['mtproto', 'api'], ['MTProto', 'API'], $name); - $doc = 'public function '; $doc .= $name; - $doc .= '('; $paramList = ''; $hasVariadic = false; @@ -224,7 +205,7 @@ class AnnotationsBuilder $doc .= $type->getName(); $doc .= ' '; } else { - Logger::log($name.'.'.$param->getName()." has no type!", Logger::WARNING); + Logger::log($name . '.' . $param->getName() . " has no type!", Logger::WARNING); } if ($param->isVariadic()) { $doc .= '...'; @@ -237,19 +218,17 @@ class AnnotationsBuilder if ($param->isOptional() && !$param->isVariadic()) { $doc .= ' = '; if ($param->isDefaultValueConstant()) { - $doc .= '\\'.\str_replace(['NULL', 'self'], ['null', 'danog\\MadelineProto\\MTProto'], $param->getDefaultValueConstantName()); + $doc .= '\\' . \str_replace(['NULL', 'self'], ['null', 'danog\\MadelineProto\\MTProto'], $param->getDefaultValueConstantName()); } else { $doc .= \str_replace('NULL', 'null', \var_export($param->getDefaultValue(), true)); } } $doc .= ', '; - - if ($param->isVariadic()) { $hasVariadic = true; $paramList .= '...'; } - $paramList .= '$'.$param->getName().', '; + $paramList .= '$' . $param->getName() . ', '; } $hasReturnValue = ($type = $method->getReturnType()) && !\in_array($type->getName(), [\Generator::class, Promise::class]); if (!$hasVariadic && !$static && !$hasReturnValue) { @@ -271,35 +250,29 @@ class AnnotationsBuilder $doc .= $type->getName() === 'self' ? $this->reflectionClasses['API'] : $type->getName(); $async = false; } - $finalParamList = $hasVariadic ? "Tools::arr($paramList)" : "[$paramList]"; - + $finalParamList = $hasVariadic ? "Tools::arr({$paramList})" : "[{$paramList}]"; $ret = $type && \in_array($type->getName(), ['self', 'void']) ? '' : 'return'; - $doc .= "\n{\n"; if ($async) { - $doc .= " $ret \$this->__call(__FUNCTION__, $finalParamList);\n"; + $doc .= " {$ret} \$this->__call(__FUNCTION__, {$finalParamList});\n"; } elseif (!$static) { - $doc .= " $ret \$this->API->$name($paramList);\n"; + $doc .= " {$ret} \$this->API->{$name}({$paramList});\n"; } else { - $doc .= " $ret \\".$method->getDeclaringClass()->getName()."::".$name."($paramList);\n"; + $doc .= " {$ret} \\" . $method->getDeclaringClass()->getName() . "::" . $name . "({$paramList});\n"; } if (!$ret && $type->getName() === 'self') { $doc .= " return \$this;\n"; } $doc .= "}\n"; - - if (!$method->getDocComment()) { - Logger::log("$name has no PHPDOC!", Logger::FATAL_ERROR); + Logger::log("{$name} has no PHPDOC!", Logger::FATAL_ERROR); } if (!$type) { - Logger::log("$name has no return type!", Logger::FATAL_ERROR); + Logger::log("{$name} has no return type!", Logger::FATAL_ERROR); } - $internalDoc['InternalDoc'][$name]['method'] = $method->getDocComment() ?? ''; - $internalDoc['InternalDoc'][$name]['method'] .= "\n ".\implode("\n ", \explode("\n", $doc)); + $internalDoc['InternalDoc'][$name]['method'] .= "\n " . \implode("\n ", \explode("\n", $doc)); } - \fwrite($handle, " $param) { - $param['type'] = \str_pad('`'.$param['type'].'`', $longest[0]+2); - $name = \str_pad('**'.$name.'**', $longest[1]+4); + $param['type'] = \str_pad('`' . $param['type'] . '`', $longest[0] + 2); + $name = \str_pad('**' . $name . '**', $longest[1] + 4); $param['description'] = \str_pad($param['description'], $longest[2]); \fwrite($handle, " * * {$param['type']} {$name} - {$param['description']}\n"); } diff --git a/src/danog/MadelineProto/Async/AsyncConstruct.php b/src/danog/MadelineProto/Async/AsyncConstruct.php index 3004628c..a0292071 100644 --- a/src/danog/MadelineProto/Async/AsyncConstruct.php +++ b/src/danog/MadelineProto/Async/AsyncConstruct.php @@ -1,4 +1,5 @@ asyncInitPromise); } } - /** * Asynchronously init. * @@ -59,7 +58,6 @@ class AsyncConstruct yield $this->asyncInitPromise; } } - /** * Set init promise. * diff --git a/src/danog/MadelineProto/Async/AsyncParameters.php b/src/danog/MadelineProto/Async/AsyncParameters.php index 223b508a..fc4fd524 100644 --- a/src/danog/MadelineProto/Async/AsyncParameters.php +++ b/src/danog/MadelineProto/Async/AsyncParameters.php @@ -1,4 +1,5 @@ callable = $callable; } - - /** * Create async parameters. * @@ -54,7 +52,6 @@ class AsyncParameters { $this->callable = $callable; } - /** * Get parameters asynchronously. * @@ -63,7 +60,6 @@ class AsyncParameters public function getParameters() { $callable = $this->callable; - return $callable(); } } diff --git a/src/danog/MadelineProto/CombinedAPI.php b/src/danog/MadelineProto/CombinedAPI.php index 309c1095..77f35ed2 100644 --- a/src/danog/MadelineProto/CombinedAPI.php +++ b/src/danog/MadelineProto/CombinedAPI.php @@ -33,19 +33,15 @@ class CombinedAPI public $serialization_interval = 30; public $serialized = 0; protected $async; - public function __magic_construct($session, $paths = []) { \set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']); \danog\MadelineProto\Magic::classExists(); - $realpaths = Serialization::realpaths($session); $this->session = $realpaths['file']; - foreach ($paths as $path => $settings) { $this->addInstance($path, $settings); } - if (\file_exists($realpaths['file'])) { if (!\file_exists($realpaths['lockfile'])) { \touch($realpaths['lockfile']); @@ -55,7 +51,6 @@ class CombinedAPI \danog\MadelineProto\Logger::log('Waiting for shared lock of serialization lockfile...'); \flock($realpaths['lockfile'], LOCK_SH); \danog\MadelineProto\Logger::log('Shared lock acquired, deserializing...'); - try { $tounserialize = \file_get_contents($realpaths['file']); } finally { @@ -63,14 +58,11 @@ class CombinedAPI \fclose($realpaths['lockfile']); } $deserialized = \unserialize($tounserialize); - /*foreach ($deserialized['instance_paths'] as $path) { - $this->addInstance($path, isset($paths[$path]) ? $paths[$path] : []); - }*/ - + $this->addInstance($path, isset($paths[$path]) ? $paths[$path] : []); + }*/ $this->event_handler = $deserialized['event_handler']; $this->event_handler_instance = $deserialized['event_handler_instance']; - if ($this->event_handler !== null) { $this->setEventHandler($this->event_handler); } @@ -79,29 +71,23 @@ class CombinedAPI $this->addInstance($path, $settings); } } - public function addInstance($path, $settings = []) { if (isset($this->instances[$path]) && isset($this->instance_paths[$path])) { if (isset($this->event_handler_instance)) { $this->event_handler_instance->referenceInstance($path); } - return; } - \danog\MadelineProto\Logger::constructor(3); - \danog\MadelineProto\Logger::log("INSTANTIATING $path..."); + \danog\MadelineProto\Logger::log("INSTANTIATING {$path}..."); $instance = new \danog\MadelineProto\API($path, $settings); - $this->instance_paths[$path] = $path; $this->instances[$path] = $instance; - if (isset($this->event_handler_instance)) { $this->event_handler_instance->referenceInstance($path); } } - public function removeInstance($path) { if (isset($this->instance_paths[$path])) { @@ -110,27 +96,22 @@ class CombinedAPI if (isset($this->instances[$path])) { unset($this->instances[$path]); } - if (isset($this->event_handler_instance)) { $this->event_handler_instance->removeInstance($path); } } - public function __destruct() { if (\danog\MadelineProto\Magic::$has_thread && \is_object(\Thread::getCurrentThread()) || Magic::isFork()) { return; } - $this->serialize(); } - public function serialize($filename = '') { /*foreach ($this->instances as $instance) { - $instance->serialize(); - }*/ - + $instance->serialize(); + }*/ if (\is_null($this->session)) { return; } @@ -147,7 +128,6 @@ class CombinedAPI \danog\MadelineProto\Logger::log('Waiting for exclusive lock of serialization lockfile...'); \flock($realpaths['lockfile'], LOCK_EX); \danog\MadelineProto\Logger::log('Lock acquired, serializing'); - try { $wrote = \file_put_contents($realpaths['tempfile'], \serialize(['event_handler' => $this->event_handler, 'event_handler_instance' => $this->event_handler_instance, 'instance_paths' => $this->instance_paths])); \rename($realpaths['tempfile'], $realpaths['file']); @@ -155,12 +135,9 @@ class CombinedAPI \flock($realpaths['lockfile'], LOCK_UN); \fclose($realpaths['lockfile']); } - $this->serialized = \time(); - return $wrote; } - public $event_handler; private $event_handler_instance; private $event_handler_methods = []; @@ -170,20 +147,17 @@ class CombinedAPI } public function setEventHandler($event_handler) { - if (!\class_exists($event_handler) || !\is_subclass_of($event_handler, '\danog\MadelineProto\CombinedEventHandler')) { + if (!\class_exists($event_handler) || !\is_subclass_of($event_handler, '\\danog\\MadelineProto\\CombinedEventHandler')) { throw new \danog\MadelineProto\Exception('Wrong event handler was defined'); } - $this->event_handler = $event_handler; - - if (!($this->event_handler_instance instanceof $this->event_handler)) { + if (!$this->event_handler_instance instanceof $this->event_handler) { $class_name = $this->event_handler; $this->event_handler_instance = new $class_name($this); } else { $this->event_handler_instance->__construct($this); } $this->event_handler_methods = []; - foreach (\get_class_methods($this->event_handler) as $method) { if ($method === 'onLoop') { $this->loop_callback = [$this->event_handler_instance, 'onLoop']; @@ -199,16 +173,13 @@ class CombinedAPI } } } - public function eventUpdateHandler($update, $instance) { if (isset($this->event_handler_methods[$update['_']])) { return $this->event_handler_methods[$update['_']]($update, $instance); } } - private $loop_callback; - public function async($async) { $this->async = $async; @@ -216,22 +187,18 @@ class CombinedAPI $instance->async($async); } } - public function setLoopCallback($callback) { $this->loop_callback = $callback; } - public function getUpdates($params = []) { } - public function loop($max_forks = 0) { if (\is_callable($max_forks)) { return \danog\MadelineProto\Tools::wait($max_forks()); } - $loops = []; foreach ($this->instances as $path => $instance) { \danog\MadelineProto\Tools::wait($instance->initAsynchronously()); @@ -250,12 +217,10 @@ class CombinedAPI } $loops[] = \danog\MadelineProto\Tools::call($instance->loop(0, ['async' => true])); } - Loop::repeat($this->serialization_interval * 1000, function () { \danog\MadelineProto\Logger::log('Serializing combined event handler'); $this->serialize(); }); - \danog\MadelineProto\Logger::log('Started update loop', \danog\MadelineProto\Logger::NOTICE); \danog\MadelineProto\Tools::wait(all($loops)); } diff --git a/src/danog/MadelineProto/CombinedEventHandler.php b/src/danog/MadelineProto/CombinedEventHandler.php index 1e235edf..dc4dd246 100644 --- a/src/danog/MadelineProto/CombinedEventHandler.php +++ b/src/danog/MadelineProto/CombinedEventHandler.php @@ -22,7 +22,6 @@ namespace danog\MadelineProto; abstract class CombinedEventHandler { private $CombinedAPI; - public function __construct($CombinedAPI) { $this->CombinedAPI = $CombinedAPI; @@ -30,7 +29,6 @@ abstract class CombinedEventHandler $this->referenceInstance($path); } } - final public function __sleep() { $keys = \method_exists($this, '__magic_sleep') ? $this->__magic_sleep() : \get_object_vars($this); @@ -46,15 +44,12 @@ abstract class CombinedEventHandler } } } - return \array_keys($keys); } - final public function referenceInstance($path) { $this->{$path} = $this->CombinedAPI->instances[$path]; } - final public function removeInstance($path) { if (isset($this->{$path})) { diff --git a/src/danog/MadelineProto/Connection.php b/src/danog/MadelineProto/Connection.php index 22a70b41..7d7ca532 100644 --- a/src/danog/MadelineProto/Connection.php +++ b/src/danog/MadelineProto/Connection.php @@ -1,4 +1,5 @@ shared->reading($reading, $this->id); } - /** * Tell the class that we have read a chunk of data from the socket. * @@ -233,7 +225,6 @@ class Connection extends Session { return $this->lastChunk; } - /** * Indicate a received HTTP response. * @@ -270,7 +261,6 @@ class Connection extends Session { return $this->httpReqCount; } - /** * Get connection ID. * @@ -280,7 +270,6 @@ class Connection extends Session { return $this->id; } - /** * Get datacenter concatenated with connection ID. * @@ -290,7 +279,6 @@ class Connection extends Session { return $this->datacenterId; } - /** * Get connection context. * @@ -300,7 +288,6 @@ class Connection extends Session { return $this->ctx; } - /** * Check if is an HTTP connection. * @@ -310,7 +297,6 @@ class Connection extends Session { return \in_array($this->ctx->getStreamName(), [HttpStream::getName(), HttpsStream::getName()]); } - /** * Check if is a media connection. * @@ -320,7 +306,6 @@ class Connection extends Session { return $this->ctx->isMedia(); } - /** * Check if is a CDN connection. * @@ -330,7 +315,6 @@ class Connection extends Session { return $this->ctx->isCDN(); } - /** * Connects to a telegram DC using the specified protocol, proxy and connection parameters. * @@ -342,18 +326,15 @@ class Connection extends Session { $this->ctx = $ctx->getCtx(); $this->datacenter = $ctx->getDc(); - $this->datacenterId = $this->datacenter.'.'.$this->id; + $this->datacenterId = $this->datacenter . '.' . $this->id; $this->API->logger->logger("Connecting to DC {$this->datacenterId}", \danog\MadelineProto\Logger::WARNING); - $ctx->setReadCallback([$this, 'haveRead']); $this->stream = yield $ctx->getStream(); - if ($this->needsReconnect) { $this->needsReconnect = false; } $this->httpReqCount = 0; $this->httpResCount = 0; - if (!isset($this->writer)) { $this->writer = new WriteLoop($this); } @@ -378,7 +359,6 @@ class Connection extends Session unset($this->new_outgoing[$message_id], $this->outgoing_messages[$message_id]); } } - $this->writer->start(); $this->reader->start(); if (!$this->checker->start()) { @@ -389,7 +369,6 @@ class Connection extends Session $this->pinger->start(); } } - /** * Send an MTProto message. * @@ -427,17 +406,13 @@ class Connection extends Session public function sendMessage(array $message, bool $flush = true): \Generator { $deferred = new Deferred(); - if (!isset($message['serialized_body'])) { $body = \is_object($message['body']) ? yield $message['body'] : $message['body']; - $refreshNext = isset($message['refreshNext']) && $message['refreshNext']; //$refreshNext = true; - if ($refreshNext) { $this->API->referenceDatabase->refreshNext(true); } - if ($message['method']) { $body = yield $this->API->getTL()->serializeMethod($message['_'], $body); } else { @@ -450,16 +425,13 @@ class Connection extends Session $message['serialized_body'] = $body; unset($body); } - $message['send_promise'] = $deferred; $this->pending_outgoing[$this->pending_outgoing_key++] = $message; if ($flush && isset($this->writer)) { $this->writer->resume(); } - return $deferred->promise(); } - /** * Flush pending packets. * @@ -500,7 +472,6 @@ class Connection extends Session $this->API = $extra->getExtra(); $this->logger = $this->API->logger; } - /** * Get main instance. * @@ -510,7 +481,6 @@ class Connection extends Session { return $this->API; } - /** * Get shared connection instance. * @@ -520,7 +490,6 @@ class Connection extends Session { return $this->shared; } - /** * Disconnect from DC. * @@ -549,7 +518,6 @@ class Connection extends Session } $this->API->logger->logger("Disconnected from DC {$this->datacenterId}"); } - /** * Reconnect to DC. * @@ -561,7 +529,6 @@ class Connection extends Session $this->disconnect(true); yield $this->API->datacenter->dcConnect($this->ctx->getDc(), $this->id); } - /** * Get name. * diff --git a/src/danog/MadelineProto/ContextConnector.php b/src/danog/MadelineProto/ContextConnector.php index c9bea431..24afa87b 100644 --- a/src/danog/MadelineProto/ContextConnector.php +++ b/src/danog/MadelineProto/ContextConnector.php @@ -37,16 +37,14 @@ class ContextConnector implements Connector $this->fromDns = $fromDns; $this->logger = $dataCenter->getAPI()->getLogger(); } - public function connect(string $uri, ?ConnectContext $ctx = null, ?CancellationToken $token = null): Promise { - return Tools::call((function () use ($uri, $ctx, $token) { - $ctx = $ctx ?? new ConnectContext; - $token = $token ?? new NullCancellationToken; - + return Tools::call((function () use ($uri, $ctx, $token): \Generator { + $ctx = $ctx ?? new ConnectContext(); + $token = $token ?? new NullCancellationToken(); $ctxs = $this->dataCenter->generateContexts(0, $uri, $ctx); if (empty($ctxs)) { - throw new Exception("No contexts for raw connection to URI $uri"); + throw new Exception("No contexts for raw connection to URI {$uri}"); } foreach ($ctxs as $ctx) { /* @var $ctx \danog\MadelineProto\Stream\ConnectionContext */ @@ -55,22 +53,20 @@ class ContextConnector implements Connector $ctx->setCancellationToken($token); $result = yield $ctx->getStream(); $this->logger->logger('OK!', \danog\MadelineProto\Logger::WARNING); - return $result->getSocket(); } catch (\Throwable $e) { if (\MADELINEPROTO_TEST === 'pony') { throw $e; } - $this->logger->logger('Connection failed: '.$e, \danog\MadelineProto\Logger::ERROR); + $this->logger->logger('Connection failed: ' . $e, \danog\MadelineProto\Logger::ERROR); if ($e instanceof MultiReasonException) { foreach ($e->getReasons() as $reason) { - $this->logger->logger('Multireason: '.$reason, \danog\MadelineProto\Logger::ERROR); + $this->logger->logger('Multireason: ' . $reason, \danog\MadelineProto\Logger::ERROR); } } } } - - throw new \danog\MadelineProto\Exception("Could not connect to URI $uri"); + throw new \danog\MadelineProto\Exception("Could not connect to URI {$uri}"); })()); } } diff --git a/src/danog/MadelineProto/Coroutine.php b/src/danog/MadelineProto/Coroutine.php index e63f5d70..ccbbb4fe 100644 --- a/src/danog/MadelineProto/Coroutine.php +++ b/src/danog/MadelineProto/Coroutine.php @@ -1,4 +1,5 @@ generator = $generator; - try { $yielded = $this->generator->current(); while (!$yielded instanceof Promise) { if ($yielded instanceof \YieldReturnValue) { $this->resolve($yielded->getReturn()); $this->generator->next(); - return; } if (!$this->generator->valid()) { @@ -83,7 +80,6 @@ final class Coroutine implements Promise, \ArrayAccess } else { $this->resolve(null); } - return; } if ($yielded instanceof \Generator) { @@ -97,7 +93,6 @@ final class Coroutine implements Promise, \ArrayAccess } } catch (\Throwable $exception) { $this->fail($exception); - return; } /* @@ -109,10 +104,8 @@ final class Coroutine implements Promise, \ArrayAccess $this->value = $value; if (!$this->immediate) { $this->immediate = true; - return; } - try { do { if ($this->exception) { @@ -127,10 +120,8 @@ final class Coroutine implements Promise, \ArrayAccess $this->resolve($yielded->getReturn()); $this->onResolve = null; $this->generator->next(); - return; } - if (!$this->generator->valid()) { if (PHP_MAJOR_VERSION >= 7) { $this->resolve($this->generator->getReturn()); @@ -138,7 +129,6 @@ final class Coroutine implements Promise, \ArrayAccess $this->resolve(null); } $this->onResolve = null; - return; } if ($yielded instanceof \Generator) { @@ -164,20 +154,19 @@ final class Coroutine implements Promise, \ArrayAccess }; $yielded->onResolve($this->onResolve); } - /** - * Throw exception into the generator + * Throw exception into the generator. * * @param \Throwable $reason Exception - * + * * @internal - * + * * @return void */ public function throw(\Throwable $reason) { if (!isset($reason->yieldedFrames)) { - if (method_exists($reason, 'updateTLTrace')) { + if (\method_exists($reason, 'updateTLTrace')) { $reason->updateTLTrace($this->getTrace()); } else { $reason->yieldedFrames = $this->getTrace(); @@ -185,7 +174,6 @@ final class Coroutine implements Promise, \ArrayAccess } $this->generator->throw($reason); } - /** * @param \Throwable $reason Failure reason. */ @@ -193,7 +181,6 @@ final class Coroutine implements Promise, \ArrayAccess { $this->resolve(new Failure($reason)); } - public function offsetExists($offset): bool { throw new Exception('Not supported!'); @@ -207,14 +194,14 @@ final class Coroutine implements Promise, \ArrayAccess */ public function offsetGet($offset) { - return Tools::call((function () use ($offset) { + return Tools::call((function () use ($offset): \Generator { $result = yield $this; return $result[$offset]; })()); } public function offsetSet($offset, $value) { - return Tools::call((function () use ($offset, $value) { + return Tools::call((function () use ($offset, $value): \Generator { $result = yield $this; if ($offset === null) { return $result[] = $value; @@ -224,12 +211,11 @@ final class Coroutine implements Promise, \ArrayAccess } public function offsetUnset($offset) { - return Tools::call((function () use ($offset) { + return Tools::call((function () use ($offset): \Generator { $result = yield $this; unset($result[$offset]); })()); } - /** * Get an attribute asynchronously. * @@ -239,19 +225,18 @@ final class Coroutine implements Promise, \ArrayAccess */ public function __get(string $offset) { - return Tools::call((function () use ($offset) { + return Tools::call((function () use ($offset): \Generator { $result = yield $this; return $result->{$offset}; })()); } public function __call(string $name, array $arguments) { - return Tools::call((function () use ($name, $arguments) { + return Tools::call((function () use ($name, $arguments): \Generator { $result = yield $this; return $result->{$name}($arguments); })()); } - /** * Get current stack trace for running coroutine. * @@ -263,13 +248,7 @@ final class Coroutine implements Promise, \ArrayAccess try { $reflector = new ReflectionGenerator($this->generator); $frames = $reflector->getTrace(); - $frames []= \array_merge( - $this->parentCoroutine ? $this->parentCoroutine->getFrame() : [], - [ - 'function' => $reflector->getFunction()->getName(), - 'args' => [] - ] - ); + $frames[] = \array_merge($this->parentCoroutine ? $this->parentCoroutine->getFrame() : [], ['function' => $reflector->getFunction()->getName(), 'args' => []]); } catch (\Throwable $e) { } if ($this->parentCoroutine) { @@ -277,9 +256,8 @@ final class Coroutine implements Promise, \ArrayAccess } return $frames; } - /** - * Get current execution frame + * Get current execution frame. * * @return array */ @@ -287,10 +265,7 @@ final class Coroutine implements Promise, \ArrayAccess { try { $reflector = new ReflectionGenerator($this->generator); - return [ - 'file' => $reflector->getExecutingFile(), - 'line' => $reflector->getExecutingLine(), - ]; + return ['file' => $reflector->getExecutingFile(), 'line' => $reflector->getExecutingLine()]; } catch (\Throwable $e) { } return []; diff --git a/src/danog/MadelineProto/DataCenter.php b/src/danog/MadelineProto/DataCenter.php index 36d20934..e3999f01 100644 --- a/src/danog/MadelineProto/DataCenter.php +++ b/src/danog/MadelineProto/DataCenter.php @@ -114,12 +114,10 @@ class DataCenter * @var \Amp\Http\Client\Cookie\CookieJar */ private $CookieJar; - public function __sleep() { return ['sockets', 'curdc', 'dclist', 'settings']; } - public function __wakeup() { $array = []; @@ -136,7 +134,6 @@ class DataCenter } $this->setDataCenterConnections($array); } - /** * Set auth key information from saved auth array. * @@ -147,7 +144,7 @@ class DataCenter public function setDataCenterConnections(array $saved) { foreach ($saved as $id => $data) { - $connection = $this->sockets[$id] = new DataCenterConnection; + $connection = $this->sockets[$id] = new DataCenterConnection(); if (isset($data['permAuthKey'])) { $connection->setPermAuthKey(new PermAuthKey($data['permAuthKey'])); } @@ -187,12 +184,11 @@ class DataCenter public function __magic_construct($API, array $dclist, array $settings, bool $reconnectAll = true, CookieJar $jar = null) { $this->API = $API; - $changed = []; $changedSettings = $this->settings !== $settings; if (!$reconnectAll) { $changed = []; - $test = ($API->getCachedConfig()['test_mode'] ?? false) ? 'test' : 'main'; + $test = $API->getCachedConfig()['test_mode'] ?? false ? 'test' : 'main'; foreach ($dclist[$test] as $ipv6 => $dcs) { foreach ($dcs as $id => $dc) { if ($dc !== ($this->dclist[$test][$ipv6][$id] ?? [])) { @@ -201,7 +197,6 @@ class DataCenter } } } - $this->dclist = $dclist; $this->settings = $settings; foreach ($this->sockets as $key => $socket) { @@ -217,96 +212,57 @@ class DataCenter unset($this->sockets[$key]); } } - if ($reconnectAll || $changedSettings || !$this->CookieJar) { - $this->CookieJar = $jar ?? new InMemoryCookieJar; - $this->HTTPClient = (new HttpClientBuilder) - ->interceptNetwork(new CookieInterceptor($this->CookieJar)) - ->usingPool(new UnlimitedConnectionPool(new DefaultConnectionFactory(new ContextConnector($this)))) - ->build(); - - $DoHHTTPClient = (new HttpClientBuilder) - ->interceptNetwork(new CookieInterceptor($this->CookieJar)) - ->usingPool(new UnlimitedConnectionPool(new DefaultConnectionFactory(new ContextConnector($this, true)))) - ->build(); - - $DoHConfig = new DoHConfig( - [ - new Nameserver('https://mozilla.cloudflare-dns.com/dns-query'), - new Nameserver('https://dns.google/resolve'), - ], - $DoHHTTPClient - ); - $nonProxiedDoHConfig = new DoHConfig( - [ - new Nameserver('https://mozilla.cloudflare-dns.com/dns-query'), - new Nameserver('https://dns.google/resolve'), - ] - ); - $this->DoHClient = Magic::$altervista || Magic::$zerowebhost ? - new Rfc1035StubResolver() : - new Rfc8484StubResolver($DoHConfig); - - $this->nonProxiedDoHClient = Magic::$altervista || Magic::$zerowebhost ? - new Rfc1035StubResolver() : - new Rfc8484StubResolver($nonProxiedDoHConfig); + $this->CookieJar = $jar ?? new InMemoryCookieJar(); + $this->HTTPClient = (new HttpClientBuilder())->interceptNetwork(new CookieInterceptor($this->CookieJar))->usingPool(new UnlimitedConnectionPool(new DefaultConnectionFactory(new ContextConnector($this))))->build(); + $DoHHTTPClient = (new HttpClientBuilder())->interceptNetwork(new CookieInterceptor($this->CookieJar))->usingPool(new UnlimitedConnectionPool(new DefaultConnectionFactory(new ContextConnector($this, true))))->build(); + $DoHConfig = new DoHConfig([new Nameserver('https://mozilla.cloudflare-dns.com/dns-query'), new Nameserver('https://dns.google/resolve')], $DoHHTTPClient); + $nonProxiedDoHConfig = new DoHConfig([new Nameserver('https://mozilla.cloudflare-dns.com/dns-query'), new Nameserver('https://dns.google/resolve')]); + $this->DoHClient = Magic::$altervista || Magic::$zerowebhost ? new Rfc1035StubResolver() : new Rfc8484StubResolver($DoHConfig); + $this->nonProxiedDoHClient = Magic::$altervista || Magic::$zerowebhost ? new Rfc1035StubResolver() : new Rfc8484StubResolver($nonProxiedDoHConfig); } } - public function dcConnect(string $dc_number, int $id = -1): \Generator { - $old = isset($this->sockets[$dc_number]) && ( - $this->sockets[$dc_number]->shouldReconnect() || - ( - $id !== -1 - && $this->sockets[$dc_number]->hasConnection($id) - && $this->sockets[$dc_number]->getConnection($id)->shouldReconnect() - ) - ); + $old = isset($this->sockets[$dc_number]) && ($this->sockets[$dc_number]->shouldReconnect() || $id !== -1 && $this->sockets[$dc_number]->hasConnection($id) && $this->sockets[$dc_number]->getConnection($id)->shouldReconnect()); if (isset($this->sockets[$dc_number]) && !$old) { - $this->API->logger("Not reconnecting to DC $dc_number ($id)"); + $this->API->logger("Not reconnecting to DC {$dc_number} ({$id})"); return false; } $ctxs = $this->generateContexts($dc_number); - if (empty($ctxs)) { return false; } foreach ($ctxs as $ctx) { try { if ($old) { - $this->API->logger->logger("Reconnecting to DC $dc_number ($id) from existing", \danog\MadelineProto\Logger::WARNING); + $this->API->logger->logger("Reconnecting to DC {$dc_number} ({$id}) from existing", \danog\MadelineProto\Logger::WARNING); $this->sockets[$dc_number]->setExtra($this->API); yield $this->sockets[$dc_number]->connect($ctx, $id); } else { - $this->API->logger->logger("Connecting to DC $dc_number from scratch", \danog\MadelineProto\Logger::WARNING); + $this->API->logger->logger("Connecting to DC {$dc_number} from scratch", \danog\MadelineProto\Logger::WARNING); $this->sockets[$dc_number] = new DataCenterConnection(); $this->sockets[$dc_number]->setExtra($this->API); yield $this->sockets[$dc_number]->connect($ctx); } $this->API->logger->logger('OK!', \danog\MadelineProto\Logger::WARNING); - return true; } catch (\Throwable $e) { if (\MADELINEPROTO_TEST === 'pony') { throw $e; } - $this->API->logger->logger('Connection failed: '.$e->getMessage(), \danog\MadelineProto\Logger::ERROR); + $this->API->logger->logger('Connection failed: ' . $e->getMessage(), \danog\MadelineProto\Logger::ERROR); } } - - throw new \danog\MadelineProto\Exception("Could not connect to DC $dc_number"); + throw new \danog\MadelineProto\Exception("Could not connect to DC {$dc_number}"); } - public function generateContexts($dc_number = 0, string $uri = '', ConnectContext $context = null) { $ctxs = []; $combos = []; - $dc_config_number = isset($this->settings[$dc_number]) ? $dc_number : 'all'; $test = $this->settings[$dc_config_number]['test_mode'] ? 'test' : 'main'; $ipv6 = $this->settings[$dc_config_number]['ipv6'] ? 'ipv6' : 'ipv4'; - switch ($this->settings[$dc_config_number]['protocol']) { case 'abridged': case 'tcp_abridged': @@ -319,7 +275,7 @@ class DataCenter case 'obfuscated2': $this->settings[$dc_config_number]['protocol'] = 'tcp_intermediate_padded'; $this->settings[$dc_config_number]['obfuscated'] = true; - // no break + // no break case 'intermediate_padded': case 'tcp_intermediate_padded': $default = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []], [IntermediatePaddedStream::getName(), []]]; @@ -359,13 +315,11 @@ class DataCenter $default = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []]]; } $combos[] = $default; - if (!isset($this->settings[$dc_config_number]['do_not_retry'])) { - if ((isset($this->dclist[$test][$ipv6][$dc_number]['tcpo_only']) && $this->dclist[$test][$ipv6][$dc_number]['tcpo_only']) || isset($this->dclist[$test][$ipv6][$dc_number]['secret'])) { + if (isset($this->dclist[$test][$ipv6][$dc_number]['tcpo_only']) && $this->dclist[$test][$ipv6][$dc_number]['tcpo_only'] || isset($this->dclist[$test][$ipv6][$dc_number]['secret'])) { $extra = isset($this->dclist[$test][$ipv6][$dc_number]['secret']) ? ['secret' => $this->dclist[$test][$ipv6][$dc_number]['secret']] : []; $combos[] = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []], [ObfuscatedStream::getName(), $extra], [IntermediatePaddedStream::getName(), []]]; } - if (\is_iterable($this->settings[$dc_config_number]['proxy'])) { $proxies = $this->settings[$dc_config_number]['proxy']; $proxy_extras = $this->settings[$dc_config_number]['proxy_extra']; @@ -423,12 +377,10 @@ class DataCenter $combo = \array_merge($first, $second); } } - \array_unshift($combos, $combo); //unset($combos[$k]); } } - if ($dc_number) { $combos[] = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []], [HttpsStream::getName(), []]]; } @@ -436,19 +388,13 @@ class DataCenter } /* @var $context \Amp\ConnectContext */ $context = $context ?? (new ConnectContext())->withMaxAttempts(1)->withConnectTimeout(1000 * $this->settings[$dc_config_number]['timeout']); - foreach ($combos as $combo) { $ipv6 = [$this->settings[$dc_config_number]['ipv6'] ? 'ipv6' : 'ipv4', $this->settings[$dc_config_number]['ipv6'] ? 'ipv4' : 'ipv6']; - foreach ($ipv6 as $ipv6) { // This is only for non-MTProto connections if (!$dc_number) { /* @var $ctx \danog\MadelineProto\Stream\ConnectionContext */ - $ctx = (new ConnectionContext()) - ->setSocketContext($context) - ->setUri($uri) - ->setIpv6($ipv6 === 'ipv6'); - + $ctx = (new ConnectionContext())->setSocketContext($context)->setUri($uri)->setIpv6($ipv6 === 'ipv6'); foreach ($combo as $stream) { if ($stream[0] === DefaultStream::getName() && $stream[1] === []) { $stream[1] = new DoHConnector($this, $ctx); @@ -458,59 +404,44 @@ class DataCenter $ctxs[] = $ctx; continue; } - // This is only for MTProto connections if (!isset($this->dclist[$test][$ipv6][$dc_number]['ip_address'])) { continue; } - $address = $this->dclist[$test][$ipv6][$dc_number]['ip_address']; $port = $this->dclist[$test][$ipv6][$dc_number]['port']; - foreach (\array_unique([$port, 443, 80, 88, 5222]) as $port) { $stream = \end($combo)[0]; - if ($stream === HttpsStream::getName()) { - $subdomain = $this->dclist['ssl_subdomains'][\preg_replace('/\D+/', '', $dc_number)]; + $subdomain = $this->dclist['ssl_subdomains'][\preg_replace('/\\D+/', '', $dc_number)]; if (\strpos($dc_number, '_media') !== false) { $subdomain .= '-1'; } $path = $this->settings[$dc_config_number]['test_mode'] ? 'apiw_test1' : 'apiw1'; - - $uri = 'tcp://'.$subdomain.'.web.telegram.org:'.$port.'/'.$path; + $uri = 'tcp://' . $subdomain . '.web.telegram.org:' . $port . '/' . $path; } elseif ($stream === HttpStream::getName()) { - $uri = 'tcp://'.$address.':'.$port.'/api'; + $uri = 'tcp://' . $address . ':' . $port . '/api'; } else { - $uri = 'tcp://'.$address.':'.$port; + $uri = 'tcp://' . $address . ':' . $port; } - if ($combo[1][0] === WssStream::getName()) { - $subdomain = $this->dclist['ssl_subdomains'][\preg_replace('/\D+/', '', $dc_number)]; + $subdomain = $this->dclist['ssl_subdomains'][\preg_replace('/\\D+/', '', $dc_number)]; if (\strpos($dc_number, '_media') !== false) { $subdomain .= '-1'; } $path = $this->settings[$dc_config_number]['test_mode'] ? 'apiws_test' : 'apiws'; - - $uri = 'tcp://'.$subdomain.'.web.telegram.org:'.$port.'/'.$path; + $uri = 'tcp://' . $subdomain . '.web.telegram.org:' . $port . '/' . $path; } elseif ($combo[1][0] === WsStream::getName()) { - $subdomain = $this->dclist['ssl_subdomains'][\preg_replace('/\D+/', '', $dc_number)]; + $subdomain = $this->dclist['ssl_subdomains'][\preg_replace('/\\D+/', '', $dc_number)]; if (\strpos($dc_number, '_media') !== false) { $subdomain .= '-1'; } $path = $this->settings[$dc_config_number]['test_mode'] ? 'apiws_test' : 'apiws'; - //$uri = 'tcp://' . $subdomain . '.web.telegram.org:' . $port . '/' . $path; - $uri = 'tcp://'.$address.':'.$port.'/'.$path; + $uri = 'tcp://' . $address . ':' . $port . '/' . $path; } - /* @var $ctx \danog\MadelineProto\Stream\ConnectionContext */ - $ctx = (new ConnectionContext()) - ->setDc($dc_number) - ->setTest($this->settings[$dc_config_number]['test_mode']) - ->setSocketContext($context) - ->setUri($uri) - ->setIpv6($ipv6 === 'ipv6'); - + $ctx = (new ConnectionContext())->setDc($dc_number)->setTest($this->settings[$dc_config_number]['test_mode'])->setSocketContext($context)->setUri($uri)->setIpv6($ipv6 === 'ipv6'); foreach ($combo as $stream) { if ($stream[0] === DefaultStream::getName() && $stream[1] === []) { $stream[1] = new DoHConnector($this, $ctx); @@ -524,22 +455,17 @@ class DataCenter } } } - - if (isset($this->dclist[$test][$ipv6][$dc_number.'_bk']['ip_address'])) { - $ctxs = \array_merge($ctxs, $this->generateContexts($dc_number.'_bk')); + if (isset($this->dclist[$test][$ipv6][$dc_number . '_bk']['ip_address'])) { + $ctxs = \array_merge($ctxs, $this->generateContexts($dc_number . '_bk')); } - if (empty($ctxs)) { unset($this->sockets[$dc_number]); - - $this->API->logger->logger("No info for DC $dc_number", \danog\MadelineProto\Logger::ERROR); + $this->API->logger->logger("No info for DC {$dc_number}", \danog\MadelineProto\Logger::ERROR); } elseif (\MADELINEPROTO_TEST === 'pony') { return [$ctxs[0]]; } - return $ctxs; } - /** * Get main API. * @@ -549,7 +475,6 @@ class DataCenter { return $this->API; } - /** * Get async HTTP client. * @@ -559,7 +484,6 @@ class DataCenter { return $this->HTTPClient; } - /** * Get async HTTP client cookies. * @@ -587,7 +511,6 @@ class DataCenter { return $this->nonProxiedDoHClient; } - /** * Get contents of file. * @@ -599,7 +522,6 @@ class DataCenter { return yield (yield $this->getHTTPClient()->request(new Request($url)))->getBody()->buffer(); } - /** * Get Connection instance for authorization. * @@ -664,8 +586,6 @@ class DataCenter { return isset($this->sockets[$dc]); } - - /** * Check if connected to datacenter using HTTP. * @@ -677,7 +597,6 @@ class DataCenter { return $this->sockets[$datacenter]->isHttp(); } - /** * Check if connected to datacenter directly using IP address. * @@ -689,7 +608,6 @@ class DataCenter { return $this->sockets[$datacenter]->byIPAddress(); } - /** * Get all DC IDs. * @@ -701,7 +619,6 @@ class DataCenter { $test = $this->settings['all']['test_mode'] ? 'test' : 'main'; $ipv6 = $this->settings['all']['ipv6'] ? 'ipv6' : 'ipv4'; - return $all ? \array_keys((array) $this->dclist[$test][$ipv6]) : \array_keys((array) $this->sockets); } } diff --git a/src/danog/MadelineProto/DataCenterConnection.php b/src/danog/MadelineProto/DataCenterConnection.php index e1389358..9276f66b 100644 --- a/src/danog/MadelineProto/DataCenterConnection.php +++ b/src/danog/MadelineProto/DataCenterConnection.php @@ -1,4 +1,5 @@ */ private $availableConnections = []; - /** * Main API instance. * * @var \danog\MadelineProto\MTProto */ private $API; - /** * Connection context. * * @var ConnectionContext */ private $ctx; - /** * DC ID. * * @var string */ private $datacenter; - /** * Linked DC ID. * * @var string */ private $linked; - /** * Loop to keep weights at sane value. * * @var \danog\MadelineProto\Loop\Generic\PeriodicLoop */ private $robinLoop; - /** * Decrement roundrobin weight by this value if busy reading. * @@ -123,14 +115,12 @@ class DataCenterConnection implements JsonSerializable * @var integer */ private $decWrite = 10; - /** * Backed up messages. * * @var array */ private $backup = []; - /** * Whether this socket has to be reconnected. * @@ -191,7 +181,6 @@ class DataCenterConnection implements JsonSerializable { $this->{$temp ? 'tempAuthKey' : 'permAuthKey'} = $key; } - /** * Get temporary authorization key. * @@ -210,7 +199,6 @@ class DataCenterConnection implements JsonSerializable { return $this->getAuthKey(false); } - /** * Check if has temporary authorization key. * @@ -220,7 +208,6 @@ class DataCenterConnection implements JsonSerializable { return $this->hasAuthKey(true); } - /** * Check if has permanent authorization key. * @@ -230,7 +217,6 @@ class DataCenterConnection implements JsonSerializable { return $this->hasAuthKey(false); } - /** * Set temporary authorization key. * @@ -253,7 +239,6 @@ class DataCenterConnection implements JsonSerializable { return $this->setAuthKey($key, false); } - /** * Bind temporary and permanent auth keys. * @@ -286,7 +271,6 @@ class DataCenterConnection implements JsonSerializable { return $this->hasTempAuthKey() ? $this->getTempAuthKey()->isAuthorized() : false; } - /** * Set the authorized boolean. * @@ -302,7 +286,6 @@ class DataCenterConnection implements JsonSerializable $this->getTempAuthKey()->authorized($authorized); } } - /** * Link permanent authorization info of main DC to media DC. * @@ -313,9 +296,8 @@ class DataCenterConnection implements JsonSerializable public function link(string $dc) { $this->linked = $dc; - $this->permAuthKey = &$this->API->datacenter->getDataCenterConnection($dc)->permAuthKey; + $this->permAuthKey =& $this->API->datacenter->getDataCenterConnection($dc)->permAuthKey; } - /** * Reset MTProto sessions. * @@ -349,7 +331,6 @@ class DataCenterConnection implements JsonSerializable $socket->flush(); } } - /** * Get connection context. * @@ -359,7 +340,6 @@ class DataCenterConnection implements JsonSerializable { return $this->ctx; } - /** * Has connection context? * @@ -369,7 +349,6 @@ class DataCenterConnection implements JsonSerializable { return isset($this->ctx); } - /** * Connect function. * @@ -380,32 +359,26 @@ class DataCenterConnection implements JsonSerializable */ public function connect(ConnectionContext $ctx, int $id = -1): \Generator { - $this->API->logger->logger("Trying shared connection via $ctx ($id)"); - + $this->API->logger->logger("Trying shared connection via {$ctx} ({$id})"); $this->ctx = $ctx->getCtx(); $this->datacenter = $ctx->getDc(); $media = $ctx->isMedia() || $ctx->isCDN(); - $count = $media ? $this->API->settings['connection_settings']['media_socket_count']['min'] : 1; - if ($count > 1) { if (!$this->robinLoop) { $this->robinLoop = new PeriodicLoop($this->API, [$this, 'even'], "robin loop DC {$this->datacenter}", $this->API->settings['connection_settings']['robin_period']); } $this->robinLoop->start(); } - $this->decRead = $media ? self::READ_WEIGHT_MEDIA : self::READ_WEIGHT; $this->decWrite = self::WRITE_WEIGHT; - if ($id === -1 || !isset($this->connections[$id])) { if ($this->connections) { $this->API->logger("Already connected!", Logger::WARNING); return; } - yield $this->connectMore($count); + yield from $this->connectMore($count); yield $this->restoreBackup(); - $this->connectionsPromise = new Success(); if ($this->connectionsDeferred) { $connectionsDeferred = $this->connectionsDeferred; @@ -414,10 +387,9 @@ class DataCenterConnection implements JsonSerializable } } else { $this->availableConnections[$id] = 0; - yield $this->connections[$id]->connect($ctx); + yield from $this->connections[$id]->connect($ctx); } } - /** * Connect to the DC using count more sockets. * @@ -425,21 +397,19 @@ class DataCenterConnection implements JsonSerializable * * @return void */ - private function connectMore(int $count) + private function connectMore(int $count): \Generator { $ctx = $this->ctx->getCtx(); $count += $previousCount = \count($this->connections); for ($x = $previousCount; $x < $count; $x++) { $connection = new Connection(); $connection->setExtra($this, $x); - yield $connection->connect($ctx); - + yield from $connection->connect($ctx); $this->connections[$x] = $connection; $this->availableConnections[$x] = 0; $ctx = $this->ctx->getCtx(); } } - /** * Signal that a connection ID disconnected. * @@ -459,12 +429,10 @@ class DataCenterConnection implements JsonSerializable $list .= $message['_'] ?? '-'; $list .= ', '; } - $this->API->logger->logger("Backed up $list from DC {$this->datacenter}.$id"); + $this->API->logger->logger("Backed up {$list} from DC {$this->datacenter}.{$id}"); $this->backup = \array_merge($this->backup, $backup); - unset($this->connections[$id], $this->availableConnections[$id]); } - /** * Close all connections to DC. * @@ -472,9 +440,8 @@ class DataCenterConnection implements JsonSerializable */ public function disconnect() { - $this->connectionsDeferred = new Deferred; + $this->connectionsDeferred = new Deferred(); $this->connectionsPromise = $this->connectionsDeferred->promise(); - $this->API->logger->logger("Disconnecting from shared DC {$this->datacenter}"); if ($this->robinLoop) { $this->robinLoop->signal(true); @@ -485,12 +452,10 @@ class DataCenterConnection implements JsonSerializable $connection->disconnect(); } $count = \count($this->backup) - $before; - $this->API->logger->logger("Backed up $count, added to $before existing messages) from DC {$this->datacenter}"); - + $this->API->logger->logger("Backed up {$count}, added to {$before} existing messages) from DC {$this->datacenter}"); $this->connections = []; $this->availableConnections = []; } - /** * Reconnect to DC. * @@ -500,9 +465,8 @@ class DataCenterConnection implements JsonSerializable { $this->API->logger->logger("Reconnecting shared DC {$this->datacenter}"); $this->disconnect(); - yield $this->connect($this->ctx); + yield from $this->connect($this->ctx); } - /** * Restore backed up messages. * @@ -513,7 +477,7 @@ class DataCenterConnection implements JsonSerializable $backup = $this->backup; $this->backup = []; $count = \count($backup); - $this->API->logger->logger("Restoring $count messages to DC {$this->datacenter}"); + $this->API->logger->logger("Restoring {$count} messages to DC {$this->datacenter}"); foreach ($backup as $message) { Tools::callFork($this->getConnection()->sendMessage($message, false)); } @@ -528,7 +492,6 @@ class DataCenterConnection implements JsonSerializable { return $this->connections[0]; } - /** * Check if any connection is available. * @@ -548,12 +511,10 @@ class DataCenterConnection implements JsonSerializable public function waitGetConnection(): Promise { if (empty($this->availableConnections)) { - $deferred = new Deferred; - $this->connectionsPromise->onResolve( - function ($e, $v) use ($deferred) { - $deferred->resolve($this->getConnection()); - } - ); + $deferred = new Deferred(); + $this->connectionsPromise->onResolve(function ($e, $v) use ($deferred) { + $deferred->resolve($this->getConnection()); + }); return $deferred->promise(); } return new Success($this->getConnection()); @@ -575,12 +536,10 @@ class DataCenterConnection implements JsonSerializable } $max = \max($this->availableConnections); $key = \array_search($max, $this->availableConnections); - // Decrease to implement round robin $this->availableConnections[$key]--; return $this->connections[$key]; } - /** * Even out round robin values. * @@ -607,7 +566,6 @@ class DataCenterConnection implements JsonSerializable } } } - /** * Indicate that one of the sockets is busy reading. * @@ -632,8 +590,6 @@ class DataCenterConnection implements JsonSerializable { $this->availableConnections[$x] += $writing ? -$this->decWrite : $this->decWrite; } - - /** * Set main instance. * @@ -645,7 +601,6 @@ class DataCenterConnection implements JsonSerializable { $this->API = $API; } - /** * Get main instance. * @@ -655,7 +610,6 @@ class DataCenterConnection implements JsonSerializable { return $this->API; } - /** * Check if is an HTTP connection. * @@ -665,7 +619,6 @@ class DataCenterConnection implements JsonSerializable { return \in_array($this->ctx->getStreamName(), [HttpStream::getName(), HttpsStream::getName()]); } - /** * Check if is connected directly by IP address. * @@ -675,7 +628,6 @@ class DataCenterConnection implements JsonSerializable { return !$this->ctx->hasStreamName(WssStream::getName()) && !$this->ctx->hasStreamName(HttpsStream::getName()); } - /** * Check if is a media connection. * @@ -685,7 +637,6 @@ class DataCenterConnection implements JsonSerializable { return $this->ctx->isMedia(); } - /** * Check if is a CDN connection. * @@ -695,7 +646,6 @@ class DataCenterConnection implements JsonSerializable { return $this->ctx->isCDN(); } - /** * Get DC-specific settings. * @@ -706,7 +656,6 @@ class DataCenterConnection implements JsonSerializable $dc_config_number = isset($this->API->settings['connection_settings'][$this->datacenter]) ? $this->datacenter : 'all'; return $this->API->settings['connection_settings'][$dc_config_number]; } - /** * JSON serialize function. * @@ -714,15 +663,7 @@ class DataCenterConnection implements JsonSerializable */ public function jsonSerialize(): array { - return $this->linked ? - [ - 'linked' => $this->linked, - 'tempAuthKey' => $this->tempAuthKey - ] : - [ - 'permAuthKey' => $this->permAuthKey, - 'tempAuthKey' => $this->tempAuthKey - ]; + return $this->linked ? ['linked' => $this->linked, 'tempAuthKey' => $this->tempAuthKey] : ['permAuthKey' => $this->permAuthKey, 'tempAuthKey' => $this->tempAuthKey]; } /** * Sleep function. diff --git a/src/danog/MadelineProto/DoHConnector.php b/src/danog/MadelineProto/DoHConnector.php index d5037cbe..ceb8c46a 100644 --- a/src/danog/MadelineProto/DoHConnector.php +++ b/src/danog/MadelineProto/DoHConnector.php @@ -31,7 +31,6 @@ use Amp\Socket\ConnectException; use Amp\Socket\Connector; use Amp\Socket\ResourceSocket; use danog\MadelineProto\Stream\ConnectionContext; - use function Amp\Socket\Internal\parseUri; class DoHConnector implements Connector @@ -53,13 +52,11 @@ class DoHConnector implements Connector $this->dataCenter = $dataCenter; $this->ctx = $ctx; } - public function connect(string $uri, ?ConnectContext $socketContext = null, ?CancellationToken $token = null): Promise { - return Tools::call((function () use ($uri, $socketContext, $token) { - $socketContext = $socketContext ?? new ConnectContext; - $token = $token ?? new NullCancellationToken; - + return Tools::call((function () use ($uri, $socketContext, $token): \Generator { + $socketContext = $socketContext ?? new ConnectContext(); + $token = $token ?? new NullCancellationToken(); $attempt = 0; $uris = []; $failures = []; @@ -105,7 +102,6 @@ class DoHConnector implements Connector if ($this->ctx->getIpv6()) { $records = \array_reverse($records); } - foreach ($records as $record) { /** @var Record $record */ if ($record->getType() === Record::AAAA) { @@ -115,34 +111,23 @@ class DoHConnector implements Connector } } } - $flags = \STREAM_CLIENT_CONNECT | \STREAM_CLIENT_ASYNC_CONNECT; $timeout = $socketContext->getConnectTimeout(); foreach ($uris as $builtUri) { try { $streamContext = \stream_context_create($socketContext->withoutTlsContext()->toStreamContextArray()); - if (!$socket = @\stream_socket_client($builtUri, $errno, $errstr, null, $flags, $streamContext)) { - throw new ConnectException(\sprintf( - 'Connection to %s failed: [Error #%d] %s%s', - $uri, - $errno, - $errstr, - $failures ? '; previous attempts: ' . \implode($failures) : '' - ), $errno); + if (!($socket = @\stream_socket_client($builtUri, $errno, $errstr, null, $flags, $streamContext))) { + throw new ConnectException(\sprintf('Connection to %s failed: [Error #%d] %s%s', $uri, $errno, $errstr, $failures ? '; previous attempts: ' . \implode($failures) : ''), $errno); } \stream_set_blocking($socket, false); - $deferred = new Deferred; + $deferred = new Deferred(); $watcher = Loop::onWritable($socket, [$deferred, 'resolve']); $id = $token->subscribe([$deferred, 'fail']); try { yield Promise\timeout($deferred->promise(), $timeout); } catch (TimeoutException $e) { - throw new ConnectException(\sprintf( - 'Connecting to %s failed: timeout exceeded (%d ms)%s', - $uri, - $timeout, - $failures ? '; previous attempts: ' . \implode($failures) : '' - ), 110); // See ETIMEDOUT in http://www.virtsync.com/c-error-codes-include-errno + throw new ConnectException(\sprintf('Connecting to %s failed: timeout exceeded (%d ms)%s', $uri, $timeout, $failures ? '; previous attempts: ' . \implode($failures) : ''), 110); + // See ETIMEDOUT in http://www.virtsync.com/c-error-codes-include-errno } finally { Loop::cancel($watcher); $token->unsubscribe($id); @@ -150,26 +135,21 @@ class DoHConnector implements Connector // The following hack looks like the only way to detect connection refused errors with PHP's stream sockets. if (\stream_socket_get_name($socket, true) === false) { \fclose($socket); - throw new ConnectException(\sprintf( - 'Connection to %s refused%s', - $uri, - $failures ? '; previous attempts: ' . \implode($failures) : '' - ), 111); // See ECONNREFUSED in http://www.virtsync.com/c-error-codes-include-errno + throw new ConnectException(\sprintf('Connection to %s refused%s', $uri, $failures ? '; previous attempts: ' . \implode($failures) : ''), 111); + // See ECONNREFUSED in http://www.virtsync.com/c-error-codes-include-errno } } catch (ConnectException $e) { // Includes only error codes used in this file, as error codes on other OS families might be different. // In fact, this might show a confusing error message on OS families that return 110 or 111 by itself. - $knownReasons = [ - 110 => 'connection timeout', - 111 => 'connection refused', - ]; + $knownReasons = [110 => 'connection timeout', 111 => 'connection refused']; $code = $e->getCode(); - $reason = $knownReasons[$code] ?? ('Error #' . $code); + $reason = $knownReasons[$code] ?? 'Error #' . $code; if (++$attempt === $socketContext->getMaxAttempts()) { break; } $failures[] = "{$uri} ({$reason})"; - continue; // Could not connect to host, try next host in the list. + continue; + // Could not connect to host, try next host in the list. } return ResourceSocket::fromClientSocket($socket, $socketContext->getTlsContext()); } diff --git a/src/danog/MadelineProto/DocsBuilder.php b/src/danog/MadelineProto/DocsBuilder.php index 69d402a3..642984ce 100644 --- a/src/danog/MadelineProto/DocsBuilder.php +++ b/src/danog/MadelineProto/DocsBuilder.php @@ -28,7 +28,6 @@ class DocsBuilder use \danog\MadelineProto\DocsBuilder\Constructors; use Tools; public $td = false; - public function __construct($logger, $settings) { $this->logger = $logger; @@ -50,19 +49,17 @@ class DocsBuilder \chdir($this->settings['output_dir']); $this->index = $settings['readme'] ? 'README.md' : 'index.md'; } - public $types = []; public $any = '*'; - public function mkDocs() { \danog\MadelineProto\Logger::log('Generating documentation index...', \danog\MadelineProto\Logger::NOTICE); \file_put_contents($this->index, '--- -title: '.$this->settings['title'].' -description: '.$this->settings['description'].' +title: ' . $this->settings['title'] . ' +description: ' . $this->settings['description'] . ' image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- -# '.$this->settings['description'].' +# ' . $this->settings['description'] . ' [Back to main documentation](..) @@ -90,14 +87,14 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png //$br = $new_namespace != $last_namespace ? '***

' : ''; $type = \str_replace(['<', '>'], ['_of_', ''], $otype); $type = \preg_replace('/.*_of_/', '', $type); - $index .= '['.\str_replace('_', '\\_', $type).']('.$type.'.md) + $index .= '[' . \str_replace('_', '\\_', $type) . '](' . $type . '.md) '; $constructors = ''; foreach ($keys['constructors'] as $data) { - $predicate = $data['predicate'].(isset($data['layer']) && $data['layer'] !== '' ? '_'.$data['layer'] : ''); + $predicate = $data['predicate'] . (isset($data['layer']) && $data['layer'] !== '' ? '_' . $data['layer'] : ''); $md_predicate = \str_replace('_', '\\_', $predicate); - $constructors .= '['.$md_predicate.'](../constructors/'.$predicate.'.md) + $constructors .= '[' . $md_predicate . '](../constructors/' . $predicate . '.md) '; } @@ -105,26 +102,25 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png foreach ($keys['methods'] as $data) { $name = $data['method']; $md_name = \str_replace(['.', '_'], ['->', '\\_'], $name); - $methods .= '[$MadelineProto->'.$md_name.'](../methods/'.$name.'.md) + $methods .= '[$MadelineProto->' . $md_name . '](../methods/' . $name . '.md) '; } - $description = isset($this->td_descriptions['types'][$otype]) ? $this->td_descriptions['types'][$otype] : 'constructors and methods of type '.$type; + $description = isset($this->td_descriptions['types'][$otype]) ? $this->td_descriptions['types'][$otype] : 'constructors and methods of type ' . $type; $symFile = \str_replace('.', '_', $type); - $redir = $symFile !== $type ? "\nredirect_from: /API_docs/types/$symFile.html" : ''; - + $redir = $symFile !== $type ? "\nredirect_from: /API_docs/types/{$symFile}.html" : ''; $header = '--- -title: '.$type.' -description: constructors and methods of type '.$type.' -image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png'.$redir.' +title: ' . $type . ' +description: constructors and methods of type ' . $type . ' +image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png' . $redir . ' --- -# Type: '.\str_replace('_', '\\_', $type).' +# Type: ' . \str_replace('_', '\\_', $type) . ' [Back to types index](index.md) '; - $header .= isset($this->td_descriptions['types'][$otype]) ? $this->td_descriptions['types'][$otype].PHP_EOL.PHP_EOL : ''; + $header .= isset($this->td_descriptions['types'][$otype]) ? $this->td_descriptions['types'][$otype] . PHP_EOL . PHP_EOL : ''; if (!isset($this->settings['td'])) { if (\in_array($type, ['User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputDialogPeer', 'DialogPeer', 'InputPeer', 'NotifyPeer', 'InputNotifyPeer'])) { $header .= 'You can directly provide the [Update](Update.md) or [Message](Message.md) object here, MadelineProto will automatically extract the destination chat id. @@ -132,23 +128,11 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png'.$redi The following syntaxes can also be used: ``` -$'.$type." = '@username'; // Username +$' . $type . " = '@username'; // Username\n\n\$" . $type . " = 'me'; // The currently logged-in user\n\n\$" . $type . ' = 44700; // bot API id (users) +$' . $type . ' = -492772765; // bot API id (chats) +$' . $type . ' = -10038575794; // bot API id (channels) -\$".$type." = 'me'; // The currently logged-in user - -\$".$type.' = 44700; // bot API id (users) -$'.$type.' = -492772765; // bot API id (chats) -$'.$type.' = -10038575794; // bot API id (channels) - -$'.$type." = 'https://t.me/danogentili'; // t.me URLs -\$".$type." = 'https://t.me/joinchat/asfln1-21fa_'; // t.me invite links - -\$".$type." = 'user#44700'; // tg-cli style id (users) -\$".$type." = 'chat#492772765'; // tg-cli style id (chats) -\$".$type." = 'channel#38575794'; // tg-cli style id (channels) -``` - -A [Chat](Chat.md), a [User](User.md), an [InputPeer](InputPeer.md), an [InputDialogPeer](InputDialogPeer.md), an [InputNotifyPeer](InputNotifyPeer.md), an [InputUser](InputUser.md), an [InputChannel](InputChannel.md), a [Peer](Peer.md), an [DialogPeer](DialogPeer.md), [NotifyPeer](NotifyPeer.md), or a [Chat](Chat.md) object can also be used.\n\n\n"; +$' . $type . " = 'https://t.me/danogentili'; // t.me URLs\n\$" . $type . " = 'https://t.me/joinchat/asfln1-21fa_'; // t.me invite links\n\n\$" . $type . " = 'user#44700'; // tg-cli style id (users)\n\$" . $type . " = 'chat#492772765'; // tg-cli style id (chats)\n\$" . $type . " = 'channel#38575794'; // tg-cli style id (channels)\n```\n\nA [Chat](Chat.md), a [User](User.md), an [InputPeer](InputPeer.md), an [InputDialogPeer](InputDialogPeer.md), an [InputNotifyPeer](InputNotifyPeer.md), an [InputUser](InputUser.md), an [InputChannel](InputChannel.md), a [Peer](Peer.md), an [DialogPeer](DialogPeer.md), [NotifyPeer](NotifyPeer.md), or a [Chat](Chat.md) object can also be used.\n\n\n"; } if (\in_array($type, ['InputEncryptedChat'])) { $header .= 'You can directly provide the [Update](Update.md) or [EncryptedMessage](EncryptedMessage.md) object here, MadelineProto will automatically extract the destination chat id. @@ -156,7 +140,7 @@ A [Chat](Chat.md), a [User](User.md), an [InputPeer](InputPeer.md), an [InputDia The following syntax can also be used: ``` -$'.$type.' = -147286699; // Numeric chat id returned by requestSecretChat, can be positive or negative +$' . $type . ' = -147286699; // Numeric chat id returned by requestSecretChat, can be positive or negative ``` @@ -166,7 +150,7 @@ $'.$type.' = -147286699; // Numeric chat id returned by requestSecretChat, can b $header .= 'The following syntax can also be used: ``` -$'.$type.' = \'filename.mp4\'; // The file path can also be used +$' . $type . ' = \'filename.mp4\'; // The file path can also be used ``` @@ -191,7 +175,7 @@ $'.$type.' = \'filename.mp4\'; // The file path can also be used $header .= 'The following syntax can also be used: ``` -$'.$type.' = 142; // Numeric message ID +$' . $type . ' = 142; // Numeric message ID ``` @@ -203,7 +187,7 @@ $'.$type.' = 142; // Numeric message ID To click these buttons simply run the `click` method: ``` -$result = $'.$type.'->click(); +$result = $' . $type . '->click(); ``` `$result` can be one of the following: @@ -224,12 +208,12 @@ You can also access the properties of the constructor as a normal array, for exa } $constructors = '### Possible values (constructors): -'.$constructors.' +' . $constructors . ' '; $methods = '### Methods that return an object of this type (methods): -'.$methods.' +' . $methods . ' '; if (!isset($this->settings['td'])) { @@ -389,7 +373,7 @@ Easy as pie: ``` $call->storage["pony"] = "fluttershy"; -\danog\MadelineProto\Logger::log($call->storage["pony"]); // fluttershy +\\danog\\MadelineProto\\Logger::log($call->storage["pony"]); // fluttershy ``` Note: when modifying this property, *never* overwrite the previous values. Always either modify the values of the array separately like showed above, or use array_merge. @@ -416,14 +400,14 @@ After modifying it, you must always parse the new configuration with a call to ` '; } } - if (\file_exists('types/'.$type.'.md')) { + if (\file_exists('types/' . $type . '.md')) { \danog\MadelineProto\Logger::log($type); } - \file_put_contents('types/'.$type.'.md', $header.$constructors.$methods); + \file_put_contents('types/' . $type . '.md', $header . $constructors . $methods); $last_namespace = $new_namespace; } \danog\MadelineProto\Logger::log('Generating types index...', \danog\MadelineProto\Logger::NOTICE); - \file_put_contents('types/'.$this->index, '--- + \file_put_contents('types/' . $this->index, '--- title: Types description: List of types image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png @@ -432,7 +416,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png [Back to API documentation index](..) -'.$index); +' . $index); \danog\MadelineProto\Logger::log('Generating additional types...', \danog\MadelineProto\Logger::NOTICE); \file_put_contents('types/string.md', '--- title: string @@ -452,7 +436,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png ## Type: bytes [Back to constructor index](index.md) -An object of type `\danog\MadelineProto\TL\Types\Bytes`. +An object of type `\\danog\\MadelineProto\\TL\\Types\\Bytes`. When casted to string, turns into a string of bytes of variable length, with length smaller than or equal to 16777215. When JSON-serialized, turns into an array of the following format: ``` @@ -604,7 +588,6 @@ Any json-encodable data. '); \danog\MadelineProto\Logger::log('Done!', \danog\MadelineProto\Logger::NOTICE); } - public static $template = 'any) as $unlink) { + foreach (\glob('constructors/' . $this->any) as $unlink) { \unlink($unlink); } if (\file_exists('constructors')) { @@ -42,10 +42,10 @@ trait Constructors } $got[$id] = ''; /* - if (preg_match('/%/', $type)) { - $type = $this->TL->getConstructors($this->td)->findByType(str_replace('%', '', $type))['predicate']; - }*/ - $layer = isset($data['layer']) && $data['layer'] !== '' ? '_'.$data['layer'] : ''; + if (preg_match('/%/', $type)) { + $type = $this->TL->getConstructors($this->td)->findByType(str_replace('%', '', $type))['predicate']; + }*/ + $layer = isset($data['layer']) && $data['layer'] !== '' ? '_' . $data['layer'] : ''; $type = \str_replace(['<', '>'], ['_of_', ''], $data['type']); $php_type = \preg_replace('/.*_of_/', '', $type); $constructor = \str_replace(['<', '>'], ['_of_', ''], $data['predicate']); @@ -74,12 +74,12 @@ trait Constructors if (\substr($param[$type_or_subtype], -1) === '>') { $param[$type_or_subtype] = \substr($param[$type_or_subtype], 0, -1); } - $params .= "'".$param['name']."' => "; - $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]).', '; + $params .= "'" . $param['name'] . "' => "; + $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); - $this->docs_constructors[$constructor] = '[$'.$md_constructor.'](../constructors/'.$php_constructor.$layer.'.md) = \\['.$params.'\\]; + $md_constructor = \str_replace('_', '\\_', $constructor . $layer); + $this->docs_constructors[$constructor] = '[$' . $md_constructor . '](../constructors/' . $php_constructor . $layer . '.md) = \\[' . $params . '\\]; '; $table = empty($data['params']) ? '' : '### Attributes: @@ -88,12 +88,11 @@ trait Constructors |----------|---------------|----------| '; if (!isset($this->TL->getDescriptions()['constructors'][$data['predicate']])) { - $this->addToLang('object_'.$data['predicate']); - if (\danog\MadelineProto\Lang::$lang['en']['object_'.$data['predicate']] !== '') { - $this->TL->getDescriptions()['constructors'][$data['predicate']]['description'] = \danog\MadelineProto\Lang::$lang['en']['object_'.$data['predicate']]; + $this->addToLang('object_' . $data['predicate']); + if (\danog\MadelineProto\Lang::$lang['en']['object_' . $data['predicate']] !== '') { + $this->TL->getDescriptions()['constructors'][$data['predicate']]['description'] = \danog\MadelineProto\Lang::$lang['en']['object_' . $data['predicate']]; } } - if (isset($this->TL->getDescriptions()['constructors'][$data['predicate']]) && !empty($data['params'])) { $table = '### Attributes: @@ -115,7 +114,7 @@ trait Constructors $param['type'] = 'DecryptedMessage'; } if ($type === 'DecryptedMessageMedia' && \in_array($param['name'], ['key', 'iv'])) { - unset(\danog\MadelineProto\Lang::$lang['en']['object_'.$data['predicate'].'_param_'.$param['name'].'_type_'.$param['type']]); + unset(\danog\MadelineProto\Lang::$lang['en']['object_' . $data['predicate'] . '_param_' . $param['name'] . '_type_' . $param['type']]); continue; } $ptype = $param[isset($param['subtype']) ? 'subtype' : 'type']; @@ -139,59 +138,58 @@ trait Constructors } $human_ptype = $ptype; if (\strpos($type, 'Input') === 0 && \in_array($ptype, ['User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputDialogPeer', 'DialogPeer', 'NotifyPeer', 'InputNotifyPeer', 'InputPeer']) && !isset($this->settings['td'])) { - $human_ptype = 'Username, chat ID, Update, Message or '.$ptype; + $human_ptype = 'Username, chat ID, Update, Message or ' . $ptype; } if (\strpos($type, 'Input') === 0 && \in_array($ptype, ['InputMedia', 'InputDocument', 'InputPhoto']) && !isset($this->settings['td'])) { - $human_ptype = 'MessageMedia, Message, Update or '.$ptype; + $human_ptype = 'MessageMedia, Message, Update or ' . $ptype; } if (\in_array($ptype, ['InputMessage']) && !isset($this->settings['td'])) { - $human_ptype = 'Message ID or '.$ptype; + $human_ptype = 'Message ID or ' . $ptype; } if (\in_array($ptype, ['InputEncryptedChat']) && !isset($this->settings['td'])) { - $human_ptype = 'Secret chat ID, Update, EncryptedMessage or '.$ptype; + $human_ptype = 'Secret chat ID, Update, EncryptedMessage or ' . $ptype; } if (\in_array($ptype, ['InputFile']) && !isset($this->settings['td'])) { - $human_ptype = 'File path or '.$ptype; + $human_ptype = 'File path or ' . $ptype; } if (\in_array($ptype, ['InputEncryptedFile']) && !isset($this->settings['td'])) { - $human_ptype = 'File path or '.$ptype; + $human_ptype = 'File path or ' . $ptype; } - $table .= '|'.\str_replace('_', '\\_', $param['name']).'|'.(isset($param['subtype']) ? 'Array of ' : '').'['.\str_replace('_', '\\_', $human_ptype).'](../'.$type_or_bare_type.'/'.$ptype.'.md) | '.(isset($param['pow']) || $this->TL->getConstructors($this->td)->findByPredicate(\lcfirst($param['type']).'Empty') || ($data['type'] === 'InputMedia' && $param['name'] === 'mime_type') || ($data['type'] === 'DocumentAttribute' && \in_array($param['name'], ['w', 'h', 'duration'])) ? 'Optional' : 'Yes').'|'; - + $table .= '|' . \str_replace('_', '\\_', $param['name']) . '|' . (isset($param['subtype']) ? 'Array of ' : '') . '[' . \str_replace('_', '\\_', $human_ptype) . '](../' . $type_or_bare_type . '/' . $ptype . '.md) | ' . (isset($param['pow']) || $this->TL->getConstructors($this->td)->findByPredicate(\lcfirst($param['type']) . 'Empty') || $data['type'] === 'InputMedia' && $param['name'] === 'mime_type' || $data['type'] === 'DocumentAttribute' && \in_array($param['name'], ['w', 'h', 'duration']) ? 'Optional' : 'Yes') . '|'; if (!isset($this->TL->getDescriptions()['constructors'][$data['predicate']]['params'][$param['name']])) { - $this->addToLang('object_'.$data['predicate'].'_param_'.$param['name'].'_type_'.$param['type']); + $this->addToLang('object_' . $data['predicate'] . '_param_' . $param['name'] . '_type_' . $param['type']); if (isset($this->TL->getDescriptions()['constructors'][$data['predicate']]['description'])) { - $this->TL->getDescriptions()['constructors'][$data['predicate']]['params'][$param['name']] = \danog\MadelineProto\Lang::$lang['en']['object_'.$data['predicate'].'_param_'.$param['name'].'_type_'.$param['type']]; + $this->TL->getDescriptions()['constructors'][$data['predicate']]['params'][$param['name']] = \danog\MadelineProto\Lang::$lang['en']['object_' . $data['predicate'] . '_param_' . $param['name'] . '_type_' . $param['type']]; } } if (isset($this->TL->getDescriptions()['constructors'][$data['predicate']]['params'][$param['name']])) { - $table .= $this->TL->getDescriptions()['constructors'][$data['predicate']]['params'][$param['name']].'|'; + $table .= $this->TL->getDescriptions()['constructors'][$data['predicate']]['params'][$param['name']] . '|'; } $table .= PHP_EOL; - $pptype = \in_array($ptype, ['string', 'bytes']) ? "'".$ptype."'" : $ptype; - $ppptype = \in_array($ptype, ['string']) ? '"'.$ptype.'"' : $ptype; - $ppptype = \in_array($ptype, ['bytes']) ? '{"_": "bytes", "bytes":"base64 encoded '.$ptype.'"}' : $ppptype; - $params .= ", '".$param['name']."' => "; - $params .= isset($param['subtype']) ? '['.$pptype.', '.$pptype.']' : $pptype; - $lua_params .= ', '.$param['name'].'='; - $lua_params .= isset($param['subtype']) ? '{'.$pptype.'}' : $pptype; - $pwr_params .= ', "'.$param['name'].'": '.(isset($param['subtype']) ? '['.$ppptype.']' : $ppptype); + $pptype = \in_array($ptype, ['string', 'bytes']) ? "'" . $ptype . "'" : $ptype; + $ppptype = \in_array($ptype, ['string']) ? '"' . $ptype . '"' : $ptype; + $ppptype = \in_array($ptype, ['bytes']) ? '{"_": "bytes", "bytes":"base64 encoded ' . $ptype . '"}' : $ppptype; + $params .= ", '" . $param['name'] . "' => "; + $params .= isset($param['subtype']) ? '[' . $pptype . ', ' . $pptype . ']' : $pptype; + $lua_params .= ', ' . $param['name'] . '='; + $lua_params .= isset($param['subtype']) ? '{' . $pptype . '}' : $pptype; + $pwr_params .= ', "' . $param['name'] . '": ' . (isset($param['subtype']) ? '[' . $ppptype . ']' : $ppptype); if ($param['name'] === 'reply_markup') { $hasreplymarkup = true; } } - $params = "['_' => '".$data['predicate']."'".$params.']'; - $lua_params = "{_='".$data['predicate']."'".$lua_params.'}'; - $pwr_params = '{"_": "'.$data['predicate'].'"'.$pwr_params.'}'; - $description = isset($this->TL->getDescriptions()['constructors'][$data['predicate']]) ? $this->TL->getDescriptions()['constructors'][$data['predicate']]['description'] : $constructor.' attributes, type and example'; - $symFile = \str_replace('.', '_', $constructor.$layer); - $redir = $symFile !== $constructor.$layer ? "\nredirect_from: /API_docs/constructors/$symFile.html" : ''; + $params = "['_' => '" . $data['predicate'] . "'" . $params . ']'; + $lua_params = "{_='" . $data['predicate'] . "'" . $lua_params . '}'; + $pwr_params = '{"_": "' . $data['predicate'] . '"' . $pwr_params . '}'; + $description = isset($this->TL->getDescriptions()['constructors'][$data['predicate']]) ? $this->TL->getDescriptions()['constructors'][$data['predicate']]['description'] : $constructor . ' attributes, type and example'; + $symFile = \str_replace('.', '_', $constructor . $layer); + $redir = $symFile !== $constructor . $layer ? "\nredirect_from: /API_docs/constructors/{$symFile}.html" : ''; $header = '--- -title: '.$data['predicate'].' -description: '.$description.' -image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png'.$redir.' +title: ' . $data['predicate'] . ' +description: ' . $description . ' +image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png' . $redir . ' --- -# Constructor: '.\str_replace('_', '\\_', $data['predicate'].$layer).' +# Constructor: ' . \str_replace('_', '\\_', $data['predicate'] . $layer) . ' [Back to constructors index](index.md) @@ -202,9 +200,9 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png'.$redi '; if (isset($this->TL->getDescriptions()['constructors'][$data['predicate']])) { - $header .= $this->TL->getDescriptions()['constructors'][$data['predicate']]['description'].PHP_EOL.PHP_EOL; + $header .= $this->TL->getDescriptions()['constructors'][$data['predicate']]['description'] . PHP_EOL . PHP_EOL; } - $type = '### Type: ['.\str_replace('_', '\\_', $php_type).'](../types/'.$php_type.'.md) + $type = '### Type: [' . \str_replace('_', '\\_', $php_type) . '](../types/' . $php_type . '.md) '; @@ -213,14 +211,14 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png'.$redi $example = '### Example: ```php -$'.$constructor.$layer.' = '.$params.'; +$' . $constructor . $layer . ' = ' . $params . '; ``` Or, if you\'re into Lua: ```lua -'.$constructor.$layer.'='.$lua_params.' +' . $constructor . $layer . '=' . $lua_params . ' ``` @@ -270,7 +268,7 @@ MadelineProto supports all html entities supported by [html_entity_decode](http: '; } } - \file_put_contents('constructors/'.$constructor.$layer.'.md', $header.$table.$type.$example); + \file_put_contents('constructors/' . $constructor . $layer . '.md', $header . $table . $type . $example); } $this->logger->logger('Generating constructors index...', \danog\MadelineProto\Logger::NOTICE); \ksort($this->docs_constructors); @@ -279,10 +277,10 @@ MadelineProto supports all html entities supported by [html_entity_decode](http: $new_namespace = \preg_replace('/_.*/', '', $constructor); $br = $new_namespace != $last_namespace ? '***

' : ''; - $value = $br.$value; + $value = $br . $value; $last_namespace = $new_namespace; } - \file_put_contents('constructors/'.$this->index, '--- + \file_put_contents('constructors/' . $this->index, '--- title: Constructors description: List of constructors image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png @@ -290,6 +288,6 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png # Constructors [Back to API documentation index](..) -'.\implode('', $this->docs_constructors)); +' . \implode('', $this->docs_constructors)); } } diff --git a/src/danog/MadelineProto/DocsBuilder/Methods.php b/src/danog/MadelineProto/DocsBuilder/Methods.php index 129d2311..d5ce6dd7 100644 --- a/src/danog/MadelineProto/DocsBuilder/Methods.php +++ b/src/danog/MadelineProto/DocsBuilder/Methods.php @@ -44,7 +44,7 @@ trait Methods } } } - foreach (\glob('methods/'.$this->any) as $unlink) { + foreach (\glob('methods/' . $this->any) as $unlink) { \unlink($unlink); } if (\file_exists('methods')) { @@ -80,31 +80,28 @@ trait Methods $type_or_subtype = isset($param['subtype']) ? 'subtype' : 'type'; $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] = '['.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]).', '; + $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']])) { - $this->addToLang('method_'.$data['method']); - - if (\danog\MadelineProto\Lang::$lang['en']['method_'.$data['method']] !== '') { - $this->td_descriptions['methods'][$data['method']]['description'] = \danog\MadelineProto\Lang::$lang['en']['method_'.$data['method']]; + $this->addToLang('method_' . $data['method']); + if (\danog\MadelineProto\Lang::$lang['en']['method_' . $data['method']] !== '') { + $this->td_descriptions['methods'][$data['method']]['description'] = \danog\MadelineProto\Lang::$lang['en']['method_' . $data['method']]; } } - $md_method = '['.$php_method.']('.$method.'.md)'; - $this->docs_methods[$method] = '$MadelineProto->'.$md_method.'(\\['.$params.'\\]) === [$'.\str_replace('_', '\\_', $type).'](../types/'.$php_type.'.md) + $md_method = '[' . $php_method . '](' . $method . '.md)'; + $this->docs_methods[$method] = '$MadelineProto->' . $md_method . '(\\[' . $params . '\\]) === [$' . \str_replace('_', '\\_', $type) . '](../types/' . $php_type . '.md) '; - if (isset($this->td_descriptions['methods'][$data['method']])) { $desc = \Parsedown::instance()->line(\trim(\explode("\n", $this->td_descriptions['methods'][$data['method']]['description'])[0], '.')); $dom = new \DOMDocument(); $dom->loadHTML(\mb_convert_encoding($desc, 'HTML-ENTITIES', 'UTF-8')); $desc = $dom->textContent; - $this->human_docs_methods[$this->td_descriptions['methods'][$data['method']]['description'].': '.$data['method']] = '* '.$desc.': '.$data['method'].' + $this->human_docs_methods[$this->td_descriptions['methods'][$data['method']]['description'] . ': ' . $data['method']] = '* ' . $desc . ': ' . $data['method'] . ' '; } - $params = ''; $lua_params = ''; $pwr_params = ''; @@ -148,47 +145,45 @@ trait Methods } $human_ptype = $ptype; if (\in_array($ptype, ['InputDialogPeer', 'DialogPeer', 'NotifyPeer', 'InputNotifyPeer', 'User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputPeer']) && !isset($this->settings['td'])) { - $human_ptype = 'Username, chat ID, Update, Message or '.$ptype; + $human_ptype = 'Username, chat ID, Update, Message or ' . $ptype; } if (\in_array($ptype, ['InputMedia', 'InputPhoto', 'InputDocument']) && !isset($this->settings['td'])) { - $human_ptype = 'MessageMedia, Update, Message or '.$ptype; + $human_ptype = 'MessageMedia, Update, Message or ' . $ptype; } if (\in_array($ptype, ['InputMessage']) && !isset($this->settings['td'])) { - $human_ptype = 'Message ID or '.$ptype; + $human_ptype = 'Message ID or ' . $ptype; } if (\in_array($ptype, ['InputEncryptedChat']) && !isset($this->settings['td'])) { - $human_ptype = 'Secret chat ID, Update, EncryptedMessage or '.$ptype; + $human_ptype = 'Secret chat ID, Update, EncryptedMessage or ' . $ptype; } if (\in_array($ptype, ['InputFile']) && !isset($this->settings['td'])) { - $human_ptype = 'File path or '.$ptype; + $human_ptype = 'File path or ' . $ptype; } if (\in_array($ptype, ['InputEncryptedFile']) && !isset($this->settings['td'])) { - $human_ptype = 'File path or '.$ptype; + $human_ptype = 'File path or ' . $ptype; } $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']); + $this->addToLang('method_' . $data['method'] . '_param_' . $param['name'] . '_type_' . $param['type']); if (isset($this->td_descriptions['methods'][$data['method']]['description'])) { - $this->td_descriptions['methods'][$data['method']]['params'][$param['name']] = \danog\MadelineProto\Lang::$lang['en']['method_'.$data['method'].'_param_'.$param['name'].'_type_'.$param['type']]; + $this->td_descriptions['methods'][$data['method']]['params'][$param['name']] = \danog\MadelineProto\Lang::$lang['en']['method_' . $data['method'] . '_param_' . $param['name'] . '_type_' . $param['type']]; } } - if (isset($this->td_descriptions['methods'][$data['method']])) { - $table .= '|'.\str_replace('_', '\\_', $param['name']).'|'.(isset($param['subtype']) ? 'Array of ' : '').'['.\str_replace('_', '\\_', $human_ptype).'](../'.$type_or_bare_type.'/'.$ptype.'.md) | '.$this->td_descriptions['methods'][$data['method']]['params'][$param['name']].' | '.(isset($param['pow']) || (($id = $this->TL->getConstructors($this->td)->findByPredicate(\lcfirst($param['type']).'Empty')) && $id['type'] === $param['type']) || (($id = $this->TL->getConstructors($this->td)->findByPredicate('input'.$param['type'].'Empty')) && $id['type'] === $param['type']) ? 'Optional' : 'Yes').'|'; + $table .= '|' . \str_replace('_', '\\_', $param['name']) . '|' . (isset($param['subtype']) ? 'Array of ' : '') . '[' . \str_replace('_', '\\_', $human_ptype) . '](../' . $type_or_bare_type . '/' . $ptype . '.md) | ' . $this->td_descriptions['methods'][$data['method']]['params'][$param['name']] . ' | ' . (isset($param['pow']) || ($id = $this->TL->getConstructors($this->td)->findByPredicate(\lcfirst($param['type']) . 'Empty')) && $id['type'] === $param['type'] || ($id = $this->TL->getConstructors($this->td)->findByPredicate('input' . $param['type'] . 'Empty')) && $id['type'] === $param['type'] ? 'Optional' : 'Yes') . '|'; } else { - $table .= '|'.\str_replace('_', '\\_', $param['name']).'|'.(isset($param['subtype']) ? 'Array of ' : '').'['.\str_replace('_', '\\_', $human_ptype).'](../'.$type_or_bare_type.'/'.$ptype.'.md) | '.(isset($param['pow']) || (($id = $this->TL->getConstructors($this->td)->findByPredicate(\lcfirst($param['type']).'Empty')) && $id['type'] === $param['type']) || (($id = $this->TL->getConstructors($this->td)->findByPredicate('input'.$param['type'].'Empty')) && $id['type'] === $param['type']) ? 'Optional' : 'Yes').'|'; + $table .= '|' . \str_replace('_', '\\_', $param['name']) . '|' . (isset($param['subtype']) ? 'Array of ' : '') . '[' . \str_replace('_', '\\_', $human_ptype) . '](../' . $type_or_bare_type . '/' . $ptype . '.md) | ' . (isset($param['pow']) || ($id = $this->TL->getConstructors($this->td)->findByPredicate(\lcfirst($param['type']) . 'Empty')) && $id['type'] === $param['type'] || ($id = $this->TL->getConstructors($this->td)->findByPredicate('input' . $param['type'] . 'Empty')) && $id['type'] === $param['type'] ? 'Optional' : 'Yes') . '|'; } $table .= PHP_EOL; - $pptype = \in_array($ptype, ['string', 'bytes']) ? "'".$ptype."'" : $ptype; - $ppptype = \in_array($ptype, ['string']) ? '"'.$ptype.'"' : $ptype; - $ppptype = \in_array($ptype, ['bytes']) ? '{"_": "bytes", "bytes":"base64 encoded '.$ptype.'"}' : $ppptype; - - $params .= "'".$param['name']."' => "; - $params .= (isset($param['subtype']) ? '['.$pptype.', '.$pptype.']' : $pptype).', '; - $json_params .= '"'.$param['name'].'": '.(isset($param['subtype']) ? '['.$ppptype.']' : $ppptype).', '; - $pwr_params .= $param['name'].' - Json encoded '.(isset($param['subtype']) ? ' array of '.$ptype : $ptype)."\n\n"; - $lua_params .= $param['name'].'='; - $lua_params .= (isset($param['subtype']) ? '{'.$pptype.'}' : $pptype).', '; + $pptype = \in_array($ptype, ['string', 'bytes']) ? "'" . $ptype . "'" : $ptype; + $ppptype = \in_array($ptype, ['string']) ? '"' . $ptype . '"' : $ptype; + $ppptype = \in_array($ptype, ['bytes']) ? '{"_": "bytes", "bytes":"base64 encoded ' . $ptype . '"}' : $ppptype; + $params .= "'" . $param['name'] . "' => "; + $params .= (isset($param['subtype']) ? '[' . $pptype . ', ' . $pptype . ']' : $pptype) . ', '; + $json_params .= '"' . $param['name'] . '": ' . (isset($param['subtype']) ? '[' . $ppptype . ']' : $ppptype) . ', '; + $pwr_params .= $param['name'] . ' - Json encoded ' . (isset($param['subtype']) ? ' array of ' . $ptype : $ptype) . "\n\n"; + $lua_params .= $param['name'] . '='; + $lua_params .= (isset($param['subtype']) ? '{' . $pptype . '}' : $pptype) . ', '; if ($param['name'] === 'reply_markup') { $hasreplymarkup = true; } @@ -205,42 +200,42 @@ trait Methods $pwr_params = "parseMode - string\n"; } } - $description = isset($this->td_descriptions['methods'][$data['method']]) ? $this->td_descriptions['methods'][$data['method']]['description'] : $data['method'].' parameters, return type and example'; + $description = isset($this->td_descriptions['methods'][$data['method']]) ? $this->td_descriptions['methods'][$data['method']]['description'] : $data['method'] . ' parameters, return type and example'; $symFile = \str_replace('.', '_', $method); - $redir = $symFile !== $method ? "\nredirect_from: /API_docs/methods/$symFile.html" : ''; + $redir = $symFile !== $method ? "\nredirect_from: /API_docs/methods/{$symFile}.html" : ''; $header = '--- -title: '.$data['method'].' -description: '.$description.' -image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png'.$redir.' +title: ' . $data['method'] . ' +description: ' . $description . ' +image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png' . $redir . ' --- -# Method: '.\str_replace('_', '\\_', $data['method']).' +# Method: ' . \str_replace('_', '\\_', $data['method']) . ' [Back to methods index](index.md) '; /* - if (isset(\danog\MadelineProto\MTProto::DISALLOWED_METHODS[$data['method']])) { - $header .= '**'.\danog\MadelineProto\MTProto::DISALLOWED_METHODS[$data['method']]."**\n\n\n\n\n"; - file_put_contents('methods/'.$method.'.md', $header); - continue; - }*/ + if (isset(\danog\MadelineProto\MTProto::DISALLOWED_METHODS[$data['method']])) { + $header .= '**'.\danog\MadelineProto\MTProto::DISALLOWED_METHODS[$data['method']]."**\n\n\n\n\n"; + file_put_contents('methods/'.$method.'.md', $header); + continue; + }*/ if ($this->td) { $header .= 'YOU CANNOT USE THIS METHOD IN MADELINEPROTO '; } - $header .= isset($this->td_descriptions['methods'][$data['method']]) ? $this->td_descriptions['methods'][$data['method']]['description'].PHP_EOL.PHP_EOL : ''; + $header .= isset($this->td_descriptions['methods'][$data['method']]) ? $this->td_descriptions['methods'][$data['method']]['description'] . PHP_EOL . PHP_EOL : ''; $table .= ' '; - $return = '### Return type: ['.\str_replace('_', '\\_', $type).'](../types/'.$php_type.'.md) + $return = '### Return type: [' . \str_replace('_', '\\_', $type) . '](../types/' . $php_type . '.md) '; $bot = !\in_array($data['method'], $bots); $example = ''; if (!isset($this->settings['td'])) { - $example .= '### Can bots use this method: **'.($bot ? 'YES' : 'NO')."**\n\n\n"; + $example .= '### Can bots use this method: **' . ($bot ? 'YES' : 'NO') . "**\n\n\n"; $example .= \str_replace('[]', '', '### MadelineProto Example ([now async for huge speed and parallelism!](https://docs.madelineproto.xyz/docs/ASYNC.html)): @@ -250,16 +245,16 @@ if (!file_exists(\'madeline.php\')) { } include \'madeline.php\'; -$MadelineProto = new \danog\MadelineProto\API(\'session.madeline\'); +$MadelineProto = new \\danog\\MadelineProto\\API(\'session.madeline\'); $MadelineProto->start(); -$'.$type.' = $MadelineProto->'.$php_method.'(['.$params.']); +$' . $type . ' = $MadelineProto->' . $php_method . '([' . $params . ']); ``` Or, if you\'re into Lua: ```lua -'.$type.' = '.$data['method'].'({'.$lua_params.'}) +' . $type . ' = ' . $data['method'] . '({' . $lua_params . '}) ``` '); @@ -276,7 +271,7 @@ You can provide bot API reply_markup objects here. $example .= ' ## Return value -If the length of the provided message is bigger than 4096, the message will be split in chunks and the method will be called multiple times, with the same parameters (except for the message), and an array of ['.\str_replace('_', '\\_', $type).'](../types/'.$php_type.'.md) will be returned instead. +If the length of the provided message is bigger than 4096, the message will be split in chunks and the method will be called multiple times, with the same parameters (except for the message), and an array of [' . \str_replace('_', '\\_', $type) . '](../types/' . $php_type . '.md) will be returned instead. '; @@ -328,12 +323,12 @@ MadelineProto supports all html entities supported by [html_entity_decode](http: '; foreach ($new['result'][$data['method']] as $error) { [$error, $code] = $error; - $example .= "|$code|$error|".$errors['human_result'][$error][0].'|'."\n"; + $example .= "|{$code}|{$error}|" . $errors['human_result'][$error][0] . '|' . "\n"; } $example .= "\n\n"; } } - \file_put_contents('methods/'.$method.'.md', $header.$table.$return.$example); + \file_put_contents('methods/' . $method . '.md', $header . $table . $return . $example); } $this->logger->logger('Generating methods index...', \danog\MadelineProto\Logger::NOTICE); \ksort($this->docs_methods); @@ -344,10 +339,10 @@ MadelineProto supports all html entities supported by [html_entity_decode](http: $br = $new_namespace != $last_namespace ? '***

' : ''; - $value = $br.$value; + $value = $br . $value; $last_namespace = $new_namespace; } - \file_put_contents('methods/api_'.$this->index, '--- + \file_put_contents('methods/api_' . $this->index, '--- title: Methods description: List of methods image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png @@ -355,7 +350,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png # Methods [Back to API documentation index](..) -[Go to the new description-version method index]('.$this->index.') +[Go to the new description-version method index](' . $this->index . ') $MadelineProto->[logout](https://docs.madelineproto.xyz/logout.html)(); @@ -383,9 +378,8 @@ $MadelineProto->[requestCall](https://docs.madelineproto.xyz/requestCall.html)($ $MadelineProto->[requestSecretChat](https://docs.madelineproto.xyz/requestSecretChat.html)($id); -'.\implode('', $this->docs_methods)); - - \file_put_contents('methods/'.$this->index, '--- +' . \implode('', $this->docs_methods)); + \file_put_contents('methods/' . $this->index, '--- title: Methods description: What do you want to do? image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png @@ -393,7 +387,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png # What do you want to do? [Go back to API documentation index](..) -[Go to the old code-version method index](api_'.$this->index.') +[Go to the old code-version method index](api_' . $this->index . ') * [Logout](https://docs.madelineproto.xyz/logout.html) @@ -417,6 +411,6 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png * [Create a secret chat bot](https://docs.madelineproto.xyz/docs/SECRET_CHATS.html) -'.\implode('', $this->human_docs_methods)); +' . \implode('', $this->human_docs_methods)); } } diff --git a/src/danog/MadelineProto/EventHandler.php b/src/danog/MadelineProto/EventHandler.php index a747c08c..e84c5f1f 100644 --- a/src/danog/MadelineProto/EventHandler.php +++ b/src/danog/MadelineProto/EventHandler.php @@ -35,8 +35,8 @@ class EventHandler extends InternalDoc return; } $this->API = $MadelineProto->API; - $this->async = &$MadelineProto->async; - $this->methods = &$MadelineProto->methods; + $this->async =& $MadelineProto->async; + $this->methods =& $MadelineProto->methods; foreach ($this->API->getMethodNamespaces() as $namespace) { $this->{$namespace} = new APIFactory($namespace, $this->API, $this->async); } diff --git a/src/danog/MadelineProto/Exception.php b/src/danog/MadelineProto/Exception.php index e490df9f..05b6723c 100644 --- a/src/danog/MadelineProto/Exception.php +++ b/src/danog/MadelineProto/Exception.php @@ -23,12 +23,10 @@ class Exception extends \Exception { use TL\PrettyException; public static $rollbar = true; - public function __toString() { - return $this->file === 'MadelineProto' ? $this->message : '\\danog\\MadelineProto\\Exception'.($this->message !== '' ? ': ' : '').$this->message.' in '.$this->file.':'.$this->line.PHP_EOL.\danog\MadelineProto\Magic::$revision.PHP_EOL.'TL Trace:'.PHP_EOL.$this->getTLTrace(); + return $this->file === 'MadelineProto' ? $this->message : '\\danog\\MadelineProto\\Exception' . ($this->message !== '' ? ': ' : '') . $this->message . ' in ' . $this->file . ':' . $this->line . PHP_EOL . \danog\MadelineProto\Magic::$revision . PHP_EOL . 'TL Trace:' . PHP_EOL . $this->getTLTrace(); } - public function __construct($message = null, $code = 0, self $previous = null, $file = null, $line = null) { $this->prettifyTL(); @@ -40,9 +38,8 @@ class Exception extends \Exception } parent::__construct($message, $code, $previous); if (\strpos($message, 'socket_accept') === false) { - \danog\MadelineProto\Logger::log($message.' in '.\basename($this->file).':'.$this->line, \danog\MadelineProto\Logger::FATAL_ERROR); + \danog\MadelineProto\Logger::log($message . ' in ' . \basename($this->file) . ':' . $this->line, \danog\MadelineProto\Logger::FATAL_ERROR); } - if (\in_array($message, ['The session is corrupted!', 'Re-executing query...', 'I had to recreate the temporary authorization key', 'This peer is not present in the internal peer database', "Couldn't get response", 'Chat forbidden', 'The php-libtgvoip extension is required to accept and manage calls. See daniil.it/MadelineProto for more info.', 'File does not exist', 'Please install this fork of phpseclib: https://github.com/danog/phpseclib'])) { return; } @@ -53,18 +50,17 @@ class Exception extends \Exception \Rollbar\Rollbar::log(\Rollbar\Payload\Level::error(), $this, \debug_backtrace(0)); } } - public static function extension(string $extensionName) { - $additional = 'Try running sudo apt-get install php'.PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION.'-'.$extensionName.'.'; + $additional = 'Try running sudo apt-get install php' . PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '-' . $extensionName . '.'; if ($extensionName === 'libtgvoip') { $additional = 'Follow the instructions @ https://voip.madelineproto.xyz to install it.'; } elseif ($extensionName === 'prime') { $additional = 'Follow the instructions @ https://prime.madelineproto.xyz to install it.'; } - $message = 'MadelineProto requires the '.$extensionName.' extension to run. '.$additional; + $message = 'MadelineProto requires the ' . $extensionName . ' extension to run. ' . $additional; if (PHP_SAPI !== 'cli') { - echo $message.'
'; + echo $message . '
'; } $file = 'MadelineProto'; $line = 1; @@ -78,17 +74,11 @@ class Exception extends \Exception public static function exceptionErrorHandler($errno = 0, $errstr = null, $errfile = null, $errline = null) { // If error is suppressed with @, don't throw an exception - if (\error_reporting() === 0 - || \strpos($errstr, 'headers already sent') - || ($errfile - && (\strpos($errfile, 'vendor/amphp') !== false || \strpos($errfile, 'vendor/league') !== false)) - ) { + if (\error_reporting() === 0 || \strpos($errstr, 'headers already sent') || $errfile && (\strpos($errfile, 'vendor/amphp') !== false || \strpos($errfile, 'vendor/league') !== false)) { return false; } - throw new self($errstr, $errno, null, $errfile, $errline); } - /** * ExceptionErrorHandler. * diff --git a/src/danog/MadelineProto/FileCallback.php b/src/danog/MadelineProto/FileCallback.php index 7dcd6927..73b623fc 100644 --- a/src/danog/MadelineProto/FileCallback.php +++ b/src/danog/MadelineProto/FileCallback.php @@ -36,7 +36,6 @@ class FileCallback implements FileCallbackInterface * @var callable */ private $callback; - /** * Construct file callback. * @@ -48,7 +47,6 @@ class FileCallback implements FileCallbackInterface $this->file = $file; $this->callback = $callback; } - /** * Get file. * @@ -58,7 +56,6 @@ class FileCallback implements FileCallbackInterface { return $this->file; } - /** * Invoke callback. * @@ -71,7 +68,6 @@ class FileCallback implements FileCallbackInterface public function __invoke($percent, $speed, $time) { $callback = $this->callback; - return $callback($percent, $speed, $time); } } diff --git a/src/danog/MadelineProto/FileCallbackInterface.php b/src/danog/MadelineProto/FileCallbackInterface.php index 7f5b177e..47c4a9aa 100644 --- a/src/danog/MadelineProto/FileCallbackInterface.php +++ b/src/danog/MadelineProto/FileCallbackInterface.php @@ -30,7 +30,6 @@ interface FileCallbackInterface * @return mixed */ public function getFile(); - /** * Invoke callback. * diff --git a/src/danog/MadelineProto/InternalDoc.php b/src/danog/MadelineProto/InternalDoc.php index e3f80261..adb0ea32 100644 --- a/src/danog/MadelineProto/InternalDoc.php +++ b/src/danog/MadelineProto/InternalDoc.php @@ -5128,7 +5128,7 @@ class InternalDoc extends APIFactory * @param string $file File to lock * @param integer $operation Locking mode * @param float $polling Polling interval - * + * * @return Promise */ public function flock(string $file, int $operation, float $polling = 0.1) diff --git a/src/danog/MadelineProto/Lang.php b/src/danog/MadelineProto/Lang.php index c9d1e560..773b111e 100644 --- a/src/danog/MadelineProto/Lang.php +++ b/src/danog/MadelineProto/Lang.php @@ -12,7 +12,7 @@ * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 - * @link https://docs.madelineproto.xyz MadelineProto documentation + * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; diff --git a/src/danog/MadelineProto/Logger.php b/src/danog/MadelineProto/Logger.php index 902f5880..1d4323ff 100644 --- a/src/danog/MadelineProto/Logger.php +++ b/src/danog/MadelineProto/Logger.php @@ -30,12 +30,10 @@ use function Amp\ByteStream\getStdout; class Logger { use Tools; - const FOREGROUND = ['default' => 39, 'black' => 30, 'red' => 31, 'green' => 32, 'yellow' => 33, 'blue' => 34, 'magenta' => 35, 'cyan' => 36, 'light_gray' => 37, 'dark_gray' => 90, 'light_red' => 91, 'light_green' => 92, 'light_yellow' => 93, 'light_blue' => 94, 'light_magenta' => 95, 'light_cyan' => 96, 'white' => 97]; const BACKGROUND = ['default' => 49, 'black' => 40, 'red' => 41, 'magenta' => 45, 'yellow' => 43, 'green' => 42, 'blue' => 44, 'cyan' => 46, 'light_gray' => 47, 'dark_gray' => 100, 'light_red' => 101, 'light_green' => 102, 'light_yellow' => 103, 'light_blue' => 104, 'light_magenta' => 105, 'light_cyan' => 106, 'white' => 107]; const SET = ['bold' => 1, 'dim' => 2, 'underlined' => 3, 'blink' => 4, 'reverse' => 5, 'hidden' => 6]; const RESET = ['all' => 0, 'bold' => 21, 'dim' => 22, 'underlined' => 24, 'blink' => 25, 'reverse' => 26, 'hidden' => 28]; - /** * Logging mode. * @@ -72,7 +70,6 @@ class Logger * @var string */ public $newline = "\n"; - /** * Default logger instance. * @@ -85,20 +82,17 @@ class Logger * @var boolean */ public static $printed = false; - const ULTRA_VERBOSE = 5; const VERBOSE = 4; const NOTICE = 3; const WARNING = 2; const ERROR = 1; const FATAL_ERROR = 0; - const NO_LOGGER = 0; const DEFAULT_LOGGER = 1; const FILE_LOGGER = 2; const ECHO_LOGGER = 3; const CALLABLE_LOGGER = 4; - /** * Construct global static logger from MadelineProto settings. * @@ -133,28 +127,24 @@ class Logger $settings['logger']['logger_param'] = $settings['logger']['param']; } if (PHP_SAPI !== 'cli' && isset($settings['logger']['logger_param']) && $settings['logger']['logger_param'] === 'MadelineProto.log') { - $settings['logger']['logger_param'] = Magic::$script_cwd.'/MadelineProto.log'; + $settings['logger']['logger_param'] = Magic::$script_cwd . '/MadelineProto.log'; } - $logger = new self($settings['logger']['logger'], $settings['logger']['logger_param'] ?? '', $prefix, $settings['logger']['logger_level'] ?? Logger::VERBOSE, $settings['logger']['max_size'] ?? 100 * 1024 * 1024); if (!self::$default) { self::$default = $logger; } - if (PHP_SAPI !== 'cli') { try { \error_reporting(E_ALL); \ini_set('log_errors', 1); - \ini_set('error_log', $settings['logger']['logger'] === self::FILE_LOGGER ? $settings['logger']['logger_param'] : Magic::$script_cwd.'/MadelineProto.log'); + \ini_set('error_log', $settings['logger']['logger'] === self::FILE_LOGGER ? $settings['logger']['logger_param'] : Magic::$script_cwd . '/MadelineProto.log'); \error_log('Enabled PHP logging'); } catch (\danog\MadelineProto\Exception $e) { $logger->logger('Could not enable PHP logging'); } } - return $logger; } - /** * Construct global logger. * @@ -170,7 +160,6 @@ class Logger { self::$default = new self($mode, $optional, $prefix, $level, $max_size); } - /** * Construct global logger. * @@ -189,21 +178,17 @@ class Logger } $this->mode = $mode; $this->optional = $mode == 2 ? Absolute::absolute($optional) : $optional; - $this->prefix = $prefix === '' ? '' : ', '.$prefix; + $this->prefix = $prefix === '' ? '' : ', ' . $prefix; $this->level = $level; - if ($this->mode === 2 && !\file_exists(\pathinfo($this->optional, PATHINFO_DIRNAME))) { - $this->optional = Magic::$script_cwd.'/MadelineProto.log'; + $this->optional = Magic::$script_cwd . '/MadelineProto.log'; } - - if ($this->mode === 2 && !\preg_match('/\.log$/', $this->optional)) { + if ($this->mode === 2 && !\preg_match('/\\.log$/', $this->optional)) { $this->optional .= '.log'; } - if ($mode === 2 && $max_size !== -1 && \file_exists($this->optional) && \filesize($this->optional) > $max_size) { \unlink($this->optional); } - $this->colors[self::ULTRA_VERBOSE] = \implode(';', [self::FOREGROUND['light_gray'], self::SET['dim']]); $this->colors[self::VERBOSE] = \implode(';', [self::FOREGROUND['green'], self::SET['bold']]); $this->colors[self::NOTICE] = \implode(';', [self::FOREGROUND['yellow'], self::SET['bold']]); @@ -211,11 +196,10 @@ class Logger $this->colors[self::ERROR] = \implode(';', [self::FOREGROUND['white'], self::SET['bold'], self::BACKGROUND['red']]); $this->colors[self::FATAL_ERROR] = \implode(';', [self::FOREGROUND['red'], self::SET['bold'], self::BACKGROUND['light_gray']]); $this->newline = PHP_EOL; - if ($this->mode === 3) { $this->stdout = getStdout(); if (PHP_SAPI !== 'cli') { - $this->newline = '
'.$this->newline; + $this->newline = '
' . $this->newline; } } elseif ($this->mode === 2) { $this->stdout = new ResourceOutputStream(\fopen($this->optional, 'a+')); @@ -230,7 +214,6 @@ class Logger } } } - /** * Log a message. * @@ -244,10 +227,9 @@ class Logger if (!\is_null(self::$default)) { self::$default->logger($param, $level, \basename(\debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php')); } else { - echo $param.PHP_EOL; + echo $param . PHP_EOL; } } - /** * Log a message. * @@ -265,12 +247,10 @@ class Logger if (!self::$printed) { self::$printed = true; $this->colors[self::NOTICE] = \implode(';', [self::FOREGROUND['light_gray'], self::SET['bold'], self::BACKGROUND['blue']]); - $this->logger('MadelineProto'); $this->logger('Copyright (C) 2016-2019 Daniil Gentili'); $this->logger('Licensed under AGPLv3'); $this->logger('https://github.com/danog/MadelineProto'); - $this->colors[self::NOTICE] = \implode(';', [self::FOREGROUND['yellow'], self::SET['bold']]); } if ($this->mode === 4) { @@ -289,22 +269,26 @@ class Logger if (empty($file)) { $file = \basename(\debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php'); } - $param = \str_pad($file.$prefix.': ', 16 + \strlen($prefix))."\t".$param; + $param = \str_pad($file . $prefix . ': ', 16 + \strlen($prefix)) . "\t" . $param; switch ($this->mode) { - case 1: - if ($this->stdout->write($param.$this->newline) instanceof Failure) { - \error_log($param); + case 1: + if ($this->stdout->write($param . $this->newline) instanceof Failure) { + \error_log($param); + } + break; + default: + $param = Magic::$isatty ? "\33[" . $this->colors[$level] . 'm' . $param . "\33[0m" . $this->newline : $param . $this->newline; + if ($this->stdout->write($param) instanceof Failure) { + switch ($this->mode) { + case 3: + echo $param; + break; + case 2: + \file_put_contents($this->optional, $param, FILE_APPEND); + break; } - break; - default: - $param = Magic::$isatty ? "\33[".$this->colors[$level].'m'.$param."\33[0m".$this->newline : $param.$this->newline; - if ($this->stdout->write($param) instanceof Failure) { - switch ($this->mode) { - case 3: echo $param; break; - case 2: \file_put_contents($this->optional, $param, FILE_APPEND); break; - } - } - break; - } + } + break; + } } } diff --git a/src/danog/MadelineProto/Loop/Connection/CheckLoop.php b/src/danog/MadelineProto/Loop/Connection/CheckLoop.php index c1c4ce6d..46e44cde 100644 --- a/src/danog/MadelineProto/Loop/Connection/CheckLoop.php +++ b/src/danog/MadelineProto/Loop/Connection/CheckLoop.php @@ -1,4 +1,5 @@ datacenter = $connection->getDatacenterID(); $this->datacenterConnection = $connection->getShared(); } - - public function loop() + public function loop(): \Generator { $API = $this->API; $datacenter = $this->datacenter; $connection = $this->connection; $shared = $this->datacenterConnection; - $timeout = $shared->getSettings()['timeout']; - $timeoutResend = $timeout * $timeout; // Typically 25 seconds, good enough + $timeoutResend = $timeout * $timeout; + // Typically 25 seconds, good enough while (true) { while (empty($connection->new_outgoing)) { if (yield $this->waitSignal($this->pause())) { return; } } - if ($connection->hasPendingCalls()) { $last_msgid = $connection->getMaxId(true); $last_chunk = $connection->getLastChunk(); - if ($shared->hasTempAuthKey()) { - $full_message_ids = $connection->getPendingCalls(); //array_values($connection->new_outgoing); + $full_message_ids = $connection->getPendingCalls(); + //array_values($connection->new_outgoing); foreach (\array_chunk($full_message_ids, 8192) as $message_ids) { $deferred = new Deferred(); - $deferred->promise()->onResolve( - function ($e, $result) use ($message_ids, $API, $connection, $datacenter, $timeoutResend) { - if ($e) { - $API->logger("Got exception in check loop for DC $datacenter"); - $API->logger((string) $e); - - return; - } - $reply = []; - foreach (\str_split($result['info']) as $key => $chr) { - $message_id = $message_ids[$key]; - if (!isset($connection->outgoing_messages[$message_id])) { - $API->logger->logger('Already got response for and forgot about message ID '.($message_id)); - continue; - } - if (!isset($connection->new_outgoing[$message_id])) { - $API->logger->logger('Already got response for '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.($message_id)); - continue; - } - $chr = \ord($chr); - switch ($chr & 7) { - case 0: - $API->logger->logger('Wrong message status 0 for '.$connection->outgoing_messages[$message_id]['_'], \danog\MadelineProto\Logger::FATAL_ERROR); - break; - case 1: - case 2: - case 3: - if ($connection->outgoing_messages[$message_id]['_'] === 'msgs_state_req') { - $connection->gotResponseForOutgoingMessageId($message_id); - break; - } - $API->logger->logger('Message '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.($message_id).' not received by server, resending...', \danog\MadelineProto\Logger::ERROR); - $connection->methodRecall('watcherId', ['message_id' => $message_id, 'postpone' => true]); - break; - case 4: - if ($chr & 32) { - if ($connection->outgoing_messages[$message_id]['sent'] + $timeoutResend < \time()) { - $API->logger->logger('Message '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.($message_id).' received by server and is being processed for way too long, resending request...', \danog\MadelineProto\Logger::ERROR); - $connection->methodRecall('', ['message_id' => $message_id, 'postpone' => true]); - } else { - $API->logger->logger('Message '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.($message_id).' received by server and is being processed, waiting...', \danog\MadelineProto\Logger::ERROR); - } - } elseif ($chr & 64) { - $API->logger->logger('Message '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.($message_id).' received by server and was already processed, requesting reply...', \danog\MadelineProto\Logger::ERROR); - $reply[] = $message_id; - } elseif ($chr & 128) { - $API->logger->logger('Message '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.($message_id).' received by server and was already sent, requesting reply...', \danog\MadelineProto\Logger::ERROR); - $reply[] = $message_id; - } else { - $API->logger->logger('Message '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.($message_id).' received by server, requesting reply...', \danog\MadelineProto\Logger::ERROR); - $reply[] = $message_id; - } - } - } - if ($reply) { - \danog\MadelineProto\Tools::callFork($connection->objectCall('msg_resend_ans_req', ['msg_ids' => $reply], ['postpone' => true])); - } - $connection->flush(); + $deferred->promise()->onResolve(function ($e, $result) use ($message_ids, $API, $connection, $datacenter, $timeoutResend) { + if ($e) { + $API->logger("Got exception in check loop for DC {$datacenter}"); + $API->logger((string) $e); + return; } - ); + $reply = []; + foreach (\str_split($result['info']) as $key => $chr) { + $message_id = $message_ids[$key]; + if (!isset($connection->outgoing_messages[$message_id])) { + $API->logger->logger('Already got response for and forgot about message ID ' . $message_id); + continue; + } + if (!isset($connection->new_outgoing[$message_id])) { + $API->logger->logger('Already got response for ' . $connection->outgoing_messages[$message_id]['_'] . ' with message ID ' . $message_id); + continue; + } + $chr = \ord($chr); + switch ($chr & 7) { + case 0: + $API->logger->logger('Wrong message status 0 for ' . $connection->outgoing_messages[$message_id]['_'], \danog\MadelineProto\Logger::FATAL_ERROR); + break; + case 1: + case 2: + case 3: + if ($connection->outgoing_messages[$message_id]['_'] === 'msgs_state_req') { + $connection->gotResponseForOutgoingMessageId($message_id); + break; + } + $API->logger->logger('Message ' . $connection->outgoing_messages[$message_id]['_'] . ' with message ID ' . $message_id . ' not received by server, resending...', \danog\MadelineProto\Logger::ERROR); + $connection->methodRecall('watcherId', ['message_id' => $message_id, 'postpone' => true]); + break; + case 4: + if ($chr & 32) { + if ($connection->outgoing_messages[$message_id]['sent'] + $timeoutResend < \time()) { + $API->logger->logger('Message ' . $connection->outgoing_messages[$message_id]['_'] . ' with message ID ' . $message_id . ' received by server and is being processed for way too long, resending request...', \danog\MadelineProto\Logger::ERROR); + $connection->methodRecall('', ['message_id' => $message_id, 'postpone' => true]); + } else { + $API->logger->logger('Message ' . $connection->outgoing_messages[$message_id]['_'] . ' with message ID ' . $message_id . ' received by server and is being processed, waiting...', \danog\MadelineProto\Logger::ERROR); + } + } elseif ($chr & 64) { + $API->logger->logger('Message ' . $connection->outgoing_messages[$message_id]['_'] . ' with message ID ' . $message_id . ' received by server and was already processed, requesting reply...', \danog\MadelineProto\Logger::ERROR); + $reply[] = $message_id; + } elseif ($chr & 128) { + $API->logger->logger('Message ' . $connection->outgoing_messages[$message_id]['_'] . ' with message ID ' . $message_id . ' received by server and was already sent, requesting reply...', \danog\MadelineProto\Logger::ERROR); + $reply[] = $message_id; + } else { + $API->logger->logger('Message ' . $connection->outgoing_messages[$message_id]['_'] . ' with message ID ' . $message_id . ' received by server, requesting reply...', \danog\MadelineProto\Logger::ERROR); + $reply[] = $message_id; + } + } + } + if ($reply) { + \danog\MadelineProto\Tools::callFork($connection->objectCall('msg_resend_ans_req', ['msg_ids' => $reply], ['postpone' => true])); + } + $connection->flush(); + }); $list = ''; // Don't edit this here pls foreach ($message_ids as $message_id) { - $list .= $connection->outgoing_messages[$message_id]['_'].', '; + $list .= $connection->outgoing_messages[$message_id]['_'] . ', '; } - $API->logger->logger("Still missing $list on DC $datacenter, sending state request", \danog\MadelineProto\Logger::ERROR); + $API->logger->logger("Still missing {$list} on DC {$datacenter}, sending state request", \danog\MadelineProto\Logger::ERROR); yield $connection->objectCall('msgs_state_req', ['msg_ids' => $message_ids], ['promise' => $deferred]); } } else { foreach ($connection->new_outgoing as $message_id) { - if (isset($connection->outgoing_messages[$message_id]['sent']) - && $connection->outgoing_messages[$message_id]['sent'] + $timeout < \time() - && $connection->outgoing_messages[$message_id]['unencrypted'] - ) { - $API->logger->logger('Still missing '.$connection->outgoing_messages[$message_id]['_'].' with message id '.($message_id)." on DC $datacenter, resending", \danog\MadelineProto\Logger::ERROR); + if (isset($connection->outgoing_messages[$message_id]['sent']) && $connection->outgoing_messages[$message_id]['sent'] + $timeout < \time() && $connection->outgoing_messages[$message_id]['unencrypted']) { + $API->logger->logger('Still missing ' . $connection->outgoing_messages[$message_id]['_'] . ' with message id ' . $message_id . " on DC {$datacenter}, resending", \danog\MadelineProto\Logger::ERROR); $connection->methodRecall('', ['message_id' => $message_id, 'postpone' => true]); } } @@ -165,12 +157,10 @@ class CheckLoop extends ResumableSignalLoop if (yield $this->waitSignal($this->pause($timeout))) { return; } - if ($connection->getMaxId(true) === $last_msgid && $connection->getLastChunk() === $last_chunk) { - $API->logger->logger("We did not receive a response for $timeout seconds: reconnecting and exiting check loop on DC $datacenter"); + $API->logger->logger("We did not receive a response for {$timeout} seconds: reconnecting and exiting check loop on DC {$datacenter}"); //$this->exitedLoop(); Tools::callForkDefer($connection->reconnect()); - return; } } else { @@ -180,7 +170,6 @@ class CheckLoop extends ResumableSignalLoop } } } - public function __toString(): string { return "check loop in DC {$this->datacenter}"; diff --git a/src/danog/MadelineProto/Loop/Connection/HttpWaitLoop.php b/src/danog/MadelineProto/Loop/Connection/HttpWaitLoop.php index 35f39f3a..1306789e 100644 --- a/src/danog/MadelineProto/Loop/Connection/HttpWaitLoop.php +++ b/src/danog/MadelineProto/Loop/Connection/HttpWaitLoop.php @@ -1,4 +1,5 @@ connection = $connection; @@ -55,18 +54,15 @@ class HttpWaitLoop extends ResumableSignalLoop $this->datacenter = $connection->getDatacenterID(); $this->datacenterConnection = $connection->getShared(); } - - public function loop() + public function loop(): \Generator { $API = $this->API; $datacenter = $this->datacenter; $connection = $this->connection; $shared = $this->datacenterConnection; - if (!$shared->isHttp()) { return; } - while (true) { if (yield $this->waitSignal($this->pause())) { return; @@ -79,14 +75,13 @@ class HttpWaitLoop extends ResumableSignalLoop return; } } - $API->logger->logger("DC $datacenter: request {$connection->countHttpSent()}, response {$connection->countHttpReceived()}"); - if ($connection->countHttpSent() === $connection->countHttpReceived() && (!empty($connection->pending_outgoing) || (!empty($connection->new_outgoing) && !$connection->hasPendingCalls()))) { + $API->logger->logger("DC {$datacenter}: request {$connection->countHttpSent()}, response {$connection->countHttpReceived()}"); + if ($connection->countHttpSent() === $connection->countHttpReceived() && (!empty($connection->pending_outgoing) || !empty($connection->new_outgoing) && !$connection->hasPendingCalls())) { yield $connection->sendMessage(['_' => 'http_wait', 'body' => ['max_wait' => 30000, 'wait_after' => 0, 'max_delay' => 0], 'contentRelated' => true, 'unencrypted' => false, 'method' => false]); } - $API->logger->logger("DC $datacenter: request {$connection->countHttpSent()}, response {$connection->countHttpReceived()}"); + $API->logger->logger("DC {$datacenter}: request {$connection->countHttpSent()}, response {$connection->countHttpReceived()}"); } } - public function __toString(): string { return "HTTP wait loop in DC {$this->datacenter}"; diff --git a/src/danog/MadelineProto/Loop/Connection/PingLoop.php b/src/danog/MadelineProto/Loop/Connection/PingLoop.php index c317d304..79842fa7 100644 --- a/src/danog/MadelineProto/Loop/Connection/PingLoop.php +++ b/src/danog/MadelineProto/Loop/Connection/PingLoop.php @@ -1,4 +1,5 @@ connection = $connection; @@ -55,14 +54,12 @@ class PingLoop extends ResumableSignalLoop $this->datacenter = $connection->getDatacenterID(); $this->datacenterConnection = $connection->getShared(); } - - public function loop() + public function loop(): \Generator { $API = $this->API; $datacenter = $this->datacenter; $connection = $this->connection; $shared = $this->datacenterConnection; - $timeout = $shared->getSettings()['timeout']; while (true) { while (!$shared->hasTempAuthKey()) { @@ -74,17 +71,16 @@ class PingLoop extends ResumableSignalLoop return; } if (\time() - $connection->getLastChunk() >= $timeout) { - $API->logger->logger("Ping DC $datacenter"); + $API->logger->logger("Ping DC {$datacenter}"); try { yield $connection->methodCallAsyncRead('ping', ['ping_id' => \random_bytes(8)]); } catch (\Throwable $e) { - $API->logger->logger("Error while pinging DC $datacenter"); + $API->logger->logger("Error while pinging DC {$datacenter}"); $API->logger->logger((string) $e); } } } } - public function __toString(): string { return "Ping loop in DC {$this->datacenter}"; diff --git a/src/danog/MadelineProto/Loop/Connection/ReadLoop.php b/src/danog/MadelineProto/Loop/Connection/ReadLoop.php index 94cb94c6..3a6a4a63 100644 --- a/src/danog/MadelineProto/Loop/Connection/ReadLoop.php +++ b/src/danog/MadelineProto/Loop/Connection/ReadLoop.php @@ -1,4 +1,5 @@ connection = $connection; @@ -65,33 +64,29 @@ class ReadLoop extends SignalLoop $this->datacenter = $connection->getDatacenterID(); $this->datacenterConnection = $connection->getShared(); } - - public function loop() + public function loop(): \Generator { $API = $this->API; $datacenter = $this->datacenter; $connection = $this->connection; $shared = $this->datacenterConnection; - while (true) { try { $error = yield $this->waitSignal($this->readMessage()); - } catch (NothingInTheSocketException | StreamException | PendingReadError | \Error $e) { + } catch (NothingInTheSocketException|StreamException|PendingReadError|\Error $e) { if ($connection->shouldReconnect()) { return; } - Tools::callForkDefer((function () use ($API, $connection, $datacenter, $e) { + Tools::callForkDefer((function () use ($API, $connection, $datacenter, $e): \Generator { $API->logger->logger($e); $API->logger->logger("Got nothing in the socket in DC {$datacenter}, reconnecting...", Logger::ERROR); yield $connection->reconnect(); })()); return; } - if (\is_int($error)) { //$this->exitedLoop(); - - Tools::callForkDefer((function () use ($error, $shared, $connection, $datacenter, $API) { + Tools::callForkDefer((function () use ($error, $shared, $connection, $datacenter, $API): \Generator { if ($error === -404) { if ($shared->hasTempAuthKey()) { $API->logger->logger("WARNING: Resetting auth key in DC {$datacenter}...", \danog\MadelineProto\Logger::WARNING); @@ -117,70 +112,53 @@ class ReadLoop extends SignalLoop yield $connection->reconnect(); } else { yield $connection->reconnect(); - throw new \danog\MadelineProto\RPCErrorException($error, $error); } })()); - return; } - $connection->httpReceived(); - Loop::defer([$connection, 'handleMessages']); - if ($shared->isHttp()) { Loop::defer([$connection, 'pingHttpWaiter']); } } } - - public function readMessage() + public function readMessage(): \Generator { $API = $this->API; $datacenter = $this->datacenter; $connection = $this->connection; $shared = $this->datacenterConnection; - if ($connection->shouldReconnect()) { $API->logger->logger('Not reading because connection is old'); - throw new NothingInTheSocketException(); } - try { $buffer = yield $connection->stream->getReadBuffer($payload_length); } catch (ClosedException $e) { $API->logger->logger($e->getReason()); if (\strpos($e->getReason(), ' ') === 0) { $payload = -\substr($e->getReason(), 7); - $API->logger->logger("Received $payload from DC ".$datacenter, \danog\MadelineProto\Logger::ERROR); - + $API->logger->logger("Received {$payload} from DC " . $datacenter, \danog\MadelineProto\Logger::ERROR); return $payload; } - throw $e; } - if ($payload_length === 4) { $payload = \danog\MadelineProto\Tools::unpackSignedInt(yield $buffer->bufferRead(4)); - $API->logger->logger("Received $payload from DC ".$datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE); - + $API->logger->logger("Received {$payload} from DC " . $datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE); return $payload; } - $connection->reading(true); try { $auth_key_id = yield $buffer->bufferRead(8); - if ($auth_key_id === "\0\0\0\0\0\0\0\0") { $message_id = yield $buffer->bufferRead(8); if (!\in_array($message_id, [1, 0])) { $connection->checkMessageId($message_id, ['outgoing' => false, 'container' => false]); } - $message_length = \unpack('V', yield $buffer->bufferRead(4))[1]; - $message_data = yield $buffer->bufferRead($message_length); $left = $payload_length - $message_length - 4 - 8 - 8; if ($left) { @@ -195,18 +173,17 @@ class ReadLoop extends SignalLoop $message_key = yield $buffer->bufferRead(16); list($aes_key, $aes_iv) = $this->aesCalculate($message_key, $shared->getTempAuthKey()->getAuthKey(), false); $encrypted_data = yield $buffer->bufferRead($payload_length - 24); - $protocol_padding = \strlen($encrypted_data) % 16; if ($protocol_padding) { $encrypted_data = \substr($encrypted_data, 0, -$protocol_padding); } $decrypted_data = $this->igeDecrypt($encrypted_data, $aes_key, $aes_iv); /* - $server_salt = substr($decrypted_data, 0, 8); - if ($server_salt != $shared->getTempAuthKey()->getServerSalt()) { - $API->logger->logger('WARNING: Server salt mismatch (my server salt '.$shared->getTempAuthKey()->getServerSalt().' is not equal to server server salt '.$server_salt.').', \danog\MadelineProto\Logger::WARNING); - } - */ + $server_salt = substr($decrypted_data, 0, 8); + if ($server_salt != $shared->getTempAuthKey()->getServerSalt()) { + $API->logger->logger('WARNING: Server salt mismatch (my server salt '.$shared->getTempAuthKey()->getServerSalt().' is not equal to server server salt '.$server_salt.').', \danog\MadelineProto\Logger::WARNING); + } + */ $session_id = \substr($decrypted_data, 8, 8); if ($session_id != $connection->session_id) { $API->logger->logger("Session ID mismatch", Logger::FATAL_ERROR); @@ -216,7 +193,6 @@ class ReadLoop extends SignalLoop $message_id = \substr($decrypted_data, 16, 8); $connection->checkMessageId($message_id, ['outgoing' => false, 'container' => false]); $seq_no = \unpack('V', \substr($decrypted_data, 24, 4))[1]; - $message_data_length = \unpack('V', \substr($decrypted_data, 28, 4))[1]; if ($message_data_length > \strlen($decrypted_data)) { throw new \danog\MadelineProto\SecurityException('message_data_length is too big'); @@ -234,30 +210,26 @@ class ReadLoop extends SignalLoop throw new \danog\MadelineProto\SecurityException('message_data_length not divisible by 4'); } $message_data = \substr($decrypted_data, 32, $message_data_length); - if ($message_key != \substr(\hash('sha256', \substr($shared->getTempAuthKey()->getAuthKey(), 96, 32).$decrypted_data, true), 8, 16)) { + if ($message_key != \substr(\hash('sha256', \substr($shared->getTempAuthKey()->getAuthKey(), 96, 32) . $decrypted_data, true), 8, 16)) { throw new \danog\MadelineProto\SecurityException('msg_key mismatch'); } $connection->incoming_messages[$message_id] = ['seq_no' => $seq_no]; } else { $API->logger->logger('Got unknown auth_key id', \danog\MadelineProto\Logger::ERROR); - return -404; } $deserialized = $API->getTL()->deserialize($message_data, ['type' => '', 'connection' => $connection]); $API->referenceDatabase->reset(); - $connection->incoming_messages[$message_id]['content'] = $deserialized; $connection->incoming_messages[$message_id]['response'] = -1; $connection->new_incoming[$message_id] = $message_id; //$connection->last_http_wait = 0; - - $API->logger->logger('Received payload from DC '.$datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE); + $API->logger->logger('Received payload from DC ' . $datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE); } finally { $connection->reading(false); } return true; } - public function __toString(): string { return "read loop in DC {$this->datacenter}"; diff --git a/src/danog/MadelineProto/Loop/Connection/WriteLoop.php b/src/danog/MadelineProto/Loop/Connection/WriteLoop.php index 39534537..8ab1b5ad 100644 --- a/src/danog/MadelineProto/Loop/Connection/WriteLoop.php +++ b/src/danog/MadelineProto/Loop/Connection/WriteLoop.php @@ -1,4 +1,5 @@ connection = $connection; @@ -62,14 +61,12 @@ class WriteLoop extends ResumableSignalLoop $ctx = $connection->getCtx(); $this->datacenter = $connection->getDatacenterID(); } - public function loop(): \Generator { $API = $this->API; $connection = $this->connection; $shared = $this->datacenterConnection; $datacenter = $this->datacenter; - $please_wait = false; while (true) { while (empty($connection->pending_outgoing) || $please_wait) { @@ -77,21 +74,18 @@ class WriteLoop extends ResumableSignalLoop $API->logger->logger('Not writing because connection is old'); return; } - $please_wait = false; - $API->logger->logger("Waiting in $this", Logger::ULTRA_VERBOSE); + $API->logger->logger("Waiting in {$this}", Logger::ULTRA_VERBOSE); if (yield $this->waitSignal($this->pause())) { - $API->logger->logger("Exiting $this", Logger::ULTRA_VERBOSE); + $API->logger->logger("Exiting {$this}", Logger::ULTRA_VERBOSE); return; } - $API->logger->logger("Done waiting in $this", Logger::ULTRA_VERBOSE); - + $API->logger->logger("Done waiting in {$this}", Logger::ULTRA_VERBOSE); if ($connection->shouldReconnect()) { $API->logger->logger('Not writing because connection is old'); return; } } - $connection->writing(true); try { $please_wait = yield $this->{$shared->hasTempAuthKey() ? 'encryptedWriteLoop' : 'unencryptedWriteLoop'}(); @@ -99,7 +93,7 @@ class WriteLoop extends ResumableSignalLoop if ($connection->shouldReconnect()) { return; } - Tools::callForkDefer((function () use ($API, $connection, $datacenter, $e) { + Tools::callForkDefer((function () use ($API, $connection, $datacenter, $e): \Generator { $API->logger->logger($e); $API->logger->logger("Got nothing in the socket in DC {$datacenter}, reconnecting...", Logger::ERROR); yield $connection->reconnect(); @@ -108,18 +102,15 @@ class WriteLoop extends ResumableSignalLoop } finally { $connection->writing(false); } - //$connection->waiter->resume(); } } - - public function unencryptedWriteLoop() + public function unencryptedWriteLoop(): \Generator { $API = $this->API; $datacenter = $this->datacenter; $connection = $this->connection; $shared = $this->datacenterConnection; - while ($connection->pending_outgoing) { $skipped_all = true; foreach ($connection->pending_outgoing as $k => $message) { @@ -130,20 +121,14 @@ class WriteLoop extends ResumableSignalLoop continue; } $skipped_all = false; - $API->logger->logger("Sending {$message['_']} as unencrypted message to DC {$datacenter}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); - $message_id = isset($message['msg_id']) ? $message['msg_id'] : $connection->generateMessageId(); $length = \strlen($message['serialized_body']); - $pad_length = -$length & 15; $pad_length += 16 * \danog\MadelineProto\Tools::randomInt($modulus = 16); - $pad = \danog\MadelineProto\Tools::random($pad_length); $buffer = yield $connection->stream->getWriteBuffer(8 + 8 + 4 + $pad_length + $length); - - yield $buffer->bufferWrite("\0\0\0\0\0\0\0\0".$message_id.\danog\MadelineProto\Tools::packUnsignedInt($length).$message['serialized_body'].$pad); - + yield $buffer->bufferWrite("\0\0\0\0\0\0\0\0" . $message_id . \danog\MadelineProto\Tools::packUnsignedInt($length) . $message['serialized_body'] . $pad); //var_dump("plain ".bin2hex($message_id)); $connection->httpSent(); $connection->outgoing_messages[$message_id] = $message; @@ -151,11 +136,8 @@ class WriteLoop extends ResumableSignalLoop $connection->outgoing_messages[$message_id]['tries'] = 0; $connection->outgoing_messages[$message_id]['unencrypted'] = true; $connection->new_outgoing[$message_id] = $message_id; - unset($connection->pending_outgoing[$k]); - $API->logger->logger("Sent {$message['_']} as unencrypted message to DC {$datacenter}!", \danog\MadelineProto\Logger::ULTRA_VERBOSE); - $message['send_promise']->resolve(isset($message['promise']) ? $message['promise'] : true); unset($message['send_promise']); } @@ -164,14 +146,12 @@ class WriteLoop extends ResumableSignalLoop } } } - public function encryptedWriteLoop(): \Generator { $API = $this->API; $datacenter = $this->datacenter; $connection = $this->connection; $shared = $this->datacenterConnection; - do { if (!$shared->hasTempAuthKey()) { return; @@ -182,13 +162,12 @@ class WriteLoop extends ResumableSignalLoop $temporary_keys = []; if (\count($to_ack = $connection->ack_queue)) { foreach (\array_chunk($connection->ack_queue, 8192) as $acks) { - $connection->pending_outgoing[$connection->pending_outgoing_key] = ['_' => 'msgs_ack', 'serialized_body' => yield $this->API->getTL()->serializeObject(['type' => ''], ['_' => 'msgs_ack','msg_ids' => $acks], 'msgs_ack'), 'contentRelated' => false, 'unencrypted' => false, 'method' => false]; + $connection->pending_outgoing[$connection->pending_outgoing_key] = ['_' => 'msgs_ack', 'serialized_body' => yield $this->API->getTL()->serializeObject(['type' => ''], ['_' => 'msgs_ack', 'msg_ids' => $acks], 'msgs_ack'), 'contentRelated' => false, 'unencrypted' => false, 'method' => false]; $temporary_keys[$connection->pending_outgoing_key] = true; $API->logger->logger("Adding msgs_ack {$connection->pending_outgoing_key}", Logger::ULTRA_VERBOSE); $connection->pending_outgoing_key++; } } - $has_http_wait = false; $messages = []; $keys = []; @@ -206,7 +185,6 @@ class WriteLoop extends ResumableSignalLoop $connection->pending_outgoing_key++; } } - $total_length = 0; $count = 0; \ksort($connection->pending_outgoing); @@ -231,45 +209,20 @@ class WriteLoop extends ResumableSignalLoop $API->logger->logger('Length overflow, postponing part of payload', \danog\MadelineProto\Logger::ULTRA_VERBOSE); break; } - $message_id = isset($message['msg_id']) ? $message['msg_id'] : $connection->generateMessageId(); - $API->logger->logger("Sending {$message['_']} as encrypted message to DC {$datacenter}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); - $MTmessage = ['_' => 'MTmessage', 'msg_id' => $message_id, 'body' => $message['serialized_body'], 'seqno' => $connection->generateOutSeqNo($message['contentRelated'])]; - if (isset($message['method']) && $message['method'] && $message['_'] !== 'http_wait') { if (!$shared->getTempAuthKey()->isInited() && $message['_'] !== 'auth.bindTempAuthKey' && !$inited) { $inited = true; $API->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['write_client_info'], $message['_']), \danog\MadelineProto\Logger::NOTICE); - $MTmessage['body'] = yield $API->getTL()->serializeMethod( - 'invokeWithLayer', - [ - 'layer' => $API->settings['tl_schema']['layer'], - 'query' => yield $API->getTL()->serializeMethod( - 'initConnection', - [ - 'api_id' => $API->settings['app_info']['api_id'], - 'api_hash' => $API->settings['app_info']['api_hash'], - 'device_model' => !$connection->isCDN() ? $API->settings['app_info']['device_model'] : 'n/a', - 'system_version' => !$connection->isCDN() ? $API->settings['app_info']['system_version'] : 'n/a', - 'app_version' => $API->settings['app_info']['app_version'], - 'system_lang_code' => $API->settings['app_info']['lang_code'], - 'lang_code' => $API->settings['app_info']['lang_code'], - 'lang_pack' => $API->settings['app_info']['lang_pack'], - 'proxy' => $connection->getCtx()->getInputClientProxy(), - 'query' => $MTmessage['body'], - ] - ), - ] - ); + $MTmessage['body'] = yield $API->getTL()->serializeMethod('invokeWithLayer', ['layer' => $API->settings['tl_schema']['layer'], 'query' => yield $API->getTL()->serializeMethod('initConnection', ['api_id' => $API->settings['app_info']['api_id'], 'api_hash' => $API->settings['app_info']['api_hash'], 'device_model' => !$connection->isCDN() ? $API->settings['app_info']['device_model'] : 'n/a', 'system_version' => !$connection->isCDN() ? $API->settings['app_info']['system_version'] : 'n/a', 'app_version' => $API->settings['app_info']['app_version'], 'system_lang_code' => $API->settings['app_info']['lang_code'], 'lang_code' => $API->settings['app_info']['lang_code'], 'lang_pack' => $API->settings['app_info']['lang_pack'], 'proxy' => $connection->getCtx()->getInputClientProxy(), 'query' => $MTmessage['body']])]); } else { if (isset($message['queue'])) { if (!isset($connection->call_queue[$message['queue']])) { $connection->call_queue[$message['queue']] = []; } $MTmessage['body'] = yield $API->getTL()->serializeMethod('invokeAfterMsgs', ['msg_ids' => $connection->call_queue[$message['queue']], 'query' => $MTmessage['body']]); - $connection->call_queue[$message['queue']][$message_id] = $message_id; if (\count($connection->call_queue[$message['queue']]) > $API->settings['msg_array_limit']['call_queue']) { \reset($connection->call_queue[$message['queue']]); @@ -279,12 +232,12 @@ class WriteLoop extends ResumableSignalLoop } // TODO /* if ($API->settings['requests']['gzip_encode_if_gt'] !== -1 && ($l = strlen($MTmessage['body'])) > $API->settings['requests']['gzip_encode_if_gt']) { - if (($g = strlen($gzipped = gzencode($MTmessage['body']))) < $l) { - $MTmessage['body'] = yield $API->getTL()->serializeObject(['type' => ''], ['_' => 'gzip_packed', 'packed_data' => $gzipped], 'gzipped data'); - $API->logger->logger('Using GZIP compression for ' . $message['_'] . ', saved ' . ($l - $g) . ' bytes of data, reduced call size by ' . $g * 100 / $l . '%', \danog\MadelineProto\Logger::ULTRA_VERBOSE); - } - unset($gzipped); - }*/ + if (($g = strlen($gzipped = gzencode($MTmessage['body']))) < $l) { + $MTmessage['body'] = yield $API->getTL()->serializeObject(['type' => ''], ['_' => 'gzip_packed', 'packed_data' => $gzipped], 'gzipped data'); + $API->logger->logger('Using GZIP compression for ' . $message['_'] . ', saved ' . ($l - $g) . ' bytes of data, reduced call size by ' . $g * 100 / $l . '%', \danog\MadelineProto\Logger::ULTRA_VERBOSE); + } + unset($gzipped); + }*/ } } $body_length = \strlen($MTmessage['body']); @@ -295,32 +248,25 @@ class WriteLoop extends ResumableSignalLoop } $count++; $total_length += $actual_length; - $MTmessage['bytes'] = $body_length; $messages[] = $MTmessage; $keys[$k] = $message_id; } if ($shared->isHttp() && $skipped && $count === \count($temporary_keys)) { foreach ($temporary_keys as $key => $true) { - $API->logger->logger("Removing temporary {$connection->pending_outgoing[$key]['_']} by $key", Logger::ULTRA_VERBOSE); + $API->logger->logger("Removing temporary {$connection->pending_outgoing[$key]['_']} by {$key}", Logger::ULTRA_VERBOSE); unset($connection->pending_outgoing[$key]); $count--; } } - $MTmessage = null; - if ($count > 1) { - $API->logger->logger("Wrapping in msg_container ($count messages of total size $total_length) as encrypted message for DC {$datacenter}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); - + $API->logger->logger("Wrapping in msg_container ({$count} messages of total size {$total_length}) as encrypted message for DC {$datacenter}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); $message_id = $connection->generateMessageId(); $connection->pending_outgoing[$connection->pending_outgoing_key] = ['_' => 'msg_container', 'container' => \array_values($keys), 'contentRelated' => false, 'method' => false, 'unencrypted' => false]; - //var_dumP("container ".bin2hex($message_id)); $keys[$connection->pending_outgoing_key++] = $message_id; - $message_data = yield $API->getTL()->serializeObject(['type' => ''], ['_' => 'msg_container', 'messages' => $messages], 'container'); - $message_data_length = \strlen($message_data); $seq_no = $connection->generateOutSeqNo(false); } elseif ($count) { @@ -330,44 +276,30 @@ class WriteLoop extends ResumableSignalLoop $message_id = $message['msg_id']; $seq_no = $message['seqno']; } else { - $API->logger->logger("NO MESSAGE SENT in DC $datacenter", \danog\MadelineProto\Logger::WARNING); - + $API->logger->logger("NO MESSAGE SENT in DC {$datacenter}", \danog\MadelineProto\Logger::WARNING); return true; } - unset($messages); - - $plaintext = $shared->getTempAuthKey()->getServerSalt().$connection->session_id.$message_id.\pack('VV', $seq_no, $message_data_length).$message_data; + $plaintext = $shared->getTempAuthKey()->getServerSalt() . $connection->session_id . $message_id . \pack('VV', $seq_no, $message_data_length) . $message_data; $padding = \danog\MadelineProto\Tools::posmod(-\strlen($plaintext), 16); if ($padding < 12) { $padding += 16; } $padding = \danog\MadelineProto\Tools::random($padding); - - $message_key = \substr(\hash('sha256', \substr($shared->getTempAuthKey()->getAuthKey(), 88, 32).$plaintext.$padding, true), 8, 16); - + $message_key = \substr(\hash('sha256', \substr($shared->getTempAuthKey()->getAuthKey(), 88, 32) . $plaintext . $padding, true), 8, 16); list($aes_key, $aes_iv) = $this->aesCalculate($message_key, $shared->getTempAuthKey()->getAuthKey()); - - $message = $shared->getTempAuthKey()->getID().$message_key.$this->igeEncrypt($plaintext.$padding, $aes_key, $aes_iv); - + $message = $shared->getTempAuthKey()->getID() . $message_key . $this->igeEncrypt($plaintext . $padding, $aes_key, $aes_iv); $buffer = yield $connection->stream->getWriteBuffer($len = \strlen($message)); - //$t = \microtime(true); yield $buffer->bufferWrite($message); - $connection->httpSent(); - $API->logger->logger("Sent encrypted payload to DC {$datacenter}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); - $sent = \time(); - if ($to_ack) { $connection->ack_queue = []; } - foreach ($keys as $key => $message_id) { - $connection->outgoing_messages[$message_id] = &$connection->pending_outgoing[$key]; - + $connection->outgoing_messages[$message_id] =& $connection->pending_outgoing[$key]; if (isset($connection->outgoing_messages[$message_id]['promise'])) { $connection->new_outgoing[$message_id] = $message_id; $connection->outgoing_messages[$message_id]['sent'] = $sent; @@ -380,17 +312,13 @@ class WriteLoop extends ResumableSignalLoop //var_dumP("encrypted ".bin2hex($message_id)." ".$connection->outgoing_messages[$message_id]['_']); unset($connection->pending_outgoing[$key]); } - //if (!empty($connection->pending_outgoing)) $connection->select(); } while (!empty($connection->pending_outgoing) && !$skipped); - if (empty($connection->pending_outgoing)) { $connection->pending_outgoing_key = 'a'; } - return $skipped; } - public function __toString(): string { return "write loop in DC {$this->datacenter}"; diff --git a/src/danog/MadelineProto/Loop/Generic/GenericLoop.php b/src/danog/MadelineProto/Loop/Generic/GenericLoop.php index 1f50c269..6efdc3e0 100644 --- a/src/danog/MadelineProto/Loop/Generic/GenericLoop.php +++ b/src/danog/MadelineProto/Loop/Generic/GenericLoop.php @@ -1,4 +1,5 @@ callback = $callback->bindTo($this); $this->name = $name; } - - public function loop() + public function loop(): \Generator { $callback = $this->callback; - while (true) { $timeout = yield $callback(); if ($timeout === self::PAUSE) { - $this->API->logger->logger("Pausing $this", \danog\MadelineProto\Logger::VERBOSE); + $this->API->logger->logger("Pausing {$this}", \danog\MadelineProto\Logger::VERBOSE); } elseif ($timeout > 0) { - $this->API->logger->logger("Pausing $this for $timeout", \danog\MadelineProto\Logger::VERBOSE); + $this->API->logger->logger("Pausing {$this} for {$timeout}", \danog\MadelineProto\Logger::VERBOSE); } if ($timeout === self::STOP || yield $this->waitSignal($this->pause($timeout))) { return; } } } - public function __toString(): string { return $this->name; diff --git a/src/danog/MadelineProto/Loop/Generic/PeriodicLoop.php b/src/danog/MadelineProto/Loop/Generic/PeriodicLoop.php index 7e45e629..c0fb8823 100644 --- a/src/danog/MadelineProto/Loop/Generic/PeriodicLoop.php +++ b/src/danog/MadelineProto/Loop/Generic/PeriodicLoop.php @@ -1,4 +1,5 @@ name = $name; $this->timeout = $timeout; } - - public function loop() + public function loop(): \Generator { $callback = $this->callback; $logger = $this->API->logger; - while (true) { $result = yield $this->waitSignal($this->pause($this->timeout)); if ($result) { - $logger->logger("Got signal in $this, exiting"); + $logger->logger("Got signal in {$this}, exiting"); return; } yield $callback(); } } - public function __toString(): string { return $this->name; diff --git a/src/danog/MadelineProto/Loop/Impl/Loop.php b/src/danog/MadelineProto/Loop/Impl/Loop.php index 5d5dd353..7aef4f90 100644 --- a/src/danog/MadelineProto/Loop/Impl/Loop.php +++ b/src/danog/MadelineProto/Loop/Impl/Loop.php @@ -1,4 +1,5 @@ API = $API; } - public function start() { if ($this->count) { //$this->API->logger->logger("NOT entering $this with running count {$this->count}", Logger::ERROR); - return false; } return \danog\MadelineProto\Tools::callFork($this->loopImpl()); } - - private function loopImpl() + private function loopImpl(): \Generator { //yield ['my_trace' => debug_backtrace(0, 1)[0], (string) $this]; $this->startedLoop(); - $this->API->logger->logger("Entered $this", Logger::ULTRA_VERBOSE); - + $this->API->logger->logger("Entered {$this}", Logger::ULTRA_VERBOSE); try { yield $this->loop(); } finally { $this->exitedLoop(); - $this->API->logger->logger("Physically exited $this", Logger::ULTRA_VERBOSE); + $this->API->logger->logger("Physically exited {$this}", Logger::ULTRA_VERBOSE); //return null; } } - public function exitedLoop() { if ($this->count) { - $this->API->logger->logger("Exited $this", Logger::ULTRA_VERBOSE); + $this->API->logger->logger("Exited {$this}", Logger::ULTRA_VERBOSE); $this->count--; } } - public function startedLoop() { $this->count++; } - public function isRunning() { return $this->count; diff --git a/src/danog/MadelineProto/Loop/Impl/ResumableSignalLoop.php b/src/danog/MadelineProto/Loop/Impl/ResumableSignalLoop.php index 0dcaf35b..c0f1207d 100644 --- a/src/danog/MadelineProto/Loop/Impl/ResumableSignalLoop.php +++ b/src/danog/MadelineProto/Loop/Impl/ResumableSignalLoop.php @@ -1,4 +1,5 @@ resumeWatcher = Loop::delay((int) ($time * 1000), [$this, 'resume'], $resume); } $this->resume = new Deferred(); - $pause = $this->pause; $this->pause = new Deferred(); if ($pause) { Loop::defer([$pause, 'resolve']); } - return $this->resume->promise(); } - public function resume($watcherId = null, $expected = 0) { if ($this->resumeWatcher) { @@ -75,15 +72,12 @@ abstract class ResumableSignalLoop extends SignalLoop implements ResumableLoopIn $resume = $this->resume; $this->resume = null; $resume->resolve(); - return $this->pause ? $this->pause->promise() : null; } } - public function resumeDefer() { Loop::defer([$this, 'resume']); - return $this->pause ? $this->pause->promise() : null; } } diff --git a/src/danog/MadelineProto/Loop/Impl/SignalLoop.php b/src/danog/MadelineProto/Loop/Impl/SignalLoop.php index ace13180..167f072d 100644 --- a/src/danog/MadelineProto/Loop/Impl/SignalLoop.php +++ b/src/danog/MadelineProto/Loop/Impl/SignalLoop.php @@ -1,4 +1,5 @@ signalDeferred) { @@ -44,7 +44,6 @@ abstract class SignalLoop extends Loop implements SignalLoopInterface } } } - public function waitSignal($promise): Promise { if ($promise instanceof \Generator) { @@ -52,7 +51,6 @@ abstract class SignalLoop extends Loop implements SignalLoopInterface } $this->signalDeferred = new Deferred(); $dpromise = $this->signalDeferred->promise(); - $promise->onResolve(function () use ($promise) { if ($this->signalDeferred !== null) { $deferred = $this->signalDeferred; @@ -60,7 +58,6 @@ abstract class SignalLoop extends Loop implements SignalLoopInterface $deferred->resolve($promise); } }); - return $dpromise; } } diff --git a/src/danog/MadelineProto/Loop/LoopInterface.php b/src/danog/MadelineProto/Loop/LoopInterface.php index d6dac026..4f851671 100644 --- a/src/danog/MadelineProto/Loop/LoopInterface.php +++ b/src/danog/MadelineProto/Loop/LoopInterface.php @@ -1,4 +1,5 @@ API = $API; $this->channelId = $channelId; } - - public function loop() + public function loop(): \Generator { $API = $this->API; $this->updater = $API->updaters[$this->channelId]; - if (!$this->API->settings['updates']['handle_updates']) { return false; } - while (!$this->API->settings['updates']['handle_updates'] || !$API->hasAllAuth()) { if (yield $this->waitSignal($this->pause())) { return; } } - $this->state = $this->channelId === false ? (yield $API->loadUpdateState()) : $API->loadChannelState($this->channelId); - + $this->state = $this->channelId === false ? yield $API->loadUpdateState() : $API->loadChannelState($this->channelId); while (true) { while (!$this->API->settings['updates']['handle_updates'] || !$API->hasAllAuth()) { if (yield $this->waitSignal($this->pause())) { @@ -73,11 +69,11 @@ class FeedLoop extends ResumableSignalLoop if (!$this->API->settings['updates']['handle_updates']) { return; } - $API->logger->logger("Resumed $this"); + $API->logger->logger("Resumed {$this}"); while ($this->incomingUpdates) { $updates = $this->incomingUpdates; $this->incomingUpdates = []; - yield $this->parse($updates); + yield from $this->parse($updates); $updates = null; } while ($this->parsedUpdates) { @@ -91,8 +87,7 @@ class FeedLoop extends ResumableSignalLoop } } } - - public function parse($updates) + public function parse($updates): \Generator { \reset($updates); while ($updates) { @@ -102,7 +97,6 @@ class FeedLoop extends ResumableSignalLoop if ($update['_'] === 'updateChannelTooLong') { $this->API->logger->logger('Got channel too long update, getting difference...', \danog\MadelineProto\Logger::VERBOSE); yield $this->updater->resume(); - continue; } if (isset($update['pts'], $update['pts_count'])) { @@ -111,12 +105,11 @@ class FeedLoop extends ResumableSignalLoop $mid = isset($update['message']['id']) ? $update['message']['id'] : '-'; $mypts = $this->state->pts(); $computed = $mypts + $pts_count; - $this->API->logger->logger("$msg. My pts: {$mypts}, remote pts: {$update['pts']}, computed pts: $computed, msg id: {$mid}, channel id: {$this->channelId}", \danog\MadelineProto\Logger::ERROR); + $this->API->logger->logger("{$msg}. My pts: {$mypts}, remote pts: {$update['pts']}, computed pts: {$computed}, msg id: {$mid}, channel id: {$this->channelId}", \danog\MadelineProto\Logger::ERROR); }; $result = $this->state->checkPts($update); if ($result < 0) { $logger('PTS duplicate'); - continue; } if ($result > 0) { @@ -130,19 +123,16 @@ class FeedLoop extends ResumableSignalLoop if (isset($update['message']['id'], $update['message']['to_id']) && !\in_array($update['_'], ['updateEditMessage', 'updateEditChannelMessage', 'updateMessageID'])) { if (!$this->API->checkMsgId($update['message'])) { $logger('MSGID duplicate'); - continue; } } $logger('PTS OK'); - $this->state->pts($update['pts']); } $this->save($update); } } - - public function feed($updates) + public function feed($updates): \Generator { $result = []; foreach ($updates as $update) { @@ -152,11 +142,9 @@ class FeedLoop extends ResumableSignalLoop } $result[$res] = true; } - return $result; } - - public function feedSingle($update) + public function feedSingle($update): \Generator { $channelId = false; switch ($update['_']) { @@ -178,7 +166,6 @@ class FeedLoop extends ResumableSignalLoop } break; } - if ($channelId && !$this->API->getChannelStates()->has($channelId)) { $this->API->loadChannelState($channelId, $update); if (!isset($this->API->feeders[$channelId])) { @@ -190,7 +177,6 @@ class FeedLoop extends ResumableSignalLoop $this->API->feeders[$channelId]->start(); $this->API->updaters[$channelId]->start(); } - switch ($update['_']) { case 'updateNewMessage': case 'updateEditMessage': @@ -200,31 +186,21 @@ class FeedLoop extends ResumableSignalLoop $from = false; $via_bot = false; $entities = false; - if ($update['message']['_'] !== 'messageEmpty' && ( - ($from = isset($update['message']['from_id']) && !yield $this->API->peerIsset($update['message']['from_id'])) || - ($to = !yield $this->API->peerIsset($update['message']['to_id'])) || - ($via_bot = isset($update['message']['via_bot_id']) && !yield $this->API->peerIsset($update['message']['via_bot_id'])) || - ($entities = isset($update['message']['entities']) && !yield $this->API->entitiesPeerIsset($update['message']['entities'])) // || - //isset($update['message']['fwd_from']) && !yield $this->fwdPeerIsset($update['message']['fwd_from']) - )) { + if ($update['message']['_'] !== 'messageEmpty' && (($from = isset($update['message']['from_id']) && !yield $this->API->peerIsset($update['message']['from_id'])) || ($to = !yield $this->API->peerIsset($update['message']['to_id'])) || ($via_bot = isset($update['message']['via_bot_id']) && !yield $this->API->peerIsset($update['message']['via_bot_id'])) || ($entities = isset($update['message']['entities']) && !yield $this->API->entitiesPeerIsset($update['message']['entities'])))) { $log = ''; if ($from) { $log .= "from_id {$update['message']['from_id']}, "; } - if ($to) { - $log .= 'to_id '.\json_encode($update['message']['to_id']).', '; + $log .= 'to_id ' . \json_encode($update['message']['to_id']) . ', '; } - if ($via_bot) { $log .= "via_bot {$update['message']['via_bot_id']}, "; } - if ($entities) { - $log .= 'entities '.\json_encode($update['message']['entities']).', '; + $log .= 'entities ' . \json_encode($update['message']['entities']) . ', '; } - - $this->API->logger->logger("Not enough data: for message update $log, getting difference...", \danog\MadelineProto\Logger::VERBOSE); + $this->API->logger->logger("Not enough data: for message update {$log}, getting difference...", \danog\MadelineProto\Logger::VERBOSE); $update = ['_' => 'updateChannelTooLong']; if ($channelId && $to) { $channelId = false; @@ -233,47 +209,39 @@ class FeedLoop extends ResumableSignalLoop break; default: if ($channelId && !yield $this->API->peerIsset($this->API->toSupergroup($channelId))) { - $this->API->logger->logger('Skipping update, I do not have the channel id '.$channelId, \danog\MadelineProto\Logger::ERROR); - + $this->API->logger->logger('Skipping update, I do not have the channel id ' . $channelId, \danog\MadelineProto\Logger::ERROR); return false; } break; } if ($channelId !== $this->channelId) { if (isset($this->API->feeders[$channelId])) { - return yield $this->API->feeders[$channelId]->feedSingle($update); + return yield from $this->API->feeders[$channelId]->feedSingle($update); } elseif ($this->channelId) { - return yield $this->API->feeders[false]->feedSingle($update); + return yield from $this->API->feeders[false]->feedSingle($update); } } - - $this->API->logger->logger('Was fed an update of type '.$update['_']." in $this...", \danog\MadelineProto\Logger::VERBOSE); + $this->API->logger->logger('Was fed an update of type ' . $update['_'] . " in {$this}...", \danog\MadelineProto\Logger::VERBOSE); $this->incomingUpdates[] = $update; - return $this->channelId; } - public function save($update) { $this->parsedUpdates[] = $update; } - public function saveMessages($messages) { foreach ($messages as $message) { if (!$this->API->checkMsgId($message)) { - $this->API->logger->logger("MSGID duplicate ({$message['id']}) in $this"); - + $this->API->logger->logger("MSGID duplicate ({$message['id']}) in {$this}"); continue; } if ($message['_'] !== 'messageEmpty') { - $this->API->logger->logger('Getdiff fed me message of type '.$message['_']." in $this...", \danog\MadelineProto\Logger::VERBOSE); + $this->API->logger->logger('Getdiff fed me message of type ' . $message['_'] . " in {$this}...", \danog\MadelineProto\Logger::VERBOSE); } - $this->parsedUpdates[] = ['_' => $this->channelId === false ? 'updateNewMessage' : 'updateNewChannelMessage', 'message' => $message, 'pts' => -1, 'pts_count' => -1]; } } - public function __toString(): string { return !$this->channelId ? 'update feed loop generic' : "update feed loop channel {$this->channelId}"; diff --git a/src/danog/MadelineProto/Loop/Update/SeqLoop.php b/src/danog/MadelineProto/Loop/Update/SeqLoop.php index d2e32624..e1d60572 100644 --- a/src/danog/MadelineProto/Loop/Update/SeqLoop.php +++ b/src/danog/MadelineProto/Loop/Update/SeqLoop.php @@ -1,4 +1,5 @@ API = $API; } - - public function loop() + public function loop(): \Generator { $API = $this->API; $this->feeder = $API->feeders[false]; - if (!$this->API->settings['updates']['handle_updates']) { return false; } - while (!$this->API->settings['updates']['handle_updates'] || !$API->hasAllAuth()) { if (yield $this->waitSignal($this->pause())) { return; } } $this->state = yield $API->loadUpdateState(); - while (true) { while (!$this->API->settings['updates']['handle_updates'] || !$API->hasAllAuth()) { if (yield $this->waitSignal($this->pause())) { @@ -68,7 +64,7 @@ class SeqLoop extends ResumableSignalLoop while ($this->incomingUpdates) { $updates = $this->incomingUpdates; $this->incomingUpdates = []; - yield $this->parse($updates); + yield from $this->parse($updates); $updates = null; } while ($this->pendingWakeups) { @@ -79,8 +75,7 @@ class SeqLoop extends ResumableSignalLoop } } } - - public function parse($updates) + public function parse($updates): \Generator { \reset($updates); while ($updates) { @@ -88,53 +83,43 @@ class SeqLoop extends ResumableSignalLoop $key = \key($updates); $update = $updates[$key]; unset($updates[$key]); - $options = $update['options']; $seq_start = $options['seq_start']; $seq_end = $options['seq_end']; - $result = $this->state->checkSeq($seq_start); if ($result > 0) { - $this->API->logger->logger('Seq hole. seq_start: '.$seq_start.' != cur seq: '.($this->state->seq() + 1), \danog\MadelineProto\Logger::ERROR); + $this->API->logger->logger('Seq hole. seq_start: ' . $seq_start . ' != cur seq: ' . ($this->state->seq() + 1), \danog\MadelineProto\Logger::ERROR); yield $this->pause(1.0); if (!$this->incomingUpdates) { yield $this->API->updaters[false]->resume(); } $this->incomingUpdates = \array_merge($this->incomingUpdates, [$update], $updates); - continue; } if ($result < 0) { - $this->API->logger->logger('Seq too old. seq_start: '.$seq_start.' != cur seq: '.($this->state->seq() + 1), \danog\MadelineProto\Logger::ERROR); + $this->API->logger->logger('Seq too old. seq_start: ' . $seq_start . ' != cur seq: ' . ($this->state->seq() + 1), \danog\MadelineProto\Logger::ERROR); continue; } $this->state->seq($seq_end); if (isset($options['date'])) { $this->state->date($options['date']); } - - yield $this->save($update); + yield from $this->save($update); } } - public function feed($updates) { - $this->API->logger->logger('Was fed updates of type '.$updates['_'].'...', \danog\MadelineProto\Logger::VERBOSE); - + $this->API->logger->logger('Was fed updates of type ' . $updates['_'] . '...', \danog\MadelineProto\Logger::VERBOSE); $this->incomingUpdates[] = $updates; } - - public function save($updates) + public function save($updates): \Generator { $this->pendingWakeups += yield $this->feeder->feed($updates['updates']); } - public function addPendingWakeups($wakeups) { $this->pendingWakeups += $wakeups; } - - public function __toString(): string { return 'update seq loop'; diff --git a/src/danog/MadelineProto/Loop/Update/UpdateLoop.php b/src/danog/MadelineProto/Loop/Update/UpdateLoop.php index 6061aaf9..59ce4026 100644 --- a/src/danog/MadelineProto/Loop/Update/UpdateLoop.php +++ b/src/danog/MadelineProto/Loop/Update/UpdateLoop.php @@ -1,4 +1,5 @@ API = $API; $this->channelId = $channelId; } - - public function loop() + public function loop(): \Generator { $API = $this->API; $feeder = $this->feeder = $API->feeders[$this->channelId]; - while (!$API->settings['updates']['handle_updates'] || !$API->hasAllAuth()) { if (yield $this->waitSignal($this->pause())) { - $API->logger->logger("Exiting $this due to signal"); - + $API->logger->logger("Exiting {$this} due to signal"); return; } } - $this->state = $state = $this->channelId === false ? (yield $API->loadUpdateState()) : $API->loadChannelState($this->channelId); - + $this->state = $state = $this->channelId === false ? yield $API->loadUpdateState() : $API->loadChannelState($this->channelId); $timeout = $API->settings['updates']['getdifference_interval']; $first = true; while (true) { while (!$API->settings['updates']['handle_updates'] || !$API->hasAllAuth()) { if (yield $this->waitSignal($this->pause())) { - $API->logger->logger("Exiting $this due to signal"); - + $API->logger->logger("Exiting {$this} due to signal"); return; } } @@ -71,7 +65,7 @@ class UpdateLoop extends ResumableSignalLoop $this->toPts = null; while (true) { if ($this->channelId) { - $API->logger->logger('Resumed and fetching '.$this->channelId.' difference...', \danog\MadelineProto\Logger::ULTRA_VERBOSE); + $API->logger->logger('Resumed and fetching ' . $this->channelId . ' difference...', \danog\MadelineProto\Logger::ULTRA_VERBOSE); if ($state->pts() <= 1) { $limit = 10; } elseif ($API->authorization['user']['bot']) { @@ -80,17 +74,14 @@ class UpdateLoop extends ResumableSignalLoop $limit = 100; } $request_pts = $state->pts(); - try { - $difference = yield $API->methodCallAsyncRead('updates.getChannelDifference', ['channel' => 'channel#'.$this->channelId, 'filter' => ['_' => 'channelMessagesFilterEmpty'], 'pts' => $request_pts, 'limit' => $limit, 'force' => true], ['datacenter' => $API->datacenter->curdc, 'postpone' => $first]); + $difference = yield $API->methodCallAsyncRead('updates.getChannelDifference', ['channel' => 'channel#' . $this->channelId, 'filter' => ['_' => 'channelMessagesFilterEmpty'], 'pts' => $request_pts, 'limit' => $limit, 'force' => true], ['datacenter' => $API->datacenter->curdc, 'postpone' => $first]); } catch (RPCErrorException $e) { if (\in_array($e->rpc, ['CHANNEL_PRIVATE', 'CHAT_FORBIDDEN', 'CHANNEL_INVALID'])) { $feeder->signal(true); unset($API->updaters[$this->channelId], $API->feeders[$this->channelId]); - $API->getChannelStates()->remove($this->channelId); - $API->logger->logger("Channel private, exiting $this"); - + $API->logger->logger("Channel private, exiting {$this}"); return true; } throw $e; @@ -99,9 +90,7 @@ class UpdateLoop extends ResumableSignalLoop $feeder->signal(true); $API->getChannelStates()->remove($this->channelId); unset($API->updaters[$this->channelId], $API->feeders[$this->channelId]); - - $API->logger->logger("Channel private, exiting $this"); - + $API->logger->logger("Channel private, exiting {$this}"); return true; } throw $e; @@ -109,8 +98,7 @@ class UpdateLoop extends ResumableSignalLoop if (isset($difference['timeout'])) { $timeout = $difference['timeout']; } - - $API->logger->logger('Got '.$difference['_'], \danog\MadelineProto\Logger::VERBOSE); + $API->logger->logger('Got ' . $difference['_'], \danog\MadelineProto\Logger::VERBOSE); switch ($difference['_']) { case 'updates.channelDifferenceEmpty': $state->update($difference); @@ -118,12 +106,11 @@ class UpdateLoop extends ResumableSignalLoop break 2; case 'updates.channelDifference': if ($request_pts >= $difference['pts'] && $request_pts > 1) { - $API->logger->logger("The PTS ({$difference['pts']}) I got with getDifference is smaller than the PTS I requested ".$state->pts().', using '.($state->pts() + 1), \danog\MadelineProto\Logger::VERBOSE); + $API->logger->logger("The PTS ({$difference['pts']}) I got with getDifference is smaller than the PTS I requested " . $state->pts() . ', using ' . ($state->pts() + 1), \danog\MadelineProto\Logger::VERBOSE); $difference['pts'] = $request_pts + 1; } $result += yield $feeder->feed($difference['other_updates']); $state->update($difference); - $feeder->saveMessages($difference['new_messages']); if (!$difference['final']) { if ($difference['pts'] >= $toPts) { @@ -144,13 +131,12 @@ class UpdateLoop extends ResumableSignalLoop unset($difference); break; default: - throw new \danog\MadelineProto\Exception('Unrecognized update difference received: '.\var_export($difference, true)); + throw new \danog\MadelineProto\Exception('Unrecognized update difference received: ' . \var_export($difference, true)); } } else { $API->logger->logger('Resumed and fetching normal difference...', \danog\MadelineProto\Logger::ULTRA_VERBOSE); - $difference = yield $API->methodCallAsyncRead('updates.getDifference', ['pts' => $state->pts(), 'date' => $state->date(), 'qts' => $state->qts()], ['datacenter' => $API->settings['connection_settings']['default_dc']]); - $API->logger->logger('Got '.$difference['_'], \danog\MadelineProto\Logger::ULTRA_VERBOSE); + $API->logger->logger('Got ' . $difference['_'], \danog\MadelineProto\Logger::ULTRA_VERBOSE); switch ($difference['_']) { case 'updates.differenceEmpty': $state->update($difference); @@ -187,32 +173,28 @@ class UpdateLoop extends ResumableSignalLoop unset($difference); break; default: - throw new \danog\MadelineProto\Exception('Unrecognized update difference received: '.\var_export($difference, true)); + throw new \danog\MadelineProto\Exception('Unrecognized update difference received: ' . \var_export($difference, true)); } } } - $API->logger->logger("Finished parsing updates in $this, now resuming feeders"); + $API->logger->logger("Finished parsing updates in {$this}, now resuming feeders"); foreach ($result as $channelId => $boh) { $API->feeders[$channelId]->resumeDefer(); } - $API->logger->logger("Finished resuming feeders in $this, signaling updates"); + $API->logger->logger("Finished resuming feeders in {$this}, signaling updates"); $API->signalUpdate(); - $API->logger->logger("Finished signaling updates in $this, pausing"); + $API->logger->logger("Finished signaling updates in {$this}, pausing"); $first = false; - if (yield $this->waitSignal($this->pause($timeout))) { - $API->logger->logger("Exiting $this due to signal"); - + $API->logger->logger("Exiting {$this} due to signal"); return; } } } - public function setLimit($toPts) { $this->toPts = $toPts; } - public function __toString(): string { return !$this->channelId ? 'getUpdate loop generic' : "getUpdate loop channel {$this->channelId}"; diff --git a/src/danog/MadelineProto/Lua.php b/src/danog/MadelineProto/Lua.php index bc489c26..a93076d9 100644 --- a/src/danog/MadelineProto/Lua.php +++ b/src/danog/MadelineProto/Lua.php @@ -25,7 +25,6 @@ class Lua public $MadelineProto; protected $Lua; protected $script; - public function __magic_construct($script, $MadelineProto) { if (!\file_exists($script)) { @@ -34,16 +33,13 @@ class Lua $this->MadelineProto = $MadelineProto; $this->MadelineProto->settings['updates']['handle_updates'] = true; $this->MadelineProto->API->datacenter->sockets[$this->MadelineProto->settings['connection_settings']['default_dc']]->startUpdateLoop(); - $this->script = $script; $this->__wakeup(); } - public function __sleep() { return ['MadelineProto', 'script']; } - public function __wakeup() { $this->Lua = new \Lua($this->script); @@ -77,7 +73,6 @@ class Lua $this->MadelineProto->{$namespace}->lua = true; } } - public function tdcliFunction($params, $cb = null, $cb_extra = null) { $params = $this->MadelineProto->td_to_mtproto($this->MadelineProto->tdcliToTd($params)); @@ -88,10 +83,8 @@ class Lua if (\is_callable($cb)) { $cb($this->MadelineProto->mtproto_to_td($result), $cb_extra); } - return $result; } - public function madelineFunction($params, $cb = null, $cb_extra = null) { $result = $this->MadelineProto->API->methodCall($params['_'], $params, ['datacenter' => $this->MadelineProto->API->datacenter->curdc]); @@ -99,15 +92,12 @@ class Lua $cb($result, $cb_extra); } self::convertObjects($result); - return $result; } - public function tdcliUpdateCallback($update) { $this->Lua->tdcliUpdateCallback($this->MadelineProto->mtproto_to_tdcli($update)); } - private function convertArray($array) { if (!\is_array($array)) { @@ -119,29 +109,23 @@ class Lua }, \array_flip($array))); } } - private function isSequential(array $arr) { if ([] === $arr) { return false; } - return isset($arr[0]) && \array_keys($arr) === \range(0, \count($arr) - 1); } - public function __get($name) { if ($name === 'API') { return $this->MadelineProto->API; } - return $this->Lua->{$name}; } - public function __call($name, $params) { self::convertObjects($params); - try { return $this->Lua->{$name}(...$params); } catch (\danog\MadelineProto\RPCErrorException $e) { @@ -160,12 +144,10 @@ class Lua return ['error_code' => $e->getCode(), 'error' => $e->getMessage()]; } } - public function __set($name, $value) { return $this->Lua->{$name} = $value; } - public static function convertObjects(&$data) { \array_walk_recursive($data, function (&$value, $key) { diff --git a/src/danog/MadelineProto/MTProto.php b/src/danog/MadelineProto/MTProto.php index 373540d3..88c647a9 100644 --- a/src/danog/MadelineProto/MTProto.php +++ b/src/danog/MadelineProto/MTProto.php @@ -66,8 +66,6 @@ class MTProto extends AsyncConstruct implements TLCallback use \danog\MadelineProto\Wrappers\Start; use \danog\MadelineProto\Wrappers\Templates; use \danog\MadelineProto\Wrappers\TOS; - - /** * Old internal version of MadelineProto. * @@ -76,8 +74,8 @@ class MTProto extends AsyncConstruct implements TLCallback * @var int */ /* - const V = 71; - */ + const V = 71; + */ /** * Internal version of MadelineProto. * @@ -133,36 +131,13 @@ class MTProto extends AsyncConstruct implements TLCallback * * @var array */ - const BAD_MSG_ERROR_CODES = [ - 16 => 'msg_id too low (most likely, client time is wrong; it would be worthwhile to synchronize it using msg_id notifications and re-send the original message with the “correct” msg_id or wrap it in a container with a new msg_id if the original message had waited too long on the client to be transmitted)', - 17 => 'msg_id too high (similar to the previous case, the client time has to be synchronized, and the message re-sent with the correct msg_id)', - 18 => 'incorrect two lower order msg_id bits (the server expects client message msg_id to be divisible by 4)', - 19 => 'container msg_id is the same as msg_id of a previously received message (this must never happen)', - 20 => 'message too old, and it cannot be verified whether the server has received a message with this msg_id or not', - 32 => 'msg_seqno too low (the server has already received a message with a lower msg_id but with either a higher or an equal and odd seqno)', - 33 => 'msg_seqno too high (similarly, there is a message with a higher msg_id but with either a lower or an equal and odd seqno)', - 34 => 'an even msg_seqno expected (irrelevant message), but odd received', - 35 => 'odd msg_seqno expected (relevant message), but even received', - 48 => 'incorrect server salt (in this case, the bad_server_salt response is received with the correct salt, and the message is to be re-sent with it)', - 64 => 'invalid container' - ]; - + const BAD_MSG_ERROR_CODES = [16 => 'msg_id too low (most likely, client time is wrong; it would be worthwhile to synchronize it using msg_id notifications and re-send the original message with the “correct” msg_id or wrap it in a container with a new msg_id if the original message had waited too long on the client to be transmitted)', 17 => 'msg_id too high (similar to the previous case, the client time has to be synchronized, and the message re-sent with the correct msg_id)', 18 => 'incorrect two lower order msg_id bits (the server expects client message msg_id to be divisible by 4)', 19 => 'container msg_id is the same as msg_id of a previously received message (this must never happen)', 20 => 'message too old, and it cannot be verified whether the server has received a message with this msg_id or not', 32 => 'msg_seqno too low (the server has already received a message with a lower msg_id but with either a higher or an equal and odd seqno)', 33 => 'msg_seqno too high (similarly, there is a message with a higher msg_id but with either a lower or an equal and odd seqno)', 34 => 'an even msg_seqno expected (irrelevant message), but odd received', 35 => 'odd msg_seqno expected (relevant message), but even received', 48 => 'incorrect server salt (in this case, the bad_server_salt response is received with the correct salt, and the message is to be re-sent with it)', 64 => 'invalid container']; /** * Localized message info flags. * * @var array */ - const MSGS_INFO_FLAGS = [ - 1 => 'nothing is known about the message (msg_id too low, the other party may have forgotten it)', - 2 => 'message not received (msg_id falls within the range of stored identifiers; however, the other party has certainly not received a message like that)', - 3 => 'message not received (msg_id too high; however, the other party has certainly not received it yet)', - 4 => 'message received (note that this response is also at the same time a receipt acknowledgment)', - 8 => ' and message already acknowledged', - 16 => ' and message not requiring acknowledgment', - 32 => ' and RPC query contained in message being processed or processing already complete', - 64 => ' and content-related response to message already generated', - 128 => ' and other party knows for a fact that message is already received' - ]; + const MSGS_INFO_FLAGS = [1 => 'nothing is known about the message (msg_id too low, the other party may have forgotten it)', 2 => 'message not received (msg_id falls within the range of stored identifiers; however, the other party has certainly not received a message like that)', 3 => 'message not received (msg_id too high; however, the other party has certainly not received it yet)', 4 => 'message received (note that this response is also at the same time a receipt acknowledgment)', 8 => ' and message already acknowledged', 16 => ' and message not requiring acknowledgment', 32 => ' and RPC query contained in message being processed or processing already complete', 64 => ' and content-related response to message already generated', 128 => ' and other party knows for a fact that message is already received']; /** * Secret chat was not found. * @@ -219,7 +194,6 @@ class MTProto extends AsyncConstruct implements TLCallback 'msg_resend_ans_req', ]; const DEFAULT_GETUPDATES_PARAMS = ['offset' => 0, 'limit' => null, 'timeout' => 0]; - /** * Instance of wrapper API. * @@ -304,7 +278,6 @@ class MTProto extends AsyncConstruct implements TLCallback * @var array */ public $channel_participants = []; - /** * When we last stored data in remote peer database (now doesn't exist anymore). * @@ -419,28 +392,24 @@ class MTProto extends AsyncConstruct implements TLCallback * @var boolean */ public $destructing = false; - /** * DataCenter instance. * * @var DataCenter */ public $datacenter; - /** * Logger instance. * * @var Logger */ public $logger; - /** * TL serializer. * * @var \danog\MadelineProto\TL\TL */ private $TL; - /** * Constructor function. * @@ -452,7 +421,6 @@ class MTProto extends AsyncConstruct implements TLCallback { $this->setInitPromise($this->__construct_async($settings)); } - /** * Async constructor function. * @@ -460,7 +428,7 @@ class MTProto extends AsyncConstruct implements TLCallback * * @return void */ - public function __construct_async($settings = []) + public function __construct_async($settings = []): \Generator { Magic::classExists(); // Parse and store settings @@ -478,11 +446,10 @@ class MTProto extends AsyncConstruct implements TLCallback $this->logger->logger(Lang::$current_lang['TL_translation'], Logger::ULTRA_VERBOSE); $callbacks = [$this, $this->referenceDatabase]; if (!($this->authorization['user']['bot'] ?? false)) { - $callbacks []= $this->minDatabase; + $callbacks[] = $this->minDatabase; } $this->TL->init($this->settings['tl_schema']['src'], $callbacks); - - yield $this->connectToAllDcs(); + yield from $this->connectToAllDcs(); $this->startLoops(); $this->datacenter->curdc = 2; if ((!isset($this->authorization['user']['bot']) || !$this->authorization['user']['bot']) && $this->datacenter->getDataCenterConnection($this->datacenter->curdc)->hasTempAuthKey()) { @@ -498,11 +465,10 @@ class MTProto extends AsyncConstruct implements TLCallback } } } - yield $this->getConfig([], ['datacenter' => $this->datacenter->curdc]); + yield from $this->getConfig([], ['datacenter' => $this->datacenter->curdc]); $this->startUpdateSystem(true); $this->v = self::V; } - /** * Sleep function. * @@ -520,64 +486,49 @@ class MTProto extends AsyncConstruct implements TLCallback '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 'TL', - // Secret chats 'secret_chats', 'temp_requested_secret_chats', 'temp_rekeyed_secret_chats', - // Object storage 'storage', ]; } - - /** * Cleanup memory and session file. * @@ -588,12 +539,11 @@ class MTProto extends AsyncConstruct implements TLCallback $this->referenceDatabase = new ReferenceDatabase($this); $callbacks = [$this, $this->referenceDatabase]; if (!($this->authorization['user']['bot'] ?? false)) { - $callbacks []= $this->minDatabase; + $callbacks[] = $this->minDatabase; } $this->TL->updateCallbacks($callbacks); return $this; } - /** * Logger. * @@ -608,10 +558,8 @@ class MTProto extends AsyncConstruct implements TLCallback if ($file === null) { $file = \basename(\debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php'); } - isset($this->logger) ? $this->logger->logger($param, $level, $file) : Logger::$default->logger($param, $level, $file); } - /** * Get TL namespaces. * @@ -621,8 +569,6 @@ class MTProto extends AsyncConstruct implements TLCallback { return $this->TL->getMethodNamespaces(); } - - /** * Get namespaced methods (method => namespace). * @@ -632,7 +578,6 @@ class MTProto extends AsyncConstruct implements TLCallback { return $this->TL->getMethodsNamespaced(); } - /** * Get TL serializer. * @@ -651,7 +596,6 @@ class MTProto extends AsyncConstruct implements TLCallback { return $this->logger; } - /** * Get async HTTP client. * @@ -661,7 +605,6 @@ class MTProto extends AsyncConstruct implements TLCallback { return $this->datacenter->getHTTPClient(); } - /** * Get async DNS client. * @@ -671,7 +614,6 @@ class MTProto extends AsyncConstruct implements TLCallback { return $this->datacenter->getDNSClient(); } - /** * Get contents of remote file asynchronously. * @@ -683,7 +625,6 @@ class MTProto extends AsyncConstruct implements TLCallback { return $this->datacenter->fileGetContents($url); } - /** * Get all datacenter connections. * @@ -693,7 +634,6 @@ class MTProto extends AsyncConstruct implements TLCallback { return $this->datacenter->getDataCenterConnections(); } - /** * Prompt serialization of instance. * @@ -728,7 +668,6 @@ class MTProto extends AsyncConstruct implements TLCallback if (!$this->configLoop) { $this->configLoop = new PeriodicLoop($this, [$this, 'getConfig'], 'config', 24 * 3600); } - $this->callCheckerLoop->start(); $this->serializeLoop->start(); $this->phoneConfigLoop->start(); @@ -763,7 +702,6 @@ class MTProto extends AsyncConstruct implements TLCallback $this->checkTosLoop = null; } } - /** * Clean up properties from previous versions of MadelineProto. * @@ -773,11 +711,11 @@ class MTProto extends AsyncConstruct implements TLCallback */ private function cleanupProperties() { - if (!($this->channels_state instanceof CombinedUpdatesState)) { + 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)) { + if (!$this->updates_state instanceof UpdatesState) { $this->updates_state = new UpdatesState($this->updates_state); } $this->channels_state->__construct([false => $this->updates_state]); @@ -797,7 +735,7 @@ class MTProto extends AsyncConstruct implements TLCallback $this->logger->logger(Lang::$current_lang['TL_translation'], Logger::ULTRA_VERBOSE); $callbacks = [$this, $this->referenceDatabase]; if (!($this->authorization['user']['bot'] ?? false)) { - $callbacks []= $this->minDatabase; + $callbacks[] = $this->minDatabase; } $this->TL->init($this->settings['tl_schema']['src'], $callbacks); } @@ -833,7 +771,6 @@ class MTProto extends AsyncConstruct implements TLCallback 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']]; @@ -878,7 +815,7 @@ class MTProto extends AsyncConstruct implements TLCallback $this->resetMTProtoSession(true, true); $this->config = ['expires' => -1]; $this->dh_config = ['version' => 0]; - yield $this->__construct_async($settings); + yield from $this->__construct_async($settings); foreach ($this->secret_chats as $chat => $data) { try { if (isset($this->secret_chats[$chat]) && $this->secret_chats[$chat]['InputEncryptedChat'] !== null) { @@ -897,7 +834,6 @@ class MTProto extends AsyncConstruct implements TLCallback $this->asyncInitPromise = true; $this->setInitPromise($this->__wakeup_async($backtrace)); } - /** * Async wakeup function. * @@ -916,11 +852,10 @@ class MTProto extends AsyncConstruct implements TLCallback return; } // Setup language - Lang::$current_lang = &Lang::$lang['en']; + 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']]; + Lang::$current_lang =& Lang::$lang[$this->settings['app_info']['lang_code']]; } - $this->settings['connection_settings']['all']['ipv6'] = Magic::$ipv6; if ($this->authorized === true) { $this->authorized = self::LOGGED_IN; @@ -932,34 +867,28 @@ class MTProto extends AsyncConstruct implements TLCallback $this->parseSettings(\array_replace_recursive($this->settings, $backtrace[2]['args'][1])); } } - - if (($this->settings['tl_schema']['src']['botAPI'] ?? '') !== __DIR__.'/TL_botAPI.tl') { + if (($this->settings['tl_schema']['src']['botAPI'] ?? '') !== __DIR__ . '/TL_botAPI.tl') { unset($this->v); } if (!\file_exists($this->settings['tl_schema']['src']['telegram'])) { unset($this->v); } - if (!isset($this->v) || $this->v !== self::V) { - yield $this->upgradeMadelineProto(); + yield from $this->upgradeMadelineProto(); $force = true; } - // Cleanup old properties, init new stuffs $this->cleanupProperties(); - // Update TL callbacks $callbacks = [$this, $this->referenceDatabase]; if (!($this->authorization['user']['bot'] ?? false)) { - $callbacks []= $this->minDatabase; + $callbacks[] = $this->minDatabase; } $this->TL->updateCallbacks($callbacks); - if ($this->event_handler && \class_exists($this->event_handler) && \is_subclass_of($this->event_handler, EventHandler::class)) { $this->setEventHandler($this->event_handler); } - - yield $this->connectToAllDcs(); + yield from $this->connectToAllDcs(); foreach ($this->calls as $id => $controller) { if (!\is_object($controller)) { unset($this->calls[$id]); @@ -971,12 +900,11 @@ class MTProto extends AsyncConstruct implements TLCallback } } $this->startLoops(); - if (yield $this->getSelf()) { + if (yield from $this->getSelf()) { $this->authorized = self::LOGGED_IN; } - if ($this->authorized === self::LOGGED_IN) { - yield $this->getCdnConfig($this->datacenter->curdc); + yield from $this->getCdnConfig($this->datacenter->curdc); $this->setupLogger(); } $this->startUpdateSystem(true); @@ -989,7 +917,6 @@ class MTProto extends AsyncConstruct implements TLCallback } $this->updaters[false]->start(); } - /** * Destructor. */ @@ -1017,7 +944,6 @@ class MTProto extends AsyncConstruct implements TLCallback } $this->logger("Successfully destroyed MadelineProto"); } - /** * Get correct settings array for the latest version. * @@ -1084,19 +1010,18 @@ class MTProto extends AsyncConstruct implements TLCallback // // To be honest, I wrote this feature just for me, since I honestly don't want to // ...go through the hassle of registering => recovering => logging in to every account I use for my services (mainly webradios and test userbots) - $system_version = 'SDK 28'; } // Detect language $lang_code = 'en'; - Lang::$current_lang = &Lang::$lang[$lang_code]; + Lang::$current_lang =& Lang::$lang[$lang_code]; if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { $lang_code = \substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2); } elseif (isset($_SERVER['LANG'])) { $lang_code = \explode('_', $_SERVER['LANG'])[0]; } if (isset(Lang::$lang[$lang_code])) { - Lang::$current_lang = &Lang::$lang[$lang_code]; + Lang::$current_lang =& Lang::$lang[$lang_code]; } // Detect language pack $lang_pack = ''; @@ -1115,11 +1040,10 @@ class MTProto extends AsyncConstruct implements TLCallback // // To be honest, I wrote this feature just for me, since I honestly don't want to // ...go through the hassle of registering => recovering => logging in to every account I use for my services (mainly webradios and test userbots) - $lang_pack = 'android'; } // Detect app version - $app_version = self::RELEASE.' ('.self::V.', '.Magic::$revision.')'; + $app_version = self::RELEASE . ' (' . self::V . ', ' . Magic::$revision . ')'; if (($settings['app_info']['api_id'] ?? 0) === 6) { // TG DEV NOTICE: these app info spoofing measures were implemented for NON-MALICIOUS purposes. // All accounts registered with a custom API ID require manual verification through recover@telegram.org, to avoid instant permabans. @@ -1135,10 +1059,8 @@ class MTProto extends AsyncConstruct implements TLCallback // // To be honest, I wrote this feature just for me, since I honestly don't want to // ...go through the hassle of registering => recovering => logging in to every account I use for my services (mainly webradios and test userbots) - $app_version = '4.9.1 (13613)'; } - // Set default settings $default_settings = ['authorization' => [ // Authorization settings @@ -1219,12 +1141,9 @@ class MTProto extends AsyncConstruct implements TLCallback // Extra parameters to pass to the proxy class using setExtra 'obfuscated' => false, 'transport' => 'tcp', - 'pfs' => false,//\extension_loaded('gmp'), - ], - 'media_socket_count' => [ - 'min' => 5, - 'max' => 10 + 'pfs' => false, ], + 'media_socket_count' => ['min' => 5, 'max' => 10], 'robin_period' => 10, 'default_dc' => 2, ], 'app_info' => [ @@ -1243,16 +1162,16 @@ class MTProto extends AsyncConstruct implements TLCallback 'layer' => 105, // layer version 'src' => [ - 'mtproto' => __DIR__.'/TL_mtproto_v1.tl', + 'mtproto' => __DIR__ . '/TL_mtproto_v1.tl', // mtproto TL scheme - 'telegram' => __DIR__.'/TL_telegram_v105.tl', + 'telegram' => __DIR__ . '/TL_telegram_v105.tl', // telegram TL scheme - 'secret' => __DIR__.'/TL_secret.tl', + 'secret' => __DIR__ . '/TL_secret.tl', // secret chats TL scheme - 'calls' => __DIR__.'/TL_calls.tl', + 'calls' => __DIR__ . '/TL_calls.tl', // calls TL scheme //'td' => __DIR__.'/TL_td.tl', // telegram-cli TL scheme - 'botAPI' => __DIR__.'/TL_botAPI.tl', + 'botAPI' => __DIR__ . '/TL_botAPI.tl', ], ], 'logger' => [ // Logger settings @@ -1266,7 +1185,7 @@ class MTProto extends AsyncConstruct implements TLCallback * $message is an array containing the messages the log, $level, is the logging level */ // write to - 'logger_param' => Magic::$script_cwd.'/MadelineProto.log', + 'logger_param' => Magic::$script_cwd . '/MadelineProto.log', 'logger' => PHP_SAPI === 'cli' ? 3 : 2, // overwrite previous setting and echo logs 'logger_level' => Logger::VERBOSE, @@ -1300,22 +1219,11 @@ class MTProto extends AsyncConstruct implements TLCallback 'callback' => 'getUpdatesUpdateHandler', // Update callback 'run_callback' => true, - ], 'secret_chats' => ['accept_chats' => true], 'serialization' => [ - 'serialization_interval' => 30, - 'cleanup_before_serialization' => false, - ], 'threading' => [ + ], 'secret_chats' => ['accept_chats' => true], 'serialization' => ['serialization_interval' => 30, 'cleanup_before_serialization' => false], 'threading' => [ 'allow_threading' => false, // Should I use threading, if it is enabled? 'handler_workers' => 10, - ], 'upload' => [ - 'allow_automatic_upload' => true, - 'part_size' => 512 * 1024, - 'parallel_chunks' => 20, - ], 'download' => [ - 'report_broken_media' => true, - 'part_size' => 1024 * 1024, - 'parallel_chunks' => 20, - ], 'pwr' => [ + ], 'upload' => ['allow_automatic_upload' => true, 'part_size' => 512 * 1024, 'parallel_chunks' => 20], 'download' => ['report_broken_media' => true, 'part_size' => 1024 * 1024, 'parallel_chunks' => 20], 'pwr' => [ 'pwr' => false, // Need info ? 'db_token' => false, @@ -1326,11 +1234,11 @@ class MTProto extends AsyncConstruct implements TLCallback ]]; $settings = \array_replace_recursive($default_settings, $settings); if (isset(Lang::$lang[$settings['app_info']['lang_code']])) { - Lang::$current_lang = &Lang::$lang[$settings['app_info']['lang_code']]; + Lang::$current_lang =& Lang::$lang[$settings['app_info']['lang_code']]; } /*if ($settings['app_info']['api_id'] < 20) { - $settings['connection_settings']['all']['protocol'] = 'obfuscated2'; - }*/ + $settings['connection_settings']['all']['protocol'] = 'obfuscated2'; + }*/ switch ($settings['logger']['logger_level']) { case 'ULTRA_VERBOSE': $settings['logger']['logger_level'] = 5; @@ -1373,7 +1281,6 @@ class MTProto extends AsyncConstruct implements TLCallback // Setup logger $this->setupLogger(); } - /** * Setup logger. * @@ -1383,7 +1290,6 @@ class MTProto extends AsyncConstruct implements TLCallback { $this->logger = Logger::getLoggerFromSettings($this->settings, isset($this->authorization['user']) ? isset($this->authorization['user']['username']) ? $this->authorization['user']['username'] : $this->authorization['user']['id'] : ''); } - /** * Reset all MTProto sessions. * @@ -1408,7 +1314,6 @@ class MTProto extends AsyncConstruct implements TLCallback } } } - /** * Check if connected to datacenter using HTTP. * @@ -1422,7 +1327,6 @@ class MTProto extends AsyncConstruct implements TLCallback { return $this->datacenter->isHttp($datacenter); } - /** * Checks whether all datacenters are authorized. * @@ -1433,16 +1337,13 @@ class MTProto extends AsyncConstruct implements TLCallback if ($this->isInitingAuthorization()) { return false; } - foreach ($this->datacenter->getDataCenterConnections() as $dc) { if (!$dc->isAuthorized() || !$dc->hasTempAuthKey()) { return false; } } - return true; } - /** * Whether we're initing authorization. * @@ -1454,7 +1355,6 @@ class MTProto extends AsyncConstruct implements TLCallback { return $this->initing_authorization; } - /** * Connects to all datacenters and if necessary creates authorization keys, binds them and writes client info. * @@ -1477,7 +1377,6 @@ class MTProto extends AsyncConstruct implements TLCallback if (!isset($this->seqUpdater)) { $this->seqUpdater = new SeqLoop($this); } - $this->datacenter->__construct($this, $this->settings['connection'], $this->settings['connection_settings'], $reconnectAll); $dcs = []; foreach ($this->datacenter->getDcs() as $new_dc) { @@ -1485,16 +1384,15 @@ class MTProto extends AsyncConstruct implements TLCallback } yield \danog\MadelineProto\Tools::all($dcs); yield $this->initAuthorization(); - yield $this->parseConfig(); + yield from $this->parseConfig(); $dcs = []; foreach ($this->datacenter->getDcs(false) as $new_dc) { $dcs[] = $this->datacenter->dcConnect($new_dc); } yield \danog\MadelineProto\Tools::all($dcs); yield $this->initAuthorization(); - yield $this->parseConfig(); - - yield $this->getPhoneConfig(); + yield from $this->parseConfig(); + yield from $this->getPhoneConfig(); } /** * Clean up MadelineProto session after logout. @@ -1527,7 +1425,6 @@ class MTProto extends AsyncConstruct implements TLCallback foreach ($this->datacenter->getDataCenterConnections() as $socket) { $socket->authorized(false); } - $this->channels_state = new CombinedUpdatesState(); $this->got_state = false; $this->msg_ids = []; @@ -1560,7 +1457,7 @@ class MTProto extends AsyncConstruct implements TLCallback $channelIds[] = $state->getChannel(); $channelId = $state->getChannel(); $pts = $state->pts(); - $pts = $channelId ? \max(1, $pts-1000000) : ($pts > 4000000 ? $pts-1000000 : \max(1, $pts-1000000)); + $pts = $channelId ? \max(1, $pts - 1000000) : ($pts > 4000000 ? $pts - 1000000 : \max(1, $pts - 1000000)); $newStates[$channelId] = new UpdatesState(['pts' => $pts], $channelId); } \sort($channelIds); @@ -1575,7 +1472,6 @@ class MTProto extends AsyncConstruct implements TLCallback $this->channels_state->__construct($newStates); $this->startUpdateSystem(); } - /** * Start the update system. * @@ -1592,7 +1488,6 @@ class MTProto extends AsyncConstruct implements TLCallback return; } $this->logger("Starting update system"); - if (!isset($this->seqUpdater)) { $this->seqUpdater = new SeqLoop($this); } @@ -1623,7 +1518,6 @@ class MTProto extends AsyncConstruct implements TLCallback $this->seqUpdater->resume(); } } - /** * Store shared phone config. * @@ -1642,7 +1536,6 @@ class MTProto extends AsyncConstruct implements TLCallback $this->logger->logger('Not fetching phone config'); } } - /** * Store RSA keys for CDN datacenters. * @@ -1654,14 +1547,13 @@ class MTProto extends AsyncConstruct implements TLCallback { try { foreach ((yield $this->methodCallAsyncRead('help.getCdnConfig', [], ['datacenter' => $datacenter]))['public_keys'] as $curkey) { - $curkey = yield (new RSA)->load($this->TL, $curkey['public_key']); + $curkey = yield (new RSA())->load($this->TL, $curkey['public_key']); $this->cdn_rsa_keys[$curkey->fp] = $curkey; } } catch (\danog\MadelineProto\TL\Exception $e) { $this->logger->logger($e->getMessage(), \danog\MadelineProto\Logger::FATAL_ERROR); } } - /** * Get cached server-side config. * @@ -1671,7 +1563,6 @@ class MTProto extends AsyncConstruct implements TLCallback { return $this->config; } - /** * Get cached (or eventually re-fetch) server-side config. * @@ -1686,11 +1577,9 @@ class MTProto extends AsyncConstruct implements TLCallback return $this->config; } $this->config = empty($config) ? yield $this->methodCallAsyncRead('help.getConfig', $config, empty($options) ? ['datacenter' => $this->settings['connection_settings']['default_dc']] : $options) : $config; - yield $this->parseConfig(); - + yield from $this->parseConfig(); return $this->config; } - /** * Parse cached config. * @@ -1701,12 +1590,11 @@ class MTProto extends AsyncConstruct implements TLCallback if (isset($this->config['dc_options'])) { $options = $this->config['dc_options']; unset($this->config['dc_options']); - yield $this->parseDcOptions($options); + yield from $this->parseDcOptions($options); } $this->logger->logger(Lang::$current_lang['config_updated'], Logger::NOTICE); $this->logger->logger($this->config, Logger::NOTICE); } - /** * Parse DC options from config. * @@ -1732,17 +1620,15 @@ class MTProto extends AsyncConstruct implements TLCallback $id = (int) $id; } unset($dc['cdn'], $dc['media_only'], $dc['id'], $dc['ipv6']); - $this->settings['connection'][$test][$ipv6][$id] = $dc; } $curdc = $this->datacenter->curdc; if (!$this->datacenter->has($curdc) || $this->datacenter->getDataCenterConnection($curdc)->byIPAddress()) { $this->logger->logger('Got new DC options, reconnecting'); - yield $this->connectToAllDcs(false); + yield from $this->connectToAllDcs(false); } $this->datacenter->curdc = $curdc; } - /** * Get info about the logged-in user. * @@ -1754,13 +1640,10 @@ class MTProto extends AsyncConstruct implements TLCallback $this->authorization = ['user' => (yield $this->methodCallAsyncRead('users.getUsers', ['id' => [['_' => 'inputUserSelf']]], ['datacenter' => $this->datacenter->curdc]))[0]]; } catch (RPCErrorException $e) { $this->logger->logger($e->getMessage()); - return false; } - return $this->authorization['user']; } - /** * Called right before serialization of method starts. * @@ -1772,7 +1655,6 @@ class MTProto extends AsyncConstruct implements TLCallback { return []; } - /** * Called right before serialization of method starts. * @@ -1784,7 +1666,6 @@ class MTProto extends AsyncConstruct implements TLCallback { return []; } - /** * Called right after deserialization of object, passing the final object. * @@ -1792,13 +1673,8 @@ class MTProto extends AsyncConstruct implements TLCallback */ public function getConstructorCallbacks(): array { - return \array_merge( - \array_fill_keys(['chat', 'chatEmpty', 'chatForbidden', 'channel', 'channelEmpty', 'channelForbidden'], [[$this, 'addChat']]), - \array_fill_keys(['user', 'userEmpty'], [[$this, 'addUser']]), - ['help.support' => [[$this, 'addSupport']]] - ); + return \array_merge(\array_fill_keys(['chat', 'chatEmpty', 'chatForbidden', 'channel', 'channelEmpty', 'channelForbidden'], [[$this, 'addChat']]), \array_fill_keys(['user', 'userEmpty'], [[$this, 'addUser']]), ['help.support' => [[$this, 'addSupport']]]); } - /** * Called right before deserialization of object. * @@ -1810,7 +1686,6 @@ class MTProto extends AsyncConstruct implements TLCallback { return []; } - /** * Called right before serialization of constructor. * @@ -1822,7 +1697,6 @@ class MTProto extends AsyncConstruct implements TLCallback { return []; } - /** * Called if objects of the specified type cannot be serialized. * @@ -1833,14 +1707,8 @@ class MTProto extends AsyncConstruct implements TLCallback */ public function getTypeMismatchCallbacks(): array { - return \array_merge( - \array_fill_keys(['User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputPeer', 'InputDialogPeer', 'InputNotifyPeer'], [$this, 'getInfo']), - \array_fill_keys(['InputMedia', 'InputDocument', 'InputPhoto'], [$this, 'getFileInfo']), - \array_fill_keys(['InputFileLocation'], [$this, 'getDownloadInfo']) - ); + return \array_merge(\array_fill_keys(['User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputPeer', 'InputDialogPeer', 'InputNotifyPeer'], [$this, 'getInfo']), \array_fill_keys(['InputMedia', 'InputDocument', 'InputPhoto'], [$this, 'getFileInfo']), \array_fill_keys(['InputFileLocation'], [$this, 'getDownloadInfo'])); } - - /** * Get debug information for var_dump. * @@ -1848,8 +1716,7 @@ class MTProto extends AsyncConstruct implements TLCallback */ public function __debugInfo(): array { - return ['MadelineProto instance '.\spl_object_hash($this)]; + return ['MadelineProto instance ' . \spl_object_hash($this)]; } - const ALL_MIMES = ['webp' => [0 => 'image/webp'], 'png' => [0 => 'image/png', 1 => 'image/x-png'], 'bmp' => [0 => 'image/bmp', 1 => 'image/x-bmp', 2 => 'image/x-bitmap', 3 => 'image/x-xbitmap', 4 => 'image/x-win-bitmap', 5 => 'image/x-windows-bmp', 6 => 'image/ms-bmp', 7 => 'image/x-ms-bmp', 8 => 'application/bmp', 9 => 'application/x-bmp', 10 => 'application/x-win-bitmap'], 'gif' => [0 => 'image/gif'], 'jpeg' => [0 => 'image/jpeg', 1 => 'image/pjpeg'], 'xspf' => [0 => 'application/xspf+xml'], 'vlc' => [0 => 'application/videolan'], 'wmv' => [0 => 'video/x-ms-wmv', 1 => 'video/x-ms-asf'], 'au' => [0 => 'audio/x-au'], 'ac3' => [0 => 'audio/ac3'], 'flac' => [0 => 'audio/x-flac'], 'ogg' => [0 => 'audio/ogg', 1 => 'video/ogg', 2 => 'application/ogg'], 'kmz' => [0 => 'application/vnd.google-earth.kmz'], 'kml' => [0 => 'application/vnd.google-earth.kml+xml'], 'rtx' => [0 => 'text/richtext'], 'rtf' => [0 => 'text/rtf'], 'jar' => [0 => 'application/java-archive', 1 => 'application/x-java-application', 2 => 'application/x-jar'], 'zip' => [0 => 'application/x-zip', 1 => 'application/zip', 2 => 'application/x-zip-compressed', 3 => 'application/s-compressed', 4 => 'multipart/x-zip'], '7zip' => [0 => 'application/x-compressed'], 'xml' => [0 => 'application/xml', 1 => 'text/xml'], 'svg' => [0 => 'image/svg+xml'], '3g2' => [0 => 'video/3gpp2'], '3gp' => [0 => 'video/3gp', 1 => 'video/3gpp'], 'mp4' => [0 => 'video/mp4'], 'm4a' => [0 => 'audio/x-m4a'], 'f4v' => [0 => 'video/x-f4v'], 'flv' => [0 => 'video/x-flv'], 'webm' => [0 => 'video/webm'], 'aac' => [0 => 'audio/x-acc'], 'm4u' => [0 => 'application/vnd.mpegurl'], 'pdf' => [0 => 'application/pdf', 1 => 'application/octet-stream'], 'pptx' => [0 => 'application/vnd.openxmlformats-officedocument.presentationml.presentation'], 'ppt' => [0 => 'application/powerpoint', 1 => 'application/vnd.ms-powerpoint', 2 => 'application/vnd.ms-office', 3 => 'application/msword'], 'docx' => [0 => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'], 'xlsx' => [0 => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 1 => 'application/vnd.ms-excel'], 'xl' => [0 => 'application/excel'], 'xls' => [0 => 'application/msexcel', 1 => 'application/x-msexcel', 2 => 'application/x-ms-excel', 3 => 'application/x-excel', 4 => 'application/x-dos_ms_excel', 5 => 'application/xls', 6 => 'application/x-xls'], 'xsl' => [0 => 'text/xsl'], 'mpeg' => [0 => 'video/mpeg'], 'mov' => [0 => 'video/quicktime'], 'avi' => [0 => 'video/x-msvideo', 1 => 'video/msvideo', 2 => 'video/avi', 3 => 'application/x-troff-msvideo'], 'movie' => [0 => 'video/x-sgi-movie'], 'log' => [0 => 'text/x-log'], 'txt' => [0 => 'text/plain'], 'css' => [0 => 'text/css'], 'html' => [0 => 'text/html'], 'wav' => [0 => 'audio/x-wav', 1 => 'audio/wave', 2 => 'audio/wav'], 'xhtml' => [0 => 'application/xhtml+xml'], 'tar' => [0 => 'application/x-tar'], 'tgz' => [0 => 'application/x-gzip-compressed'], 'psd' => [0 => 'application/x-photoshop', 1 => 'image/vnd.adobe.photoshop'], 'exe' => [0 => 'application/x-msdownload'], 'js' => [0 => 'application/x-javascript'], 'mp3' => [0 => 'audio/mpeg', 1 => 'audio/mpg', 2 => 'audio/mpeg3', 3 => 'audio/mp3'], 'rar' => [0 => 'application/x-rar', 1 => 'application/rar', 2 => 'application/x-rar-compressed'], 'gzip' => [0 => 'application/x-gzip'], 'hqx' => [0 => 'application/mac-binhex40', 1 => 'application/mac-binhex', 2 => 'application/x-binhex40', 3 => 'application/x-mac-binhex40'], 'cpt' => [0 => 'application/mac-compactpro'], 'bin' => [0 => 'application/macbinary', 1 => 'application/mac-binary', 2 => 'application/x-binary', 3 => 'application/x-macbinary'], 'oda' => [0 => 'application/oda'], 'ai' => [0 => 'application/postscript'], 'smil' => [0 => 'application/smil'], 'mif' => [0 => 'application/vnd.mif'], 'wbxml' => [0 => 'application/wbxml'], 'wmlc' => [0 => 'application/wmlc'], 'dcr' => [0 => 'application/x-director'], 'dvi' => [0 => 'application/x-dvi'], 'gtar' => [0 => 'application/x-gtar'], 'php' => [0 => 'application/x-httpd-php', 1 => 'application/php', 2 => 'application/x-php', 3 => 'text/php', 4 => 'text/x-php', 5 => 'application/x-httpd-php-source'], 'swf' => [0 => 'application/x-shockwave-flash'], 'sit' => [0 => 'application/x-stuffit'], 'z' => [0 => 'application/x-compress'], 'mid' => [0 => 'audio/midi'], 'aif' => [0 => 'audio/x-aiff', 1 => 'audio/aiff'], 'ram' => [0 => 'audio/x-pn-realaudio'], 'rpm' => [0 => 'audio/x-pn-realaudio-plugin'], 'ra' => [0 => 'audio/x-realaudio'], 'rv' => [0 => 'video/vnd.rn-realvideo'], 'jp2' => [0 => 'image/jp2', 1 => 'video/mj2', 2 => 'image/jpx', 3 => 'image/jpm'], 'tiff' => [0 => 'image/tiff'], 'eml' => [0 => 'message/rfc822'], 'pem' => [0 => 'application/x-x509-user-cert', 1 => 'application/x-pem-file'], 'p10' => [0 => 'application/x-pkcs10', 1 => 'application/pkcs10'], 'p12' => [0 => 'application/x-pkcs12'], 'p7a' => [0 => 'application/x-pkcs7-signature'], 'p7c' => [0 => 'application/pkcs7-mime', 1 => 'application/x-pkcs7-mime'], 'p7r' => [0 => 'application/x-pkcs7-certreqresp'], 'p7s' => [0 => 'application/pkcs7-signature'], 'crt' => [0 => 'application/x-x509-ca-cert', 1 => 'application/pkix-cert'], 'crl' => [0 => 'application/pkix-crl', 1 => 'application/pkcs-crl'], 'pgp' => [0 => 'application/pgp'], 'gpg' => [0 => 'application/gpg-keys'], 'rsa' => [0 => 'application/x-pkcs7'], 'ics' => [0 => 'text/calendar'], 'zsh' => [0 => 'text/x-scriptzsh'], 'cdr' => [0 => 'application/cdr', 1 => 'application/coreldraw', 2 => 'application/x-cdr', 3 => 'application/x-coreldraw', 4 => 'image/cdr', 5 => 'image/x-cdr', 6 => 'zz-application/zz-winassoc-cdr'], 'wma' => [0 => 'audio/x-ms-wma'], 'vcf' => [0 => 'text/x-vcard'], 'srt' => [0 => 'text/srt'], 'vtt' => [0 => 'text/vtt'], 'ico' => [0 => 'image/x-icon', 1 => 'image/x-ico', 2 => 'image/vnd.microsoft.icon'], 'csv' => [0 => 'text/x-comma-separated-values', 1 => 'text/comma-separated-values', 2 => 'application/vnd.msexcel'], 'json' => [0 => 'application/json', 1 => 'text/json']]; } diff --git a/src/danog/MadelineProto/MTProto/AuthKey.php b/src/danog/MadelineProto/MTProto/AuthKey.php index 5ee2c99c..8853e59a 100644 --- a/src/danog/MadelineProto/MTProto/AuthKey.php +++ b/src/danog/MadelineProto/MTProto/AuthKey.php @@ -1,4 +1,5 @@ setAuthKey($old['auth_key']); @@ -61,8 +61,6 @@ abstract class AuthKey implements JsonSerializable $this->setServerSalt($old['server_salt']); } } - - /** * Set auth key. * @@ -75,7 +73,6 @@ abstract class AuthKey implements JsonSerializable $this->authKey = $authKey; $this->id = \substr(\sha1($authKey, true), -8); } - /** * Check if auth key is present. * @@ -85,7 +82,6 @@ abstract class AuthKey implements JsonSerializable { return $this->authKey !== null; } - /** * Get auth key. * @@ -95,7 +91,6 @@ abstract class AuthKey implements JsonSerializable { return $this->authKey; } - /** * Get auth key ID. * @@ -105,7 +100,6 @@ abstract class AuthKey implements JsonSerializable { return $this->id; } - /** * Set server salt. * @@ -117,7 +111,6 @@ abstract class AuthKey implements JsonSerializable { $this->serverSalt = $salt; } - /** * Get server salt. * @@ -127,7 +120,6 @@ abstract class AuthKey implements JsonSerializable { return $this->serverSalt; } - /** * Check if has server salt. * @@ -137,14 +129,12 @@ abstract class AuthKey implements JsonSerializable { return $this->serverSalt !== null; } - /** * Check if we are logged in. * * @return boolean */ abstract public function isAuthorized(): bool; - /** * Set the authorized boolean. * diff --git a/src/danog/MadelineProto/MTProto/PermAuthKey.php b/src/danog/MadelineProto/MTProto/PermAuthKey.php index 37007706..56c04d09 100644 --- a/src/danog/MadelineProto/MTProto/PermAuthKey.php +++ b/src/danog/MadelineProto/MTProto/PermAuthKey.php @@ -1,4 +1,5 @@ authorized; } - /** * Set the authorized boolean. * @@ -63,8 +62,6 @@ class PermAuthKey extends AuthKey { $this->authorized = $authorized; } - - /** * JSON serialization function. * @@ -72,11 +69,7 @@ class PermAuthKey extends AuthKey */ public function jsonSerialize(): array { - return [ - 'auth_key' => 'pony'.\base64_encode($this->authKey), - 'server_salt' => $this->serverSalt, - 'authorized' => $this->authorized - ]; + return ['auth_key' => 'pony' . \base64_encode($this->authKey), 'server_salt' => $this->serverSalt, 'authorized' => $this->authorized]; } /** * Sleep function. @@ -85,11 +78,6 @@ class PermAuthKey extends AuthKey */ public function __sleep() { - return [ - 'authKey', - 'id', - 'serverSalt', - 'authorized' - ]; + return ['authKey', 'id', 'serverSalt', 'authorized']; } } diff --git a/src/danog/MadelineProto/MTProto/TempAuthKey.php b/src/danog/MadelineProto/MTProto/TempAuthKey.php index cdbac332..0eaecec8 100644 --- a/src/danog/MadelineProto/MTProto/TempAuthKey.php +++ b/src/danog/MadelineProto/MTProto/TempAuthKey.php @@ -1,4 +1,5 @@ init($old['connection_inited']); } } - /** * Init or deinit connection for auth key. * @@ -82,7 +79,6 @@ class TempAuthKey extends AuthKey implements JsonSerializable { return $this->inited; } - /** * Bind auth key. * @@ -96,11 +92,10 @@ class TempAuthKey extends AuthKey implements JsonSerializable $this->bound = $bound; if (!$pfs) { foreach (['authKey', 'id', 'serverSalt'] as $key) { - $this->{$key} = &$bound->{$key}; + $this->{$key} =& $bound->{$key}; } } } - /** * Check if auth key is bound. * @@ -110,7 +105,6 @@ class TempAuthKey extends AuthKey implements JsonSerializable { return $this->bound !== null; } - /** * Check if we are logged in. * @@ -120,7 +114,6 @@ class TempAuthKey extends AuthKey implements JsonSerializable { return $this->bound ? $this->bound->isAuthorized() : false; } - /** * Set the authorized boolean. * @@ -132,7 +125,6 @@ class TempAuthKey extends AuthKey implements JsonSerializable { $this->bound->authorized($authorized); } - /** * Set expiration date of temporary auth key. * @@ -144,7 +136,6 @@ class TempAuthKey extends AuthKey implements JsonSerializable { $this->expires = $expires; } - /** * Check if auth key has expired. * @@ -154,7 +145,6 @@ class TempAuthKey extends AuthKey implements JsonSerializable { return \time() > $this->expires; } - /** * JSON serialization function. * @@ -162,15 +152,8 @@ class TempAuthKey extends AuthKey implements JsonSerializable */ public function jsonSerialize(): array { - return [ - 'auth_key' => 'pony'.\base64_encode($this->authKey), - 'server_salt' => $this->serverSalt, - 'bound' => $this->isBound(), - 'expires' => $this->expires, - 'connection_inited' => $this->inited - ]; + return ['auth_key' => 'pony' . \base64_encode($this->authKey), 'server_salt' => $this->serverSalt, 'bound' => $this->isBound(), 'expires' => $this->expires, 'connection_inited' => $this->inited]; } - /** * Sleep function. * @@ -178,14 +161,7 @@ class TempAuthKey extends AuthKey implements JsonSerializable */ public function __sleep() { - return [ - 'authKey', - 'id', - 'serverSalt', - 'bound', - 'expires', - 'inited' - ]; + return ['authKey', 'id', 'serverSalt', 'bound', 'expires', 'inited']; } /** * Wakeup function. diff --git a/src/danog/MadelineProto/MTProtoSession/AckHandler.php b/src/danog/MadelineProto/MTProtoSession/AckHandler.php index 170f5ac1..5ea32ce6 100644 --- a/src/danog/MadelineProto/MTProtoSession/AckHandler.php +++ b/src/danog/MadelineProto/MTProtoSession/AckHandler.php @@ -28,31 +28,27 @@ trait AckHandler { // The server acknowledges that it received my message if (!isset($this->outgoing_messages[$message_id])) { - $this->logger->logger("WARNING: Couldn't find message id ".$message_id.' in the array of outgoing messages. Maybe try to increase its size?', \danog\MadelineProto\Logger::WARNING); - + $this->logger->logger("WARNING: Couldn't find message id " . $message_id . ' in the array of outgoing messages. Maybe try to increase its size?', \danog\MadelineProto\Logger::WARNING); return false; } //$this->logger->logger("Ack-ed ".$this->outgoing_messages[$message_id]['_']." with message ID $message_id on DC $datacenter"); /* - if (isset($this->outgoing_messages[$message_id]['body'])) { - unset($this->outgoing_messages[$message_id]['body']); - } - if (isset($this->new_outgoing[$message_id])) { - unset($this->new_outgoing[$message_id]); - }*/ + if (isset($this->outgoing_messages[$message_id]['body'])) { + unset($this->outgoing_messages[$message_id]['body']); + } + if (isset($this->new_outgoing[$message_id])) { + unset($this->new_outgoing[$message_id]); + }*/ return true; } - public function gotResponseForOutgoingMessageId($message_id): bool { // The server acknowledges that it received my message if (isset($this->new_outgoing[$message_id])) { unset($this->new_outgoing[$message_id]); } - if (!isset($this->outgoing_messages[$message_id])) { - $this->logger->logger("WARNING: Couldn't find message id ".$message_id.' in the array of outgoing messages. Maybe try to increase its size?', \danog\MadelineProto\Logger::WARNING); - + $this->logger->logger("WARNING: Couldn't find message id " . $message_id . ' in the array of outgoing messages. Maybe try to increase its size?', \danog\MadelineProto\Logger::WARNING); return false; } if (isset($this->outgoing_messages[$message_id]['body'])) { @@ -61,28 +57,21 @@ trait AckHandler if (isset($this->outgoing_messages[$message_id]['serialized_body'])) { unset($this->outgoing_messages[$message_id]['serialized_body']); } - return true; } - public function ackIncomingMessageId($message_id): bool { // I let the server know that I received its message if (!isset($this->incoming_messages[$message_id])) { - $this->logger->logger("WARNING: Couldn't find message id ".$message_id.' in the array of incoming messages. Maybe try to increase its size?', \danog\MadelineProto\Logger::WARNING); + $this->logger->logger("WARNING: Couldn't find message id " . $message_id . ' in the array of incoming messages. Maybe try to increase its size?', \danog\MadelineProto\Logger::WARNING); } /*if ($this->temp_auth_key['id'] === null || $this->temp_auth_key['id'] === "\0\0\0\0\0\0\0\0") { - // || (isset($this->incoming_messages[$message_id]['ack']) && $this->incoming_messages[$message_id]['ack'])) { - return; - }*/ + // || (isset($this->incoming_messages[$message_id]['ack']) && $this->incoming_messages[$message_id]['ack'])) { + return; + }*/ $this->ack_queue[$message_id] = $message_id; - return true; } - - - - /** * Check if there are some pending calls. * @@ -95,26 +84,17 @@ trait AckHandler $pfs = $settings['pfs']; $unencrypted = !$this->shared->hasTempAuthKey(); $notBound = !$this->shared->isBound(); - $pfsNotBound = $pfs && $notBound; - foreach ($this->new_outgoing as $message_id) { - if (isset($this->outgoing_messages[$message_id]['sent']) - && $this->outgoing_messages[$message_id]['sent'] + $timeout < \time() - && $unencrypted === $this->outgoing_messages[$message_id]['unencrypted'] - && $this->outgoing_messages[$message_id]['_'] !== 'msgs_state_req' - ) { + if (isset($this->outgoing_messages[$message_id]['sent']) && $this->outgoing_messages[$message_id]['sent'] + $timeout < \time() && $unencrypted === $this->outgoing_messages[$message_id]['unencrypted'] && $this->outgoing_messages[$message_id]['_'] !== 'msgs_state_req') { if ($pfsNotBound && $this->outgoing_messages[$message_id]['_'] !== 'auth.bindTempAuthKey') { continue; } - return true; } } - return false; } - /** * Get all pending calls (also clear pending state requests). * @@ -127,28 +107,20 @@ trait AckHandler $pfs = $settings['pfs']; $unencrypted = !$this->shared->hasTempAuthKey(); $notBound = !$this->shared->isBound(); - $pfsNotBound = $pfs && $notBound; - $result = []; foreach ($this->new_outgoing as $k => $message_id) { - if (isset($this->outgoing_messages[$message_id]['sent']) - && $this->outgoing_messages[$message_id]['sent'] + $timeout < \time() - && $unencrypted === $this->outgoing_messages[$message_id]['unencrypted'] - ) { + if (isset($this->outgoing_messages[$message_id]['sent']) && $this->outgoing_messages[$message_id]['sent'] + $timeout < \time() && $unencrypted === $this->outgoing_messages[$message_id]['unencrypted']) { if ($pfsNotBound && $this->outgoing_messages[$message_id]['_'] !== 'auth.bindTempAuthKey') { continue; } if ($this->outgoing_messages[$message_id]['_'] === 'msgs_state_req') { unset($this->new_outgoing[$k], $this->outgoing_messages[$message_id]); - continue; } - $result[] = $message_id; } } - return $result; } } diff --git a/src/danog/MadelineProto/MTProtoSession/CallHandler.php b/src/danog/MadelineProto/MTProtoSession/CallHandler.php index 910057b5..2612c198 100644 --- a/src/danog/MadelineProto/MTProtoSession/CallHandler.php +++ b/src/danog/MadelineProto/MTProtoSession/CallHandler.php @@ -24,7 +24,6 @@ use Amp\Promise; use Amp\Success; use danog\MadelineProto\Async\AsyncParameters; use danog\MadelineProto\Tools; - use function Amp\Promise\all; /** @@ -48,17 +47,13 @@ trait CallHandler if ($datacenter === $this->datacenter) { $datacenter = false; } - $message_ids = $this->outgoing_messages[$message_id]['container'] ?? [$message_id]; - foreach ($message_ids as $message_id) { if (isset($this->outgoing_messages[$message_id]['body'])) { if ($datacenter) { - $res = $this->API->datacenter->waitGetConnection($datacenter)->onResolve( - function ($e, $r) use ($message_id) { - return $r->sendMessage($this->outgoing_messages[$message_id], false); - } - ); + $res = $this->API->datacenter->waitGetConnection($datacenter)->onResolve(function ($e, $r) use ($message_id) { + return $r->sendMessage($this->outgoing_messages[$message_id], false); + }); } else { $res = $this->sendMessage($this->outgoing_messages[$message_id], false); } @@ -66,7 +61,7 @@ trait CallHandler $this->ackOutgoingMessageId($message_id); $this->gotResponseForOutgoingMessageId($message_id); } else { - $this->logger->logger('Could not resend '.(isset($this->outgoing_messages[$message_id]['_']) ? $this->outgoing_messages[$message_id]['_'] : $message_id)); + $this->logger->logger('Could not resend ' . (isset($this->outgoing_messages[$message_id]['_']) ? $this->outgoing_messages[$message_id]['_'] : $message_id)); } } if (!$postpone) { @@ -77,7 +72,6 @@ trait CallHandler } } } - /** * Call method and wait asynchronously for response. * @@ -97,22 +91,17 @@ trait CallHandler $deferred->fail($e); } else { if (\is_array($read_deferred)) { - $read_deferred = \array_map( - function ($value) { - return $value->promise(); - }, - $read_deferred - ); + $read_deferred = \array_map(function ($value) { + return $value->promise(); + }, $read_deferred); $deferred->resolve(all($read_deferred)); } else { $deferred->resolve($read_deferred->promise()); } } }); - - return ($aargs['noResponse'] ?? false) ? new Success() : $deferred->promise(); + return $aargs['noResponse'] ?? false ? new Success() : $deferred->promise(); } - /** * Call method and make sure it is asynchronously sent. * @@ -126,7 +115,6 @@ trait CallHandler { return \danog\MadelineProto\Tools::call($this->methodCallAsyncWriteGenerator($method, $args, $aargs)); } - /** * Call method and make sure it is asynchronously sent (generator). * @@ -138,24 +126,18 @@ trait CallHandler */ public function methodCallAsyncWriteGenerator(string $method, $args = [], array $aargs = ['msg_id' => null]): \Generator { - if (\is_array($args) - && isset($args['id']['_']) - && isset($args['id']['dc_id']) - && $args['id']['_'] === 'inputBotInlineMessageID' - && $this->datacenter !== $args['id']['dc_id'] - ) { + if (\is_array($args) && isset($args['id']['_']) && isset($args['id']['dc_id']) && $args['id']['_'] === 'inputBotInlineMessageID' && $this->datacenter !== $args['id']['dc_id']) { $aargs['datacenter'] = $args['id']['dc_id']; return $this->API->methodCallAsyncWriteGenerator($method, $args, $aargs); } - if (($aargs['file'] ?? false) && !$this->isMedia() && $this->API->datacenter->has($this->datacenter.'_media')) { + if (($aargs['file'] ?? false) && !$this->isMedia() && $this->API->datacenter->has($this->datacenter . '_media')) { $this->logger->logger('Using media DC'); - $aargs['datacenter'] = $this->datacenter.'_media'; + $aargs['datacenter'] = $this->datacenter . '_media'; return $this->API->methodCallAsyncWriteGenerator($method, $args, $aargs); } if (\in_array($method, ['messages.setEncryptedTyping', 'messages.readEncryptedHistory', 'messages.sendEncrypted', 'messages.sendEncryptedFile', 'messages.sendEncryptedService', 'messages.receivedQueue'])) { $aargs['queue'] = 'secret'; } - if (\is_array($args)) { if (isset($args['multiple'])) { $aargs['multiple'] = true; @@ -170,18 +152,15 @@ trait CallHandler $new_aargs = $aargs; $new_aargs['postpone'] = true; unset($new_aargs['multiple']); - if (isset($args['multiple'])) { unset($args['multiple']); } foreach ($args as $single_args) { $promises[] = $this->methodCallAsyncWrite($method, $single_args, $new_aargs); } - if (!isset($aargs['postpone'])) { $this->writer->resume(); } - return yield all($promises); } $args = yield $this->API->botAPIToMTProto($args); @@ -189,37 +168,21 @@ trait CallHandler $args['ping_id'] = Tools::packSignedLong($args['ping_id']); } } - $deferred = new Deferred(); - $message = \array_merge( - $aargs, - [ - '_' => $method, - 'type' => $this->API->getTL()->getMethods()->findByMethod($method)['type'], - 'contentRelated' => $this->contentRelated($method), - 'promise' => $deferred, - 'method' => true, - 'unencrypted' => !$this->shared->hasTempAuthKey() && \strpos($method, '.') === false - ] - ); - + $message = \array_merge($aargs, ['_' => $method, 'type' => $this->API->getTL()->getMethods()->findByMethod($method)['type'], 'contentRelated' => $this->contentRelated($method), 'promise' => $deferred, 'method' => true, 'unencrypted' => !$this->shared->hasTempAuthKey() && \strpos($method, '.') === false]); if (\is_object($args) && $args instanceof AsyncParameters) { $message['body'] = yield $args->fetchParameters(); } else { $message['body'] = $args; } - - if (($method === 'users.getUsers' && $args === ['id' => [['_' => 'inputUserSelf']]]) || $method === 'auth.exportAuthorization' || $method === 'updates.getDifference') { + if ($method === 'users.getUsers' && $args === ['id' => [['_' => 'inputUserSelf']]] || $method === 'auth.exportAuthorization' || $method === 'updates.getDifference') { $message['user_related'] = true; } $aargs['postpone'] = $aargs['postpone'] ?? false; $deferred = yield $this->sendMessage($message, !$aargs['postpone']); - $this->checker->resume(); - return $deferred; } - /** * Send object and make sure it is asynchronously sent (generator). * @@ -235,7 +198,6 @@ trait CallHandler if (isset($aargs['promise'])) { $message['promise'] = $aargs['promise']; } - $aargs['postpone'] = $aargs['postpone'] ?? false; return $this->sendMessage($message, !$aargs['postpone']); } diff --git a/src/danog/MadelineProto/MTProtoSession/MsgIdHandler.php b/src/danog/MadelineProto/MTProtoSession/MsgIdHandler.php index 9bbda36a..d8c7a76f 100644 --- a/src/danog/MadelineProto/MTProtoSession/MsgIdHandler.php +++ b/src/danog/MadelineProto/MTProtoSession/MsgIdHandler.php @@ -26,7 +26,6 @@ trait MsgIdHandler { public $max_incoming_id; public $max_outgoing_id; - public function checkMessageId($new_message_id, $aargs) { if (!\is_object($new_message_id)) { @@ -34,18 +33,18 @@ trait MsgIdHandler } $min_message_id = (new \tgseclib\Math\BigInteger(\time() + $this->time_delta - 300))->bitwise_leftShift(32); if ($min_message_id->compare($new_message_id) > 0) { - $this->API->logger->logger('Given message id ('.$new_message_id.') is too old compared to the min value ('.$min_message_id.').', \danog\MadelineProto\Logger::WARNING); + $this->API->logger->logger('Given message id (' . $new_message_id . ') is too old compared to the min value (' . $min_message_id . ').', \danog\MadelineProto\Logger::WARNING); } $max_message_id = (new \tgseclib\Math\BigInteger(\time() + $this->time_delta + 30))->bitwise_leftShift(32); if ($max_message_id->compare($new_message_id) < 0) { - throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is too new compared to the max value ('.$max_message_id.'). Consider syncing your date.'); + throw new \danog\MadelineProto\Exception('Given message id (' . $new_message_id . ') is too new compared to the max value (' . $max_message_id . '). Consider syncing your date.'); } if ($aargs['outgoing']) { if (!$new_message_id->divide(\danog\MadelineProto\Magic::$four)[1]->equals(\danog\MadelineProto\Magic::$zero)) { - throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is not divisible by 4. Consider syncing your date.'); + throw new \danog\MadelineProto\Exception('Given message id (' . $new_message_id . ') is not divisible by 4. Consider syncing your date.'); } if (!\danog\MadelineProto\Magic::$has_thread && $new_message_id->compare($key = $this->getMaxId($incoming = false)) <= 0) { - throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is lower than or equal to the current limit ('.$key.'). Consider syncing your date.', 1); + throw new \danog\MadelineProto\Exception('Given message id (' . $new_message_id . ') is lower than or equal to the current limit (' . $key . '). Consider syncing your date.', 1); } if (\count($this->outgoing_messages) > $this->API->settings['msg_array_limit']['outgoing']) { \reset($this->outgoing_messages); @@ -63,11 +62,11 @@ trait MsgIdHandler $key = $this->getMaxId($incoming = true); if ($aargs['container']) { if ($new_message_id->compare($key = $this->getMaxId($incoming = true)) >= 0) { - $this->API->logger->logger('WARNING: Given message id ('.$new_message_id.') is bigger than or equal to the current limit ('.$key.'). Consider syncing your date.', \danog\MadelineProto\Logger::WARNING); + $this->API->logger->logger('WARNING: Given message id (' . $new_message_id . ') is bigger than or equal to the current limit (' . $key . '). Consider syncing your date.', \danog\MadelineProto\Logger::WARNING); } } else { if ($new_message_id->compare($key = $this->getMaxId($incoming = true)) <= 0) { - $this->API->logger->logger('WARNING: Given message id ('.$new_message_id.') is lower than or equal to the current limit ('.$key.'). Consider syncing your date.', \danog\MadelineProto\Logger::WARNING); + $this->API->logger->logger('WARNING: Given message id (' . $new_message_id . ') is lower than or equal to the current limit (' . $key . '). Consider syncing your date.', \danog\MadelineProto\Logger::WARNING); } } if (\count($this->incoming_messages) > $this->API->settings['msg_array_limit']['incoming']) { @@ -81,7 +80,6 @@ trait MsgIdHandler $this->incoming_messages[\strrev($new_message_id->toBytes())] = []; } } - public function generateMessageId() { $message_id = (new \tgseclib\Math\BigInteger(\time() + $this->time_delta))->bitwise_leftShift(32); @@ -89,17 +87,14 @@ trait MsgIdHandler $message_id = $key->add(\danog\MadelineProto\Magic::$four); } $this->checkMessageId($message_id, ['outgoing' => true, 'container' => false]); - return \strrev($message_id->toBytes()); } - public function getMaxId($incoming) { $incoming = $incoming ? 'incoming' : 'outgoing'; - if (isset($this->{'max_'.$incoming.'_id'}) && \is_object($this->{'max_'.$incoming.'_id'})) { - return $this->{'max_'.$incoming.'_id'}; + if (isset($this->{'max_' . $incoming . '_id'}) && \is_object($this->{'max_' . $incoming . '_id'})) { + return $this->{'max_' . $incoming . '_id'}; } - return \danog\MadelineProto\Magic::$zero; } } diff --git a/src/danog/MadelineProto/MTProtoSession/ResponseHandler.php b/src/danog/MadelineProto/MTProtoSession/ResponseHandler.php index 7fb8b399..6a61de74 100644 --- a/src/danog/MadelineProto/MTProtoSession/ResponseHandler.php +++ b/src/danog/MadelineProto/MTProtoSession/ResponseHandler.php @@ -28,35 +28,33 @@ use danog\MadelineProto\MTProto; */ trait ResponseHandler { - public function sendMsgsStateInfo($req_msg_id, $msg_ids) + public function sendMsgsStateInfo($req_msg_id, $msg_ids): \Generator { - $this->logger->logger('Sending state info for '.\count($msg_ids).' message IDs'); + $this->logger->logger('Sending state info for ' . \count($msg_ids) . ' message IDs'); $info = ''; foreach ($msg_ids as $msg_id) { $cur_info = 0; if (!isset($this->incoming_messages[$msg_id])) { $msg_id = new \tgseclib\Math\BigInteger(\strrev($msg_id), 256); if ((new \tgseclib\Math\BigInteger(\time() + $this->time_delta + 30))->bitwise_leftShift(32)->compare($msg_id) < 0) { - $this->logger->logger("Do not know anything about $msg_id and it is too small"); + $this->logger->logger("Do not know anything about {$msg_id} and it is too small"); $cur_info |= 3; } elseif ((new \tgseclib\Math\BigInteger(\time() + $this->time_delta - 300))->bitwise_leftShift(32)->compare($msg_id) > 0) { - $this->logger->logger("Do not know anything about $msg_id and it is too big"); + $this->logger->logger("Do not know anything about {$msg_id} and it is too big"); $cur_info |= 1; } else { - $this->logger->logger("Do not know anything about $msg_id"); + $this->logger->logger("Do not know anything about {$msg_id}"); $cur_info |= 2; } } else { - $this->logger->logger("Know about $msg_id"); + $this->logger->logger("Know about {$msg_id}"); $cur_info |= 4; } $info .= \chr($cur_info); } $this->outgoing_messages[yield $this->objectCall('msgs_state_info', ['req_msg_id' => $req_msg_id, 'info' => $info], ['postpone' => true])]['response'] = $req_msg_id; } - public $n = 0; - public function handleMessages() { $only_updates = true; @@ -67,8 +65,7 @@ trait ResponseHandler unset($this->new_incoming[$current_msg_id]); continue; } - $this->logger->logger((isset($this->incoming_messages[$current_msg_id]['from_container']) ? 'Inside of container, received ' : 'Received ').$this->incoming_messages[$current_msg_id]['content']['_'].' from DC '.$this->datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE); - + $this->logger->logger((isset($this->incoming_messages[$current_msg_id]['from_container']) ? 'Inside of container, received ' : 'Received ') . $this->incoming_messages[$current_msg_id]['content']['_'] . ' from DC ' . $this->datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE); switch ($this->incoming_messages[$current_msg_id]['content']['_']) { case 'msgs_ack': unset($this->new_incoming[$current_msg_id]); @@ -78,7 +75,6 @@ trait ResponseHandler $this->ackOutgoingMessageId($msg_id); // Acknowledge that the server received my message } - unset($this->incoming_messages[$current_msg_id]['content']); break; case 'rpc_result': @@ -89,47 +85,39 @@ trait ResponseHandler $req_msg_id = $this->incoming_messages[$current_msg_id]['content']['req_msg_id']; $this->incoming_messages[$current_msg_id]['content'] = $this->incoming_messages[$current_msg_id]['content']['result']; $this->checkInSeqNo($current_msg_id); - $this->handleResponse($req_msg_id, $current_msg_id); break; - case 'future_salts': case 'msgs_state_info': $msg_id_type = 'req_msg_id'; - // no break + // no break case 'bad_server_salt': case 'bad_msg_notification': $msg_id_type = isset($msg_id_type) ? $msg_id_type : 'bad_msg_id'; - // no break + // no break case 'pong': $msg_id_type = isset($msg_id_type) ? $msg_id_type : 'msg_id'; unset($this->new_incoming[$current_msg_id]); $this->checkInSeqNo($current_msg_id); $only_updates = false; - $this->handleResponse($this->incoming_messages[$current_msg_id]['content'][$msg_id_type], $current_msg_id); unset($msg_id_type); break; - case 'new_session_created': unset($this->new_incoming[$current_msg_id]); $this->checkInSeqNo($current_msg_id); $only_updates = false; - $this->shared->getTempAuthKey()->setServerSalt($this->incoming_messages[$current_msg_id]['content']['server_salt']); $this->ackIncomingMessageId($current_msg_id); - // Acknowledge that I received the server's response if ($this->API->authorized === MTProto::LOGGED_IN && !$this->API->isInitingAuthorization() && $this->API->datacenter->getDataCenterConnection($this->API->datacenter->curdc)->hasTempAuthKey() && isset($this->API->updaters[false])) { $this->API->updaters[false]->resumeDefer(); } - unset($this->incoming_messages[$current_msg_id]['content']); break; case 'msg_container': unset($this->new_incoming[$current_msg_id]); $only_updates = false; - foreach ($this->incoming_messages[$current_msg_id]['content']['messages'] as $message) { $this->checkMessageId($message['msg_id'], ['outgoing' => false, 'container' => true]); $this->incoming_messages[$message['msg_id']] = ['seq_no' => $message['seqno'], 'content' => $message['body'], 'from_container' => true]; @@ -138,14 +126,12 @@ trait ResponseHandler \ksort($this->new_incoming); //$this->handleMessages(); //$this->checkInSeqNo($current_msg_id); - unset($this->incoming_messages[$current_msg_id]['content']); break; case 'msg_copy': unset($this->new_incoming[$current_msg_id]); $this->checkInSeqNo($current_msg_id); $only_updates = false; - $this->ackIncomingMessageId($current_msg_id); // Acknowledge that I received the server's response if (isset($this->incoming_messages[$this->incoming_messages[$current_msg_id]['content']['orig_message']['msg_id']])) { @@ -157,25 +143,19 @@ trait ResponseHandler $this->incoming_messages[$message['orig_message']['msg_id']] = ['content' => $this->incoming_messages[$current_msg_id]['content']['orig_message']]; $this->new_incoming[$message['orig_message']['msg_id']] = $message['orig_message']['msg_id']; } - unset($this->incoming_messages[$current_msg_id]['content']); break; - case 'http_wait': unset($this->new_incoming[$current_msg_id]); $this->checkInSeqNo($current_msg_id); $only_updates = false; - $this->logger->logger($this->incoming_messages[$current_msg_id]['content'], \danog\MadelineProto\Logger::NOTICE); - unset($this->incoming_messages[$current_msg_id]['content']); break; - case 'msgs_state_req': $this->checkInSeqNo($current_msg_id); $only_updates = false; unset($this->new_incoming[$current_msg_id]); - \danog\MadelineProto\Tools::callFork($this->sendMsgsStateInfo($current_msg_id, $this->incoming_messages[$current_msg_id]['content']['msg_ids'])); unset($this->incoming_messages[$current_msg_id]['content']); break; @@ -183,11 +163,10 @@ trait ResponseHandler $this->checkInSeqNo($current_msg_id); $only_updates = false; unset($this->new_incoming[$current_msg_id]); - foreach ($this->incoming_messages[$current_msg_id]['content']['msg_ids'] as $key => $msg_id) { $info = \ord($this->incoming_messages[$current_msg_id]['content']['info'][$key]); $msg_id = new \tgseclib\Math\BigInteger(\strrev($msg_id), 256); - $status = 'Status for message id '.$msg_id.': '; + $status = 'Status for message id ' . $msg_id . ': '; /*if ($info & 4) { *$this->gotResponseForOutgoingMessageId($msg_id); *} @@ -203,7 +182,6 @@ trait ResponseHandler case 'msg_detailed_info': $this->checkInSeqNo($current_msg_id); unset($this->new_incoming[$current_msg_id]); - $only_updates = false; if (isset($this->outgoing_messages[$this->incoming_messages[$current_msg_id]['content']['msg_id']])) { if (isset($this->incoming_messages[$this->incoming_messages[$current_msg_id]['content']['answer_msg_id']])) { @@ -217,7 +195,6 @@ trait ResponseHandler $this->checkInSeqNo($current_msg_id); $only_updates = false; unset($this->new_incoming[$current_msg_id]); - if (isset($this->incoming_messages[$this->incoming_messages[$current_msg_id]['content']['answer_msg_id']])) { $this->ackIncomingMessageId($this->incoming_messages[$current_msg_id]['content']['answer_msg_id']); } else { @@ -228,7 +205,6 @@ trait ResponseHandler $this->checkInSeqNo($current_msg_id); $only_updates = false; unset($this->new_incoming[$current_msg_id]); - $ok = true; foreach ($this->incoming_messages[$current_msg_id]['content']['msg_ids'] as $msg_id) { if (!isset($this->outgoing_messages[$msg_id]) || isset($this->incoming_messages[$msg_id])) { @@ -247,7 +223,6 @@ trait ResponseHandler $this->checkInSeqNo($current_msg_id); $only_updates = false; unset($this->new_incoming[$current_msg_id]); - \danog\MadelineProto\Tools::callFork($this->sendMsgsStateInfo($current_msg_id, $this->incoming_messages[$current_msg_id]['content']['msg_ids'])); foreach ($this->incoming_messages[$current_msg_id]['content']['msg_ids'] as $msg_id) { if (isset($this->incoming_messages[$msg_id]['response']) && isset($this->outgoing_messages[$this->incoming_messages[$msg_id]['response']])) { @@ -260,29 +235,24 @@ trait ResponseHandler $this->ackIncomingMessageId($current_msg_id); // Acknowledge that I received the server's response $response_type = $this->API->getTL()->getConstructors()->findByPredicate($this->incoming_messages[$current_msg_id]['content']['_'])['type']; - switch ($response_type) { case 'Updates': unset($this->new_incoming[$current_msg_id]); - if (!$this->isCdn()) { \danog\MadelineProto\Tools::callForkDefer($this->API->handleUpdates($this->incoming_messages[$current_msg_id]['content'])); } - unset($this->incoming_messages[$current_msg_id]['content']); - $only_updates = true && $only_updates; break; default: $only_updates = false; - $this->logger->logger('Trying to assign a response of type '.$response_type.' to its request...', \danog\MadelineProto\Logger::VERBOSE); + $this->logger->logger('Trying to assign a response of type ' . $response_type . ' to its request...', \danog\MadelineProto\Logger::VERBOSE); foreach ($this->new_outgoing as $key => $expecting_msg_id) { $expecting = $this->outgoing_messages[$expecting_msg_id]; if (!isset($expecting['type'])) { continue; } - - $this->logger->logger('Does the request of return type '.$expecting['type'].' match?', \danog\MadelineProto\Logger::VERBOSE); + $this->logger->logger('Does the request of return type ' . $expecting['type'] . ' match?', \danog\MadelineProto\Logger::VERBOSE); if ($response_type === $expecting['type']) { $this->logger->logger('Yes', \danog\MadelineProto\Logger::VERBOSE); unset($this->new_incoming[$current_msg_id]); @@ -291,8 +261,7 @@ trait ResponseHandler } $this->logger->logger('No', \danog\MadelineProto\Logger::VERBOSE); } - - $this->logger->logger('Dunno how to handle '.PHP_EOL.\var_export($this->incoming_messages[$current_msg_id]['content'], true), \danog\MadelineProto\Logger::FATAL_ERROR); + $this->logger->logger('Dunno how to handle ' . PHP_EOL . \var_export($this->incoming_messages[$current_msg_id]['content'], true), \danog\MadelineProto\Logger::FATAL_ERROR); unset($this->new_incoming[$current_msg_id]); break; } @@ -302,12 +271,9 @@ trait ResponseHandler if ($this->pending_outgoing) { $this->writer->resume(); } - //$this->n--; - return $only_updates; } - /** * Reject request with exception. * @@ -321,9 +287,8 @@ trait ResponseHandler if (isset($request['promise']) && \is_object($request['promise'])) { Loop::defer(function () use (&$request, $data) { if (isset($request['promise'])) { - $this->logger->logger('Rejecting: '.(isset($request['_']) ? $request['_'] : '-')); - $this->logger->logger("Rejecting: $data"); - + $this->logger->logger('Rejecting: ' . (isset($request['_']) ? $request['_'] : '-')); + $this->logger->logger("Rejecting: {$data}"); $promise = $request['promise']; unset($request['promise']); try { @@ -335,8 +300,8 @@ trait ResponseHandler $this->logger->logger("Got promise already resolved error", \danog\MadelineProto\Logger::FATAL_ERROR); } } else { - $this->logger->logger('Rejecting: already got response for '.(isset($request['_']) ? $request['_'] : '-')); - $this->logger->logger("Rejecting: $data"); + $this->logger->logger('Rejecting: already got response for ' . (isset($request['_']) ? $request['_'] : '-')); + $this->logger->logger("Rejecting: {$data}"); } }); } elseif (isset($request['container'])) { @@ -344,28 +309,24 @@ trait ResponseHandler $this->handleReject($this->outgoing_messages[$message_id], $data); } } else { - $this->logger->logger('Rejecting: already got response for '.(isset($request['_']) ? $request['_'] : '-')); - $this->logger->logger("Rejecting: $data"); + $this->logger->logger('Rejecting: already got response for ' . (isset($request['_']) ? $request['_'] : '-')); + $this->logger->logger("Rejecting: {$data}"); } } - public function handleResponse($request_id, $response_id) { - $response = &$this->incoming_messages[$response_id]['content']; + $response =& $this->incoming_messages[$response_id]['content']; unset($this->incoming_messages[$response_id]['content']); - $request = &$this->outgoing_messages[$request_id]; - + $request =& $this->outgoing_messages[$request_id]; if (isset($response['_'])) { switch ($response['_']) { case 'rpc_error': if (($request['method'] ?? false) && $request['_'] !== 'auth.bindTempAuthKey' && $this->shared->hasTempAuthKey() && !$this->shared->getTempAuthKey()->isInited()) { $this->shared->getTempAuthKey()->init(true); } - if (\in_array($response['error_message'], ['PERSISTENT_TIMESTAMP_EMPTY', 'PERSISTENT_TIMESTAMP_INVALID'])) { $this->gotResponseForOutgoingMessageId($request_id); $this->handleReject($request, new \danog\MadelineProto\PTSException($response['error_message'])); - return; } if ($response['error_message'] === 'PERSISTENT_TIMESTAMP_OUTDATED') { @@ -373,14 +334,11 @@ trait ResponseHandler } if (\strpos($response['error_message'], 'FILE_REFERENCE_') === 0) { $this->logger->logger("Got {$response['error_message']}, refreshing file reference and repeating method call..."); - $request['refreshReferences'] = true; if (isset($request['serialized_body'])) { unset($request['serialized_body']); } - $this->methodRecall('', ['message_id' => $request_id, 'postpone' => true]); - return; } switch ($response['error_code']) { @@ -389,32 +347,26 @@ trait ResponseHandler if ($response['error_message'] === 'MSG_WAIT_FAILED') { $this->call_queue[$request['queue']] = []; $this->methodRecall('', ['message_id' => $request_id, 'postpone' => true]); - return; } if (\in_array($response['error_message'], ['MSGID_DECREASE_RETRY', 'HISTORY_GET_FAILED', 'RPC_CALL_FAIL', 'PERSISTENT_TIMESTAMP_OUTDATED', 'RPC_MCGET_FAIL', 'no workers running', 'No workers running'])) { - Loop::delay(1 * 1000, [$this, 'methodRecall'], ['message_id' => $request_id, ]); + Loop::delay(1 * 1000, [$this, 'methodRecall'], ['message_id' => $request_id]); return; } $this->gotResponseForOutgoingMessageId($request_id); - $this->handleReject($request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code'], $request['_'] ?? '')); - return; case 303: $this->API->datacenter->curdc = $datacenter = (int) \preg_replace('/[^0-9]+/', '', $response['error_message']); - - if (isset($request['file']) && $request['file'] && $this->API->datacenter->has($datacenter.'_media')) { + if (isset($request['file']) && $request['file'] && $this->API->datacenter->has($datacenter . '_media')) { \danog\MadelineProto\Logger::log('Using media DC'); $datacenter .= '_media'; } - if (isset($request['user_related']) && $request['user_related']) { $this->API->settings['connection_settings']['default_dc'] = $this->API->authorized_dc = $this->API->datacenter->curdc; } Loop::defer([$this, 'methodRecall'], ['message_id' => $request_id, 'datacenter' => $datacenter]); //$this->API->methodRecall('', ['message_id' => $request_id, 'datacenter' => $datacenter, 'postpone' => true]); - return; case 401: switch ($response['error_message']) { @@ -422,123 +374,95 @@ trait ResponseHandler case 'SESSION_REVOKED': case 'SESSION_EXPIRED': $this->gotResponseForOutgoingMessageId($request_id); - $this->logger->logger($response['error_message'], \danog\MadelineProto\Logger::FATAL_ERROR); foreach ($this->API->datacenter->getDataCenterConnections() as $socket) { $socket->setTempAuthKey(null); $socket->setPermAuthKey(null); $socket->resetSession(); } - if ($response['error_message'] === 'USER_DEACTIVATED') { $this->logger->logger('!!!!!!! WARNING !!!!!!!', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger("Telegram's flood prevention system suspended this account.", \danog\MadelineProto\Logger::ERROR); $this->logger->logger('To continue, manual verification is required.', \danog\MadelineProto\Logger::FATAL_ERROR); - $phone = isset($this->authorization['user']['phone']) ? '+'.$this->authorization['user']['phone'] : 'you are currently using'; - $this->logger->logger('Send an email to recover@telegram.org, asking to unban the phone number '.$phone.', and shortly describe what will you do with this phone number.', \danog\MadelineProto\Logger::FATAL_ERROR); + $phone = isset($this->authorization['user']['phone']) ? '+' . $this->authorization['user']['phone'] : 'you are currently using'; + $this->logger->logger('Send an email to recover@telegram.org, asking to unban the phone number ' . $phone . ', and shortly describe what will you do with this phone number.', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger('Then login again.', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger('If you intentionally deleted this account, ignore this message.', \danog\MadelineProto\Logger::FATAL_ERROR); } - $this->API->resetSession(); - - \danog\MadelineProto\Tools::callFork((function () use (&$request, &$response) { + \danog\MadelineProto\Tools::callFork((function () use (&$request, &$response): \Generator { yield $this->API->initAuthorization(); - $this->handleReject($request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code'], $request['_'] ?? '')); })()); - return; case 'AUTH_KEY_UNREGISTERED': case 'AUTH_KEY_INVALID': if ($this->API->authorized !== MTProto::LOGGED_IN) { $this->gotResponseForOutgoingMessageId($request_id); - - \danog\MadelineProto\Tools::callFork((function () use (&$request, &$response) { + \danog\MadelineProto\Tools::callFork((function () use (&$request, &$response): \Generator { yield $this->API->initAuthorization(); - $this->handleReject($request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code'], $request['_'] ?? '')); })()); - return; } $this->session_id = null; $this->shared->setTempAuthKey(null); $this->shared->setPermAuthKey(null); - $this->logger->logger('Auth key not registered, resetting temporary and permanent auth keys...', \danog\MadelineProto\Logger::ERROR); - if ($this->API->authorized_dc === $this->datacenter && $this->API->authorized === MTProto::LOGGED_IN) { $this->gotResponseForOutgoingMessageId($request_id); - $this->logger->logger('Permanent auth key was main authorized key, logging out...', \danog\MadelineProto\Logger::FATAL_ERROR); foreach ($this->API->datacenter->getDataCenterConnections() as $socket) { $socket->setTempAuthKey(null); $socket->setPermAuthKey(null); } - $this->logger->logger('!!!!!!! WARNING !!!!!!!', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger("Telegram's flood prevention system suspended this account.", \danog\MadelineProto\Logger::ERROR); $this->logger->logger('To continue, manual verification is required.', \danog\MadelineProto\Logger::FATAL_ERROR); - $phone = isset($this->authorization['user']['phone']) ? '+'.$this->authorization['user']['phone'] : 'you are currently using'; - $this->logger->logger('Send an email to recover@telegram.org, asking to unban the phone number '.$phone.', and quickly describe what will you do with this phone number.', \danog\MadelineProto\Logger::FATAL_ERROR); + $phone = isset($this->authorization['user']['phone']) ? '+' . $this->authorization['user']['phone'] : 'you are currently using'; + $this->logger->logger('Send an email to recover@telegram.org, asking to unban the phone number ' . $phone . ', and quickly describe what will you do with this phone number.', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger('Then login again.', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger('If you intentionally deleted this account, ignore this message.', \danog\MadelineProto\Logger::FATAL_ERROR); - $this->API->resetSession(); - - \danog\MadelineProto\Tools::callFork((function () use (&$request, &$response) { + \danog\MadelineProto\Tools::callFork((function () use (&$request, &$response): \Generator { yield $this->API->initAuthorization(); - $this->handleReject($request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code'], $request['_'] ?? '')); })()); - return; } - \danog\MadelineProto\Tools::callFork((function () use ($request_id) { + \danog\MadelineProto\Tools::callFork((function () use ($request_id): \Generator { yield $this->API->initAuthorization(); - - $this->methodRecall('', ['message_id' => $request_id, ]); + $this->methodRecall('', ['message_id' => $request_id]); })()); - return; case 'AUTH_KEY_PERM_EMPTY': $this->logger->logger('Temporary auth key not bound, resetting temporary auth key...', \danog\MadelineProto\Logger::ERROR); - $this->shared->setTempAuthKey(null); - \danog\MadelineProto\Tools::callFork((function () use ($request_id) { + \danog\MadelineProto\Tools::callFork((function () use ($request_id): \Generator { yield $this->API->initAuthorization(); - $this->methodRecall('', ['message_id' => $request_id, ]); + $this->methodRecall('', ['message_id' => $request_id]); })()); - return; } $this->gotResponseForOutgoingMessageId($request_id); - $this->handleReject($request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code'], $request['_'] ?? '')); - return; case 420: $seconds = \preg_replace('/[^0-9]+/', '', $response['error_message']); $limit = $request['FloodWaitLimit'] ?? $this->API->settings['flood_timeout']['wait_if_lt']; if (\is_numeric($seconds) && $seconds < $limit) { //$this->gotResponseForOutgoingMessageId($request_id); - - $this->logger->logger('Flood, waiting '.$seconds.' seconds before repeating async call of '.($request['_'] ?? '').'...', \danog\MadelineProto\Logger::NOTICE); + $this->logger->logger('Flood, waiting ' . $seconds . ' seconds before repeating async call of ' . ($request['_'] ?? '') . '...', \danog\MadelineProto\Logger::NOTICE); $request['sent'] = ($request['sent'] ?? \time()) + $seconds; - Loop::delay($seconds * 1000, [$this, 'methodRecall'], ['message_id' => $request_id, ]); - + Loop::delay($seconds * 1000, [$this, 'methodRecall'], ['message_id' => $request_id]); return; } // no break default: $this->gotResponseForOutgoingMessageId($request_id); - $this->handleReject($request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code'], $request['_'] ?? '')); - return; } - return; case 'boolTrue': case 'boolFalse': @@ -546,41 +470,35 @@ trait ResponseHandler break; case 'bad_server_salt': case 'bad_msg_notification': - $this->logger->logger('Received bad_msg_notification: '.MTProto::BAD_MSG_ERROR_CODES[$response['error_code']], \danog\MadelineProto\Logger::WARNING); + $this->logger->logger('Received bad_msg_notification: ' . MTProto::BAD_MSG_ERROR_CODES[$response['error_code']], \danog\MadelineProto\Logger::WARNING); switch ($response['error_code']) { case 48: $this->shared->getTempAuthKey()->setServerSalt($response['new_server_salt']); $this->methodRecall('', ['message_id' => $request_id, 'postpone' => true]); - return; case 16: case 17: $this->time_delta = (int) (new \tgseclib\Math\BigInteger(\strrev($response_id), 256))->bitwise_rightShift(32)->subtract(new \tgseclib\Math\BigInteger(\time()))->toString(); - $this->logger->logger('Set time delta to '.$this->time_delta, \danog\MadelineProto\Logger::WARNING); + $this->logger->logger('Set time delta to ' . $this->time_delta, \danog\MadelineProto\Logger::WARNING); $this->API->resetMTProtoSession(); $this->shared->setTempAuthKey(null); - \danog\MadelineProto\Tools::callFork((function () use ($request_id) { + \danog\MadelineProto\Tools::callFork((function () use ($request_id): \Generator { yield $this->API->initAuthorization(); - $this->methodRecall('', ['message_id' => $request_id, ]); + $this->methodRecall('', ['message_id' => $request_id]); })()); - return; } $this->gotResponseForOutgoingMessageId($request_id); - $this->handleReject($request, new \danog\MadelineProto\RPCErrorException('Received bad_msg_notification: '.MTProto::BAD_MSG_ERROR_CODES[$response['error_code']], $response['error_code'], $request['_'] ?? '')); - + $this->handleReject($request, new \danog\MadelineProto\RPCErrorException('Received bad_msg_notification: ' . MTProto::BAD_MSG_ERROR_CODES[$response['error_code']], $response['error_code'], $request['_'] ?? '')); return; } } - if (($request['method'] ?? false) && $request['_'] !== 'auth.bindTempAuthKey' && $this->shared->hasTempAuthKey() && !$this->shared->getTempAuthKey()->isInited()) { $this->shared->getTempAuthKey()->init(true); } - if (!isset($request['promise'])) { $this->gotResponseForOutgoingMessageId($request_id); - $this->logger->logger('Response: already got response for '.(isset($request['_']) ? $request['_'] : '-').' with message ID '.$request_id); - + $this->logger->logger('Response: already got response for ' . (isset($request['_']) ? $request['_'] : '-') . ' with message ID ' . $request_id); return; } $botAPI = isset($request['botAPI']) && $request['botAPI']; @@ -591,27 +509,26 @@ trait ResponseHandler unset($request); $this->gotResponseForOutgoingMessageId($request_id); $r = isset($response['_']) ? $response['_'] : \json_encode($response); - $this->logger->logger("Defer sending $r to deferred", Logger::ULTRA_VERBOSE); - \danog\MadelineProto\Tools::callFork(( - function () use ($request_id, $response, $botAPI) { - $r = isset($response['_']) ? $response['_'] : \json_encode($response); - $this->logger->logger("Deferred: sent $r to deferred", Logger::ULTRA_VERBOSE); - if ($botAPI) { - $response = yield $this->MTProtoToBotAPI($response); - } - if (isset($this->outgoing_messages[$request_id]['promise'])) { // This should not happen but happens, should debug - $promise = $this->outgoing_messages[$request_id]['promise']; - unset($this->outgoing_messages[$request_id]['promise']); - try { - $promise->resolve($response); - } catch (\Error $e) { - if (\strpos($e->getMessage(), "Promise has already been resolved") !== 0) { - throw $e; - } - $this->logger->logger("Got promise already resolved error", \danog\MadelineProto\Logger::FATAL_ERROR); + $this->logger->logger("Defer sending {$r} to deferred", Logger::ULTRA_VERBOSE); + \danog\MadelineProto\Tools::callFork((function () use ($request_id, $response, $botAPI): \Generator { + $r = isset($response['_']) ? $response['_'] : \json_encode($response); + $this->logger->logger("Deferred: sent {$r} to deferred", Logger::ULTRA_VERBOSE); + if ($botAPI) { + $response = yield $this->MTProtoToBotAPI($response); + } + if (isset($this->outgoing_messages[$request_id]['promise'])) { + // This should not happen but happens, should debug + $promise = $this->outgoing_messages[$request_id]['promise']; + unset($this->outgoing_messages[$request_id]['promise']); + try { + $promise->resolve($response); + } catch (\Error $e) { + if (\strpos($e->getMessage(), "Promise has already been resolved") !== 0) { + throw $e; } + $this->logger->logger("Got promise already resolved error", \danog\MadelineProto\Logger::FATAL_ERROR); } } - )()); + })()); } } diff --git a/src/danog/MadelineProto/MTProtoSession/SeqNoHandler.php b/src/danog/MadelineProto/MTProtoSession/SeqNoHandler.php index ac91a942..96857c5d 100644 --- a/src/danog/MadelineProto/MTProtoSession/SeqNoHandler.php +++ b/src/danog/MadelineProto/MTProtoSession/SeqNoHandler.php @@ -28,9 +28,7 @@ trait SeqNoHandler { public $session_out_seq_no = 0; public $session_in_seq_no = 0; - public $session_id; - public function generateOutSeqNo($contentRelated) { $in = $contentRelated ? 1 : 0; @@ -39,17 +37,15 @@ trait SeqNoHandler //$this->API->logger->logger("OUT: $value + $in = ".$this->session_out_seq_no); return $value * 2 + $in; } - public function checkInSeqNo($current_msg_id) { $type = isset($this->incoming_messages[$current_msg_id]['content']['_']) ? $this->incoming_messages[$current_msg_id]['content']['_'] : '-'; if (isset($this->incoming_messages[$current_msg_id]['seq_no']) && ($seq_no = $this->generateInSeqNo($this->contentRelated($this->incoming_messages[$current_msg_id]['content']))) !== $this->incoming_messages[$current_msg_id]['seq_no']) { - $this->API->logger->logger('SECURITY WARNING: Seqno mismatch (should be '.$seq_no.', is '.$this->incoming_messages[$current_msg_id]['seq_no'].', '.$type.')', \danog\MadelineProto\Logger::ULTRA_VERBOSE); + $this->API->logger->logger('SECURITY WARNING: Seqno mismatch (should be ' . $seq_no . ', is ' . $this->incoming_messages[$current_msg_id]['seq_no'] . ', ' . $type . ')', \danog\MadelineProto\Logger::ULTRA_VERBOSE); } elseif (isset($seq_no)) { - $this->API->logger->logger('Seqno OK (should be '.$seq_no.', is '.$this->incoming_messages[$current_msg_id]['seq_no'].', '.$type.')', \danog\MadelineProto\Logger::ULTRA_VERBOSE); + $this->API->logger->logger('Seqno OK (should be ' . $seq_no . ', is ' . $this->incoming_messages[$current_msg_id]['seq_no'] . ', ' . $type . ')', \danog\MadelineProto\Logger::ULTRA_VERBOSE); } } - public function generateInSeqNo($contentRelated) { $in = $contentRelated ? 1 : 0; @@ -58,11 +54,9 @@ trait SeqNoHandler //$this->API->logger->logger("IN: $value + $in = ".$this->session_in_seq_no); return $value * 2 + $in; } - public function contentRelated($method) { $method = \is_array($method) && isset($method['_']) ? $method['_'] : $method; - return \is_string($method) ? !\in_array($method, MTProto::NOT_CONTENT_RELATED) : true; } } diff --git a/src/danog/MadelineProto/MTProtoSession/Session.php b/src/danog/MadelineProto/MTProtoSession/Session.php index a55e81dd..f5083021 100644 --- a/src/danog/MadelineProto/MTProtoSession/Session.php +++ b/src/danog/MadelineProto/MTProtoSession/Session.php @@ -1,4 +1,5 @@ session_out_seq_no = 0; } } - /** * Backup eventual unsent messages before session deletion. * diff --git a/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php b/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php index 3d815c78..e21cab0e 100644 --- a/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php @@ -46,7 +46,6 @@ trait AuthKeyHandler * @var boolean */ private $pending_auth = false; - /** * Create authorization key. * @@ -62,7 +61,6 @@ trait AuthKeyHandler $connection = $this->datacenter->getAuthConnection($datacenter); $cdn = $connection->isCDN(); $req_pq = $cdn ? 'req_pq' : 'req_pq_multi'; - for ($retry_id_total = 1; $retry_id_total <= $this->settings['max_tries']['authorization']; $retry_id_total++) { try { $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['req_pq'], \danog\MadelineProto\Logger::VERBOSE); @@ -128,7 +126,6 @@ trait AuthKeyHandler list($p, $q) = [$q, $p]; } } - if (!$pq->equals($p->multiply($q))) { $this->logger->logger('Automatic factorization failed, trying alt py module', \danog\MadelineProto\Logger::ERROR); $p = new \tgseclib\Math\BigInteger(\danog\PrimeModule::python_single_alt($pq->__toString())); @@ -138,7 +135,6 @@ trait AuthKeyHandler list($p, $q) = [$q, $p]; } } - if (!$pq->equals($p->multiply($q))) { $this->logger->logger('Automatic factorization failed, trying py module', \danog\MadelineProto\Logger::ERROR); $p = new \tgseclib\Math\BigInteger(\danog\PrimeModule::python_single($pq->__toString())); @@ -148,7 +144,6 @@ trait AuthKeyHandler list($p, $q) = [$q, $p]; } } - if (!$pq->equals($p->multiply($q))) { $this->logger->logger('Automatic factorization failed, trying native module', \danog\MadelineProto\Logger::ERROR); $p = new \tgseclib\Math\BigInteger(\danog\PrimeModule::native_single($pq->__toString())); @@ -158,37 +153,32 @@ trait AuthKeyHandler list($p, $q) = [$q, $p]; } } - if (!$pq->equals($p->multiply($q))) { $this->logger->logger('Automatic factorization failed, trying wolfram module', \danog\MadelineProto\Logger::ERROR); - - $p = new \tgseclib\Math\BigInteger(yield $this->wolframSingle($pq->__toString())); + $p = new \tgseclib\Math\BigInteger(yield from $this->wolframSingle($pq->__toString())); if (!$p->equals(\danog\MadelineProto\Magic::$zero)) { $q = $pq->divide($p)[0]; if ($p->compare($q) > 0) { list($p, $q) = [$q, $p]; } } - if (!$pq->equals($p->multiply($q))) { - throw new \danog\MadelineProto\SecurityException("Couldn't compute p and q, install prime.madelineproto.xyz to fix. Original pq: {$pq}, computed p: {$p}, computed q: {$q}, computed pq: ".$p->multiply($q)); + throw new \danog\MadelineProto\SecurityException("Couldn't compute p and q, install prime.madelineproto.xyz to fix. Original pq: {$pq}, computed p: {$p}, computed q: {$q}, computed pq: " . $p->multiply($q)); } } } } } } - - $this->logger->logger('Factorization '.$pq.' = '.$p.' * '.$q, \danog\MadelineProto\Logger::VERBOSE); + $this->logger->logger('Factorization ' . $pq . ' = ' . $p . ' * ' . $q, \danog\MadelineProto\Logger::VERBOSE); /* * *********************************************************************** * Serialize object for req_DH_params */ $p_bytes = $p->toBytes(); $q_bytes = $q->toBytes(); - $new_nonce = \danog\MadelineProto\Tools::random(32); - $data_unserialized = ['_' => 'p_q_inner_data'.($expires_in < 0 ? '' : '_temp'), 'pq' => $pq_bytes, 'p' => $p_bytes, 'q' => $q_bytes, 'nonce' => $nonce, 'server_nonce' => $server_nonce, 'new_nonce' => $new_nonce, 'expires_in' => $expires_in, 'dc' => \preg_replace('|_.*|', '', $datacenter)]; + $data_unserialized = ['_' => 'p_q_inner_data' . ($expires_in < 0 ? '' : '_temp'), 'pq' => $pq_bytes, 'p' => $p_bytes, 'q' => $q_bytes, 'nonce' => $nonce, 'server_nonce' => $server_nonce, 'new_nonce' => $new_nonce, 'expires_in' => $expires_in, 'dc' => \preg_replace('|_.*|', '', $datacenter)]; $p_q_inner_data = yield $this->TL->serializeObject(['type' => ''], $data_unserialized, 'p_q_inner_data'); /* * *********************************************************************** @@ -196,8 +186,7 @@ trait AuthKeyHandler */ $sha_digest = \sha1($p_q_inner_data, true); $random_bytes = \danog\MadelineProto\Tools::random(255 - \strlen($p_q_inner_data) - \strlen($sha_digest)); - $to_encrypt = $sha_digest.$p_q_inner_data.$random_bytes; - + $to_encrypt = $sha_digest . $p_q_inner_data . $random_bytes; $encrypted_data = $key->encrypt($to_encrypt); $this->logger->logger('Starting Diffie Hellman key exchange', \danog\MadelineProto\Logger::VERBOSE); /* @@ -248,10 +237,8 @@ trait AuthKeyHandler * Get key, iv and decrypt answer */ $encrypted_answer = $server_dh_params['encrypted_answer']; - - $tmp_aes_key = \sha1($new_nonce.$server_nonce, true).\substr(\sha1($server_nonce.$new_nonce, true), 0, 12); - $tmp_aes_iv = \substr(\sha1($server_nonce.$new_nonce, true), 12, 8).\sha1($new_nonce.$new_nonce, true).\substr($new_nonce, 0, 4); - + $tmp_aes_key = \sha1($new_nonce . $server_nonce, true) . \substr(\sha1($server_nonce . $new_nonce, true), 0, 12); + $tmp_aes_iv = \substr(\sha1($server_nonce . $new_nonce, true), 12, 8) . \sha1($new_nonce . $new_nonce, true) . \substr($new_nonce, 0, 4); $answer_with_hash = $this->igeDecrypt($encrypted_answer, $tmp_aes_key, $tmp_aes_iv); /* * *********************************************************************** @@ -331,8 +318,8 @@ trait AuthKeyHandler * *********************************************************************** * encrypt client_DH_inner_data */ - $data_with_sha = \sha1($data, true).$data; - $data_with_sha_padded = $data_with_sha.\danog\MadelineProto\Tools::random(\danog\MadelineProto\Tools::posmod(-\strlen($data_with_sha), 16)); + $data_with_sha = \sha1($data, true) . $data; + $data_with_sha_padded = $data_with_sha . \danog\MadelineProto\Tools::random(\danog\MadelineProto\Tools::posmod(-\strlen($data_with_sha), 16)); $encrypted_data = $this->igeEncrypt($data_with_sha_padded, $tmp_aes_key, $tmp_aes_iv); $this->logger->logger('Executing set_client_DH_params...', \danog\MadelineProto\Logger::VERBOSE); /* @@ -362,9 +349,9 @@ trait AuthKeyHandler $auth_key_str = $auth_key->toBytes(); $auth_key_sha = \sha1($auth_key_str, true); $auth_key_aux_hash = \substr($auth_key_sha, 0, 8); - $new_nonce_hash1 = \substr(\sha1($new_nonce.\chr(1).$auth_key_aux_hash, true), -16); - $new_nonce_hash2 = \substr(\sha1($new_nonce.\chr(2).$auth_key_aux_hash, true), -16); - $new_nonce_hash3 = \substr(\sha1($new_nonce.\chr(3).$auth_key_aux_hash, true), -16); + $new_nonce_hash1 = \substr(\sha1($new_nonce . \chr(1) . $auth_key_aux_hash, true), -16); + $new_nonce_hash2 = \substr(\sha1($new_nonce . \chr(2) . $auth_key_aux_hash, true), -16); + $new_nonce_hash3 = \substr(\sha1($new_nonce . \chr(3) . $auth_key_aux_hash, true), -16); /* * *********************************************************************** * Check if the client's nonce and the server's nonce are the same @@ -389,16 +376,13 @@ trait AuthKeyHandler throw new \danog\MadelineProto\SecurityException('wrong new_nonce_hash1'); } $this->logger->logger('Diffie Hellman key exchange processed successfully!', \danog\MadelineProto\Logger::VERBOSE); - $key = $expires_in < 0 ? new PermAuthKey() : new TempAuthKey(); if ($expires_in >= 0) { $key->expires(\time() + $expires_in); } $key->setServerSalt(\substr($new_nonce, 0, 8) ^ \substr($server_nonce, 0, 8)); $key->setAuthKey($auth_key_str); - $this->logger->logger('Auth key generated', \danog\MadelineProto\Logger::NOTICE); - return $key; case 'dh_gen_retry': if ($Set_client_DH_params_answer['new_nonce_hash2'] != $new_nonce_hash2) { @@ -419,21 +403,20 @@ trait AuthKeyHandler } } } catch (\danog\MadelineProto\SecurityException $e) { - $this->logger->logger('An exception occurred while generating the authorization key: '.$e->getMessage().' in '.\basename($e->getFile(), '.php').' on line '.$e->getLine().'. Retrying...', \danog\MadelineProto\Logger::WARNING); + $this->logger->logger('An exception occurred while generating the authorization key: ' . $e->getMessage() . ' in ' . \basename($e->getFile(), '.php') . ' on line ' . $e->getLine() . '. Retrying...', \danog\MadelineProto\Logger::WARNING); } catch (\danog\MadelineProto\Exception $e) { - $this->logger->logger('An exception occurred while generating the authorization key: '.$e->getMessage().' in '.\basename($e->getFile(), '.php').' on line '.$e->getLine().'. Retrying...', \danog\MadelineProto\Logger::WARNING); + $this->logger->logger('An exception occurred while generating the authorization key: ' . $e->getMessage() . ' in ' . \basename($e->getFile(), '.php') . ' on line ' . $e->getLine() . '. Retrying...', \danog\MadelineProto\Logger::WARNING); $req_pq = $req_pq === 'req_pq_multi' ? 'req_pq' : 'req_pq_multi'; } catch (\danog\MadelineProto\RPCErrorException $e) { - $this->logger->logger('An RPCErrorException occurred while generating the authorization key: '.$e->getMessage().' Retrying (try number '.$retry_id_total.')...', \danog\MadelineProto\Logger::WARNING); + $this->logger->logger('An RPCErrorException occurred while generating the authorization key: ' . $e->getMessage() . ' Retrying (try number ' . $retry_id_total . ')...', \danog\MadelineProto\Logger::WARNING); } catch (\Throwable $e) { - $this->logger->logger('An exception occurred while generating the authorization key: '.$e.PHP_EOL.' Retrying (try number '.$retry_id_total.')...', \danog\MadelineProto\Logger::WARNING); + $this->logger->logger('An exception occurred while generating the authorization key: ' . $e . PHP_EOL . ' Retrying (try number ' . $retry_id_total . ')...', \danog\MadelineProto\Logger::WARNING); } } if (!$cdn) { throw new \danog\MadelineProto\SecurityException('Auth Failed'); } } - /** * Check validity of g_a parameters. * @@ -459,10 +442,8 @@ trait AuthKeyHandler if ($g_a->compare(\danog\MadelineProto\Magic::$twoe1984) < 0 || $g_a->compare($p->subtract(\danog\MadelineProto\Magic::$twoe1984)) >= 0) { throw new \danog\MadelineProto\SecurityException('g_a is invalid (2^1984 < g_a < p - 2^1984 is false).'); } - return true; } - /** * Check validity of p and g parameters. * @@ -492,11 +473,11 @@ trait AuthKeyHandler * Almost always fails */ /* - $this->logger->logger('Executing p/g checks (2/3)...', \danog\MadelineProto\Logger::VERBOSE); - if (!$p->subtract(\danog\MadelineProto\Magic::$one)->divide(\danog\MadelineProto\Magic::$two)[0]->isPrime()) { - throw new \danog\MadelineProto\SecurityException("p isn't a safe 2048-bit prime ((p - 1) / 2 isn't a prime)."); - } - */ + $this->logger->logger('Executing p/g checks (2/3)...', \danog\MadelineProto\Logger::VERBOSE); + if (!$p->subtract(\danog\MadelineProto\Magic::$one)->divide(\danog\MadelineProto\Magic::$two)[0]->isPrime()) { + throw new \danog\MadelineProto\SecurityException("p isn't a safe 2048-bit prime ((p - 1) / 2 isn't a prime)."); + } + */ /* * *********************************************************************** * Check validity of p @@ -515,10 +496,8 @@ trait AuthKeyHandler if ($g->compare(\danog\MadelineProto\Magic::$one) <= 0 || $g->compare($p->subtract(\danog\MadelineProto\Magic::$one)) >= 0) { throw new \danog\MadelineProto\SecurityException('g is invalid (1 < g < p - 1 is false).'); } - return true; } - /** * Get diffie-hellman configuration. * @@ -531,16 +510,13 @@ trait AuthKeyHandler $dh_config = yield $this->methodCallAsyncRead('messages.getDhConfig', ['version' => $this->dh_config['version'], 'random_length' => 0], ['datacenter' => $this->datacenter->curdc]); if ($dh_config['_'] === 'messages.dhConfigNotModified') { $this->logger->logger('DH configuration not modified', \danog\MadelineProto\Logger::VERBOSE); - return $this->dh_config; } $dh_config['p'] = new \tgseclib\Math\BigInteger((string) $dh_config['p'], 256); $dh_config['g'] = new \tgseclib\Math\BigInteger($dh_config['g']); $this->checkPG($dh_config['p'], $dh_config['g']); - return $this->dh_config = $dh_config; } - /** * Bind temporary and permanent auth keys. * @@ -555,7 +531,6 @@ trait AuthKeyHandler { $datacenterConnection = $this->datacenter->getDataCenterConnection($datacenter); $connection = $datacenterConnection->getAuthConnection(); - for ($retry_id_total = 1; $retry_id_total <= $this->settings['max_tries']['authorization']; $retry_id_total++) { try { $this->logger->logger('Binding authorization keys...', \danog\MadelineProto\Logger::VERBOSE); @@ -564,34 +539,31 @@ trait AuthKeyHandler $temp_auth_key_id = $datacenterConnection->getTempAuthKey()->getID(); $perm_auth_key_id = $datacenterConnection->getPermAuthKey()->getID(); $temp_session_id = $connection->session_id; - $message_data = yield $this->TL->serializeObject(['type' => ''], ['_' => 'bind_auth_key_inner','nonce' => $nonce, 'temp_auth_key_id' => $temp_auth_key_id, 'perm_auth_key_id' => $perm_auth_key_id, 'temp_session_id' => $temp_session_id, 'expires_at' => $expires_at], 'bindTempAuthKey_inner'); + $message_data = yield $this->TL->serializeObject(['type' => ''], ['_' => 'bind_auth_key_inner', 'nonce' => $nonce, 'temp_auth_key_id' => $temp_auth_key_id, 'perm_auth_key_id' => $perm_auth_key_id, 'temp_session_id' => $temp_session_id, 'expires_at' => $expires_at], 'bindTempAuthKey_inner'); $message_id = $connection->generateMessageId(); $seq_no = 0; - $encrypted_data = \danog\MadelineProto\Tools::random(16).$message_id.\pack('VV', $seq_no, \strlen($message_data)).$message_data; + $encrypted_data = \danog\MadelineProto\Tools::random(16) . $message_id . \pack('VV', $seq_no, \strlen($message_data)) . $message_data; $message_key = \substr(\sha1($encrypted_data, true), -16); $padding = \danog\MadelineProto\Tools::random(\danog\MadelineProto\Tools::posmod(-\strlen($encrypted_data), 16)); list($aes_key, $aes_iv) = $this->oldAesCalculate($message_key, $datacenterConnection->getPermAuthKey()->getAuthKey()); - $encrypted_message = $datacenterConnection->getPermAuthKey()->getID().$message_key.$this->igeEncrypt($encrypted_data.$padding, $aes_key, $aes_iv); + $encrypted_message = $datacenterConnection->getPermAuthKey()->getID() . $message_key . $this->igeEncrypt($encrypted_data . $padding, $aes_key, $aes_iv); $res = yield $connection->methodCallAsyncRead('auth.bindTempAuthKey', ['perm_auth_key_id' => $perm_auth_key_id, 'nonce' => $nonce, 'expires_at' => $expires_at, 'encrypted_message' => $encrypted_message], ['msg_id' => $message_id]); if ($res === true) { - $this->logger->logger('Bound temporary and permanent authorization keys, DC '.$datacenter, \danog\MadelineProto\Logger::NOTICE); + $this->logger->logger('Bound temporary and permanent authorization keys, DC ' . $datacenter, \danog\MadelineProto\Logger::NOTICE); $datacenterConnection->bind(); $datacenterConnection->flush(); - return true; } } catch (\danog\MadelineProto\SecurityException $e) { - $this->logger->logger('An exception occurred while generating the authorization key: '.$e->getMessage().' Retrying (try number '.$retry_id_total.')...', \danog\MadelineProto\Logger::WARNING); + $this->logger->logger('An exception occurred while generating the authorization key: ' . $e->getMessage() . ' Retrying (try number ' . $retry_id_total . ')...', \danog\MadelineProto\Logger::WARNING); } catch (\danog\MadelineProto\Exception $e) { - $this->logger->logger('An exception occurred while generating the authorization key: '.$e->getMessage().' Retrying (try number '.$retry_id_total.')...', \danog\MadelineProto\Logger::WARNING); + $this->logger->logger('An exception occurred while generating the authorization key: ' . $e->getMessage() . ' Retrying (try number ' . $retry_id_total . ')...', \danog\MadelineProto\Logger::WARNING); } catch (\danog\MadelineProto\RPCErrorException $e) { - $this->logger->logger('An RPCErrorException occurred while generating the authorization key: '.$e->getMessage().' Retrying (try number '.$retry_id_total.')...', \danog\MadelineProto\Logger::WARNING); + $this->logger->logger('An RPCErrorException occurred while generating the authorization key: ' . $e->getMessage() . ' Retrying (try number ' . $retry_id_total . ')...', \danog\MadelineProto\Logger::WARNING); } } - throw new \danog\MadelineProto\SecurityException('An error occurred while binding temporary and permanent authorization keys.'); } - /** * Factorize number asynchronously using the wolfram API. * @@ -602,22 +574,11 @@ trait AuthKeyHandler private function wolframSingle($what): \Generator { $code = yield $this->datacenter->fileGetContents('http://www.wolframalpha.com/api/v1/code'); - $query = 'Do prime factorization of '.$what; - $params = [ - 'async' => true, - 'banners' => 'raw', - 'debuggingdata' => false, - 'format' => 'moutput', - 'formattimeout' => 8, - 'input' => $query, - 'output' => 'JSON', - 'proxycode' => \json_decode($code, true)['code'], - ]; - $url = 'https://www.wolframalpha.com/input/json.jsp?'.\http_build_query($params); - + $query = 'Do prime factorization of ' . $what; + $params = ['async' => true, 'banners' => 'raw', 'debuggingdata' => false, 'format' => 'moutput', 'formattimeout' => 8, 'input' => $query, 'output' => 'JSON', 'proxycode' => \json_decode($code, true)['code']]; + $url = 'https://www.wolframalpha.com/input/json.jsp?' . \http_build_query($params); $request = new Request($url); - $request->setHeader('referer', 'https://www.wolframalpha.com/input/?i='.\urlencode($query)); - + $request->setHeader('referer', 'https://www.wolframalpha.com/input/?i=' . \urlencode($query)); $res = \json_decode(yield (yield $this->datacenter->getHTTPClient()->request($request))->getBody()->buffer(), true); if (!isset($res['queryresult']['pods'])) { return false; @@ -625,24 +586,20 @@ trait AuthKeyHandler $fres = false; foreach ($res['queryresult']['pods'] as $cur) { if ($cur['id'] === 'Divisors') { - $fres = \explode(', ', \preg_replace(["/{\d+, /", "/, \d+}$/"], '', $cur['subpods'][0]['moutput'])); + $fres = \explode(', ', \preg_replace(["/{\\d+, /", "/, \\d+}\$/"], '', $cur['subpods'][0]['moutput'])); break; } } if (\is_array($fres)) { $fres = $fres[0]; - $newval = \intval($fres); if (\is_int($newval)) { $fres = $newval; } - return $fres; } - return false; } - /** * Asynchronously create, bind and check auth keys for all DCs. * @@ -658,9 +615,7 @@ trait AuthKeyHandler } $this->logger("Initing authorization..."); $initing = $this->initing_authorization; - $this->initing_authorization = true; - try { $dcs = []; $postpone = []; @@ -688,26 +643,22 @@ trait AuthKeyHandler $first = \array_shift($dcs)(); yield $first; } - foreach ($dcs as $id => &$dc) { $dc = $dc(); } yield \danog\MadelineProto\Tools::all($dcs); - foreach ($postpone as $id => $socket) { - yield $this->initAuthorizationSocket($id, $socket); + yield from $this->initAuthorizationSocket($id, $socket); } - if ($this->pending_auth && empty($this->init_auth_dcs)) { $this->pending_auth = false; - yield $this->initAuthorization(); + yield from $this->initAuthorization(); } } finally { $this->pending_auth = false; $this->initing_authorization = $initing; } } - /** * Init auth keys for single DC. * @@ -720,20 +671,17 @@ trait AuthKeyHandler */ public function initAuthorizationSocket(string $id, DataCenterConnection $socket): \Generator { - $this->logger("Initing authorization DC $id..."); + $this->logger("Initing authorization DC {$id}..."); $this->init_auth_dcs[$id] = true; $connection = $socket->getAuthConnection(); - try { $socket->createSession(); - $cdn = $socket->isCDN(); $media = $socket->isMedia(); - if (!$socket->hasTempAuthKey() || !$socket->hasPermAuthKey() || !$socket->isBound()) { if (!$socket->hasPermAuthKey() && !$cdn && !$media) { $this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['gen_perm_auth_key'], $id), \danog\MadelineProto\Logger::NOTICE); - $socket->setPermAuthKey(yield $this->createAuthKey(-1, $id)); + $socket->setPermAuthKey(yield from $this->createAuthKey(-1, $id)); //$socket->authorized(false); } if ($media) { @@ -745,40 +693,35 @@ trait AuthKeyHandler if ($this->datacenter->getDataCenterConnection($id)->getSettings()['pfs']) { if (!$cdn) { $this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['gen_temp_auth_key'], $id), \danog\MadelineProto\Logger::NOTICE); - //$authorized = $socket->authorized; //$socket->authorized = false; - $socket->setTempAuthKey(null); - $socket->setTempAuthKey(yield $this->createAuthKey($this->settings['authorization']['default_temp_auth_key_expires_in'], $id)); - yield $this->bindTempAuthKey($this->settings['authorization']['default_temp_auth_key_expires_in'], $id); - + $socket->setTempAuthKey(yield from $this->createAuthKey($this->settings['authorization']['default_temp_auth_key_expires_in'], $id)); + yield from $this->bindTempAuthKey($this->settings['authorization']['default_temp_auth_key_expires_in'], $id); $this->config = yield $connection->methodCallAsyncRead('help.getConfig', []); - - yield $this->syncAuthorization($id); + yield from $this->syncAuthorization($id); } elseif (!$socket->hasTempAuthKey()) { $this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['gen_temp_auth_key'], $id), \danog\MadelineProto\Logger::NOTICE); - $socket->setTempAuthKey(yield $this->createAuthKey($this->settings['authorization']['default_temp_auth_key_expires_in'], $id)); + $socket->setTempAuthKey(yield from $this->createAuthKey($this->settings['authorization']['default_temp_auth_key_expires_in'], $id)); } } else { if (!$cdn) { $socket->bind(false); $this->config = yield $connection->methodCallAsyncRead('help.getConfig', []); - yield $this->syncAuthorization($id); + yield from $this->syncAuthorization($id); } elseif (!$socket->hasTempAuthKey()) { $this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['gen_temp_auth_key'], $id), \danog\MadelineProto\Logger::NOTICE); - $socket->setTempAuthKey(yield $this->createAuthKey($this->settings['authorization']['default_temp_auth_key_expires_in'], $id)); + $socket->setTempAuthKey(yield from $this->createAuthKey($this->settings['authorization']['default_temp_auth_key_expires_in'], $id)); } } } elseif (!$cdn) { - yield $this->syncAuthorization($id); + yield from $this->syncAuthorization($id); } } finally { - $this->logger("Done initing authorization DC $id"); + $this->logger("Done initing authorization DC {$id}"); unset($this->init_auth_dcs[$id]); } } - /** * Sync authorization data between DCs. * @@ -801,15 +744,15 @@ trait AuthKeyHandler } if ($authorized_socket->hasTempAuthKey() && $authorized_socket->hasPermAuthKey() && $authorized_socket->isAuthorized() && $this->authorized === self::LOGGED_IN && !$socket->isAuthorized() && !$authorized_socket->isCDN()) { try { - $this->logger->logger('Trying to copy authorization from dc '.$authorized_dc_id.' to dc '.$id); + $this->logger->logger('Trying to copy authorization from dc ' . $authorized_dc_id . ' to dc ' . $id); $exported_authorization = yield $this->methodCallAsyncRead('auth.exportAuthorization', ['dc_id' => \preg_replace('|_.*|', '', $id)], ['datacenter' => $authorized_dc_id]); $authorization = yield $this->methodCallAsyncRead('auth.importAuthorization', $exported_authorization, ['datacenter' => $id]); $socket->authorized(true); break; } catch (\danog\MadelineProto\Exception $e) { - $this->logger->logger('Failure while syncing authorization from DC '.$authorized_dc_id.' to DC '.$id.': '.$e->getMessage(), \danog\MadelineProto\Logger::ERROR); + $this->logger->logger('Failure while syncing authorization from DC ' . $authorized_dc_id . ' to DC ' . $id . ': ' . $e->getMessage(), \danog\MadelineProto\Logger::ERROR); } catch (\danog\MadelineProto\RPCErrorException $e) { - $this->logger->logger('Failure while syncing authorization from DC '.$authorized_dc_id.' to DC '.$id.': '.$e->getMessage(), \danog\MadelineProto\Logger::ERROR); + $this->logger->logger('Failure while syncing authorization from DC ' . $authorized_dc_id . ' to DC ' . $id . ': ' . $e->getMessage(), \danog\MadelineProto\Logger::ERROR); if ($e->rpc === 'DC_ID_INVALID') { break; } diff --git a/src/danog/MadelineProto/MTProtoTools/CallHandler.php b/src/danog/MadelineProto/MTProtoTools/CallHandler.php index 3ac73f81..2912cafe 100644 --- a/src/danog/MadelineProto/MTProtoTools/CallHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/CallHandler.php @@ -40,7 +40,6 @@ trait CallHandler { return \danog\MadelineProto\Tools::wait($this->methodCallAsyncRead($method, $args, $aargs)); } - /** * Call method and wait asynchronously for response. * @@ -54,16 +53,13 @@ trait CallHandler */ public function methodCallAsyncRead(string $method, $args = [], array $aargs = ['msg_id' => null]): Promise { - $deferred = new Deferred; - $this->datacenter->waitGetConnection($aargs['datacenter'] ?? $this->datacenter->curdc)->onResolve( - static function ($e, $res) use (&$method, &$args, &$aargs, &$deferred) { - if ($e) { - throw $e; - } - $deferred->resolve($res->methodCallAsyncRead($method, $args, $aargs)); + $deferred = new Deferred(); + $this->datacenter->waitGetConnection($aargs['datacenter'] ?? $this->datacenter->curdc)->onResolve(static function ($e, $res) use (&$method, &$args, &$aargs, &$deferred) { + if ($e) { + throw $e; } - ); - + $deferred->resolve($res->methodCallAsyncRead($method, $args, $aargs)); + }); return $deferred->promise(); } /** @@ -77,16 +73,13 @@ trait CallHandler */ public function methodCallAsyncWrite(string $method, $args = [], array $aargs = ['msg_id' => null]): Promise { - $deferred = new Deferred; - $this->datacenter->waitGetConnection($aargs['datacenter'] ?? $this->datacenter->curdc)->onResolve( - static function ($e, $res) use (&$method, &$args, &$aargs, &$deferred) { - if ($e) { - throw $e; - } - $deferred->resolve($res->methodCallAsyncWrite($method, $args, $aargs)); + $deferred = new Deferred(); + $this->datacenter->waitGetConnection($aargs['datacenter'] ?? $this->datacenter->curdc)->onResolve(static function ($e, $res) use (&$method, &$args, &$aargs, &$deferred) { + if ($e) { + throw $e; } - ); - + $deferred->resolve($res->methodCallAsyncWrite($method, $args, $aargs)); + }); return $deferred->promise(); } } diff --git a/src/danog/MadelineProto/MTProtoTools/CombinedUpdatesState.php b/src/danog/MadelineProto/MTProtoTools/CombinedUpdatesState.php index e003e1cc..d17990ea 100644 --- a/src/danog/MadelineProto/MTProtoTools/CombinedUpdatesState.php +++ b/src/danog/MadelineProto/MTProtoTools/CombinedUpdatesState.php @@ -30,7 +30,6 @@ class CombinedUpdatesState * @var array */ private $states = []; - /** * Constructor function. * @@ -49,7 +48,6 @@ class CombinedUpdatesState $this->states[$channel] = $state; } } - /** * Get or update multiple parameters. * @@ -66,10 +64,8 @@ class CombinedUpdatesState if (!isset($this->states[$channel])) { return $this->states[$channel] = new UpdatesState($init, $channel); } - return $this->states[$channel]->update($init); } - /** * Remove update state. * @@ -83,7 +79,6 @@ class CombinedUpdatesState unset($this->states[$channel]); } } - /** * Check if update state is present. * @@ -95,7 +90,6 @@ class CombinedUpdatesState { return isset($this->states[$channel]); } - /** * Are we currently busy? * diff --git a/src/danog/MadelineProto/MTProtoTools/Crypt.php b/src/danog/MadelineProto/MTProtoTools/Crypt.php index ff3b9543..47083c89 100644 --- a/src/danog/MadelineProto/MTProtoTools/Crypt.php +++ b/src/danog/MadelineProto/MTProtoTools/Crypt.php @@ -35,14 +35,12 @@ trait Crypt public static function aesCalculate(string $msg_key, string $auth_key, bool $to_server = true): array { $x = $to_server ? 0 : 8; - $sha256_a = \hash('sha256', $msg_key.\substr($auth_key, $x, 36), true); - $sha256_b = \hash('sha256', \substr($auth_key, 40 + $x, 36).$msg_key, true); - $aes_key = \substr($sha256_a, 0, 8).\substr($sha256_b, 8, 16).\substr($sha256_a, 24, 8); - $aes_iv = \substr($sha256_b, 0, 8).\substr($sha256_a, 8, 16).\substr($sha256_b, 24, 8); - + $sha256_a = \hash('sha256', $msg_key . \substr($auth_key, $x, 36), true); + $sha256_b = \hash('sha256', \substr($auth_key, 40 + $x, 36) . $msg_key, true); + $aes_key = \substr($sha256_a, 0, 8) . \substr($sha256_b, 8, 16) . \substr($sha256_a, 24, 8); + $aes_iv = \substr($sha256_b, 0, 8) . \substr($sha256_a, 8, 16) . \substr($sha256_b, 24, 8); return [$aes_key, $aes_iv]; } - /** * AES KDF function for MTProto v1. * @@ -57,16 +55,14 @@ trait Crypt public static function oldAesCalculate(string $msg_key, string $auth_key, bool $to_server = true): array { $x = $to_server ? 0 : 8; - $sha1_a = \sha1($msg_key.\substr($auth_key, $x, 32), true); - $sha1_b = \sha1(\substr($auth_key, 32 + $x, 16).$msg_key.\substr($auth_key, 48 + $x, 16), true); - $sha1_c = \sha1(\substr($auth_key, 64 + $x, 32).$msg_key, true); - $sha1_d = \sha1($msg_key.\substr($auth_key, 96 + $x, 32), true); - $aes_key = \substr($sha1_a, 0, 8).\substr($sha1_b, 8, 12).\substr($sha1_c, 4, 12); - $aes_iv = \substr($sha1_a, 8, 12).\substr($sha1_b, 0, 8).\substr($sha1_c, 16, 4).\substr($sha1_d, 0, 8); - + $sha1_a = \sha1($msg_key . \substr($auth_key, $x, 32), true); + $sha1_b = \sha1(\substr($auth_key, 32 + $x, 16) . $msg_key . \substr($auth_key, 48 + $x, 16), true); + $sha1_c = \sha1(\substr($auth_key, 64 + $x, 32) . $msg_key, true); + $sha1_d = \sha1($msg_key . \substr($auth_key, 96 + $x, 32), true); + $aes_key = \substr($sha1_a, 0, 8) . \substr($sha1_b, 8, 12) . \substr($sha1_c, 4, 12); + $aes_iv = \substr($sha1_a, 8, 12) . \substr($sha1_b, 0, 8) . \substr($sha1_c, 16, 4) . \substr($sha1_d, 0, 8); return [$aes_key, $aes_iv]; } - /** * CTR encrypt. * @@ -83,10 +79,8 @@ trait Crypt $cipher = new \tgseclib\Crypt\AES('ctr'); $cipher->setKey($key); $cipher->setIV($iv); - return @$cipher->encrypt($message); } - /** * IGE encrypt. * @@ -103,7 +97,6 @@ trait Crypt $cipher = new \tgseclib\Crypt\AES('ige'); $cipher->setKey($key); $cipher->setIV($iv); - return @$cipher->encrypt($message); } /** @@ -122,7 +115,6 @@ trait Crypt $cipher = new \tgseclib\Crypt\AES('ige'); $cipher->setKey($key); $cipher->setIV($iv); - return @$cipher->decrypt($message); } } diff --git a/src/danog/MadelineProto/MTProtoTools/Files.php b/src/danog/MadelineProto/MTProtoTools/Files.php index 2401fe83..1480916e 100644 --- a/src/danog/MadelineProto/MTProtoTools/Files.php +++ b/src/danog/MadelineProto/MTProtoTools/Files.php @@ -62,17 +62,16 @@ trait Files $cb = $file; $file = $file->getFile(); } - if (\is_string($file) || (\is_object($file) && \method_exists($file, '__toString'))) { + if (\is_string($file) || \is_object($file) && \method_exists($file, '__toString')) { if (\filter_var($file, FILTER_VALIDATE_URL)) { - return yield $this->uploadFromUrl($file, 0, $fileName, $cb, $encrypted); + return yield from $this->uploadFromUrl($file, 0, $fileName, $cb, $encrypted); } } elseif (\is_array($file)) { - return yield $this->uploadFromTgfile($file, $cb, $encrypted); + return yield from $this->uploadFromTgfile($file, $cb, $encrypted); } if (!$this->settings['upload']['allow_automatic_upload']) { - return yield $this->uploadFromUrl($file, 0, $fileName, $cb, $encrypted); + return yield from $this->uploadFromUrl($file, 0, $fileName, $cb, $encrypted); } - $file = \danog\MadelineProto\Absolute::absolute($file); if (!yield exists($file)) { throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['file_not_exist']); @@ -80,19 +79,15 @@ trait Files if (empty($fileName)) { $fileName = \basename($file); } - StatCache::clear($file); - $size = (yield \stat($file))['size']; if ($size > 512 * 1024 * 3000) { throw new \danog\MadelineProto\Exception('Given file is too big!'); } - $stream = yield open($file, 'rb'); $mime = $this->getMimeFromFile($file); - try { - return yield $this->uploadFromStream($stream, $size, $mime, $fileName, $cb, $encrypted); + return yield from $this->uploadFromStream($stream, $size, $mime, $fileName, $cb, $encrypted); } finally { yield $stream->close(); } @@ -116,23 +111,20 @@ trait Files } /** @var $response \Amp\Http\Client\Response */ $request = new Request($url); - $request->setTransferTimeout(10*1000*3600); + $request->setTransferTimeout(10 * 1000 * 3600); $request->setBodySizeLimit(512 * 1024 * 3000); $response = yield $this->datacenter->getHTTPClient()->request($request); - if (200 !== $status = $response->getStatus()) { - throw new Exception("Wrong status code: $status ".$response->getReason()); + if (200 !== ($status = $response->getStatus())) { + throw new Exception("Wrong status code: {$status} " . $response->getReason()); } $mime = \trim(\explode(';', $response->getHeader('content-type') ?? 'application/octet-stream')[0]); $size = $response->getHeader('content-length') ?? $size; - $stream = $response->getBody(); if (!$size) { - $this->logger->logger("No content length for $url, caching first"); - + $this->logger->logger("No content length for {$url}, caching first"); $body = $stream; $stream = new BlockingFile(\fopen('php://temp', 'r+b'), 'php://temp', 'r+b'); - - while (null !== $chunk = yield $body->read()) { + while (null !== ($chunk = yield $body->read())) { yield $stream->write($chunk); } $size = $stream->tell(); @@ -141,8 +133,7 @@ trait Files } yield $stream->seek(0); } - - return yield $this->uploadFromStream($stream, $size, $mime, $fileName, $cb, $encrypted); + return yield from $this->uploadFromStream($stream, $size, $mime, $fileName, $cb, $encrypted); } /** * Upload file from stream. @@ -162,7 +153,6 @@ trait Files $cb = $stream; $stream = $stream->getFile(); } - /* @var $stream \Amp\ByteStream\OutputStream */ if (!\is_object($stream)) { $stream = new ResourceOutputStream($stream); @@ -178,11 +168,9 @@ trait Files } catch (StreamException $e) { } } - $created = false; - if ($stream instanceof Handle) { - $callable = static function (int $offset, int $size) use ($stream, $seekable) { + $callable = static function (int $offset, int $size) use ($stream, $seekable): \Generator { if ($seekable) { while ($stream->tell() !== $offset) { yield $stream->seek($offset); @@ -192,13 +180,11 @@ trait Files }; } else { if (!$stream instanceof BufferedRawStream) { - $ctx = (new ConnectionContext) - ->addStream(PremadeStream::getName(), $stream) - ->addStream(SimpleBufferedRawStream::getName()); + $ctx = (new ConnectionContext())->addStream(PremadeStream::getName(), $stream)->addStream(SimpleBufferedRawStream::getName()); $stream = yield $ctx->getStream(); $created = true; } - $callable = static function (int $offset, int $size) use ($stream) { + $callable = static function (int $offset, int $size) use ($stream): \Generator { $reader = yield $stream->getReadBuffer($l); try { return yield $reader->bufferRead($size); @@ -209,8 +195,7 @@ trait Files }; $seekable = false; } - - $res = yield $this->uploadFromCallable($callable, $size, $mime, $fileName, $cb, $seekable, $encrypted); + $res = (yield from $this->uploadFromCallable($callable, $size, $mime, $fileName, $cb, $seekable, $encrypted)); if ($created) { $stream->disconnect(); } @@ -243,29 +228,25 @@ trait Files } if ($cb === null) { $cb = function ($percent) { - $this->logger->logger('Upload status: '.$percent.'%', \danog\MadelineProto\Logger::NOTICE); + $this->logger->logger('Upload status: ' . $percent . '%', \danog\MadelineProto\Logger::NOTICE); }; } - $datacenter = $this->settings['connection_settings']['default_dc']; - if ($this->datacenter->has($datacenter.'_media')) { + if ($this->datacenter->has($datacenter . '_media')) { $datacenter .= '_media'; } - $part_size = $this->settings['upload']['part_size']; $parallel_chunks = $this->settings['upload']['parallel_chunks'] ? $this->settings['upload']['parallel_chunks'] : 3000; - $part_total_num = (int) \ceil($size / $part_size); $part_num = 0; $method = $size > 10 * 1024 * 1024 ? 'upload.saveBigFilePart' : 'upload.saveFilePart'; - $constructor = 'input'.($encrypted === true ? 'Encrypted' : '').($size > 10 * 1024 * 1024 ? 'FileBig' : 'File').($encrypted === true ? 'Uploaded' : ''); + $constructor = 'input' . ($encrypted === true ? 'Encrypted' : '') . ($size > 10 * 1024 * 1024 ? 'FileBig' : 'File') . ($encrypted === true ? 'Uploaded' : ''); $file_id = \danog\MadelineProto\Tools::random(8); - $ige = null; if ($encrypted === true) { $key = \danog\MadelineProto\Tools::random(32); $iv = \danog\MadelineProto\Tools::random(32); - $digest = \hash('md5', $key.$iv, true); + $digest = \hash('md5', $key . $iv, true); $fingerprint = \danog\MadelineProto\Tools::unpackSignedInt(\substr($digest, 0, 4) ^ \substr($digest, 4, 4)); $ige = new \tgseclib\Crypt\AES('ige'); $ige->setIV($iv); @@ -275,7 +256,6 @@ trait Files } //$ctx = \hash_init('md5'); $promises = []; - $speed = 0; $time = 0; $cb = function () use ($cb, $part_total_num, &$speed, &$time) { @@ -283,88 +263,72 @@ trait Files $cur++; \danog\MadelineProto\Tools::callFork($cb($cur * 100 / $part_total_num, $speed, $time)); }; - - $callable = static function (int $part_num) use ($file_id, $part_total_num, $part_size, $callable, $ige) { + $callable = static function (int $part_num) use ($file_id, $part_total_num, $part_size, $callable, $ige): \Generator { $bytes = yield $callable($part_num * $part_size, $part_size); - if ($ige) { $bytes = $ige->encrypt(\str_pad($bytes, $part_size, \chr(0))); } //\hash_update($ctx, $bytes); - return ['file_id' => $file_id, 'file_part' => $part_num, 'file_total_parts' => $part_total_num, 'bytes' => $bytes]; }; - $resPromises = []; $exception = null; - $start = \microtime(true); while ($part_num < $part_total_num) { - $writePromise = $this->methodCallAsyncWrite( - $method, - $callable($part_num), - ['heavy' => true, 'file' => true, 'datacenter' => &$datacenter] - ); + $writePromise = $this->methodCallAsyncWrite($method, $callable($part_num), ['heavy' => true, 'file' => true, 'datacenter' => &$datacenter]); if (!$seekable) { yield $writePromise; } - $writePromise->onResolve( - function ($e, $readDeferred) use ($cb, $part_num, &$resPromises, &$exception) { - if ($e) { - $this->logger("Got exception while uploading: $e"); - $exception = $e; - return; - } - $resPromises []= $readDeferred->promise(); - try { - // Wrote chunk! - if (!yield Tools::call($readDeferred->promise())) { - throw new \danog\MadelineProto\Exception('Upload of part '.$part_num.' failed'); - } - // Got OK from server for chunk! - $cb(); - } catch (\Throwable $e) { - $this->logger("Got exception while uploading: $e"); - $exception = $e; - } + $writePromise->onResolve(function ($e, $readDeferred) use ($cb, $part_num, &$resPromises, &$exception): \Generator { + if ($e) { + $this->logger("Got exception while uploading: {$e}"); + $exception = $e; + return; } - ); - $promises []= $writePromise; + $resPromises[] = $readDeferred->promise(); + try { + // Wrote chunk! + if (!yield Tools::call($readDeferred->promise())) { + throw new \danog\MadelineProto\Exception('Upload of part ' . $part_num . ' failed'); + } + // Got OK from server for chunk! + $cb(); + } catch (\Throwable $e) { + $this->logger("Got exception while uploading: {$e}"); + $exception = $e; + } + }); + $promises[] = $writePromise; ++$part_num; - - if (!($part_num % $parallel_chunks)) { // By default, 10 mb at a time, for a typical bandwidth of 1gbps (run the code in this every second) + if (!($part_num % $parallel_chunks)) { + // By default, 10 mb at a time, for a typical bandwidth of 1gbps (run the code in this every second) yield Tools::all($promises); $promises = []; if ($exception) { throw $exception; } - $time = \microtime(true) - $start; - $speed = (int) (($size * 8) / $time) / 1000000; - $this->logger->logger("Partial upload time: $time"); - $this->logger->logger("Partial upload speed: $speed mbps"); + $speed = (int) ($size * 8 / $time) / 1000000; + $this->logger->logger("Partial upload time: {$time}"); + $this->logger->logger("Partial upload speed: {$speed} mbps"); } } - yield all($promises); yield all($resPromises); - $time = \microtime(true) - $start; - $speed = (int) (($size * 8) / $time) / 1000000; - $this->logger->logger("Total upload time: $time"); - $this->logger->logger("Total upload speed: $speed mbps"); - + $speed = (int) ($size * 8 / $time) / 1000000; + $this->logger->logger("Total upload time: {$time}"); + $this->logger->logger("Total upload speed: {$speed} mbps"); $constructor = ['_' => $constructor, 'id' => $file_id, 'parts' => $part_total_num, 'name' => $fileName, 'mime_type' => $mime]; if ($encrypted === true) { $constructor['key_fingerprint'] = $fingerprint; $constructor['key'] = $key; $constructor['iv'] = $iv; } - $constructor['md5_checksum'] = ''; //\hash_final($ctx); - + $constructor['md5_checksum'] = ''; + //\hash_final($ctx); return $constructor; } - /** * Upload file to secret chat. * @@ -374,11 +338,10 @@ trait Files * * @return \Generator */ - public function uploadEncrypted($file, string $fileName = '', $cb = null): \Generator + public function uploadEncrypted($file, string $fileName = '', $cb = null): \Generator { return $this->upload($file, $fileName, $cb, true); } - /** * Reupload telegram file. * @@ -394,15 +357,13 @@ trait Files $cb = $media; $media = $media->getFile(); } - $media = yield $this->getDownloadInfo($media); + $media = (yield from $this->getDownloadInfo($media)); if (!isset($media['size'], $media['mime'])) { throw new Exception('Wrong file provided!'); } $size = $media['size']; $mime = $media['mime']; - $chunk_size = $this->settings['upload']['part_size']; - $bridge = new class($size, $chunk_size, $cb) { /** * Read promises. @@ -440,7 +401,6 @@ trait Files * @var ?callable */ private $cb; - /** * Constructor. * @@ -451,9 +411,9 @@ trait Files public function __construct(int $size, int $partSize, ?callable $cb) { for ($x = 0; $x < $size; $x += $partSize) { - $this->read []= new Deferred; - $this->write []= new Deferred; - $this->wrote []= $size - $x < $partSize ? $size - $x : $partSize; + $this->read[] = new Deferred(); + $this->write[] = new Deferred(); + $this->wrote[] = $size - $x < $partSize ? $size - $x : $partSize; } $this->partSize = $partSize; $this->cb = $cb; @@ -504,16 +464,12 @@ trait Files $reader = [$bridge, 'read']; $writer = [$bridge, 'write']; $cb = [$bridge, 'callback']; - $read = $this->uploadFromCallable($reader, $size, $mime, '', $cb, true, $encrypted); $write = $this->downloadToCallable($media, $writer, null, true, 0, -1, $chunk_size); - list($res) = yield \danog\MadelineProto\Tools::all([$read, $write]); - return $res; } - - private function genAllFile($media) + private function genAllFile($media): \Generator { $res = [$this->TL->getConstructors()->findByPredicate($media['_'])['type'] => $media]; switch ($media['_']) { @@ -531,15 +487,7 @@ trait Files throw new \danog\MadelineProto\Exception('No access hash'); } $res['Photo'] = $media['photo']; - $res['InputPhoto'] = [ - '_' => 'inputPhoto', - 'id' => $media['photo']['id'], - 'access_hash' => $media['photo']['access_hash'], - 'file_reference' => yield $this->referenceDatabase->getReference( - ReferenceDatabase::PHOTO_LOCATION, - $media['photo'] - ), - ]; + $res['InputPhoto'] = ['_' => 'inputPhoto', 'id' => $media['photo']['id'], 'access_hash' => $media['photo']['access_hash'], 'file_reference' => yield $this->referenceDatabase->getReference(ReferenceDatabase::PHOTO_LOCATION, $media['photo'])]; $res['InputMedia'] = ['_' => 'inputMediaPhoto', 'id' => $res['InputPhoto']]; if (isset($media['ttl_seconds'])) { $res['InputMedia']['ttl_seconds'] = $media['ttl_seconds']; @@ -550,15 +498,7 @@ trait Files throw new \danog\MadelineProto\Exception('No access hash'); } $res['Document'] = $media['document']; - $res['InputDocument'] = [ - '_' => 'inputDocument', - 'id' => $media['document']['id'], - 'access_hash' => $media['document']['access_hash'], - 'file_reference' => yield $this->referenceDatabase->getReference( - ReferenceDatabase::DOCUMENT_LOCATION, - $media['document'] - ), - ]; + $res['InputDocument'] = ['_' => 'inputDocument', 'id' => $media['document']['id'], 'access_hash' => $media['document']['access_hash'], 'file_reference' => yield $this->referenceDatabase->getReference(ReferenceDatabase::DOCUMENT_LOCATION, $media['document'])]; $res['InputMedia'] = ['_' => 'inputMediaDocument', 'id' => $res['InputDocument']]; if (isset($media['ttl_seconds'])) { $res['InputMedia']['ttl_seconds'] = $media['ttl_seconds']; @@ -571,15 +511,7 @@ trait Files if (!isset($media['access_hash'])) { throw new \danog\MadelineProto\Exception('No access hash'); } - $res['InputDocument'] = [ - '_' => 'inputDocument', - 'id' => $media['id'], - 'access_hash' => $media['access_hash'], - 'file_reference' => yield $this->referenceDatabase->getReference( - ReferenceDatabase::DOCUMENT_LOCATION, - $media - ), - ]; + $res['InputDocument'] = ['_' => 'inputDocument', 'id' => $media['id'], 'access_hash' => $media['access_hash'], 'file_reference' => yield $this->referenceDatabase->getReference(ReferenceDatabase::DOCUMENT_LOCATION, $media)]; $res['InputMedia'] = ['_' => 'inputMediaDocument', 'id' => $res['InputDocument']]; $res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $media]; break; @@ -587,25 +519,15 @@ trait Files if (!isset($media['access_hash'])) { throw new \danog\MadelineProto\Exception('No access hash'); } - $res['InputPhoto'] = [ - '_' => 'inputPhoto', - 'id' => $media['id'], - 'access_hash' => $media['access_hash'], - 'file_reference' => yield $this->referenceDatabase->getReference( - ReferenceDatabase::PHOTO_LOCATION, - $media - ), - ]; + $res['InputPhoto'] = ['_' => 'inputPhoto', 'id' => $media['id'], 'access_hash' => $media['access_hash'], 'file_reference' => yield $this->referenceDatabase->getReference(ReferenceDatabase::PHOTO_LOCATION, $media)]; $res['InputMedia'] = ['_' => 'inputMediaPhoto', 'id' => $res['InputPhoto']]; $res['MessageMedia'] = ['_' => 'messageMediaPhoto', 'photo' => $media]; break; default: throw new \danog\MadelineProto\Exception("Could not convert media object of type {$media['_']}"); } - return $res; } - /** * Get info about file. * @@ -632,13 +554,11 @@ trait Files case 'updateEditMessage': case 'updateEditChannelMessage': $constructor = $constructor['message']; - - // no break + // no break case 'message': $constructor = $constructor['media']; } - - return yield $this->genAllFile($constructor); + return yield from $this->genAllFile($constructor); } /** * Get download info of the propic of a user @@ -655,7 +575,7 @@ trait Files */ public function getPropicInfo($data): \Generator { - return yield $this->getDownloadInfo($this->chats[(yield $this->getInfo($data))['bot_api_id']]); + return yield from $this->getDownloadInfo($this->chats[(yield $this->getInfo($data))['bot_api_id']]); } /** * Get download info of file @@ -688,17 +608,16 @@ trait Files case 'updateNewMessage': case 'updateNewChannelMessage': $message_media = $message_media['message']; - // no break + // no break case 'message': - return yield $this->getDownloadInfo($message_media['media']); + return yield from $this->getDownloadInfo($message_media['media']); case 'updateNewEncryptedMessage': $message_media = $message_media['message']; - // Secret media // no break case 'encryptedMessage': if ($message_media['decrypted_message']['media']['_'] === 'decryptedMessageMediaExternalDocument') { - return yield $this->getDownloadInfo($message_media['decrypted_message']['media']); + return yield from $this->getDownloadInfo($message_media['decrypted_message']['media']); } $res['InputFileLocation'] = ['_' => 'inputEncryptedFileLocation', 'id' => $message_media['file']['id'], 'access_hash' => $message_media['file']['access_hash'], 'dc_id' => $message_media['file']['dc_id']]; $res['size'] = $message_media['decrypted_message']['media']['size']; @@ -708,7 +627,7 @@ trait Files if (isset($message_media['decrypted_message']['media']['file_name'])) { $pathinfo = \pathinfo($message_media['decrypted_message']['media']['file_name']); if (isset($pathinfo['extension'])) { - $res['ext'] = '.'.$pathinfo['extension']; + $res['ext'] = '.' . $pathinfo['extension']; } $res['name'] = $pathinfo['filename']; } @@ -723,7 +642,7 @@ trait Files case 'documentAttributeFilename': $pathinfo = \pathinfo($attribute['file_name']); if (isset($pathinfo['extension'])) { - $res['ext'] = '.'.$pathinfo['extension']; + $res['ext'] = '.' . $pathinfo['extension']; } $res['name'] = $pathinfo['filename']; break; @@ -736,7 +655,7 @@ trait Files if (isset($audio) && isset($audio['title']) && !isset($res['name'])) { $res['name'] = $audio['title']; if (isset($audio['performer'])) { - $res['name'] .= ' - '.$audio['performer']; + $res['name'] .= ' - ' . $audio['performer']; } } if (!isset($res['ext']) || $res['ext'] === '') { @@ -748,7 +667,6 @@ trait Files if (!isset($res['name']) || $res['name'] === '') { $res['name'] = Tools::unpackSignedLongString($message_media['file']['access_hash']); } - return $res; // Wallpapers case 'wallPaper': @@ -762,132 +680,89 @@ trait Files $res['MessageMedia'] = $message_media; $message_media = $message_media['photo']; $size = \end($message_media['sizes']); - - $res = \array_merge($res, yield $this->getDownloadInfo($size)); - - $res['InputFileLocation'] = [ - '_' => 'inputPhotoFileLocation', - 'thumb_size' => $res['thumb_size'] ?? 'x', - 'dc_id' => $message_media['dc_id'], - 'access_hash' => $message_media['access_hash'], - 'id' => $message_media['id'], - 'file_reference' => yield $this->referenceDatabase->getReference( - ReferenceDatabase::PHOTO_LOCATION, - $message_media - ), - ]; - + $res = \array_merge($res, yield from $this->getDownloadInfo($size)); + $res['InputFileLocation'] = ['_' => 'inputPhotoFileLocation', 'thumb_size' => $res['thumb_size'] ?? 'x', 'dc_id' => $message_media['dc_id'], 'access_hash' => $message_media['access_hash'], 'id' => $message_media['id'], 'file_reference' => yield $this->referenceDatabase->getReference(ReferenceDatabase::PHOTO_LOCATION, $message_media)]; return $res; case 'user': case 'folder': case 'channel': case 'chat': case 'updateUserPhoto': - $res = yield $this->getDownloadInfo($message_media['photo']); - - if (\is_array($message_media) && ($message_media['min'] ?? false) && isset($message_media['access_hash'])) { // bot API file ID + $res = (yield from $this->getDownloadInfo($message_media['photo'])); + if (\is_array($message_media) && ($message_media['min'] ?? false) && isset($message_media['access_hash'])) { + // bot API file ID $message_media['min'] = false; $peer = $this->genAll($message_media)['InputPeer']; } else { $peer = (yield $this->getInfo($message_media))['InputPeer']; } - $res['InputFileLocation'] = [ - '_' => 'inputPeerPhotoFileLocation', - 'big' => $res['big'], - 'dc_id' => $res['InputFileLocation']['dc_id'], - 'peer' => $peer, - 'volume_id' => $res['InputFileLocation']['volume_id'], - 'local_id' => $res['InputFileLocation']['local_id'], - // The peer field will be added later - ]; + $res['InputFileLocation'] = ['_' => 'inputPeerPhotoFileLocation', 'big' => $res['big'], 'dc_id' => $res['InputFileLocation']['dc_id'], 'peer' => $peer, 'volume_id' => $res['InputFileLocation']['volume_id'], 'local_id' => $res['InputFileLocation']['local_id']]; return $res; - case 'userProfilePhoto': case 'chatPhoto': $size = $message_media['photo_big'] ?? $message_media['photo_small']; - - $res = yield $this->getDownloadInfo($size); + $res = (yield from $this->getDownloadInfo($size)); $res['big'] = isset($message_media['photo_big']); $res['InputFileLocation']['dc_id'] = $message_media['dc_id']; - return $res; case 'photoStrippedSize': $res['size'] = \strlen($message_media['bytes']); $res['data'] = $message_media['bytes']; $res['thumb_size'] = 'JPG'; return $res; - case 'photoCachedSize': $res['size'] = \strlen($message_media['bytes']); $res['data'] = $message_media['bytes']; //$res['thumb_size'] = $res['data']; $res['thumb_size'] = $message_media['type']; - if ($message_media['location']['_'] === 'fileLocationUnavailable') { - $res['name'] = Tools::unpackSignedLongString($message_media['volume_id']).'_'.$message_media['local_id']; + $res['name'] = Tools::unpackSignedLongString($message_media['volume_id']) . '_' . $message_media['local_id']; $res['mime'] = $this->getMimeFromBuffer($res['data']); $res['ext'] = $this->getExtensionFromMime($res['mime']); } else { - $res = \array_merge($res, yield $this->getDownloadInfo($message_media['location'])); + $res = \array_merge($res, yield from $this->getDownloadInfo($message_media['location'])); } - return $res; case 'photoSize': - $res = yield $this->getDownloadInfo($message_media['location']); - + $res = (yield from $this->getDownloadInfo($message_media['location'])); $res['thumb_size'] = $message_media['type']; //$res['thumb_size'] = $size; if (isset($message_media['size'])) { $res['size'] = $message_media['size']; } - return $res; - case 'fileLocationUnavailable': throw new \danog\MadelineProto\Exception('File location unavailable'); case 'fileLocation': - $res['name'] = Tools::unpackSignedLongString($message_media['volume_id']).'_'.$message_media['local_id']; - $res['InputFileLocation'] = [ - '_' => 'inputFileLocation', - 'volume_id' => $message_media['volume_id'], - 'local_id' => $message_media['local_id'], - 'secret' => $message_media['secret'], - 'dc_id' => $message_media['dc_id'], - 'file_reference' => yield $this->referenceDatabase->getReference( - ReferenceDatabase::PHOTO_LOCATION_LOCATION, - $message_media - ), - ]; + $res['name'] = Tools::unpackSignedLongString($message_media['volume_id']) . '_' . $message_media['local_id']; + $res['InputFileLocation'] = ['_' => 'inputFileLocation', 'volume_id' => $message_media['volume_id'], 'local_id' => $message_media['local_id'], 'secret' => $message_media['secret'], 'dc_id' => $message_media['dc_id'], 'file_reference' => yield $this->referenceDatabase->getReference(ReferenceDatabase::PHOTO_LOCATION_LOCATION, $message_media)]; $res['ext'] = $this->getExtensionFromLocation($res['InputFileLocation'], '.jpg'); $res['mime'] = $this->getMimeFromExtension($res['ext'], 'image/jpeg'); - return $res; case 'fileLocationToBeDeprecated': - $res['name'] = Tools::unpackSignedLongString($message_media['volume_id']).'_'.$message_media['local_id']; + $res['name'] = Tools::unpackSignedLongString($message_media['volume_id']) . '_' . $message_media['local_id']; $res['ext'] = '.jpg'; $res['mime'] = $this->getMimeFromExtension($res['ext'], 'image/jpeg'); $res['InputFileLocation'] = [ - '_' => 'inputFileLocationTemp', // Will be overwritten + '_' => 'inputFileLocationTemp', + // Will be overwritten 'volume_id' => $message_media['volume_id'], 'local_id' => $message_media['local_id'], ]; - return $res; - // Documents case 'decryptedMessageMediaExternalDocument': case 'document': $message_media = ['_' => 'messageMediaDocument', 'ttl_seconds' => 0, 'document' => $message_media]; - // no break + // no break case 'messageMediaDocument': $res['MessageMedia'] = $message_media; - foreach ($message_media['document']['attributes'] as $attribute) { switch ($attribute['_']) { case 'documentAttributeFilename': $pathinfo = \pathinfo($attribute['file_name']); if (isset($pathinfo['extension'])) { - $res['ext'] = '.'.$pathinfo['extension']; + $res['ext'] = '.' . $pathinfo['extension']; } $res['name'] = $pathinfo['filename']; break; @@ -899,22 +774,10 @@ trait Files if (isset($audio) && isset($audio['title']) && !isset($res['name'])) { $res['name'] = $audio['title']; if (isset($audio['performer'])) { - $res['name'] .= ' - '.$audio['performer']; + $res['name'] .= ' - ' . $audio['performer']; } } - - $res['InputFileLocation'] = [ - '_' => 'inputDocumentFileLocation', - 'id' => $message_media['document']['id'], - 'access_hash' => $message_media['document']['access_hash'], - 'version' => isset($message_media['document']['version']) ? $message_media['document']['version'] : 0, - 'dc_id' => $message_media['document']['dc_id'], - 'file_reference' => yield $this->referenceDatabase->getReference( - ReferenceDatabase::DOCUMENT_LOCATION, - $message_media['document'] - ), - ]; - + $res['InputFileLocation'] = ['_' => 'inputDocumentFileLocation', 'id' => $message_media['document']['id'], 'access_hash' => $message_media['document']['access_hash'], 'version' => isset($message_media['document']['version']) ? $message_media['document']['version'] : 0, 'dc_id' => $message_media['document']['dc_id'], 'file_reference' => yield $this->referenceDatabase->getReference(ReferenceDatabase::DOCUMENT_LOCATION, $message_media['document'])]; if (!isset($res['ext']) || $res['ext'] === '') { $res['ext'] = $this->getExtensionFromLocation($res['InputFileLocation'], $this->getExtensionFromMime($message_media['document']['mime_type'])); } @@ -924,107 +787,106 @@ trait Files if (isset($message_media['document']['size'])) { $res['size'] = $message_media['document']['size']; } - $res['name'] .= '_'.$message_media['document']['id']; + $res['name'] .= '_' . $message_media['document']['id']; $res['mime'] = $message_media['document']['mime_type']; - return $res; default: - throw new \danog\MadelineProto\Exception('Invalid constructor provided: '.$message_media['_']); + throw new \danog\MadelineProto\Exception('Invalid constructor provided: ' . $message_media['_']); } } /* - public function download_to_browser_single_async($message_media, $cb = null) - { - if (php_sapi_name() === 'cli') { - throw new Exception('Cannot download file to browser from command line: start this script from a browser'); - } - if (headers_sent()) { - throw new Exception('Headers already sent, cannot stream file to browser!'); - } + public function download_to_browser_single_async($message_media, $cb = null) + { + if (php_sapi_name() === 'cli') { + throw new Exception('Cannot download file to browser from command line: start this script from a browser'); + } + if (headers_sent()) { + throw new Exception('Headers already sent, cannot stream file to browser!'); + } - if (is_object($message_media) && $message_media instanceof FileCallbackInterface) { - $cb = $message_media; - $message_media = $message_media->getFile(); - } + if (is_object($message_media) && $message_media instanceof FileCallbackInterface) { + $cb = $message_media; + $message_media = $message_media->getFile(); + } - $message_media = yield $this->getDownloadInfo($message_media); + $message_media = yield $this->getDownloadInfo($message_media); - $servefile = $_SERVER['REQUEST_METHOD'] !== 'HEAD'; + $servefile = $_SERVER['REQUEST_METHOD'] !== 'HEAD'; - if (isset($_SERVER['HTTP_RANGE'])) { - $range = explode('=', $_SERVER['HTTP_RANGE'], 2); - if (count($range) == 1) { - $range[1] = ''; - } - list($size_unit, $range_orig) = $range; - if ($size_unit == 'bytes') { - //multiple ranges could be specified at the same time, but for simplicity only serve the first range - //http://tools.ietf.org/id/draft-ietf-http-range-retrieval-00.txt - $list = explode(',', $range_orig, 2); - if (count($list) == 1) { - $list[1] = ''; - } - list($range, $extra_ranges) = $list; - } else { - $range = ''; - return Tools::noCache(416, '

416 Requested Range Not Satisfiable.


Could not use selected range.

'); - } - } else { - $range = ''; - } - $listseek = explode('-', $range, 2); - if (count($listseek) == 1) { - $listseek[1] = ''; - } - list($seek_start, $seek_end) = $listseek; + if (isset($_SERVER['HTTP_RANGE'])) { + $range = explode('=', $_SERVER['HTTP_RANGE'], 2); + if (count($range) == 1) { + $range[1] = ''; + } + list($size_unit, $range_orig) = $range; + if ($size_unit == 'bytes') { + //multiple ranges could be specified at the same time, but for simplicity only serve the first range + //http://tools.ietf.org/id/draft-ietf-http-range-retrieval-00.txt + $list = explode(',', $range_orig, 2); + if (count($list) == 1) { + $list[1] = ''; + } + list($range, $extra_ranges) = $list; + } else { + $range = ''; + return Tools::noCache(416, '

416 Requested Range Not Satisfiable.


Could not use selected range.

'); + } + } else { + $range = ''; + } + $listseek = explode('-', $range, 2); + if (count($listseek) == 1) { + $listseek[1] = ''; + } + list($seek_start, $seek_end) = $listseek; - $seek_end = empty($seek_end) ? ($message_media['size'] - 1) : min(abs(intval($seek_end)), $message_media['size'] - 1); + $seek_end = empty($seek_end) ? ($message_media['size'] - 1) : min(abs(intval($seek_end)), $message_media['size'] - 1); - if (!empty($seek_start) && $seek_end < abs(intval($seek_start))) { - return Tools::noCache(416, '

416 Requested Range Not Satisfiable.


Could not use selected range.

'); - } - $seek_start = empty($seek_start) ? 0 : abs(intval($seek_start)); - if ($servefile) { - if ($seek_start > 0 || $seek_end < $select['file_size'] - 1) { - header('HTTP/1.1 206 Partial Content'); - header('Content-Range: bytes '.$seek_start.'-'.$seek_end.'/'.$select['file_size']); - header('Content-Length: '.($seek_end - $seek_start + 1)); - } else { - header('Content-Length: '.$select['file_size']); - } - header('Content-Type: '.$select['mime']); - header('Cache-Control: max-age=31556926;'); - header('Content-Transfer-Encoding: Binary'); - header('Accept-Ranges: bytes'); - //header('Content-disposition: attachment: filename="'.basename($select['file_path']).'"'); - $MadelineProto->downloadToStream($select['file_id'], fopen('php://output', 'w'), function ($percent) { - flush(); - ob_flush(); - \danog\MadelineProto\Logger::log('Download status: '.$percent.'%'); - }, $seek_start, $seek_end + 1); - //analytics(true, $file_path, $MadelineProto->getSelf()['id'], $dbuser, $dbpassword); - $MadelineProto->API->getting_state = false; - $MadelineProto->API->storeDb([], true); - $MadelineProto->API->resetSession(); - } else { - if ($seek_start > 0 || $seek_end < $select['file_size'] - 1) { - header('HTTP/1.1 206 Partial Content'); - header('Content-Range: bytes '.$seek_start.'-'.$seek_end.'/'.$select['file_size']); - header('Content-Length: '.($seek_end - $seek_start + 1)); - } else { - header('Content-Length: '.$select['file_size']); - } - header('Content-Type: '.$select['mime']); - header('Cache-Control: max-age=31556926;'); - header('Content-Transfer-Encoding: Binary'); - header('Accept-Ranges: bytes'); - analytics(true, $file_path, null, $dbuser, $dbpassword); - //header('Content-disposition: attachment: filename="'.basename($select['file_path']).'"'); - } + if (!empty($seek_start) && $seek_end < abs(intval($seek_start))) { + return Tools::noCache(416, '

416 Requested Range Not Satisfiable.


Could not use selected range.

'); + } + $seek_start = empty($seek_start) ? 0 : abs(intval($seek_start)); + if ($servefile) { + if ($seek_start > 0 || $seek_end < $select['file_size'] - 1) { + header('HTTP/1.1 206 Partial Content'); + header('Content-Range: bytes '.$seek_start.'-'.$seek_end.'/'.$select['file_size']); + header('Content-Length: '.($seek_end - $seek_start + 1)); + } else { + header('Content-Length: '.$select['file_size']); + } + header('Content-Type: '.$select['mime']); + header('Cache-Control: max-age=31556926;'); + header('Content-Transfer-Encoding: Binary'); + header('Accept-Ranges: bytes'); + //header('Content-disposition: attachment: filename="'.basename($select['file_path']).'"'); + $MadelineProto->downloadToStream($select['file_id'], fopen('php://output', 'w'), function ($percent) { + flush(); + ob_flush(); + \danog\MadelineProto\Logger::log('Download status: '.$percent.'%'); + }, $seek_start, $seek_end + 1); + //analytics(true, $file_path, $MadelineProto->getSelf()['id'], $dbuser, $dbpassword); + $MadelineProto->API->getting_state = false; + $MadelineProto->API->storeDb([], true); + $MadelineProto->API->resetSession(); + } else { + if ($seek_start > 0 || $seek_end < $select['file_size'] - 1) { + header('HTTP/1.1 206 Partial Content'); + header('Content-Range: bytes '.$seek_start.'-'.$seek_end.'/'.$select['file_size']); + header('Content-Length: '.($seek_end - $seek_start + 1)); + } else { + header('Content-Length: '.$select['file_size']); + } + header('Content-Type: '.$select['mime']); + header('Cache-Control: max-age=31556926;'); + header('Content-Transfer-Encoding: Binary'); + header('Accept-Ranges: bytes'); + analytics(true, $file_path, null, $dbuser, $dbpassword); + //header('Content-disposition: attachment: filename="'.basename($select['file_path']).'"'); + } - header('Content-Length: '.$info['size']); - header('Content-Type: '.$info['mime']); - }*/ + header('Content-Length: '.$info['size']); + header('Content-Type: '.$info['mime']); + }*/ /** * Extract photo size. * @@ -1052,12 +914,9 @@ trait Files $cb = $dir; $dir = $dir->getFile(); } - - $message_media = yield $this->getDownloadInfo($message_media); - - return yield $this->downloadToFile($message_media, $dir.'/'.$message_media['name'].$message_media['ext'], $cb); + $message_media = (yield from $this->getDownloadInfo($message_media)); + return yield from $this->downloadToFile($message_media, $dir . '/' . $message_media['name'] . $message_media['ext'], $cb); } - /** * Download file. * @@ -1078,25 +937,20 @@ trait Files yield \touch($file); } $file = \realpath($file); - $message_media = yield $this->getDownloadInfo($message_media); - + $message_media = (yield from $this->getDownloadInfo($message_media)); StatCache::clear($file); - $size = (yield \stat($file))['size']; $stream = yield open($file, 'cb'); - $this->logger->logger('Waiting for lock of file to download...'); $unlock = yield \danog\MadelineProto\Tools::flock($file, LOCK_EX); $this->logger->logger('Got lock of file to download'); - try { - yield $this->downloadToStream($message_media, $stream, $cb, $size, -1); + yield from $this->downloadToStream($message_media, $stream, $cb, $size, -1); } finally { $unlock(); yield $stream->close(); StatCache::clear($file); } - return $file; } /** @@ -1112,13 +966,11 @@ trait Files */ public function downloadToStream($message_media, $stream, $cb = null, int $offset = 0, int $end = -1): \Generator { - $message_media = yield $this->getDownloadInfo($message_media); - + $message_media = (yield from $this->getDownloadInfo($message_media)); if (\is_object($stream) && $stream instanceof FileCallbackInterface) { $cb = $stream; $stream = $stream->getFile(); } - /** @var $stream \Amp\ByteStream\OutputStream */ if (!\is_object($stream)) { $stream = new ResourceOutputStream($stream); @@ -1134,7 +986,7 @@ trait Files } catch (StreamException $e) { } } - $callable = static function (string $payload, int $offset) use ($stream, $seekable) { + $callable = static function (string $payload, int $offset) use ($stream, $seekable): \Generator { if ($seekable) { while ($stream->tell() !== $offset) { yield $stream->seek($offset); @@ -1142,8 +994,7 @@ trait Files } return yield $stream->write($payload); }; - - return yield $this->downloadToCallable($message_media, $callable, $cb, $seekable, $offset, $end); + return yield from $this->downloadToCallable($message_media, $callable, $cb, $seekable, $offset, $end); } /** * Download file to callable. @@ -1163,36 +1014,30 @@ trait Files */ public function downloadToCallable($message_media, $callable, $cb = null, bool $seekable = true, int $offset = 0, int $end = -1, int $part_size = null): \Generator { - $message_media = yield $this->getDownloadInfo($message_media); - + $message_media = (yield from $this->getDownloadInfo($message_media)); if (\is_object($callable) && $callable instanceof FileCallbackInterface) { $cb = $callable; $callable = $callable->getFile(); } - if (!\is_callable($callable)) { throw new Exception('Wrong callable provided'); } if ($cb === null) { $cb = function ($percent) { - $this->logger->logger('Download status: '.$percent.'%', \danog\MadelineProto\Logger::NOTICE); + $this->logger->logger('Download status: ' . $percent . '%', \danog\MadelineProto\Logger::NOTICE); }; } - if ($end === -1 && isset($message_media['size'])) { $end = $message_media['size']; } - $part_size = $part_size ?? $this->settings['download']['part_size']; $parallel_chunks = $this->settings['download']['parallel_chunks'] ? $this->settings['download']['parallel_chunks'] : 3000; - $datacenter = isset($message_media['InputFileLocation']['dc_id']) ? $message_media['InputFileLocation']['dc_id'] : $this->settings['connection_settings']['default_dc']; - if ($this->datacenter->has($datacenter.'_media')) { + if ($this->datacenter->has($datacenter . '_media')) { $datacenter .= '_media'; } - if (isset($message_media['key'])) { - $digest = \hash('md5', $message_media['key'].$message_media['iv'], true); + $digest = \hash('md5', $message_media['key'] . $message_media['iv'], true); $fingerprint = \danog\MadelineProto\Tools::unpackSignedInt(\substr($digest, 0, 4) ^ \substr($digest, 4, 4)); if ($fingerprint !== $message_media['key_fingerprint']) { throw new \danog\MadelineProto\Exception('Fingerprint mismatch!'); @@ -1203,7 +1048,6 @@ trait Files $ige->enableContinuousBuffer(); $seekable = false; } - if ($offset === $end) { $cb(100, 0, 0); return true; @@ -1211,35 +1055,24 @@ trait Files $params = []; $start_at = $offset % $part_size; $probable_end = $end !== -1 ? $end : 512 * 1024 * 3000; - $breakOut = false; for ($x = $offset - $start_at; $x < $probable_end; $x += $part_size) { $end_at = $part_size; - if ($end !== -1 && $x + $part_size > $end) { $end_at = $end % $part_size; $breakOut = true; } - - $params[] = [ - 'offset' => $x, - 'limit' => $part_size, - 'part_start_at' => $start_at, - 'part_end_at' => $end_at, - ]; - + $params[] = ['offset' => $x, 'limit' => $part_size, 'part_start_at' => $start_at, 'part_end_at' => $end_at]; $start_at = 0; if ($breakOut) { break; } } - if (!$params) { $cb(100, 0, 0); return true; } $count = \count($params); - $time = 0; $speed = 0; $origCb = $cb; @@ -1248,21 +1081,17 @@ trait Files $cur++; \danog\MadelineProto\Tools::callFork($cb($cur * 100 / $count, $time, $speed)); }; - $cdn = false; - $params[0]['previous_promise'] = new Success(true); - $start = \microtime(true); - $size = yield $this->downloadPart($message_media, $cdn, $datacenter, $old_dc, $ige, $cb, $initParam = \array_shift($params), $callable, $seekable); - if ($initParam['part_end_at'] - $initParam['part_start_at'] !== $size) { // Premature end for undefined length files + $size = (yield from $this->downloadPart($message_media, $cdn, $datacenter, $old_dc, $ige, $cb, $initParam = \array_shift($params), $callable, $seekable)); + if ($initParam['part_end_at'] - $initParam['part_start_at'] !== $size) { + // Premature end for undefined length files $origCb(100, 0, 0); return true; } - if ($params) { $previous_promise = new Success(true); - $promises = []; foreach ($params as $key => $param) { $param['previous_promise'] = $previous_promise; @@ -1272,10 +1101,9 @@ trait Files $size += $res; } }); - $promises[] = $previous_promise; - - if (!($key % $parallel_chunks)) { // 20 mb at a time, for a typical bandwidth of 1gbps + if (!($key % $parallel_chunks)) { + // 20 mb at a time, for a typical bandwidth of 1gbps $res = yield \danog\MadelineProto\Tools::all($promises); $promises = []; foreach ($res as $r) { @@ -1283,11 +1111,10 @@ trait Files break 2; } } - $time = \microtime(true) - $start; - $speed = (int) (($size * 8) / $time) / 1000000; - $this->logger->logger("Partial download time: $time"); - $this->logger->logger("Partial download speed: $speed mbps"); + $speed = (int) ($size * 8 / $time) / 1000000; + $this->logger->logger("Partial download time: {$time}"); + $this->logger->logger("Partial download speed: {$speed} mbps"); } } if ($promises) { @@ -1295,21 +1122,17 @@ trait Files } } $time = \microtime(true) - $start; - $speed = (int) (($size * 8) / $time) / 1000000; - $this->logger->logger("Total download time: $time"); - $this->logger->logger("Total download speed: $speed mbps"); - + $speed = (int) ($size * 8 / $time) / 1000000; + $this->logger->logger("Total download time: {$time}"); + $this->logger->logger("Total download speed: {$speed} mbps"); if ($cdn) { $this->clearCdnHashes($message_media['file_token']); } - if (!isset($message_media['size'])) { $origCb(100, $time, $speed); } - return true; } - /** * Download file part. * @@ -1329,34 +1152,20 @@ trait Files private function downloadPart(&$message_media, bool &$cdn, &$datacenter, &$old_dc, &$ige, $cb, array $offset, $callable, bool $seekable, bool $postpone = false): \Generator { static $method = [ - false => 'upload.getFile', // non-cdn - true => 'upload.getCdnFile', // cdn + false => 'upload.getFile', + // non-cdn + true => 'upload.getCdnFile', ]; do { if (!$cdn) { - $basic_param = [ - 'location' => $message_media['InputFileLocation'], - ]; + $basic_param = ['location' => $message_media['InputFileLocation']]; } else { - $basic_param = [ - 'file_token' => $message_media['file_token'], - ]; + $basic_param = ['file_token' => $message_media['file_token']]; } - //$x = 0; while (true) { try { - $res = yield $this->methodCallAsyncRead( - $method[$cdn], - $basic_param + $offset, - [ - 'heavy' => true, - 'file' => true, - 'FloodWaitLimit' => 0, - 'datacenter' => &$datacenter, - 'postpone' => $postpone, - ] - ); + $res = yield $this->methodCallAsyncRead($method[$cdn], $basic_param + $offset, ['heavy' => true, 'file' => true, 'FloodWaitLimit' => 0, 'datacenter' => &$datacenter, 'postpone' => $postpone]); break; } catch (\danog\MadelineProto\RPCErrorException $e) { if (\strpos($e->rpc, 'FLOOD_WAIT_') === 0) { @@ -1372,14 +1181,13 @@ trait Files } } } - if ($res['_'] === 'upload.fileCdnRedirect') { $cdn = true; $message_media['file_token'] = $res['file_token']; $message_media['cdn_key'] = $res['encryption_key']; $message_media['cdn_iv'] = $res['encryption_iv']; $old_dc = $datacenter; - $datacenter = $res['dc_id'].'_cdn'; + $datacenter = $res['dc_id'] . '_cdn'; if (!$this->datacenter->has($datacenter)) { $this->config['expires'] = -1; yield $this->getConfig([], ['datacenter' => $this->datacenter->curdc]); @@ -1388,7 +1196,6 @@ trait Files } elseif ($res['_'] === 'upload.cdnFileReuploadNeeded') { $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['cdn_reupload'], \danog\MadelineProto\Logger::NOTICE); yield $this->getConfig([], ['datacenter' => $this->datacenter->curdc]); - try { $this->addCdnHashes($message_media['file_token'], yield $this->methodCallAsyncRead('upload.reuploadCdnFile', ['file_token' => $message_media['file_token'], 'request_token' => $res['request_token']], ['heavy' => true, 'datacenter' => $old_dc])); } catch (\danog\MadelineProto\RPCErrorException $e) { @@ -1404,24 +1211,17 @@ trait Files continue; } $res['bytes'] = (string) $res['bytes']; - if ($cdn === false && $res['type']['_'] === 'storage.fileUnknown' && $res['bytes'] === '') { $datacenter = 0; } - while ($cdn === false && - $res['type']['_'] === 'storage.fileUnknown' && - $res['bytes'] === '' && - $this->datacenter->has(++$datacenter) - ) { + while ($cdn === false && $res['type']['_'] === 'storage.fileUnknown' && $res['bytes'] === '' && $this->datacenter->has(++$datacenter)) { $res = yield $this->methodCallAsyncRead('upload.getFile', $basic_param + $offset, ['heavy' => true, 'file' => true, 'FloodWaitLimit' => 0, 'datacenter' => $datacenter]); } - if ($res['bytes'] === '') { return 0; } - if (isset($message_media['cdn_key'])) { - $ivec = \substr($message_media['cdn_iv'], 0, 12).\pack('N', $offset['offset'] >> 4); + $ivec = \substr($message_media['cdn_iv'], 0, 12) . \pack('N', $offset['offset'] >> 4); $res['bytes'] = $this->ctrEncrypt($res['bytes'], $message_media['cdn_key'], $ivec); $this->checkCdnHash($message_media['file_token'], $offset['offset'], $res['bytes'], $old_dc); } @@ -1431,18 +1231,15 @@ trait Files if ($offset['part_start_at'] || $offset['part_end_at'] !== $offset['limit']) { $res['bytes'] = \substr($res['bytes'], $offset['part_start_at'], $offset['part_end_at'] - $offset['part_start_at']); } - if (!$seekable) { - yield $offset['previous_promise']; + yield from $offset['previous_promise']; } $res = yield $callable($res['bytes'], $offset['offset'] + $offset['part_start_at']); $cb(); return $res; } while (true); } - private $cdn_hashes = []; - private function addCdnHashes($file, $hashes) { if (!isset($this->cdn_hashes[$file])) { @@ -1452,30 +1249,26 @@ trait Files $this->cdn_hashes[$file][$hash['offset']] = ['limit' => $hash['limit'], 'hash' => (string) $hash['hash']]; } } - - private function checkCdnHash($file, $offset, $data, &$datacenter) + private function checkCdnHash($file, $offset, $data, &$datacenter): \Generator { while (\strlen($data)) { if (!isset($this->cdn_hashes[$file][$offset])) { $this->addCdnHashes($file, yield $this->methodCallAsyncRead('upload.getCdnFileHashes', ['file_token' => $file, 'offset' => $offset], ['datacenter' => $datacenter])); } if (!isset($this->cdn_hashes[$file][$offset])) { - throw new \danog\MadelineProto\Exception('Could not fetch CDN hashes for offset '.$offset); + throw new \danog\MadelineProto\Exception('Could not fetch CDN hashes for offset ' . $offset); } if (\hash('sha256', \substr($data, 0, $this->cdn_hashes[$file][$offset]['limit']), true) !== $this->cdn_hashes[$file][$offset]['hash']) { - throw new \danog\MadelineProto\SecurityException('CDN hash mismatch for offset '.$offset); + throw new \danog\MadelineProto\SecurityException('CDN hash mismatch for offset ' . $offset); } $data = \substr($data, $this->cdn_hashes[$file][$offset]['limit']); $offset += $this->cdn_hashes[$file][$offset]['limit']; } - return true; } - private function clearCdnHashes($file) { unset($this->cdn_hashes[$file]); - return true; } } diff --git a/src/danog/MadelineProto/MTProtoTools/MinDatabase.php b/src/danog/MadelineProto/MTProtoTools/MinDatabase.php index 224ae0be..90434ecb 100644 --- a/src/danog/MadelineProto/MTProtoTools/MinDatabase.php +++ b/src/danog/MadelineProto/MTProtoTools/MinDatabase.php @@ -29,26 +29,8 @@ use danog\MadelineProto\Tools; class MinDatabase implements TLCallback { use Tools; - - const SWITCH_CONSTRUCTORS = [ - 'inputChannel', - 'inputUser', - 'inputPeerUser', - 'inputPeerChannel', - ]; - const CATCH_PEERS = [ - 'message', - 'messageService', - 'peerUser', - 'peerChannel', - 'messageEntityMentionName', - - 'messageFwdHeader', - 'messageActionChatCreate', - 'messageActionChatAddUser', - 'messageActionChatDeleteUser', - 'messageActionChatJoinedByLink', - ]; + const SWITCH_CONSTRUCTORS = ['inputChannel', 'inputUser', 'inputPeerUser', 'inputPeerChannel']; + const CATCH_PEERS = ['message', 'messageService', 'peerUser', 'peerChannel', 'messageEntityMentionName', 'messageFwdHeader', 'messageActionChatCreate', 'messageActionChatAddUser', 'messageActionChatDeleteUser', 'messageActionChatJoinedByLink']; const ORIGINS = ['message', 'messageService']; /** * References indexed by location. @@ -68,23 +50,19 @@ class MinDatabase implements TLCallback * @var \danog\MadelineProto\MTProto */ private $API; - public function __construct(MTProto $API) { $this->API = $API; $this->init(); } - public function __wakeup() { $this->init(); } - public function __sleep() { return ['db', 'API']; } - public function init() { foreach ($this->db as $id => $origin) { @@ -93,48 +71,37 @@ class MinDatabase implements TLCallback } } } - public function getMethodCallbacks(): array { return []; } - public function getMethodBeforeCallbacks(): array { return []; } - public function getConstructorCallbacks(): array { - return \array_merge( - \array_fill_keys(self::CATCH_PEERS, [[$this, 'addPeer']]), - \array_fill_keys(self::ORIGINS, [[$this, 'addOrigin']]) - ); + return \array_merge(\array_fill_keys(self::CATCH_PEERS, [[$this, 'addPeer']]), \array_fill_keys(self::ORIGINS, [[$this, 'addOrigin']])); } - public function getConstructorBeforeCallbacks(): array { return \array_fill_keys(self::ORIGINS, [[$this, 'addOriginContext']]); } - public function getConstructorSerializeCallbacks(): array { return \array_fill_keys(self::SWITCH_CONSTRUCTORS, [$this, 'populateFrom']); } - public function getTypeMismatchCallbacks(): array { return []; } - public function reset() { if ($this->cache) { - $this->API->logger->logger('Found '.\count($this->cache).' pending contexts', \danog\MadelineProto\Logger::ERROR); + $this->API->logger->logger('Found ' . \count($this->cache) . ' pending contexts', \danog\MadelineProto\Logger::ERROR); $this->cache = []; } } - public function addPeer(array $location) { if (!$this->cache) { @@ -148,18 +115,15 @@ class MinDatabase implements TLCallback if ($frame['args'][1]['subtype'] === $previous) { continue; } - $frames[] = $frame['args'][1]['subtype']; $previous = $frame['args'][1]['subtype']; } elseif (isset($frame['args'][1]['type'])) { if ($frame['args'][1]['type'] === '') { break; } - if ($frame['args'][1]['type'] === $previous) { continue; } - $frames[] = $frame['args'][1]['type']; $previous = $frame['args'][1]['type']; } @@ -168,10 +132,9 @@ class MinDatabase implements TLCallback $frames = \array_reverse($frames); $tl_trace = \array_shift($frames); foreach ($frames as $frame) { - $tl_trace .= "['".$frame."']"; + $tl_trace .= "['" . $frame . "']"; } $this->API->logger->logger($tl_trace, \danog\MadelineProto\Logger::ERROR); - return false; } $peers = []; @@ -204,16 +167,13 @@ class MinDatabase implements TLCallback foreach ($peers as $id => $true) { $this->cache[$key][$id] = $id; } - return true; } - public function addOriginContext(string $type) { $this->API->logger->logger("Adding peer origin context for {$type}!", \danog\MadelineProto\Logger::ULTRA_VERBOSE); $this->cache[] = []; } - public function addOrigin(array $data = []) { $cache = \array_pop($this->cache); @@ -236,10 +196,9 @@ class MinDatabase implements TLCallback } $this->db[$id] = $origin; } - $this->API->logger->logger("Added origin ({$data['_']}) to ".\count($cache).' peer locations', \danog\MadelineProto\Logger::ULTRA_VERBOSE); + $this->API->logger->logger("Added origin ({$data['_']}) to " . \count($cache) . ' peer locations', \danog\MadelineProto\Logger::ULTRA_VERBOSE); } - - public function populateFrom(array $object) + public function populateFrom(array $object): \Generator { if (!($object['min'] ?? false)) { return $object; @@ -250,17 +209,14 @@ class MinDatabase implements TLCallback $new['_'] .= 'FromMessage'; $new['peer'] = (yield $this->API->getInfo($new['peer']))['InputPeer']; if ($new['peer']['min']) { - $this->API->logger->logger("Don't have origin peer subinfo with min peer $id, this may fail"); + $this->API->logger->logger("Don't have origin peer subinfo with min peer {$id}, this may fail"); return $object; } return $new; } - $this->API->logger->logger("Don't have origin info with min peer $id, this may fail"); - - + $this->API->logger->logger("Don't have origin info with min peer {$id}, this may fail"); return $object; } - /** * Check if location info is available for peer. * @@ -274,6 +230,6 @@ class MinDatabase implements TLCallback } public function __debugInfo() { - return ['MinDatabase instance '.\spl_object_hash($this)]; + return ['MinDatabase instance ' . \spl_object_hash($this)]; } } diff --git a/src/danog/MadelineProto/MTProtoTools/PasswordCalculator.php b/src/danog/MadelineProto/MTProtoTools/PasswordCalculator.php index 4a01e5b6..b2b489b5 100644 --- a/src/danog/MadelineProto/MTProtoTools/PasswordCalculator.php +++ b/src/danog/MadelineProto/MTProtoTools/PasswordCalculator.php @@ -1,4 +1,5 @@ logger = $logger; } - /** * Popupate 2FA configuration. * @@ -115,7 +111,6 @@ class PasswordCalculator $this->checkPG($object['current_algo']['p'], $object['current_algo']['g']); $object['current_algo']['gForHash'] = \str_pad($object['current_algo']['g']->toBytes(), 256, \chr(0), \STR_PAD_LEFT); $object['current_algo']['pForHash'] = \str_pad($object['current_algo']['p']->toBytes(), 256, \chr(0), \STR_PAD_LEFT); - break; default: throw new Exception("Unknown KDF algo {$object['current_algo']['_']}"); @@ -146,7 +141,6 @@ class PasswordCalculator $this->checkPG($object['new_algo']['p'], $object['new_algo']['g']); $object['new_algo']['gForHash'] = \str_pad($object['new_algo']['g']->toBytes(), 256, \chr(0), \STR_PAD_LEFT); $object['new_algo']['pForHash'] = \str_pad($object['new_algo']['p']->toBytes(), 256, \chr(0), \STR_PAD_LEFT); - break; default: throw new Exception("Unknown KDF algo {$object['new_algo']['_']}"); @@ -154,7 +148,6 @@ class PasswordCalculator $this->new_algo = $object['new_algo']; $this->secure_random = $object['secure_random']; } - /** * Create a random string (eventually prefixed by the specified string). * @@ -163,9 +156,8 @@ class PasswordCalculator */ public function createSalt(string $prefix = ''): string { - return $prefix.\danog\MadelineProto\Tools::random(32); + return $prefix . \danog\MadelineProto\Tools::random(32); } - /** * Hash specified data using the salt with SHA256. * @@ -177,9 +169,8 @@ class PasswordCalculator */ public function hashSha256(string $data, string $salt): string { - return \hash('sha256', $salt.$data.$salt, true); + return \hash('sha256', $salt . $data . $salt, true); } - /** * Hashes the specified password. * @@ -193,10 +184,8 @@ class PasswordCalculator $buf = $this->hashSha256($password, $client_salt); $buf = $this->hashSha256($buf, $server_salt); $hash = \hash_pbkdf2('sha512', $buf, $client_salt, 100000, 0, true); - return $this->hashSha256($hash, $server_salt); } - /** * Get the InputCheckPassword object for checking the validity of a password using account.checkPassword. * @@ -214,42 +203,30 @@ class PasswordCalculator $gForHash = $this->current_algo['gForHash']; $p = $this->current_algo['p']; $pForHash = $this->current_algo['pForHash']; - $B = $this->srp_B; $BForHash = $this->srp_BForHash; $id = $this->srp_id; - $x = new BigInteger($this->hashPassword($password, $client_salt, $server_salt), 256); $g_x = $g->powMod($x, $p); - - $k = new BigInteger(\hash('sha256', $pForHash.$gForHash, true), 256); + $k = new BigInteger(\hash('sha256', $pForHash . $gForHash, true), 256); $kg_x = $k->multiply($g_x)->powMod(Magic::$one, $p); - $a = new BigInteger(\danog\MadelineProto\Tools::random(2048 / 8), 256); $A = $g->powMod($a, $p); $this->checkG($A, $p); $AForHash = \str_pad($A->toBytes(), 256, \chr(0), \STR_PAD_LEFT); - $b_kg_x = $B->powMod(Magic::$one, $p)->subtract($kg_x); - - $u = new BigInteger(\hash('sha256', $AForHash.$BForHash, true), 256); + $u = new BigInteger(\hash('sha256', $AForHash . $BForHash, true), 256); $ux = $u->multiply($x); $a_ux = $a->add($ux); - $S = $b_kg_x->powMod($a_ux, $p); - $SForHash = \str_pad($S->toBytes(), 256, \chr(0), \STR_PAD_LEFT); $K = \hash('sha256', $SForHash, true); - $h1 = \hash('sha256', $pForHash, true); $h2 = \hash('sha256', $gForHash, true); $h1 ^= $h2; - - $M1 = \hash('sha256', $h1.\hash('sha256', $client_salt, true).\hash('sha256', $server_salt, true).$AForHash.$BForHash.$K, true); - + $M1 = \hash('sha256', $h1 . \hash('sha256', $client_salt, true) . \hash('sha256', $server_salt, true) . $AForHash . $BForHash . $K, true); return ['_' => 'inputCheckPasswordSRP', 'srp_id' => $id, 'A' => $AForHash, 'M1' => $M1]; } - /** * Get parameters to be passed to the account.updatePasswordSettings to update/set a 2FA password. * @@ -261,36 +238,24 @@ class PasswordCalculator public function getPassword(array $params): array { $oldPassword = $this->getCheckPassword($params['password'] ?? ''); - $return = ['password' => $oldPassword, 'new_settings' => ['_' => 'account.passwordInputSettings', 'new_algo' => ['_' => 'passwordKdfAlgoUnknown'], 'new_password_hash' => '', 'hint' => '']]; - - $new_settings = &$return['new_settings']; - + $new_settings =& $return['new_settings']; if (isset($params['new_password']) && $params['new_password'] !== '') { $client_salt = $this->createSalt($this->new_algo['salt1']); $server_salt = $this->new_algo['salt2']; $g = $this->new_algo['g']; $p = $this->new_algo['p']; $pForHash = $this->new_algo['pForHash']; - $x = new BigInteger($this->hashPassword($params['new_password'], $client_salt, $server_salt), 256); $v = $g->powMod($x, $p); $vForHash = \str_pad($v->toBytes(), 256, \chr(0), \STR_PAD_LEFT); - - $new_settings['new_algo'] = [ - '_' => 'passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow', - 'salt1' => $client_salt, - 'salt2' => $server_salt, - 'g' => (int) $g->toString(), - 'p' => $pForHash, - ]; + $new_settings['new_algo'] = ['_' => 'passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow', 'salt1' => $client_salt, 'salt2' => $server_salt, 'g' => (int) $g->toString(), 'p' => $pForHash]; $new_settings['new_password_hash'] = $vForHash; $new_settings['hint'] = $params['hint'] ?? ''; if (isset($params['email'])) { $new_settings['email'] = $params['email']; } } - return $return; } } diff --git a/src/danog/MadelineProto/MTProtoTools/PeerHandler.php b/src/danog/MadelineProto/MTProtoTools/PeerHandler.php index 2d5af9d0..43bff35e 100644 --- a/src/danog/MadelineProto/MTProtoTools/PeerHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/PeerHandler.php @@ -29,9 +29,7 @@ trait PeerHandler public $caching_simple = []; public $caching_simple_username = []; public $caching_possible_username = []; - public $caching_full_info = []; - /** * Convert MTProto channel ID to bot API channel ID. * @@ -43,7 +41,6 @@ trait PeerHandler { return -($id + \pow(10, (int) \floor(\log($id, 10) + 3))); } - /** * Convert bot API channel ID to MTProto channel ID. * @@ -55,7 +52,6 @@ trait PeerHandler { return -$id - \pow(10, (int) \floor(\log(-$id, 10))); } - /** * Check whether provided bot API ID is a channel. * @@ -66,10 +62,8 @@ trait PeerHandler public static function isSupergroup($id): bool { $log = \log(-$id, 10); - return ($log - \intval($log)) * 1000 < 10; } - /** * Set support info. * @@ -83,7 +77,6 @@ trait PeerHandler { $this->supportUser = $support['user']['id']; } - /** * Add user info. * @@ -109,14 +102,12 @@ trait PeerHandler } else { $this->logger->logger("No access hash with user {$user['id']}, tried and failed to fetch data..."); } - return; } switch ($user['_']) { case 'user': if (!isset($this->chats[$user['id']]) || $this->chats[$user['id']] !== $user) { $this->logger->logger("Updated user {$user['id']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); - if (($user['min'] ?? false) && isset($this->chats[$user['id']]) && !($this->chats[$user['id']]['min'] ?? false)) { $this->logger->logger("{$user['id']} is min, filling missing fields", \danog\MadelineProto\Logger::ULTRA_VERBOSE); if (isset($this->chats[$user['id']]['access_hash'])) { @@ -124,7 +115,6 @@ trait PeerHandler $user['access_hash'] = $this->chats[$user['id']]['access_hash']; } } - $this->chats[$user['id']] = $user; $this->cachePwrChat($user['id'], false, true); } @@ -135,7 +125,6 @@ trait PeerHandler throw new \danog\MadelineProto\Exception('Invalid user provided', $user); } } - /** * Add chat to database. * @@ -168,7 +157,6 @@ trait PeerHandler if (isset($chat['username']) && !isset($this->caching_simple_username[$chat['username']])) { $this->caching_possible_username[$bot_api_id] = $chat['username']; } - $this->cachePwrChat($bot_api_id, false, true); } elseif (isset($chat['username']) && !isset($this->chats[$bot_api_id]) && !isset($this->caching_simple_username[$chat['username']])) { $this->logger->logger("No access hash with {$chat['_']} {$bot_api_id}, trying to fetch by username..."); @@ -176,14 +164,12 @@ trait PeerHandler } else { $this->logger->logger("No access hash with {$chat['_']} {$bot_api_id}, tried and failed to fetch data..."); } - return; } if (!isset($this->chats[$bot_api_id]) || $this->chats[$bot_api_id] !== $chat) { - $this->logger->logger("Updated chat $bot_api_id", \danog\MadelineProto\Logger::ULTRA_VERBOSE); - + $this->logger->logger("Updated chat {$bot_api_id}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); if (($chat['min'] ?? false) && isset($this->chats[$bot_api_id]) && !($this->chats[$bot_api_id]['min'] ?? false)) { - $this->logger->logger("$bot_api_id is min, filling missing fields", \danog\MadelineProto\Logger::ULTRA_VERBOSE); + $this->logger->logger("{$bot_api_id} is min, filling missing fields", \danog\MadelineProto\Logger::ULTRA_VERBOSE); $newchat = $this->chats[$bot_api_id]; foreach (['title', 'username', 'photo', 'banned_rights', 'megagroup', 'verified'] as $field) { if (isset($chat[$field])) { @@ -192,33 +178,29 @@ trait PeerHandler } $chat = $newchat; } - $this->chats[$bot_api_id] = $chat; - - if ($this->settings['peer']['full_fetch'] && (!isset($this->full_chats[$bot_api_id]) || $this->full_chats[$bot_api_id]['full']['participants_count'] !== (yield $this->getFullInfo($bot_api_id))['full']['participants_count'])) { + if ($this->settings['peer']['full_fetch'] && (!isset($this->full_chats[$bot_api_id]) || $this->full_chats[$bot_api_id]['full']['participants_count'] !== (yield from $this->getFullInfo($bot_api_id))['full']['participants_count'])) { $this->cachePwrChat($bot_api_id, $this->settings['peer']['full_fetch'], true); } } break; default: - throw new \danog\MadelineProto\Exception('Invalid chat provided at key '.$key.': '.\var_export($chat, true)); + throw new \danog\MadelineProto\Exception('Invalid chat provided at key ' . $key . ': ' . \var_export($chat, true)); break; } } - private function cachePwrChat($id, $full_fetch, $send) { - \danog\MadelineProto\Tools::callFork((function () use ($id, $full_fetch, $send) { + \danog\MadelineProto\Tools::callFork((function () use ($id, $full_fetch, $send): \Generator { try { - yield $this->getPwrChat($id, $full_fetch, $send); + yield from $this->getPwrChat($id, $full_fetch, $send); } catch (\danog\MadelineProto\Exception $e) { - $this->logger->logger('While caching: '.$e->getMessage(), \danog\MadelineProto\Logger::WARNING); + $this->logger->logger('While caching: ' . $e->getMessage(), \danog\MadelineProto\Logger::WARNING); } catch (\danog\MadelineProto\RPCErrorException $e) { - $this->logger->logger('While caching: '.$e->getMessage(), \danog\MadelineProto\Logger::WARNING); + $this->logger->logger('While caching: ' . $e->getMessage(), \danog\MadelineProto\Logger::WARNING); } })()); } - /** * Check if peer is present in internal peer database. * @@ -229,7 +211,7 @@ trait PeerHandler public function peerIsset($id): \Generator { try { - return isset($this->chats[(yield $this->getInfo($id))['bot_api_id']]); + return isset($this->chats[(yield from $this->getInfo($id))['bot_api_id']]); } catch (\danog\MadelineProto\Exception $e) { return false; } catch (\danog\MadelineProto\RPCErrorException $e) { @@ -239,11 +221,9 @@ trait PeerHandler if ($e->rpc === 'CHANNEL_PRIVATE') { return true; } - return false; } } - /** * Check if all peer entities are in db. * @@ -258,7 +238,7 @@ trait PeerHandler try { foreach ($entities as $entity) { if ($entity['_'] === 'messageEntityMentionName' || $entity['_'] === 'inputMessageEntityMentionName') { - if (!yield $this->peerIsset($entity['user_id'])) { + if (!(yield from $this->peerIsset($entity['user_id']))) { return false; } } @@ -266,10 +246,8 @@ trait PeerHandler } catch (\danog\MadelineProto\Exception $e) { return false; } - return true; } - /** * Check if fwd peer is set. * @@ -282,19 +260,17 @@ trait PeerHandler public function fwdPeerIsset(array $fwd): \Generator { try { - if (isset($fwd['user_id']) && !yield $this->peerIsset($fwd['user_id'])) { + if (isset($fwd['user_id']) && !(yield from $this->peerIsset($fwd['user_id']))) { return false; } - if (isset($fwd['channel_id']) && !yield $this->peerIsset($this->toSupergroup($fwd['channel_id']))) { + if (isset($fwd['channel_id']) && !(yield from $this->peerIsset($this->toSupergroup($fwd['channel_id'])))) { return false; } } catch (\danog\MadelineProto\Exception $e) { return false; } - return true; } - /** * Get folder ID from object. * @@ -327,7 +303,7 @@ trait PeerHandler case 'updateDialogUnreadMark': case 'updateNotifySettings': $id = $id['peer']; - // no break + // no break case 'updateDraftMessage': case 'inputDialogPeer': case 'dialogPeer': @@ -339,15 +315,12 @@ trait PeerHandler case 'folderPeer': case 'inputFolderPeer': return $this->getId($id['peer']); - case 'inputUserFromMessage': case 'inputPeerUserFromMessage': return $id['user_id']; - case 'inputChannelFromMessage': case 'inputPeerChannelFromMessage': return $this->toSupergroup($id['channel_id']); - case 'inputUserSelf': case 'inputPeerSelf': return $this->authorization['user']['id']; @@ -383,9 +356,7 @@ trait PeerHandler if (!isset($id['from_id']) || $id['to_id']['_'] !== 'peerUser' || $id['to_id']['user_id'] !== $this->authorization['user']['id']) { return $this->getId($id['to_id']); } - return $id['from_id']; - case 'updateChannelReadMessagesContents': case 'updateChannelAvailableMessages': case 'updateChannel': @@ -399,7 +370,7 @@ trait PeerHandler return $this->toSupergroup($id['channel_id']); case 'updateChatParticipants': $id = $id['participants']; - // no break + // no break case 'updateChatUserTyping': case 'updateChatParticipantAdd': case 'updateChatParticipantDelete': @@ -434,18 +405,18 @@ trait PeerHandler case 'updateEditChannelMessage': return $this->getId($id['message']); default: - throw new \danog\MadelineProto\Exception('Invalid constructor given '.\var_export($id, true)); + throw new \danog\MadelineProto\Exception('Invalid constructor given ' . \var_export($id, true)); } } if (\is_string($id)) { if (\strpos($id, '#') !== false) { - if (\preg_match('/^channel#(\d*)/', $id, $matches)) { + if (\preg_match('/^channel#(\\d*)/', $id, $matches)) { return $this->toSupergroup($matches[1]); } - if (\preg_match('/^chat#(\d*)/', $id, $matches)) { - $id = '-'.$matches[1]; + if (\preg_match('/^chat#(\\d*)/', $id, $matches)) { + $id = '-' . $matches[1]; } - if (\preg_match('/^user#(\d*)/', $id, $matches)) { + if (\preg_match('/^user#(\\d*)/', $id, $matches)) { return $matches[1]; } } @@ -454,13 +425,10 @@ trait PeerHandler if (\is_string($id)) { $id = \danog\MadelineProto\Magic::$bigint ? (float) $id : (int) $id; } - return $id; } - return false; } - /** * Get info about peer, returns an Info object. * @@ -483,14 +451,13 @@ trait PeerHandler return $this->getSecretChat($id['chat_id']); case 'updateNewEncryptedMessage': $id = $id['message']; - // no break + // no break case 'encryptedMessage': case 'encryptedMessageService': $id = $id['chat_id']; if (!isset($this->secret_chats[$id])) { throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['sec_peer_not_in_db']); } - return $this->secret_chats[$id]; } } @@ -499,13 +466,11 @@ trait PeerHandler if ($try_id !== false) { $id = $try_id; } - $tried_simple = false; - if (\is_numeric($id)) { if (!isset($this->chats[$id])) { try { - $this->logger->logger("Try fetching $id with access hash 0"); + $this->logger->logger("Try fetching {$id} with access hash 0"); $this->caching_simple[$id] = true; if ($id < 0) { if ($this->isSupergroup($id)) { @@ -530,7 +495,7 @@ trait PeerHandler if (isset($this->chats[$id])) { if (($this->chats[$id]['min'] ?? false) && $this->minDatabase->hasPeer($id) && !isset($this->caching_full_info[$id])) { $this->caching_full_info[$id] = true; - $this->logger->logger("Only have min peer for $id in database, trying to fetch full info"); + $this->logger->logger("Only have min peer for {$id} in database, trying to fetch full info"); try { if ($id < 0) { yield $this->methodCallAsyncRead('channels.getChannels', ['id' => [$this->genAll($this->chats[$id], $folder_id)['InputChannel']]], ['datacenter' => $this->datacenter->curdc]); @@ -545,7 +510,6 @@ trait PeerHandler unset($this->caching_full_info[$id]); } } - try { return $this->genAll($this->chats[$id], $folder_id); } catch (\danog\MadelineProto\Exception $e) { @@ -558,56 +522,50 @@ trait PeerHandler } if (!isset($this->settings['pwr']['requests']) || $this->settings['pwr']['requests'] === true && $recursive) { $dbres = []; - try { - $dbres = \json_decode(yield $this->datacenter->fileGetContents('https://id.pwrtelegram.xyz/db/getusername?id='.$id), true); + $dbres = \json_decode(yield $this->datacenter->fileGetContents('https://id.pwrtelegram.xyz/db/getusername?id=' . $id), true); } catch (\Throwable $e) { $this->logger->logger($e); } if (isset($dbres['ok']) && $dbres['ok']) { - yield $this->resolveUsername('@'.$dbres['result']); - - return yield $this->getInfo($id, false); + yield from $this->resolveUsername('@' . $dbres['result']); + return yield from $this->getInfo($id, false); } } if ($tried_simple && isset($this->caching_possible_username[$id])) { - $this->logger->logger("No access hash with $id, trying to fetch by username..."); - + $this->logger->logger("No access hash with {$id}, trying to fetch by username..."); $user = $this->caching_possible_username[$id]; unset($this->caching_possible_username[$id]); - - return yield $this->getInfo($user); + return yield from $this->getInfo($user); } - throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database'); } - if (\preg_match('@(?:t|telegram)\.(?:me|dog)/(joinchat/)?([a-z0-9_-]*)@i', $id, $matches)) { + if (\preg_match('@(?:t|telegram)\\.(?:me|dog)/(joinchat/)?([a-z0-9_-]*)@i', $id, $matches)) { if ($matches[1] === '') { $id = $matches[2]; } else { $invite = yield $this->methodCallAsyncRead('messages.checkChatInvite', ['hash' => $matches[2]], ['datacenter' => $this->datacenter->curdc]); if (isset($invite['chat'])) { - return yield $this->getInfo($invite['chat']); + return yield from $this->getInfo($invite['chat']); } throw new \danog\MadelineProto\Exception('You have not joined this chat'); } } $id = \strtolower(\str_replace('@', '', $id)); if ($id === 'me') { - return yield $this->getInfo($this->authorization['user']['id']); + return yield from $this->getInfo($this->authorization['user']['id']); } if ($id === 'support') { if (!$this->supportUser) { yield $this->methodCallAsyncRead('help.getSupport', [], ['datacenter' => $this->settings['connection_settings']['default_dc']]); } - - return yield $this->getInfo($this->supportUser); + return yield from $this->getInfo($this->supportUser); } foreach ($this->chats as $bot_api_id => $chat) { if (isset($chat['username']) && \strtolower($chat['username']) === $id) { if ($chat['min'] ?? false && !isset($this->caching_full_info[$bot_api_id])) { $this->caching_full_info[$bot_api_id] = true; - $this->logger->logger("Only have min peer for $bot_api_id in database, trying to fetch full info"); + $this->logger->logger("Only have min peer for {$bot_api_id} in database, trying to fetch full info"); try { if ($bot_api_id < 0) { yield $this->methodCallAsyncRead('channels.getChannels', ['id' => [$this->genAll($this->chats[$bot_api_id], $folder_id)['InputChannel']]], ['datacenter' => $this->datacenter->curdc]); @@ -622,19 +580,15 @@ trait PeerHandler unset($this->caching_full_info[$bot_api_id]); } } - return $this->genAll($this->chats[$bot_api_id], $folder_id); } } if ($recursive) { - yield $this->resolveUsername($id); - - return yield $this->getInfo($id, false); + yield from $this->resolveUsername($id); + return yield from $this->getInfo($id, false); } - throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database'); } - private function genAll($constructor, $folder_id = null) { $res = [$this->TL->getConstructors()->findByPredicate($constructor['_'])['type'] => $constructor]; @@ -656,7 +610,7 @@ trait PeerHandler $res['InputNotifyPeer'] = ['_' => 'inputNotifyPeer', 'peer' => $res['InputPeer']]; $res['user_id'] = $constructor['id']; $res['bot_api_id'] = $constructor['id']; - $res['type'] = ($constructor['bot'] ?? false) ? 'bot' : 'user'; + $res['type'] = $constructor['bot'] ?? false ? 'bot' : 'user'; break; case 'chat': case 'chatForbidden': @@ -683,12 +637,12 @@ trait PeerHandler $res['InputChannel'] = ['_' => 'inputChannel', 'channel_id' => $constructor['id'], 'access_hash' => $constructor['access_hash'], 'min' => $constructor['min']]; $res['channel_id'] = $constructor['id']; $res['bot_api_id'] = $this->toSupergroup($constructor['id']); - $res['type'] = ($constructor['megagroup'] ?? false) ? 'supergroup' : 'channel'; + $res['type'] = $constructor['megagroup'] ?? false ? 'supergroup' : 'channel'; break; case 'channelForbidden': throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database'); default: - throw new \danog\MadelineProto\Exception('Invalid constructor given '.\var_export($constructor, true)); + throw new \danog\MadelineProto\Exception('Invalid constructor given ' . \var_export($constructor, true)); } if ($folder_id) { $res['FolderPeer'] = ['_' => 'folderPeer', 'peer' => $res['Peer'], 'folder_id' => $folder_id]; @@ -696,7 +650,6 @@ trait PeerHandler } return $res; } - /** * When were full info for this chat last cached. * @@ -708,7 +661,6 @@ trait PeerHandler { return isset($this->full_chats[$id]['last_update']) ? $this->full_chats[$id]['last_update'] : 0; } - /** * Get full info about peer, returns an FullInfo object. * @@ -720,7 +672,7 @@ trait PeerHandler */ public function getFullInfo($id): \Generator { - $partial = yield $this->getInfo($id); + $partial = (yield from $this->getInfo($id)); if (\time() - $this->fullChatLastUpdated($partial['bot_api_id']) < (isset($this->settings['peer']['full_info_cache_time']) ? $this->settings['peer']['full_info_cache_time'] : 0)) { return \array_merge($partial, $this->full_chats[$partial['bot_api_id']]); } @@ -737,17 +689,13 @@ trait PeerHandler $full = (yield $this->methodCallAsyncRead('channels.getFullChannel', ['channel' => $partial['InputChannel']], ['datacenter' => $this->datacenter->curdc]))['full_chat']; break; } - $res = []; $res['full'] = $full; $res['last_update'] = \time(); $this->full_chats[$partial['bot_api_id']] = $res; - - $partial = yield $this->getInfo($id); - + $partial = (yield from $this->getInfo($id)); return \array_merge($partial, $res); } - /** * Get full info about peer (including full list of channel members), returns a Chat object. * @@ -759,7 +707,7 @@ trait PeerHandler */ public function getPwrChat($id, $fullfetch = true, $send = true): \Generator { - $full = $fullfetch ? yield $this->getFullInfo($id) : yield $this->getInfo($id); + $full = $fullfetch ? yield from $this->getFullInfo($id) : (yield from $this->getInfo($id)); $res = ['id' => $full['bot_api_id'], 'type' => $full['type']]; switch ($full['type']) { case 'user': @@ -828,15 +776,15 @@ trait PeerHandler if (isset($res['participants']) && $fullfetch) { foreach ($res['participants'] as $key => $participant) { $newres = []; - $newres['user'] = yield $this->getPwrChat($participant['user_id'], false, true); + $newres['user'] = (yield from $this->getPwrChat($participant['user_id'], false, true)); if (isset($participant['inviter_id'])) { - $newres['inviter'] = yield $this->getPwrChat($participant['inviter_id'], false, true); + $newres['inviter'] = (yield from $this->getPwrChat($participant['inviter_id'], false, true)); } if (isset($participant['promoted_by'])) { - $newres['promoted_by'] = yield $this->getPwrChat($participant['promoted_by'], false, true); + $newres['promoted_by'] = (yield from $this->getPwrChat($participant['promoted_by'], false, true)); } if (isset($participant['kicked_by'])) { - $newres['kicked_by'] = yield $this->getPwrChat($participant['kicked_by'], false, true); + $newres['kicked_by'] = (yield from $this->getPwrChat($participant['kicked_by'], false, true)); } if (isset($participant['date'])) { $newres['date'] = $participant['date']; @@ -873,15 +821,14 @@ trait PeerHandler $limit = 200; $filters = ['channelParticipantsAdmins', 'channelParticipantsBots']; foreach ($filters as $filter) { - yield $this->fetchParticipants($full['InputChannel'], $filter, '', $total_count, $res); + yield from $this->fetchParticipants($full['InputChannel'], $filter, '', $total_count, $res); } $q = ''; - $filters = ['channelParticipantsSearch', 'channelParticipantsKicked', 'channelParticipantsBanned']; foreach ($filters as $filter) { - yield $this->recurseAlphabetSearchParticipants($full['InputChannel'], $filter, $q, $total_count, $res); + yield from $this->recurseAlphabetSearchParticipants($full['InputChannel'], $filter, $q, $total_count, $res); } - $this->logger->logger('Fetched '.\count($res['participants'])." out of $total_count"); + $this->logger->logger('Fetched ' . \count($res['participants']) . " out of {$total_count}"); $res['participants'] = \array_values($res['participants']); } if (!$fullfetch) { @@ -890,64 +837,55 @@ trait PeerHandler if ($fullfetch || $send) { $this->storeDb($res); } - return $res; } - - private function recurseAlphabetSearchParticipants($channel, $filter, $q, $total_count, &$res) + private function recurseAlphabetSearchParticipants($channel, $filter, $q, $total_count, &$res): \Generator { - if (!yield $this->fetchParticipants($channel, $filter, $q, $total_count, $res)) { + if (!(yield from $this->fetchParticipants($channel, $filter, $q, $total_count, $res))) { return false; } - for ($x = 'a'; $x !== 'aa' && $total_count > \count($res['participants']); $x++) { - yield $this->recurseAlphabetSearchParticipants($channel, $filter, $q.$x, $total_count, $res); + yield from $this->recurseAlphabetSearchParticipants($channel, $filter, $q . $x, $total_count, $res); } } - - private function fetchParticipants($channel, $filter, $q, $total_count, &$res) + private function fetchParticipants($channel, $filter, $q, $total_count, &$res): \Generator { $offset = 0; $limit = 200; $has_more = false; $cached = false; $last_count = -1; - do { try { $gres = yield $this->methodCallAsyncRead('channels.getParticipants', ['channel' => $channel, 'filter' => ['_' => $filter, 'q' => $q], 'offset' => $offset, 'limit' => $limit, 'hash' => $hash = $this->getParticipantsHash($channel, $filter, $q, $offset, $limit)], ['datacenter' => $this->datacenter->curdc, 'heavy' => true]); } catch (\danog\MadelineProto\RPCErrorException $e) { if ($e->rpc === 'CHAT_ADMIN_REQUIRED') { $this->logger->logger($e->rpc); - return $has_more; } throw $e; } - if ($cached = $gres['_'] === 'channels.channelParticipantsNotModified') { $gres = $this->fetchParticipantsCache($channel, $filter, $q, $offset, $limit); } else { $this->storeParticipantsCache($gres, $channel, $filter, $q, $offset, $limit); } - if ($last_count !== -1 && $last_count !== $gres['count']) { $has_more = true; } else { $last_count = $gres['count']; } - foreach ($gres['participants'] as $participant) { $newres = []; - $newres['user'] = yield $this->getPwrChat($participant['user_id'], false, true); + $newres['user'] = (yield from $this->getPwrChat($participant['user_id'], false, true)); if (isset($participant['inviter_id'])) { - $newres['inviter'] = yield $this->getPwrChat($participant['inviter_id'], false, true); + $newres['inviter'] = (yield from $this->getPwrChat($participant['inviter_id'], false, true)); } if (isset($participant['kicked_by'])) { - $newres['kicked_by'] = yield $this->getPwrChat($participant['kicked_by'], false, true); + $newres['kicked_by'] = (yield from $this->getPwrChat($participant['kicked_by'], false, true)); } if (isset($participant['promoted_by'])) { - $newres['promoted_by'] = yield $this->getPwrChat($participant['promoted_by'], false, true); + $newres['promoted_by'] = (yield from $this->getPwrChat($participant['promoted_by'], false, true)); } if (isset($participant['date'])) { $newres['date'] = $participant['date']; @@ -980,22 +918,18 @@ trait PeerHandler } $res['participants'][$participant['user_id']] = $newres; } - $this->logger->logger('Fetched '.\count($gres['participants'])." channel participants with filter $filter, query $q, offset $offset, limit $limit, hash $hash: ".($cached ? 'cached' : 'not cached').', '.($offset + \count($gres['participants'])).' participants out of '.$gres['count'].', in total fetched '.\count($res['participants']).' out of '.$total_count); + $this->logger->logger('Fetched ' . \count($gres['participants']) . " channel participants with filter {$filter}, query {$q}, offset {$offset}, limit {$limit}, hash {$hash}: " . ($cached ? 'cached' : 'not cached') . ', ' . ($offset + \count($gres['participants'])) . ' participants out of ' . $gres['count'] . ', in total fetched ' . \count($res['participants']) . ' out of ' . $total_count); $offset += \count($gres['participants']); } while (\count($gres['participants'])); - if ($offset === $limit) { return true; } - return $has_more; } - private function fetchParticipantsCache($channel, $filter, $q, $offset, $limit) { return $this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit]; } - private function storeParticipantsCache($gres, $channel, $filter, $q, $offset, $limit) { //return; @@ -1008,13 +942,11 @@ trait PeerHandler $gres['hash'] = \danog\MadelineProto\Tools::genVectorHash($ids); $this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit] = $gres; } - private function getParticipantsHash($channel, $filter, $q, $offset, $limit) { return isset($this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit]) ? $this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit]['hash'] : 0; } - - private function storeDb($res, $force = false) + private function storeDb($res, $force = false): \Generator { $settings = isset($this->settings['connection_settings'][$this->datacenter->curdc]) ? $this->settings['connection_settings'][$this->datacenter->curdc] : $this->settings['connection_settings']['all']; if (!isset($this->settings['pwr']) || $this->settings['pwr']['pwr'] === false || $settings['test_mode']) { @@ -1033,29 +965,22 @@ trait PeerHandler if (empty($this->qres)) { return false; } - try { $payload = \json_encode($this->qres); //$path = '/tmp/ids'.hash('sha256', $payload); //file_put_contents($path, $payload); $id = isset($this->authorization['user']['username']) ? $this->authorization['user']['username'] : $this->authorization['user']['id']; - - $request = new Request('https://id.pwrtelegram.xyz/db'.$this->settings['pwr']['db_token'].'/addnewmadeline?d=pls&from='.$id, 'POST'); + $request = new Request('https://id.pwrtelegram.xyz/db' . $this->settings['pwr']['db_token'] . '/addnewmadeline?d=pls&from=' . $id, 'POST'); $request->setHeader('content-type', 'application/json'); $request->setBody($payload); - - $result = yield ( - yield $this->datacenter->getHTTPClient()->request($request) - )->getBody()->buffer(); - - $this->logger->logger("============ $result =============", \danog\MadelineProto\Logger::VERBOSE); + $result = yield (yield $this->datacenter->getHTTPClient()->request($request))->getBody()->buffer(); + $this->logger->logger("============ {$result} =============", \danog\MadelineProto\Logger::VERBOSE); $this->qres = []; $this->last_stored = \time() + 10; } catch (\danog\MadelineProto\Exception $e) { - $this->logger->logger('======= COULD NOT STORE IN DB DUE TO '.$e->getMessage().' =============', \danog\MadelineProto\Logger::VERBOSE); + $this->logger->logger('======= COULD NOT STORE IN DB DUE TO ' . $e->getMessage() . ' =============', \danog\MadelineProto\Logger::VERBOSE); } } - /** * Resolve username (use getInfo instead). * @@ -1069,11 +994,10 @@ trait PeerHandler $this->caching_simple_username[$username] = true; $res = yield $this->methodCallAsyncRead('contacts.resolveUsername', ['username' => \str_replace('@', '', $username)], ['datacenter' => $this->datacenter->curdc]); } catch (\danog\MadelineProto\RPCErrorException $e) { - $this->logger->logger('Username resolution failed with error '.$e->getMessage(), \danog\MadelineProto\Logger::ERROR); + $this->logger->logger('Username resolution failed with error ' . $e->getMessage(), \danog\MadelineProto\Logger::ERROR); if (\strpos($e->rpc, 'FLOOD_WAIT_') === 0 || $e->rpc === 'AUTH_KEY_UNREGISTERED' || $e->rpc === 'USERNAME_INVALID') { throw $e; } - return false; } finally { if (isset($this->caching_simple_username[$username])) { @@ -1083,7 +1007,6 @@ trait PeerHandler if ($res['_'] === 'contacts.resolvedPeer') { return $res; } - return false; } } diff --git a/src/danog/MadelineProto/MTProtoTools/ReferenceDatabase.php b/src/danog/MadelineProto/MTProtoTools/ReferenceDatabase.php index 8f41fb69..dc3faa15 100644 --- a/src/danog/MadelineProto/MTProtoTools/ReferenceDatabase.php +++ b/src/danog/MadelineProto/MTProtoTools/ReferenceDatabase.php @@ -38,7 +38,6 @@ class ReferenceDatabase implements TLCallback const PHOTO_LOCATION_LOCATION = 2; // DEPRECATED: Reference from a location (can only be document location) const DOCUMENT_LOCATION_LOCATION = 0; - // Peer + photo ID const USER_PHOTO_ORIGIN = 0; // Peer (default photo ID) @@ -57,42 +56,15 @@ class ReferenceDatabase implements TLCallback const STICKER_SET_EMOTICON_ORIGIN = 8; // const WALLPAPER_ORIGIN = 9; - const LOCATION_CONTEXT = [ //'inputFileLocation' => self::PHOTO_LOCATION_LOCATION, // DEPRECATED 'inputDocumentFileLocation' => self::DOCUMENT_LOCATION, - 'inputPhotoFileLocation' => self::PHOTO_LOCATION, - 'inputPhoto' => self::PHOTO_LOCATION, - 'inputDocument' => self::DOCUMENT_LOCATION, - ]; - const METHOD_CONTEXT = [ - 'photos.updateProfilePhoto' => self::USER_PHOTO_ORIGIN, - 'photos.getUserPhotos' => self::USER_PHOTO_ORIGIN, - 'photos.uploadProfilePhoto' => self::USER_PHOTO_ORIGIN, - 'messages.getStickers' => self::STICKER_SET_EMOTICON_ORIGIN, - ]; - const CONSTRUCTOR_CONTEXT = [ - 'message' => self::MESSAGE_ORIGIN, - 'messageService' => self::MESSAGE_ORIGIN, - - 'chatFull' => self::PEER_PHOTO_ORIGIN, - 'channelFull' => self::PEER_PHOTO_ORIGIN, - 'chat' => self::PEER_PHOTO_ORIGIN, - 'channel' => self::PEER_PHOTO_ORIGIN, - - 'updateUserPhoto' => self::USER_PHOTO_ORIGIN, - 'user' => self::USER_PHOTO_ORIGIN, - 'userFull' => self::USER_PHOTO_ORIGIN, - - 'wallPaper' => self::WALLPAPER_ORIGIN, - - 'messages.savedGifs' => self::SAVED_GIFS_ORIGIN, - - 'messages.recentStickers' => self::STICKER_SET_RECENT_ORIGIN, - 'messages.favedStickers' => self::STICKER_SET_FAVED_ORIGIN, - 'messages.stickerSet' => self::STICKER_SET_ID_ORIGIN, - 'document' => self::STICKER_SET_ID_ORIGIN, + 'inputPhotoFileLocation' => self::PHOTO_LOCATION, + 'inputPhoto' => self::PHOTO_LOCATION, + 'inputDocument' => self::DOCUMENT_LOCATION, ]; + const METHOD_CONTEXT = ['photos.updateProfilePhoto' => self::USER_PHOTO_ORIGIN, 'photos.getUserPhotos' => self::USER_PHOTO_ORIGIN, 'photos.uploadProfilePhoto' => self::USER_PHOTO_ORIGIN, 'messages.getStickers' => self::STICKER_SET_EMOTICON_ORIGIN]; + const CONSTRUCTOR_CONTEXT = ['message' => self::MESSAGE_ORIGIN, 'messageService' => self::MESSAGE_ORIGIN, 'chatFull' => self::PEER_PHOTO_ORIGIN, 'channelFull' => self::PEER_PHOTO_ORIGIN, 'chat' => self::PEER_PHOTO_ORIGIN, 'channel' => self::PEER_PHOTO_ORIGIN, 'updateUserPhoto' => self::USER_PHOTO_ORIGIN, 'user' => self::USER_PHOTO_ORIGIN, 'userFull' => self::USER_PHOTO_ORIGIN, 'wallPaper' => self::WALLPAPER_ORIGIN, 'messages.savedGifs' => self::SAVED_GIFS_ORIGIN, 'messages.recentStickers' => self::STICKER_SET_RECENT_ORIGIN, 'messages.favedStickers' => self::STICKER_SET_FAVED_ORIGIN, 'messages.stickerSet' => self::STICKER_SET_ID_ORIGIN, 'document' => self::STICKER_SET_ID_ORIGIN]; /** * References indexed by location. * @@ -105,70 +77,56 @@ class ReferenceDatabase implements TLCallback private $API; private $refresh = false; private $refreshCount = 0; - public function __construct(MTProto $API) { $this->API = $API; $this->init(); } - public function __wakeup() { $this->init(); } - public function __sleep() { return ['db', 'API']; } - public function init() { foreach ($this->db as $key => $value) { - if ($key[0] === "0") { // Unsetting deprecated DOCUMENT_LOCATION_LOCATION + if ($key[0] === "0") { + // Unsetting deprecated DOCUMENT_LOCATION_LOCATION unset($this->db[$key]); } } } - public function getMethodCallbacks(): array { return \array_fill_keys(\array_keys(self::METHOD_CONTEXT), [[$this, 'addOriginMethod']]); } - public function getMethodBeforeCallbacks(): array { return \array_fill_keys(\array_keys(self::METHOD_CONTEXT), [[$this, 'addOriginMethodContext']]); } - public function getConstructorCallbacks(): array { - return \array_merge( - \array_fill_keys(['document', 'photo', 'fileLocation'], [[$this, 'addReference']]), - \array_fill_keys(\array_keys(self::CONSTRUCTOR_CONTEXT), [[$this, 'addOrigin']]), - ['document' => [[$this, 'addReference'], [$this, 'addOrigin']]] - ); + return \array_merge(\array_fill_keys(['document', 'photo', 'fileLocation'], [[$this, 'addReference']]), \array_fill_keys(\array_keys(self::CONSTRUCTOR_CONTEXT), [[$this, 'addOrigin']]), ['document' => [[$this, 'addReference'], [$this, 'addOrigin']]]); } - public function getConstructorBeforeCallbacks(): array { return \array_fill_keys(\array_keys(self::CONSTRUCTOR_CONTEXT), [[$this, 'addOriginContext']]); } - public function getConstructorSerializeCallbacks(): array { return \array_fill_keys(\array_keys(self::LOCATION_CONTEXT), [$this, 'populateReference']); } - public function getTypeMismatchCallbacks(): array { return []; } - public function reset() { if ($this->cacheContexts) { - $this->API->logger->logger('Found '.\count($this->cacheContexts).' pending contexts', \danog\MadelineProto\Logger::ERROR); + $this->API->logger->logger('Found ' . \count($this->cacheContexts) . ' pending contexts', \danog\MadelineProto\Logger::ERROR); $this->cacheContexts = []; } if ($this->cache) { @@ -176,7 +134,6 @@ class ReferenceDatabase implements TLCallback $this->cache = []; } } - public function addReference(array $location) { if (!$this->cacheContexts) { @@ -189,18 +146,15 @@ class ReferenceDatabase implements TLCallback if ($frame['args'][1]['subtype'] === $previous) { continue; } - $frames[] = $frame['args'][1]['subtype']; $previous = $frame['args'][1]['subtype']; } elseif (isset($frame['args'][1]['type'])) { if ($frame['args'][1]['type'] === '') { break; } - if ($frame['args'][1]['type'] === $previous) { continue; } - $frames[] = $frame['args'][1]['type']; $previous = $frame['args'][1]['type']; } @@ -209,15 +163,13 @@ class ReferenceDatabase implements TLCallback $frames = \array_reverse($frames); $tl_trace = \array_shift($frames); foreach ($frames as $frame) { - $tl_trace .= "['".$frame."']"; + $tl_trace .= "['" . $frame . "']"; } $this->API->logger->logger($tl_trace, \danog\MadelineProto\Logger::ERROR); - return false; } if (!isset($location['file_reference'])) { $this->API->logger->logger("Object {$location['_']} does not have reference", \danog\MadelineProto\Logger::ERROR); - return false; } $key = \count($this->cacheContexts) - 1; @@ -232,27 +184,24 @@ class ReferenceDatabase implements TLCallback $locationType = self::PHOTO_LOCATION_LOCATION; break; default: - throw new Exception('Unknown location type provided: '.$location['_']); + throw new Exception('Unknown location type provided: ' . $location['_']); } - $this->API->logger->logger("Caching reference from location of type $locationType from {$location['_']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); + $this->API->logger->logger("Caching reference from location of type {$locationType} from {$location['_']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); if (!isset($this->cache[$key])) { $this->cache[$key] = []; } $this->cache[$key][$this->serializeLocation($locationType, $location)] = (string) $location['file_reference']; - return true; } - public function addOriginContext(string $type) { if (!isset(self::CONSTRUCTOR_CONTEXT[$type])) { - throw new \danog\MadelineProto\Exception("Unknown origin type provided: $type"); + throw new \danog\MadelineProto\Exception("Unknown origin type provided: {$type}"); } $originContext = self::CONSTRUCTOR_CONTEXT[$type]; - $this->API->logger->logger("Adding origin context $originContext for {$type}!", \danog\MadelineProto\Logger::ULTRA_VERBOSE); + $this->API->logger->logger("Adding origin context {$originContext} for {$type}!", \danog\MadelineProto\Logger::ULTRA_VERBOSE); $this->cacheContexts[] = $originContext; } - public function addOrigin(array $data = []) { $key = \count($this->cacheContexts) - 1; @@ -261,8 +210,7 @@ class ReferenceDatabase implements TLCallback } $originType = \array_pop($this->cacheContexts); if (!isset($this->cache[$key])) { - $this->API->logger->logger("Removing origin context $originType for {$data['_']}, nothing in the reference cache!", \danog\MadelineProto\Logger::ULTRA_VERBOSE); - + $this->API->logger->logger("Removing origin context {$originType} for {$data['_']}, nothing in the reference cache!", \danog\MadelineProto\Logger::ULTRA_VERBOSE); return; } $cache = $this->cache[$key]; @@ -316,12 +264,10 @@ class ReferenceDatabase implements TLCallback if (!isset($this->cache[$key])) { $this->cache[$key] = []; } - foreach ($cache as $location => $reference) { $this->cache[$key][$location] = $reference; } - $this->API->logger->logger("Skipped origin $originType ({$data['_']}) for ".\count($cache).' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE); - + $this->API->logger->logger("Skipped origin {$originType} ({$data['_']}) for " . \count($cache) . ' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE); return; } break; @@ -334,19 +280,17 @@ class ReferenceDatabase implements TLCallback foreach ($cache as $location => $reference) { $this->storeReference($location, $reference, $originType, $origin); } - $this->API->logger->logger("Added origin $originType ({$data['_']}) to ".\count($cache).' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE); + $this->API->logger->logger("Added origin {$originType} ({$data['_']}) to " . \count($cache) . ' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE); } - public function addOriginMethodContext(string $type) { if (!isset(self::METHOD_CONTEXT[$type])) { throw new \danog\MadelineProto\Exception("Unknown origin type provided: {$type}"); } $originContext = self::METHOD_CONTEXT[$type]; - $this->API->logger->logger("Adding origin context $originContext for {$type}!", \danog\MadelineProto\Logger::ULTRA_VERBOSE); + $this->API->logger->logger("Adding origin context {$originContext} for {$type}!", \danog\MadelineProto\Logger::ULTRA_VERBOSE); $this->cacheContexts[] = $originContext; } - public function addOriginMethod(array $data, array $res) { $key = \count($this->cacheContexts) - 1; @@ -355,8 +299,7 @@ class ReferenceDatabase implements TLCallback } $originType = \array_pop($this->cacheContexts); if (!isset($this->cache[$key])) { - $this->API->logger->logger("Removing origin context $originType for {$data['_']}, nothing in the reference cache!", \danog\MadelineProto\Logger::ULTRA_VERBOSE); - + $this->API->logger->logger("Removing origin context {$originType} for {$data['_']}, nothing in the reference cache!", \danog\MadelineProto\Logger::ULTRA_VERBOSE); return; } $cache = $this->cache[$key]; @@ -384,16 +327,13 @@ class ReferenceDatabase implements TLCallback foreach ($res['photos'] as $photo) { $origin['max_id'] = $photo['id']; $dc_id = $photo['dc_id']; - $location = $this->serializeLocation(self::PHOTO_LOCATION, $photo); if (isset($cache[$location])) { $reference = $cache[$location]; unset($cache[$location]); - $this->storeReference($location, $reference, $originType, $origin); $count++; } - if (isset($photo['sizes'])) { foreach ($photo['sizes'] as $size) { if (isset($size['location'])) { @@ -409,8 +349,7 @@ class ReferenceDatabase implements TLCallback } } } - $this->API->logger->logger("Added origin $originType ({$data['_']}) to $count references", \danog\MadelineProto\Logger::ULTRA_VERBOSE); - + $this->API->logger->logger("Added origin {$originType} ({$data['_']}) to {$count} references", \danog\MadelineProto\Logger::ULTRA_VERBOSE); return; case 'messages.getStickers': $origin['emoticon'] = $body['emoticon']; @@ -421,9 +360,8 @@ class ReferenceDatabase implements TLCallback foreach ($cache as $location => $reference) { $this->storeReference($location, $reference, $originType, $origin); } - $this->API->logger->logger("Added origin $originType ({$data['_']}) to ".\count($cache).' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE); + $this->API->logger->logger("Added origin {$originType} ({$data['_']}) to " . \count($cache) . ' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE); } - public function storeReference(string $location, string $reference, int $originType, array $origin) { if (!isset($this->db[$location])) { @@ -431,17 +369,14 @@ class ReferenceDatabase implements TLCallback } $this->db[$location]['reference'] = $reference; $this->db[$location]['origins'][$originType] = $origin; - if ($this->refresh) { $this->refreshed[$location] = true; } - $key = \count($this->cacheContexts) - 1; if ($key >= 0) { $this->cache[$key][$location] = $reference; } } - public function refreshNext($refresh = false) { if ($this->refreshCount === 1 && !$refresh) { @@ -459,23 +394,18 @@ class ReferenceDatabase implements TLCallback $this->refreshCount--; } } - public function refreshReference(int $locationType, array $location) { return $this->refreshReferenceInternal($this->serializeLocation($locationType, $location)); } - - public function refreshReferenceInternal(string $location) + public function refreshReferenceInternal(string $location): \Generator { if (isset($this->refreshed[$location])) { $this->API->logger->logger('Reference already refreshed!', \danog\MadelineProto\Logger::VERBOSE); - return $this->db[$location]['reference']; } - \ksort($this->db[$location]['origins']); $count = 0; - foreach ($this->db[$location]['origins'] as $originType => &$origin) { $count++; $this->API->logger->logger("Try {$count} refreshing file reference with origin type {$originType}", \danog\MadelineProto\Logger::VERBOSE); @@ -521,67 +451,54 @@ class ReferenceDatabase implements TLCallback yield $this->API->methodCallAsyncRead('account.getWallPapers', $origin, ['datacenter' => $this->API->settings['connection_settings']['default_dc']]); break; default: - throw new \danog\MadelineProto\Exception("Unknown origin type $originType"); + throw new \danog\MadelineProto\Exception("Unknown origin type {$originType}"); } if (isset($this->refreshed[$location])) { return $this->db[$location]['reference']; } } - throw new Exception('Did not refresh reference'); } - - public function populateReference(array $object) + public function populateReference(array $object): \Generator { $object['file_reference'] = yield $this->getReference(self::LOCATION_CONTEXT[$object['_']], $object); - return $object; } - public function getReference(int $locationType, array $location) { $locationString = $this->serializeLocation($locationType, $location); if (!isset($this->db[$locationString]['reference'])) { if (isset($location['file_reference'])) { - $this->API->logger->logger("Using outdated file reference for location of type $locationType object {$location['_']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); - + $this->API->logger->logger("Using outdated file reference for location of type {$locationType} object {$location['_']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); return $location['file_reference']; } - if (!$this->refresh) { - $this->API->logger->logger("Using null file reference for location of type $locationType object {$location['_']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); - + $this->API->logger->logger("Using null file reference for location of type {$locationType} object {$location['_']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); return ''; } - - throw new \danog\MadelineProto\Exception("Could not find file reference for location of type $locationType object {$location['_']}"); + throw new \danog\MadelineProto\Exception("Could not find file reference for location of type {$locationType} object {$location['_']}"); } - $this->API->logger->logger("Getting file reference for location of type $locationType object {$location['_']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); - + $this->API->logger->logger("Getting file reference for location of type {$locationType} object {$location['_']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); if ($this->refresh) { return $this->refreshReferenceInternal($locationString); } - return $this->db[$locationString]['reference']; } - private function serializeLocation(int $locationType, array $location) { switch ($locationType) { case self::DOCUMENT_LOCATION: case self::PHOTO_LOCATION: - return $locationType.(\is_int($location['id']) ? \danog\MadelineProto\Tools::packSignedLong($location['id']) : $location['id']); + return $locationType . (\is_int($location['id']) ? \danog\MadelineProto\Tools::packSignedLong($location['id']) : $location['id']); case self::PHOTO_LOCATION_LOCATION: $dc_id = \danog\MadelineProto\Tools::packSignedInt($location['dc_id']); $volume_id = \is_int($location['volume_id']) ? \danog\MadelineProto\Tools::packSignedLong($location['volume_id']) : $location['volume_id']; $local_id = \danog\MadelineProto\Tools::packSignedInt($location['local_id']); - - return $locationType.$dc_id.$volume_id.$local_id; + return $locationType . $dc_id . $volume_id . $local_id; } } - public function __debugInfo() { - return ['ReferenceDatabase instance '.\spl_object_hash($this)]; + return ['ReferenceDatabase instance ' . \spl_object_hash($this)]; } } diff --git a/src/danog/MadelineProto/MTProtoTools/UpdateHandler.php b/src/danog/MadelineProto/MTProtoTools/UpdateHandler.php index 2fa3f2eb..219dbadb 100644 --- a/src/danog/MadelineProto/MTProtoTools/UpdateHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/UpdateHandler.php @@ -34,7 +34,6 @@ trait UpdateHandler private $channels_state; public $updates = []; public $updates_key = 0; - /** * PWR update handler. * @@ -56,7 +55,6 @@ trait UpdateHandler \in_array($this->settings['pwr']['updateHandler'], [['danog\\MadelineProto\\API', 'getUpdatesUpdateHandler'], 'getUpdatesUpdateHandler']) ? $this->getUpdatesUpdateHandler($update) : $this->settings['pwr']['updateHandler']($update); } } - /** * Getupdates update handler. * @@ -73,7 +71,6 @@ trait UpdateHandler } $this->updates[$this->updates_key++] = $update; } - /** * Get updates. * @@ -92,9 +89,7 @@ trait UpdateHandler if (!$this->settings['updates']['run_callback']) { $this->settings['updates']['run_callback'] = true; } - $params = \array_merge(self::DEFAULT_GETUPDATES_PARAMS, $params); - if (empty($this->updates)) { $this->update_deferred = new Deferred(); if (!$params['timeout']) { @@ -102,11 +97,9 @@ trait UpdateHandler } yield \danog\MadelineProto\Tools::first([$this->waitUpdate(), \danog\MadelineProto\Tools::sleep($params['timeout'])]); } - if (empty($this->updates)) { return []; } - if ($params['offset'] < 0) { $params['offset'] = \array_reverse(\array_keys((array) $this->updates))[\abs($params['offset']) - 1]; } @@ -118,13 +111,10 @@ trait UpdateHandler $updates[] = ['update_id' => $key, 'update' => $value]; } } - return $updates; } - public $update_resolved = false; public $update_deferred; - /** * Wait for update. * @@ -141,7 +131,6 @@ trait UpdateHandler $this->update_resolved = false; $this->update_deferred = new Deferred(); } - /** * Signal update. * @@ -161,8 +150,6 @@ trait UpdateHandler } }); } - - /** * Check message ID. * @@ -177,7 +164,6 @@ trait UpdateHandler if (!isset($message['to_id'])) { return true; } - try { $peer_id = $this->getId($message['to_id']); } catch (\danog\MadelineProto\Exception $e) { @@ -188,13 +174,10 @@ trait UpdateHandler $message_id = $message['id']; if (!isset($this->msg_ids[$peer_id]) || $message_id > $this->msg_ids[$peer_id]) { $this->msg_ids[$peer_id] = $message_id; - return true; } - return false; } - /** * Get channel state. * @@ -202,16 +185,14 @@ trait UpdateHandler * * @return UpdatesState|UpdatesState[] */ - public function loadUpdateState() + public function loadUpdateState(): \Generator { if (!$this->got_state) { $this->got_state = true; - $this->channels_state->get(false, yield $this->getUpdatesState()); + $this->channels_state->get(false, yield from $this->getUpdatesState()); } - return $this->channels_state->get(false); } - /** * Load channel state. * @@ -226,7 +207,6 @@ trait UpdateHandler { return $this->channels_state->get($channelId, $init); } - /** * Get channel states. * @@ -238,7 +218,6 @@ trait UpdateHandler { return $this->channels_state; } - /** * Get update state. * @@ -250,11 +229,8 @@ trait UpdateHandler { $data = yield $this->methodCallAsyncRead('updates.getState', [], ['datacenter' => $this->settings['connection_settings']['default_dc']]); yield $this->getCdnConfig($this->settings['connection_settings']['default_dc']); - return $data; } - - /** * Undocumented function. * @@ -273,16 +249,13 @@ trait UpdateHandler if ($actual_updates) { $updates = $actual_updates; } - $this->logger->logger('Parsing updates ('.$updates['_'].') received via the socket...', \danog\MadelineProto\Logger::VERBOSE); + $this->logger->logger('Parsing updates (' . $updates['_'] . ') received via the socket...', \danog\MadelineProto\Logger::VERBOSE); switch ($updates['_']) { case 'updates': case 'updatesCombined': $result = []; foreach ($updates['updates'] as $key => $update) { - if ($update['_'] === 'updateNewMessage' || $update['_'] === 'updateReadMessagesContents' || - $update['_'] === 'updateEditMessage' || $update['_'] === 'updateDeleteMessages' || - $update['_'] === 'updateReadHistoryInbox' || $update['_'] === 'updateReadHistoryOutbox' || - $update['_'] === 'updateWebPage' || $update['_'] === 'updateMessageID') { + if ($update['_'] === 'updateNewMessage' || $update['_'] === 'updateReadMessagesContents' || $update['_'] === 'updateEditMessage' || $update['_'] === 'updateDeleteMessages' || $update['_'] === 'updateReadHistoryInbox' || $update['_'] === 'updateReadHistoryOutbox' || $update['_'] === 'updateWebPage' || $update['_'] === 'updateMessageID') { $result[yield $this->feeders[false]->feedSingle($update)] = true; unset($updates['updates'][$key]); } @@ -308,20 +281,18 @@ trait UpdateHandler $updates['user_id'] = (yield $this->getInfo($updates['request']['body']['peer']))['bot_api_id']; $updates['message'] = $updates['request']['body']['message']; unset($updates['request']); - // no break + // no break case 'updateShortMessage': case 'updateShortChatMessage': $from_id = isset($updates['from_id']) ? $updates['from_id'] : ($updates['out'] ? $this->authorization['user']['id'] : $updates['user_id']); $to_id = isset($updates['chat_id']) ? -$updates['chat_id'] : ($updates['out'] ? $updates['user_id'] : $this->authorization['user']['id']); - if (!yield $this->peerIsset($from_id) || !yield $this->peerIsset($to_id) || isset($updates['via_bot_id']) && !yield $this->peerIsset($updates['via_bot_id']) || isset($updates['entities']) && !yield $this->entitiesPeerIsset($updates['entities']) || isset($updates['fwd_from']) && !yield $this->fwdPeerIsset($updates['fwd_from'])) { + if (!(yield from $this->peerIsset($from_id) || !(yield from $this->peerIsset($to_id) || isset($updates['via_bot_id']) && !(yield from $this->peerIsset($updates['via_bot_id']) || isset($updates['entities']) && !(yield from $this->entitiesPeerIsset($updates['entities']) || isset($updates['fwd_from']) && !yield $this->fwdPeerIsset($updates['fwd_from'])))))) { yield $this->updaters[false]->resume(); - return; } $message = $updates; $message['_'] = 'message'; $message['from_id'] = $from_id; - try { $message['to_id'] = (yield $this->getInfo($to_id))['Peer']; } catch (\danog\MadelineProto\Exception $e) { @@ -340,7 +311,7 @@ trait UpdateHandler $this->updaters[false]->resume(); break; default: - throw new \danog\MadelineProto\ResponseException('Unrecognized update received: '.\var_export($updates, true)); + throw new \danog\MadelineProto\ResponseException('Unrecognized update received: ' . \var_export($updates, true)); break; } } @@ -368,13 +339,11 @@ trait UpdateHandler $this->logger->logger('Got new dc options', \danog\MadelineProto\Logger::VERBOSE); $this->config['dc_options'] = $update['dc_options']; yield $this->parseConfig(); - return; } if ($update['_'] === 'updatePhoneCall') { if (!\class_exists('\\danog\\MadelineProto\\VoIP')) { $this->logger->logger('The php-libtgvoip extension is required to accept and manage calls. See daniil.it/MadelineProto for more info.', \danog\MadelineProto\Logger::WARNING); - return; } switch ($update['phone_call']['_']) { @@ -403,54 +372,50 @@ trait UpdateHandler if (!isset($this->calls[$update['phone_call']['id']])) { return; } - return $this->calls[$update['phone_call']['id']]->discard($update['phone_call']['reason'], [], $update['phone_call']['need_debug']); } } if ($update['_'] === 'updateNewEncryptedMessage' && !isset($update['message']['decrypted_message'])) { if (isset($update['qts'])) { - $cur_state = yield $this->loadUpdateState(); + $cur_state = (yield from $this->loadUpdateState()); if ($cur_state->qts() === -1) { $cur_state->qts($update['qts']); } if ($update['qts'] < $cur_state->qts()) { - $this->logger->logger('Duplicate update. update qts: '.$update['qts'].' <= current qts '.$cur_state->qts().', chat id: '.$update['message']['chat_id'], \danog\MadelineProto\Logger::ERROR); - + $this->logger->logger('Duplicate update. update qts: ' . $update['qts'] . ' <= current qts ' . $cur_state->qts() . ', chat id: ' . $update['message']['chat_id'], \danog\MadelineProto\Logger::ERROR); return false; } if ($update['qts'] > $cur_state->qts() + 1) { - $this->logger->logger('Qts hole. Fetching updates manually: update qts: '.$update['qts'].' > current qts '.$cur_state->qts().'+1, chat id: '.$update['message']['chat_id'], \danog\MadelineProto\Logger::ERROR); + $this->logger->logger('Qts hole. Fetching updates manually: update qts: ' . $update['qts'] . ' > current qts ' . $cur_state->qts() . '+1, chat id: ' . $update['message']['chat_id'], \danog\MadelineProto\Logger::ERROR); $this->updaters[false]->resumeDefer(); - return false; } - $this->logger->logger('Applying qts: '.$update['qts'].' over current qts '.$cur_state->qts().', chat id: '.$update['message']['chat_id'], \danog\MadelineProto\Logger::VERBOSE); + $this->logger->logger('Applying qts: ' . $update['qts'] . ' over current qts ' . $cur_state->qts() . ', chat id: ' . $update['message']['chat_id'], \danog\MadelineProto\Logger::VERBOSE); yield $this->methodCallAsyncRead('messages.receivedQueue', ['max_qts' => $cur_state->qts($update['qts'])], ['datacenter' => $this->settings['connection_settings']['default_dc']]); } yield $this->handleEncryptedUpdate($update); - return; } /* - if ($update['_'] === 'updateEncryptedChatTyping') { - $update = ['_' => 'updateUserTyping', 'user_id' => $this->encrypted_chats[$update['chat_id']]['user_id'], 'action' => ['_' => 'sendMessageTypingAction']]; - } - */ + if ($update['_'] === 'updateEncryptedChatTyping') { + $update = ['_' => 'updateUserTyping', 'user_id' => $this->encrypted_chats[$update['chat_id']]['user_id'], 'action' => ['_' => 'sendMessageTypingAction']]; + } + */ if ($update['_'] === 'updateEncryption') { switch ($update['chat']['_']) { case 'encryptedChatRequested': if ($this->settings['secret_chats']['accept_chats'] === false || \is_array($this->settings['secret_chats']['accept_chats']) && !\in_array($update['chat']['admin_id'], $this->settings['secret_chats']['accept_chats'])) { return; } - $this->logger->logger('Accepting secret chat '.$update['chat']['id'], \danog\MadelineProto\Logger::NOTICE); + $this->logger->logger('Accepting secret chat ' . $update['chat']['id'], \danog\MadelineProto\Logger::NOTICE); try { yield $this->acceptSecretChat($update['chat']); } catch (RPCErrorException $e) { - $this->logger->logger("Error while accepting secret chat: $e", Logger::FATAL_ERROR); + $this->logger->logger("Error while accepting secret chat: {$e}", Logger::FATAL_ERROR); } break; case 'encryptedChatDiscarded': - $this->logger->logger('Deleting secret chat '.$update['chat']['id'].' because it was revoked by the other user', \danog\MadelineProto\Logger::NOTICE); + $this->logger->logger('Deleting secret chat ' . $update['chat']['id'] . ' because it was revoked by the other user', \danog\MadelineProto\Logger::NOTICE); if (isset($this->secret_chats[$update['chat']['id']])) { unset($this->secret_chats[$update['chat']['id']]); } @@ -460,17 +425,15 @@ trait UpdateHandler if (isset($this->temp_rekeyed_secret_chats[$update['chat']['id']])) { unset($this->temp_rekeyed_secret_chats[$update['chat']['id']]); } - break; case 'encryptedChat': - $this->logger->logger('Completing creation of secret chat '.$update['chat']['id'], \danog\MadelineProto\Logger::NOTICE); + $this->logger->logger('Completing creation of secret chat ' . $update['chat']['id'], \danog\MadelineProto\Logger::NOTICE); yield $this->completeSecretChat($update['chat']); break; } //$this->logger->logger($update, \danog\MadelineProto\Logger::NOTICE); } //if ($update['_'] === 'updateServiceNotification' && strpos($update['type'], 'AUTH_KEY_DROP_') === 0) { - //} if (!$this->settings['updates']['handle_updates']) { return; @@ -488,7 +451,6 @@ trait UpdateHandler $this->getUpdatesUpdateHandler($update); } } - /** * Send update to webhook. * @@ -502,23 +464,20 @@ trait UpdateHandler //$this->logger->logger($update, $payload, json_last_error()); if ($payload === '') { $this->logger->logger('EMPTY UPDATE'); - return; } - \danog\MadelineProto\Tools::callFork((function () use ($payload) { + \danog\MadelineProto\Tools::callFork((function () use ($payload): \Generator { $request = new Request($this->hook_url, 'POST'); $request->setHeader('content-type', 'application/json'); $request->setBody($payload); - $result = yield (yield $this->datacenter->getHTTPClient()->request($request))->getBody()->buffer(); - - $this->logger->logger('Result of webhook query is '.$result, \danog\MadelineProto\Logger::NOTICE); + $this->logger->logger('Result of webhook query is ' . $result, \danog\MadelineProto\Logger::NOTICE); $result = \json_decode($result, true); if (\is_array($result) && isset($result['method']) && $result['method'] != '' && \is_string($result['method'])) { try { $this->logger->logger('Reverse webhook command returned', yield $this->methodCallAsyncRead($result['method'], $result, ['datacenter' => $this->datacenter->curdc])); } catch (\Throwable $e) { - $this->logger->logger("Reverse webhook command returned: $e"); + $this->logger->logger("Reverse webhook command returned: {$e}"); } } })()); diff --git a/src/danog/MadelineProto/MTProtoTools/UpdatesState.php b/src/danog/MadelineProto/MTProtoTools/UpdatesState.php index a992a734..2fc58d2a 100644 --- a/src/danog/MadelineProto/MTProtoTools/UpdatesState.php +++ b/src/danog/MadelineProto/MTProtoTools/UpdatesState.php @@ -48,21 +48,18 @@ class UpdatesState * @var int */ private $date = 1; - /** * Channel ID. * * @var int|bool */ private $channelId; - /** * Is busy? * * @var bool */ private $syncLoading = false; - /** * Init function. * @@ -74,7 +71,6 @@ class UpdatesState $this->channelId = $channelId; $this->update($init); } - /** * Sleep function. * @@ -84,7 +80,6 @@ class UpdatesState { return $this->channelId ? ['pts', 'channelId'] : ['pts', 'qts', 'seq', 'date', 'channelId']; } - /** * Is this state relative to a channel? * @@ -94,7 +89,6 @@ class UpdatesState { return (bool) $this->channelId; } - /** * Get the channel ID. * @@ -104,7 +98,6 @@ class UpdatesState { return $this->channelId; } - /** * Are we currently busy? * @@ -117,10 +110,8 @@ class UpdatesState if ($set !== null) { $this->syncLoading = $set; } - return $this->syncLoading; } - /** * Update multiple parameters. * @@ -135,10 +126,8 @@ class UpdatesState $this->{$param}($init[$param]); } } - return $this; } - /** * Get/set PTS. * @@ -151,10 +140,8 @@ class UpdatesState if ($set !== 0 && $set > $this->pts) { $this->pts = $set; } - return $this->pts; } - /** * Get/set QTS. * @@ -167,10 +154,8 @@ class UpdatesState if ($set !== 0 && $set > $this->qts) { $this->qts = $set; } - return $this->qts; } - /** * Get/set seq. * @@ -183,10 +168,8 @@ class UpdatesState if ($set !== 0 && $set > $this->seq) { $this->seq = $set; } - return $this->seq; } - /** * Get/set date. * @@ -199,10 +182,8 @@ class UpdatesState if ($set !== 0 && $set > $this->date) { $this->date = $set; } - return $this->date; } - /** * Check validity of PTS contained in update. * @@ -214,7 +195,6 @@ class UpdatesState { return $update['pts'] - ($this->pts + $update['pts_count']); } - /** * Check validity of seq contained in update. * diff --git a/src/danog/MadelineProto/Magic.php b/src/danog/MadelineProto/Magic.php index c558edbf..9ff784c0 100644 --- a/src/danog/MadelineProto/Magic.php +++ b/src/danog/MadelineProto/Magic.php @@ -25,7 +25,6 @@ use Amp\DoH\Rfc8484StubResolver; use Amp\Loop; use Amp\Loop\Driver; use ReflectionClass; - use function Amp\ByteStream\getInputBufferStream; use function Amp\ByteStream\getStdin; use function Amp\Dns\resolver; @@ -105,7 +104,6 @@ class Magic * @var int */ public static $pid; - /** * Whether we've inited all static constants. * @@ -208,21 +206,18 @@ class Magic * @var boolean */ public static $zerowebhost = false; - /** * Whether a signal was sent to the processand the system must shut down. * * @var boolean */ public static $signaled = false; - /** * Encoded emojis. * * @var string */ 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. * @@ -265,7 +260,6 @@ class Magic self::$twoe2048 = new \tgseclib\Math\BigInteger('32317006071311007300714876688669951960444102669715484032130345427524655138867890893197201411522913463688717960921898019494119559150490921095088152386448283120630877367300996091750197750389652106796057638384067568276792218642619756161838094338476170470581645852036305042887575891541065808607552399123930385521914333389668342420684974786564569494856176035326322058077805659331026192708460314150258592864177116725943603718461857357598351152301645904403697613233287231227125684710820209725157101726931323469678542580656697935045997268352998638215525166389437335543602135433229604645318478604952148193555853611059596230656'); self::$twozerotwosixone = new \tgseclib\Math\BigInteger(20261); self::$zeroeight = new \tgseclib\Math\BigInteger('2147483648'); - try { self::$isatty = \defined('STDOUT') && \function_exists('posix_isatty') && \posix_isatty(STDOUT); } catch (\danog\MadelineProto\Exception $e) { @@ -273,14 +267,14 @@ class Magic self::$altervista = isset($_SERVER['SERVER_ADMIN']) && \strpos($_SERVER['SERVER_ADMIN'], 'altervista.org'); self::$zerowebhost = isset($_SERVER['SERVER_ADMIN']) && \strpos($_SERVER['SERVER_ADMIN'], '000webhost.io'); self::$can_getmypid = !self::$altervista && !self::$zerowebhost; - self::$revision = @\file_get_contents(__DIR__.'/../../../.git/refs/heads/master'); + self::$revision = @\file_get_contents(__DIR__ . '/../../../.git/refs/heads/master'); if (self::$revision) { self::$revision = \trim(self::$revision); $latest = @\file_get_contents('https://phar.madelineproto.xyz/release'); if ($latest) { $latest = self::$revision === \trim($latest) ? '' : ' (AN UPDATE IS REQUIRED)'; } - self::$revision = 'Revision: '.self::$revision.$latest; + self::$revision = 'Revision: ' . self::$revision . $latest; } self::$can_parallel = false; if (PHP_SAPI === 'cli' && !(\class_exists(\Phar::class) && \Phar::running())) { @@ -308,7 +302,6 @@ class Magic } $backtrace = \debug_backtrace(0); self::$script_cwd = self::$cwd = \dirname(\end($backtrace)['file']); - try { self::$cwd = \getcwd(); self::$can_getcwd = true; @@ -327,25 +320,24 @@ class Magic })); } /*if (!self::$altervista && !self::$zerowebhost) { - $DohConfig = new DoHConfig( - [ - new Nameserver('https://mozilla.cloudflare-dns.com/dns-query'), - new Nameserver('https://dns.google/resolve'), - ] - ); - resolver(new Rfc8484StubResolver($DohConfig)); - }*/ + $DohConfig = new DoHConfig( + [ + new Nameserver('https://mozilla.cloudflare-dns.com/dns-query'), + new Nameserver('https://dns.google/resolve'), + ] + ); + resolver(new Rfc8484StubResolver($DohConfig)); + }*/ if (PHP_SAPI !== 'cli') { try { \error_reporting(E_ALL); \ini_set('log_errors', 1); - \ini_set('error_log', Magic::$script_cwd.'/MadelineProto.log'); + \ini_set('error_log', Magic::$script_cwd . '/MadelineProto.log'); \error_log('Enabled PHP logging'); } catch (\danog\MadelineProto\Exception $e) { //$this->logger->logger('Could not enable PHP logging'); } } - $res = \json_decode(@\file_get_contents('https://rpc.madelineproto.xyz/v3.json'), true); if (isset($res['ok']) && $res['ok']) { RPCErrorException::$errorMethodMap = $res['result']; @@ -354,7 +346,6 @@ class Magic self::$inited = true; } } - /** * Check if this is a POSIX fork of the main PHP process. * @@ -368,18 +359,15 @@ class Magic if (!self::$can_getmypid) { return false; } - try { if (self::$pid === null) { self::$pid = \getmypid(); } - return self::$isFork = self::$pid !== \getmypid(); } catch (\danog\MadelineProto\Exception $e) { return self::$can_getmypid = false; } } - /** * Get current working directory. * @@ -389,7 +377,6 @@ class Magic { return self::$can_getcwd ? \getcwd() : self::$cwd; } - /** * Shutdown system. * @@ -406,7 +393,6 @@ class Magic getInputBufferStream()->unreference(); if ($code !== 0) { $driver = Loop::get(); - $reflectionClass = new ReflectionClass(Driver::class); $reflectionProperty = $reflectionClass->getProperty('watchers'); $reflectionProperty->setAccessible(true); diff --git a/src/danog/MadelineProto/MyTelegramOrgWrapper.php b/src/danog/MadelineProto/MyTelegramOrgWrapper.php index 3a5d5ddb..35444aa3 100644 --- a/src/danog/MadelineProto/MyTelegramOrgWrapper.php +++ b/src/danog/MadelineProto/MyTelegramOrgWrapper.php @@ -1,4 +1,5 @@ settings = MTProto::getSettings($settings, $this->settings); $this->__wakeup(); } - public function __wakeup() { if ($this->settings === null) { $this->settings = []; } - if (!$this->jar || !($this->jar instanceof InMemoryCookieJar)) { - $this->jar = new InMemoryCookieJar; + if (!$this->jar || !$this->jar instanceof InMemoryCookieJar) { + $this->jar = new InMemoryCookieJar(); } $this->settings = MTProto::getSettings($this->settings); - $this->datacenter = new DataCenter( - new class($this->settings) { - public function __construct($settings) - { - $this->logger = Logger::getLoggerFromSettings($settings); - } - public function getLogger() - { - return $this->logger; - } - }, - [], - $this->settings['connection_settings'], - true, - $this->jar - ); + $this->datacenter = new DataCenter(new class($this->settings) { + public function __construct($settings) + { + $this->logger = Logger::getLoggerFromSettings($settings); + } + public function getLogger() + { + return $this->logger; + } + }, [], $this->settings['connection_settings'], true, $this->jar); } - - public function login($number) + public function login($number): \Generator { $this->number = $number; - $request = new Request(self::MY_TELEGRAM_URL.'/auth/send_password', 'POST'); + $request = new Request(self::MY_TELEGRAM_URL . '/auth/send_password', 'POST'); $request->setBody(\http_build_query(['phone' => $number])); $request->setHeaders($this->getHeaders('origin')); $response = yield $this->datacenter->getHTTPClient()->request($request); $result = yield $response->getBody()->buffer(); $resulta = \json_decode($result, true); - if (!isset($resulta['random_hash'])) { throw new Exception($result); } $this->hash = $resulta['random_hash']; } - - public function completeLogin($password) + public function completeLogin($password): \Generator { if ($this->logged) { throw new Exception('Already logged in!'); } - - $request = new Request(self::MY_TELEGRAM_URL.'/auth/login', 'POST'); + $request = new Request(self::MY_TELEGRAM_URL . '/auth/login', 'POST'); $request->setBody(\http_build_query(['phone' => $this->number, 'random_hash' => $this->hash, 'password' => $password])); $request->setHeaders($this->getHeaders('origin')); $request->setHeader('user-agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13'); $response = yield $this->datacenter->getHTTPClient()->request($request); $result = yield $response->getBody()->buffer(); - - switch ($result) { case 'true': //Logger::log(['Login OK'], Logger::VERBOSE); @@ -112,52 +97,41 @@ class MyTelegramOrgWrapper default: throw new Exception($result); } - return $this->logged = true; } - public function loggedIn() { return $this->logged; } - - public function hasApp() + public function hasApp(): \Generator { if (!$this->logged) { throw new Exception('Not logged in!'); } - - $request = new Request(self::MY_TELEGRAM_URL.'/apps'); + $request = new Request(self::MY_TELEGRAM_URL . '/apps'); $request->setHeaders($this->getHeaders('refer')); $response = yield $this->datacenter->getHTTPClient()->request($request); $result = yield $response->getBody()->buffer(); - $title = \explode('', \explode('', $result)[1])[0]; switch ($title) { case 'App configuration': return true; case 'Create new application': $this->creation_hash = \explode('"/>', \explode('<input type="hidden" name="hash" value="', $result)[1])[0]; - return false; } - $this->logged = false; - throw new Exception($title); } - - public function getApp() + public function getApp(): \Generator { if (!$this->logged) { throw new Exception('Not logged in!'); } - - $request = new Request(self::MY_TELEGRAM_URL.'/apps'); + $request = new Request(self::MY_TELEGRAM_URL . '/apps'); $request->setHeaders($this->getHeaders('refer')); $response = yield $this->datacenter->getHTTPClient()->request($request); $result = yield $response->getBody()->buffer(); - $cose = \explode('<label for="app_id" class="col-md-4 text-right control-label">App api_id:</label> <div class="col-md-7"> <span class="form-control input-xlarge uneditable-input" onclick="this.select();"><strong>', $result); @@ -168,41 +142,33 @@ class MyTelegramOrgWrapper <span class="form-control input-xlarge uneditable-input" onclick="this.select();">', $result); $asd = \explode('</span>', $cose[1]); $api_hash = $asd[0]; - return ['api_id' => (int) $api_id, 'api_hash' => $api_hash]; } - - public function createApp($settings) + public function createApp($settings): \Generator { if (!$this->logged) { throw new Exception('Not logged in!'); } - if (yield $this->hasApp()) { + if (yield from $this->hasApp()) { throw new Exception('The app was already created!'); } - - $request = new Request(self::MY_TELEGRAM_URL.'/apps/create', 'POST'); + $request = new Request(self::MY_TELEGRAM_URL . '/apps/create', 'POST'); $request->setHeaders($this->getHeaders('app')); $request->setBody(\http_build_query(['hash' => $this->creation_hash, 'app_title' => $settings['app_title'], 'app_shortname' => $settings['app_shortname'], 'app_url' => $settings['app_url'], 'app_platform' => $settings['app_platform'], 'app_desc' => $settings['app_desc']])); $response = yield $this->datacenter->getHTTPClient()->request($request); $result = yield $response->getBody()->buffer(); - if ($result) { throw new Exception(\html_entity_decode($result)); } - - $request = new Request(self::MY_TELEGRAM_URL.'/apps'); + $request = new Request(self::MY_TELEGRAM_URL . '/apps'); $request->setHeaders($this->getHeaders('refer')); $response = yield $this->datacenter->getHTTPClient()->request($request); $result = yield $response->getBody()->buffer(); - $title = \explode('', \explode('', $result)[1])[0]; if ($title === 'Create new application') { $this->creation_hash = \explode('"/>', \explode('<input type="hidden" name="hash" value="', $result)[1])[0]; - throw new \danog\MadelineProto\Exception('App creation failed'); } - $cose = \explode('<label for="app_id" class="col-md-4 text-right control-label">App api_id:</label> <div class="col-md-7"> <span class="form-control input-xlarge uneditable-input" onclick="this.select();"><strong>', $result); @@ -213,10 +179,8 @@ class MyTelegramOrgWrapper <span class="form-control input-xlarge uneditable-input" onclick="this.select();">', $result); $asd = \explode('</span>', $cose['1']); $api_hash = $asd['0']; - return ['api_id' => (int) $api_id, 'api_hash' => $api_hash]; } - /** * Function for generating curl request headers. */ @@ -228,43 +192,39 @@ class MyTelegramOrgWrapper $headers[] = 'Connection: keep-alive'; $headers[] = 'Accept-Language: it-IT,it;q=0.8,en-US;q=0.6,en;q=0.4'; $headers[] = 'User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36'; - // Add additional headers based on the type of request. switch ($httpType) { case 'origin': - $headers[] = 'Origin: '.self::MY_TELEGRAM_URL; + $headers[] = 'Origin: ' . self::MY_TELEGRAM_URL; //$headers[] = 'Accept-Encoding: gzip, deflate, br'; $headers[] = 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8'; $headers[] = 'Accept: application/json, text/javascript, */*; q=0.01'; - $headers[] = 'Referer: '.self::MY_TELEGRAM_URL.'/auth'; + $headers[] = 'Referer: ' . self::MY_TELEGRAM_URL . '/auth'; $headers[] = 'X-Requested-With: XMLHttpRequest'; break; case 'refer': //$headers[] = 'Accept-Encoding: gzip, deflate, sdch, br'; $headers[] = 'Upgrade-Insecure-Requests: 1'; $headers[] = 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'; - $headers[] = 'Referer: '.self::MY_TELEGRAM_URL; + $headers[] = 'Referer: ' . self::MY_TELEGRAM_URL; $headers[] = 'Cache-Control: max-age=0'; break; case 'app': - $headers[] = 'Origin: '.self::MY_TELEGRAM_URL; + $headers[] = 'Origin: ' . self::MY_TELEGRAM_URL; //$headers[] = 'Accept-Encoding: gzip, deflate, br'; $headers[] = 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8'; $headers[] = 'Accept: */*'; - $headers[] = 'Referer: '.self::MY_TELEGRAM_URL.'/apps'; + $headers[] = 'Referer: ' . self::MY_TELEGRAM_URL . '/apps'; $headers[] = 'X-Requested-With: XMLHttpRequest'; break; } - $final_headers = []; foreach ($headers as $header) { list($key, $value) = \explode(':', $header, 2); $final_headers[\trim($key)] = \trim($value); } - return $final_headers; } - public function async($async) { $this->async = $async; @@ -277,9 +237,8 @@ class MyTelegramOrgWrapper { $name .= '_async'; $async = \is_array(\end($arguments)) && isset(\end($arguments)['async']) ? \end($arguments)['async'] : $this->async; - if (!\method_exists($this, $name)) { - throw new Exception("$name does not exist!"); + throw new Exception("{$name} does not exist!"); } return $async ? $this->{$name}(...$arguments) : Tools::wait($this->{$name}(...$arguments)); } diff --git a/src/danog/MadelineProto/PTSException.php b/src/danog/MadelineProto/PTSException.php index 91ab6f70..986a0256 100644 --- a/src/danog/MadelineProto/PTSException.php +++ b/src/danog/MadelineProto/PTSException.php @@ -22,12 +22,10 @@ namespace danog\MadelineProto; class PTSException extends \Exception { use TL\PrettyException; - public function __toString() { - return \get_class($this).($this->message !== '' ? ': ' : '').$this->message.PHP_EOL.'TL Trace:'.PHP_EOL.PHP_EOL.$this->getTLTrace().PHP_EOL; + return \get_class($this) . ($this->message !== '' ? ': ' : '') . $this->message . PHP_EOL . 'TL Trace:' . PHP_EOL . PHP_EOL . $this->getTLTrace() . PHP_EOL; } - public function __construct($message, $file = '') { parent::__construct($message); diff --git a/src/danog/MadelineProto/PredefinedConnector.php b/src/danog/MadelineProto/PredefinedConnector.php index e69de29b..b3d9bbc7 100644 --- a/src/danog/MadelineProto/PredefinedConnector.php +++ b/src/danog/MadelineProto/PredefinedConnector.php @@ -0,0 +1 @@ +<?php diff --git a/src/danog/MadelineProto/RPCErrorException.php b/src/danog/MadelineProto/RPCErrorException.php index 345a5896..2eef69c0 100644 --- a/src/danog/MadelineProto/RPCErrorException.php +++ b/src/danog/MadelineProto/RPCErrorException.php @@ -24,101 +24,43 @@ class RPCErrorException extends \Exception use TL\PrettyException; private $fetched = false; public static $rollbar = true; - - public static $descriptions = [ - 'RPC_MCGET_FAIL' => 'Telegram is having internal issues, please try again later.', - 'RPC_CALL_FAIL' => 'Telegram is having internal issues, please try again later.', - 'USER_PRIVACY_RESTRICTED' => "The user's privacy settings do not allow you to do this", - 'CHANNEL_PRIVATE' => "You haven't joined this channel/supergroup", - 'USER_IS_BOT' => "Bots can't send messages to other bots", - 'BOT_METHOD_INVALID' => 'This method cannot be run by a bot', - 'PHONE_CODE_EXPIRED' => 'The phone code you provided has expired, this may happen if it was sent to any chat on telegram (if the code is sent through a telegram chat (not the official account) to avoid it append or prepend to the code some chars)', - 'USERNAME_INVALID' => 'The provided username is not valid', - 'ACCESS_TOKEN_INVALID' => 'The provided token is not valid', - 'ACTIVE_USER_REQUIRED' => 'The method is only available to already activated users', - 'FIRSTNAME_INVALID' => 'The first name is invalid', - 'LASTNAME_INVALID' => 'The last name is invalid', - 'PHONE_NUMBER_INVALID' => 'The phone number is invalid', - 'PHONE_CODE_HASH_EMPTY' => 'phone_code_hash is missing', - 'PHONE_CODE_EMPTY' => 'phone_code is missing', - 'PHONE_CODE_EXPIRED' => 'The confirmation code has expired', - 'API_ID_INVALID' => 'The api_id/api_hash combination is invalid', - 'PHONE_NUMBER_OCCUPIED' => 'The phone number is already in use', - 'PHONE_NUMBER_UNOCCUPIED' => 'The phone number is not yet being used', - 'USERS_TOO_FEW' => 'Not enough users (to create a chat, for example)', - 'USERS_TOO_MUCH' => 'The maximum number of users has been exceeded (to create a chat, for example)', - 'TYPE_CONSTRUCTOR_INVALID' => 'The type constructor is invalid', - 'FILE_PART_INVALID' => 'The file part number is invalid', - 'FILE_PARTS_INVALID' => 'The number of file parts is invalid', - 'MD5_CHECKSUM_INVALID' => 'The MD5 checksums do not match', - 'PHOTO_INVALID_DIMENSIONS' => 'The photo dimensions are invalid', - 'FIELD_NAME_INVALID' => 'The field with the name FIELD_NAME is invalid', - 'FIELD_NAME_EMPTY' => 'The field with the name FIELD_NAME is missing', - 'MSG_WAIT_FAILED' => 'A waiting call returned an error', - 'USERNAME_NOT_OCCUPIED' => 'The provided username is not occupied', - 'PHONE_NUMBER_BANNED' => 'The provided phone number is banned from telegram', - 'AUTH_KEY_UNREGISTERED' => 'The authorization key has expired', - 'INVITE_HASH_EXPIRED' => 'The invite link has expired', - 'USER_DEACTIVATED' => 'The user was deactivated', - 'USER_ALREADY_PARTICIPANT' => 'The user is already in the group', - 'MESSAGE_ID_INVALID' => 'The provided message id is invalid', - 'PEER_ID_INVALID' => 'The provided peer id is invalid', - 'CHAT_ID_INVALID' => 'The provided chat id is invalid', - 'MESSAGE_DELETE_FORBIDDEN' => "You can't delete one of the messages you tried to delete, most likely because it is a service message.", - 'CHAT_ADMIN_REQUIRED' => 'You must be an admin in this chat to do this', - -429 => 'Too many requests', - 'PEER_FLOOD' => "You are spamreported, you can't do this", - ]; + public static $descriptions = ['RPC_MCGET_FAIL' => 'Telegram is having internal issues, please try again later.', 'RPC_CALL_FAIL' => 'Telegram is having internal issues, please try again later.', 'USER_PRIVACY_RESTRICTED' => "The user's privacy settings do not allow you to do this", 'CHANNEL_PRIVATE' => "You haven't joined this channel/supergroup", 'USER_IS_BOT' => "Bots can't send messages to other bots", 'BOT_METHOD_INVALID' => 'This method cannot be run by a bot', 'PHONE_CODE_EXPIRED' => 'The phone code you provided has expired, this may happen if it was sent to any chat on telegram (if the code is sent through a telegram chat (not the official account) to avoid it append or prepend to the code some chars)', 'USERNAME_INVALID' => 'The provided username is not valid', 'ACCESS_TOKEN_INVALID' => 'The provided token is not valid', 'ACTIVE_USER_REQUIRED' => 'The method is only available to already activated users', 'FIRSTNAME_INVALID' => 'The first name is invalid', 'LASTNAME_INVALID' => 'The last name is invalid', 'PHONE_NUMBER_INVALID' => 'The phone number is invalid', 'PHONE_CODE_HASH_EMPTY' => 'phone_code_hash is missing', 'PHONE_CODE_EMPTY' => 'phone_code is missing', 'PHONE_CODE_EXPIRED' => 'The confirmation code has expired', 'API_ID_INVALID' => 'The api_id/api_hash combination is invalid', 'PHONE_NUMBER_OCCUPIED' => 'The phone number is already in use', 'PHONE_NUMBER_UNOCCUPIED' => 'The phone number is not yet being used', 'USERS_TOO_FEW' => 'Not enough users (to create a chat, for example)', 'USERS_TOO_MUCH' => 'The maximum number of users has been exceeded (to create a chat, for example)', 'TYPE_CONSTRUCTOR_INVALID' => 'The type constructor is invalid', 'FILE_PART_INVALID' => 'The file part number is invalid', 'FILE_PARTS_INVALID' => 'The number of file parts is invalid', 'MD5_CHECKSUM_INVALID' => 'The MD5 checksums do not match', 'PHOTO_INVALID_DIMENSIONS' => 'The photo dimensions are invalid', 'FIELD_NAME_INVALID' => 'The field with the name FIELD_NAME is invalid', 'FIELD_NAME_EMPTY' => 'The field with the name FIELD_NAME is missing', 'MSG_WAIT_FAILED' => 'A waiting call returned an error', 'USERNAME_NOT_OCCUPIED' => 'The provided username is not occupied', 'PHONE_NUMBER_BANNED' => 'The provided phone number is banned from telegram', 'AUTH_KEY_UNREGISTERED' => 'The authorization key has expired', 'INVITE_HASH_EXPIRED' => 'The invite link has expired', 'USER_DEACTIVATED' => 'The user was deactivated', 'USER_ALREADY_PARTICIPANT' => 'The user is already in the group', 'MESSAGE_ID_INVALID' => 'The provided message id is invalid', 'PEER_ID_INVALID' => 'The provided peer id is invalid', 'CHAT_ID_INVALID' => 'The provided chat id is invalid', 'MESSAGE_DELETE_FORBIDDEN' => "You can't delete one of the messages you tried to delete, most likely because it is a service message.", 'CHAT_ADMIN_REQUIRED' => 'You must be an admin in this chat to do this', -429 => 'Too many requests', 'PEER_FLOOD' => "You are spamreported, you can't do this"]; public static $errorMethodMap = []; - private $caller = ''; public static function localizeMessage($method, $code, $error) { if (!$method || !$code || !$error) { return $error; } - - $error = \preg_replace('/\d+$/', "X", $error); - + $error = \preg_replace('/\\d+$/', "X", $error); $description = self::$descriptions[$error] ?? ''; - - - if (!isset(self::$errorMethodMap[$code][$method][$error]) - || !isset(self::$descriptions[$error]) - || $code === 500 - ) { - $res = \json_decode(@\file_get_contents('https://rpc.pwrtelegram.xyz/?method='.$method.'&code='.$code.'&error='.$error, false, \stream_context_create(['http'=>['timeout' => 3]])), true); + if (!isset(self::$errorMethodMap[$code][$method][$error]) || !isset(self::$descriptions[$error]) || $code === 500) { + $res = \json_decode(@\file_get_contents('https://rpc.pwrtelegram.xyz/?method=' . $method . '&code=' . $code . '&error=' . $error, false, \stream_context_create(['http' => ['timeout' => 3]])), true); if (isset($res['ok']) && $res['ok'] && isset($res['result'])) { $description = $res['result']; - self::$descriptions[$error] = $description; self::$errorMethodMap[$code][$method][$error] = $error; } } - if (!$description) { return $error; } return $description; } - public function __toString() { - $result = \sprintf(\danog\MadelineProto\Lang::$current_lang['rpc_tg_error'], self::localizeMessage($this->caller, $this->code, $this->message)." ({$this->code})", $this->rpc, $this->file, $this->line.PHP_EOL, \danog\MadelineProto\Magic::$revision.PHP_EOL.PHP_EOL).PHP_EOL.$this->getTLTrace().PHP_EOL; + $result = \sprintf(\danog\MadelineProto\Lang::$current_lang['rpc_tg_error'], self::localizeMessage($this->caller, $this->code, $this->message) . " ({$this->code})", $this->rpc, $this->file, $this->line . PHP_EOL, \danog\MadelineProto\Magic::$revision . PHP_EOL . PHP_EOL) . PHP_EOL . $this->getTLTrace() . PHP_EOL; if (PHP_SAPI !== 'cli') { - $result = \str_replace(PHP_EOL, '<br>'.PHP_EOL, $result); + $result = \str_replace(PHP_EOL, '<br>' . PHP_EOL, $result); } - return $result; } - public function __construct($message = null, $code = 0, $caller = '', Exception $previous = null) { $this->rpc = $message; parent::__construct($message, $code, $previous); $this->prettifyTL($caller); $this->caller = $caller; - $additional = []; foreach ($this->getTrace() as $level) { if (isset($level['function']) && $level['function'] === 'methodCall') { diff --git a/src/danog/MadelineProto/RSA.php b/src/danog/MadelineProto/RSA.php index b338baf3..dc655750 100644 --- a/src/danog/MadelineProto/RSA.php +++ b/src/danog/MadelineProto/RSA.php @@ -1,4 +1,5 @@ <?php + /** * RSA module. * @@ -45,7 +46,6 @@ class RSA * @var string */ public $fp; - /** * Load RSA key. * @@ -62,11 +62,9 @@ class RSA $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 $TL->serializeObject(['type' => 'bytes'], $this->n->toBytes(), 'key')).(yield $TL->serializeObject(['type' => 'bytes'], $this->e->toBytes(), 'key')), true), -8); - + $this->fp = \substr(\sha1(yield $TL->serializeObject(['type' => 'bytes'], $this->n->toBytes(), 'key') . yield $TL->serializeObject(['type' => 'bytes'], $this->e->toBytes(), 'key'), true), -8); return $this; } - /** * Sleep function. * @@ -76,7 +74,6 @@ class RSA { return ['e', 'n', 'fp']; } - /** * Encrypt data. * @@ -87,7 +84,6 @@ class RSA public function encrypt($data): string { \danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['rsa_encrypting'], Logger::VERBOSE); - return (new \tgseclib\Math\BigInteger((string) $data, 256))->powMod($this->e, $this->n)->toBytes(); } } diff --git a/src/danog/MadelineProto/SecretChats/AuthKeyHandler.php b/src/danog/MadelineProto/SecretChats/AuthKeyHandler.php index 51d0cc51..d7f0d5ce 100644 --- a/src/danog/MadelineProto/SecretChats/AuthKeyHandler.php +++ b/src/danog/MadelineProto/SecretChats/AuthKeyHandler.php @@ -40,7 +40,6 @@ trait AuthKeyHandler * @var array */ protected $secret_chats = []; - /** * Accept secret chat. * @@ -53,8 +52,7 @@ trait AuthKeyHandler //$this->logger->logger($params['id'],$this->secretChatStatus($params['id'])); if ($this->secretChatStatus($params['id']) !== 0) { //$this->logger->logger($this->secretChatStatus($params['id'])); - $this->logger->logger("I've already accepted secret chat ".$params['id']); - + $this->logger->logger("I've already accepted secret chat " . $params['id']); return false; } $dh_config = yield $this->getDhConfig(); @@ -71,10 +69,9 @@ trait AuthKeyHandler $g_b = $dh_config['g']->powMod($b, $dh_config['p']); $this->checkG($g_b, $dh_config['p']); yield $this->methodCallAsyncRead('messages.acceptEncryption', ['peer' => $params['id'], 'g_b' => $g_b->toBytes(), 'key_fingerprint' => $key['fingerprint']], ['datacenter' => $this->datacenter->curdc]); - yield $this->notifyLayer($params['id']); - $this->logger->logger('Secret chat '.$params['id'].' accepted successfully!', \danog\MadelineProto\Logger::NOTICE); + yield from $this->notifyLayer($params['id']); + $this->logger->logger('Secret chat ' . $params['id'] . ' accepted successfully!', \danog\MadelineProto\Logger::NOTICE); } - /** * Request secret chat. * @@ -89,7 +86,7 @@ trait AuthKeyHandler throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database'); } $user = $user['InputUser']; - $this->logger->logger('Creating secret chat with '.$user['user_id'].'...', \danog\MadelineProto\Logger::VERBOSE); + $this->logger->logger('Creating secret chat with ' . $user['user_id'] . '...', \danog\MadelineProto\Logger::VERBOSE); $dh_config = yield $this->getDhConfig(); $this->logger->logger('Generating a...', \danog\MadelineProto\Logger::VERBOSE); $a = new \tgseclib\Math\BigInteger(\danog\MadelineProto\Tools::random(256), 256); @@ -99,11 +96,9 @@ trait AuthKeyHandler $res = yield $this->methodCallAsyncRead('messages.requestEncryption', ['user_id' => $user, 'g_a' => $g_a->toBytes()], ['datacenter' => $this->datacenter->curdc]); $this->temp_requested_secret_chats[$res['id']] = $a; $this->updaters[false]->resume(); - $this->logger->logger('Secret chat '.$res['id'].' requested successfully!', \danog\MadelineProto\Logger::NOTICE); - + $this->logger->logger('Secret chat ' . $res['id'] . ' requested successfully!', \danog\MadelineProto\Logger::NOTICE); return $res['id']; } - /** * Complete secret chat. * @@ -115,8 +110,7 @@ trait AuthKeyHandler { if ($this->secretChatStatus($params['id']) !== 1) { //$this->logger->logger($this->secretChatStatus($params['id'])); - $this->logger->logger('Could not find and complete secret chat '.$params['id']); - + $this->logger->logger('Could not find and complete secret chat ' . $params['id']); return false; } $dh_config = yield $this->getDhConfig(); @@ -127,29 +121,25 @@ trait AuthKeyHandler $key['fingerprint'] = \substr(\sha1($key['auth_key'], true), -8); //$this->logger->logger($key); if ($key['fingerprint'] !== $params['key_fingerprint']) { - yield $this->discardSecretChat($params['id']); - + yield from $this->discardSecretChat($params['id']); throw new \danog\MadelineProto\SecurityException('Invalid key fingerprint!'); } $key['visualization_orig'] = \substr(\sha1($key['auth_key'], true), 16); $key['visualization_46'] = \substr(\hash('sha256', $key['auth_key'], true), 20); $this->secret_chats[$params['id']] = ['key' => $key, 'admin' => true, 'user_id' => $params['participant_id'], 'InputEncryptedChat' => ['chat_id' => $params['id'], 'access_hash' => $params['access_hash'], '_' => 'inputEncryptedChat'], 'in_seq_no_x' => 0, 'out_seq_no_x' => 1, 'in_seq_no' => 0, 'out_seq_no' => 0, 'layer' => 8, 'ttl' => 0, 'ttr' => 100, 'updated' => \time(), 'incoming' => [], 'outgoing' => [], 'created' => \time(), 'rekeying' => [0], 'key_x' => 'to server', 'mtproto' => 1]; - yield $this->notifyLayer($params['id']); - $this->logger->logger('Secret chat '.$params['id'].' completed successfully!', \danog\MadelineProto\Logger::NOTICE); + yield from $this->notifyLayer($params['id']); + $this->logger->logger('Secret chat ' . $params['id'] . ' completed successfully!', \danog\MadelineProto\Logger::NOTICE); } - private function notifyLayer($chat): \Generator { yield $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionNotifyLayer', 'layer' => $this->TL->getSecretLayer()]]], ['datacenter' => $this->datacenter->curdc]); } - /** * Temporary rekeyed secret chats. * * @var array */ protected $temp_rekeyed_secret_chats = []; - /** * Rekey secret chat. * @@ -162,7 +152,7 @@ trait AuthKeyHandler if ($this->secret_chats[$chat]['rekeying'][0] !== 0) { return; } - $this->logger->logger('Rekeying secret chat '.$chat.'...', \danog\MadelineProto\Logger::VERBOSE); + $this->logger->logger('Rekeying secret chat ' . $chat . '...', \danog\MadelineProto\Logger::VERBOSE); $dh_config = yield $this->getDhConfig(); $this->logger->logger('Generating a...', \danog\MadelineProto\Logger::VERBOSE); $a = new \tgseclib\Math\BigInteger(\danog\MadelineProto\Tools::random(256), 256); @@ -174,10 +164,8 @@ trait AuthKeyHandler $this->secret_chats[$chat]['rekeying'] = [1, $e]; yield $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionRequestKey', 'g_a' => $g_a->toBytes(), 'exchange_id' => $e]]], ['datacenter' => $this->datacenter->curdc]); $this->updaters[false]->resume(); - return $e; } - /** * Accept rekeying. * @@ -197,11 +185,10 @@ trait AuthKeyHandler } if ($my_exchange_id->compare($other_exchange_id) === 0) { $this->secret_chats[$chat]['rekeying'] = [0]; - return; } } - $this->logger->logger('Accepting rekeying of secret chat '.$chat.'...', \danog\MadelineProto\Logger::VERBOSE); + $this->logger->logger('Accepting rekeying of secret chat ' . $chat . '...', \danog\MadelineProto\Logger::VERBOSE); $dh_config = yield $this->getDhConfig(); $this->logger->logger('Generating b...', \danog\MadelineProto\Logger::VERBOSE); $b = new \tgseclib\Math\BigInteger(\danog\MadelineProto\Tools::random(256), 256); @@ -218,7 +205,6 @@ trait AuthKeyHandler yield $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionAcceptKey', 'g_b' => $g_b->toBytes(), 'exchange_id' => $params['exchange_id'], 'key_fingerprint' => $key['fingerprint']]]], ['datacenter' => $this->datacenter->curdc]); $this->updaters[false]->resume(); } - /** * Commit rekeying of secret chat. * @@ -231,10 +217,9 @@ trait AuthKeyHandler { if ($this->secret_chats[$chat]['rekeying'][0] !== 1 || !isset($this->temp_rekeyed_secret_chats[$params['exchange_id']])) { $this->secret_chats[$chat]['rekeying'] = [0]; - return; } - $this->logger->logger('Committing rekeying of secret chat '.$chat.'...', \danog\MadelineProto\Logger::VERBOSE); + $this->logger->logger('Committing rekeying of secret chat ' . $chat . '...', \danog\MadelineProto\Logger::VERBOSE); $dh_config = yield $this->getDhConfig(); $params['g_b'] = new \tgseclib\Math\BigInteger((string) $params['g_b'], 256); $this->checkG($params['g_b'], $dh_config['p']); @@ -244,7 +229,6 @@ trait AuthKeyHandler $key['visualization_46'] = \substr(\hash('sha256', $key['auth_key'], true), 20); if ($key['fingerprint'] !== $params['key_fingerprint']) { yield $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionAbortKey', 'exchange_id' => $params['exchange_id']]]], ['datacenter' => $this->datacenter->curdc]); - throw new \danog\MadelineProto\SecurityException('Invalid key fingerprint!'); } yield $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionCommitKey', 'exchange_id' => $params['exchange_id'], 'key_fingerprint' => $key['fingerprint']]]], ['datacenter' => $this->datacenter->curdc]); @@ -256,7 +240,6 @@ trait AuthKeyHandler $this->secret_chats[$chat]['updated'] = \time(); $this->updaters[false]->resume(); } - /** * Complete rekeying. * @@ -272,10 +255,9 @@ trait AuthKeyHandler } if ($this->temp_rekeyed_secret_chats[$params['exchange_id']]['fingerprint'] !== $params['key_fingerprint']) { yield $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionAbortKey', 'exchange_id' => $params['exchange_id']]]], ['datacenter' => $this->datacenter->curdc]); - throw new \danog\MadelineProto\SecurityException('Invalid key fingerprint!'); } - $this->logger->logger('Completing rekeying of secret chat '.$chat.'...', \danog\MadelineProto\Logger::VERBOSE); + $this->logger->logger('Completing rekeying of secret chat ' . $chat . '...', \danog\MadelineProto\Logger::VERBOSE); $this->secret_chats[$chat]['rekeying'] = [0]; $this->secret_chats[$chat]['old_key'] = $this->secret_chats[$chat]['key']; $this->secret_chats[$chat]['key'] = $this->temp_rekeyed_secret_chats[$params['exchange_id']]; @@ -283,11 +265,9 @@ trait AuthKeyHandler $this->secret_chats[$chat]['updated'] = \time(); unset($this->temp_rekeyed_secret_chats[$params['exchange_id']]); yield $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionNoop']]], ['datacenter' => $this->datacenter->curdc]); - $this->logger->logger('Secret chat '.$chat.' rekeyed successfully!', \danog\MadelineProto\Logger::VERBOSE); - + $this->logger->logger('Secret chat ' . $chat . ' rekeyed successfully!', \danog\MadelineProto\Logger::VERBOSE); return true; } - /** * Get secret chat status. * @@ -303,10 +283,8 @@ trait AuthKeyHandler if (isset($this->temp_requested_secret_chats[$chat])) { return MTProto::SECRET_REQUESTED; } - return MTProto::SECRET_EMPTY; } - /** * Get secret chat. * @@ -318,7 +296,6 @@ trait AuthKeyHandler { return $this->secret_chats[\is_array($chat) ? $chat['chat_id'] : $chat]; } - /** * Check whether secret chat exists. * @@ -330,7 +307,6 @@ trait AuthKeyHandler { return isset($this->secret_chats[\is_array($chat) ? $chat['chat_id'] : $chat]); } - /** * Discard secret chat. * @@ -340,15 +316,13 @@ trait AuthKeyHandler */ public function discardSecretChat(int $chat): \Generator { - $this->logger->logger('Discarding secret chat '.$chat.'...', \danog\MadelineProto\Logger::VERBOSE); + $this->logger->logger('Discarding secret chat ' . $chat . '...', \danog\MadelineProto\Logger::VERBOSE); if (isset($this->secret_chats[$chat])) { unset($this->secret_chats[$chat]); } if (isset($this->temp_requested_secret_chats[$chat])) { unset($this->temp_requested_secret_chats[$chat]); } - - try { yield $this->methodCallAsyncRead('messages.discardEncryption', ['chat_id' => $chat], ['datacenter' => $this->datacenter->curdc]); } catch (\danog\MadelineProto\RPCErrorException $e) { diff --git a/src/danog/MadelineProto/SecretChats/MessageHandler.php b/src/danog/MadelineProto/SecretChats/MessageHandler.php index a1485f9d..eace87b4 100644 --- a/src/danog/MadelineProto/SecretChats/MessageHandler.php +++ b/src/danog/MadelineProto/SecretChats/MessageHandler.php @@ -38,7 +38,6 @@ trait MessageHandler { if (!isset($this->secret_chats[$chat_id])) { $this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['secret_chat_skipping'], $chat_id)); - return false; } $message['random_id'] = \danog\MadelineProto\Tools::random(8); @@ -52,30 +51,27 @@ trait MessageHandler } $this->secret_chats[$chat_id]['outgoing'][$this->secret_chats[$chat_id]['out_seq_no']] = $message; $message = yield $this->TL->serializeObject(['type' => $constructor = $this->secret_chats[$chat_id]['layer'] === 8 ? 'DecryptedMessage' : 'DecryptedMessageLayer'], $message, $constructor, $this->secret_chats[$chat_id]['layer']); - $message = \danog\MadelineProto\Tools::packUnsignedInt(\strlen($message)).$message; + $message = \danog\MadelineProto\Tools::packUnsignedInt(\strlen($message)) . $message; if ($this->secret_chats[$chat_id]['mtproto'] === 2) { $padding = \danog\MadelineProto\Tools::posmod(-\strlen($message), 16); if ($padding < 12) { $padding += 16; } $message .= \danog\MadelineProto\Tools::random($padding); - $message_key = \substr(\hash('sha256', \substr($this->secret_chats[$chat_id]['key']['auth_key'], 88 + ($this->secret_chats[$chat_id]['admin'] ? 0 : 8), 32).$message, true), 8, 16); + $message_key = \substr(\hash('sha256', \substr($this->secret_chats[$chat_id]['key']['auth_key'], 88 + ($this->secret_chats[$chat_id]['admin'] ? 0 : 8), 32) . $message, true), 8, 16); list($aes_key, $aes_iv) = $this->aesCalculate($message_key, $this->secret_chats[$chat_id]['key']['auth_key'], $this->secret_chats[$chat_id]['admin']); } else { $message_key = \substr(\sha1($message, true), -16); list($aes_key, $aes_iv) = $this->oldAesCalculate($message_key, $this->secret_chats[$chat_id]['key']['auth_key'], true); $message .= \danog\MadelineProto\Tools::random(\danog\MadelineProto\Tools::posmod(-\strlen($message), 16)); } - $message = $this->secret_chats[$chat_id]['key']['fingerprint'].$message_key.$this->igeEncrypt($message, $aes_key, $aes_iv); - + $message = $this->secret_chats[$chat_id]['key']['fingerprint'] . $message_key . $this->igeEncrypt($message, $aes_key, $aes_iv); return $message; } - private function handleEncryptedUpdate(array $message): \Generator { if (!isset($this->secret_chats[$message['message']['chat_id']])) { $this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['secret_chat_skipping'], $message['message']['chat_id'])); - return false; } $auth_key_id = \substr($message['message']['bytes'], 0, 8); @@ -84,40 +80,36 @@ trait MessageHandler if (isset($this->secret_chats[$message['message']['chat_id']]['old_key']['fingerprint'])) { if ($auth_key_id !== $this->secret_chats[$message['message']['chat_id']]['old_key']['fingerprint']) { yield $this->discardSecretChat($message['message']['chat_id']); - throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['fingerprint_mismatch']); } $old = true; } else { yield $this->discardSecretChat($message['message']['chat_id']); - throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['fingerprint_mismatch']); } } $message_key = \substr($message['message']['bytes'], 8, 16); $encrypted_data = \substr($message['message']['bytes'], 24); if ($this->secret_chats[$message['message']['chat_id']]['mtproto'] === 2) { - $this->logger->logger('Trying MTProto v2 decryption for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE); - + $this->logger->logger('Trying MTProto v2 decryption for chat ' . $message['message']['chat_id'] . '...', \danog\MadelineProto\Logger::NOTICE); try { $message_data = $this->tryMTProtoV2Decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data); - $this->logger->logger('MTProto v2 decryption OK for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE); + $this->logger->logger('MTProto v2 decryption OK for chat ' . $message['message']['chat_id'] . '...', \danog\MadelineProto\Logger::NOTICE); } catch (\danog\MadelineProto\SecurityException $e) { - $this->logger->logger('MTProto v2 decryption failed with message '.$e->getMessage().', trying MTProto v1 decryption for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE); + $this->logger->logger('MTProto v2 decryption failed with message ' . $e->getMessage() . ', trying MTProto v1 decryption for chat ' . $message['message']['chat_id'] . '...', \danog\MadelineProto\Logger::NOTICE); $message_data = $this->tryMTProtoV1Decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data); - $this->logger->logger('MTProto v1 decryption OK for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE); + $this->logger->logger('MTProto v1 decryption OK for chat ' . $message['message']['chat_id'] . '...', \danog\MadelineProto\Logger::NOTICE); $this->secret_chats[$message['message']['chat_id']]['mtproto'] = 1; } } else { - $this->logger->logger('Trying MTProto v1 decryption for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE); - + $this->logger->logger('Trying MTProto v1 decryption for chat ' . $message['message']['chat_id'] . '...', \danog\MadelineProto\Logger::NOTICE); try { $message_data = $this->tryMTProtoV1Decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data); - $this->logger->logger('MTProto v1 decryption OK for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE); + $this->logger->logger('MTProto v1 decryption OK for chat ' . $message['message']['chat_id'] . '...', \danog\MadelineProto\Logger::NOTICE); } catch (\danog\MadelineProto\SecurityException $e) { - $this->logger->logger('MTProto v1 decryption failed with message '.$e->getMessage().', trying MTProto v2 decryption for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE); + $this->logger->logger('MTProto v1 decryption failed with message ' . $e->getMessage() . ', trying MTProto v2 decryption for chat ' . $message['message']['chat_id'] . '...', \danog\MadelineProto\Logger::NOTICE); $message_data = $this->tryMTProtoV2Decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data); - $this->logger->logger('MTProto v2 decryption OK for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE); + $this->logger->logger('MTProto v2 decryption OK for chat ' . $message['message']['chat_id'] . '...', \danog\MadelineProto\Logger::NOTICE); $this->secret_chats[$message['message']['chat_id']]['mtproto'] = 2; } } @@ -131,7 +123,6 @@ trait MessageHandler $this->secret_chats[$message['message']['chat_id']]['incoming'][$this->secret_chats[$message['message']['chat_id']]['in_seq_no']] = $message['message']; yield $this->handleDecryptedUpdate($message); } - private function tryMTProtoV1Decrypt($message_key, $chat_id, $old, $encrypted_data) { list($aes_key, $aes_iv) = $this->oldAesCalculate($message_key, $this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], true); @@ -150,10 +141,8 @@ trait MessageHandler if (\strlen($decrypted_data) % 16 != 0) { throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['length_not_divisible_16']); } - return $message_data; } - private function tryMTProtoV2Decrypt($message_key, $chat_id, $old, $encrypted_data) { list($aes_key, $aes_iv) = $this->aesCalculate($message_key, $this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], !$this->secret_chats[$chat_id]['admin']); @@ -163,7 +152,7 @@ trait MessageHandler if ($message_data_length > \strlen($decrypted_data)) { throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_data_length_too_big']); } - if ($message_key != \substr(\hash('sha256', \substr($this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], 88 + ($this->secret_chats[$chat_id]['admin'] ? 8 : 0), 32).$decrypted_data, true), 8, 16)) { + if ($message_key != \substr(\hash('sha256', \substr($this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], 88 + ($this->secret_chats[$chat_id]['admin'] ? 8 : 0), 32) . $decrypted_data, true), 8, 16)) { throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_key_mismatch']); } if (\strlen($decrypted_data) - 4 - $message_data_length < 12) { @@ -175,7 +164,6 @@ trait MessageHandler if (\strlen($decrypted_data) % 16 != 0) { throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['length_not_divisible_16']); } - return $message_data; } } diff --git a/src/danog/MadelineProto/SecretChats/ResponseHandler.php b/src/danog/MadelineProto/SecretChats/ResponseHandler.php index 8fadebb8..05ecb477 100644 --- a/src/danog/MadelineProto/SecretChats/ResponseHandler.php +++ b/src/danog/MadelineProto/SecretChats/ResponseHandler.php @@ -24,7 +24,7 @@ namespace danog\MadelineProto\SecretChats; */ trait ResponseHandler { - private function handleDecryptedUpdate($update) + private function handleDecryptedUpdate($update): \Generator { /*if (isset($update['message']['decrypted_message']['random_bytes']) && strlen($update['message']['decrypted_message']['random_bytes']) < 15) { throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['rand_bytes_too_short']); @@ -35,15 +35,12 @@ trait ResponseHandler switch ($update['message']['decrypted_message']['action']['_']) { case 'decryptedMessageActionRequestKey': yield $this->acceptRekey($update['message']['chat_id'], $update['message']['decrypted_message']['action']); - return; case 'decryptedMessageActionAcceptKey': yield $this->commitRekey($update['message']['chat_id'], $update['message']['decrypted_message']['action']); - return; case 'decryptedMessageActionCommitKey': yield $this->completeRekey($update['message']['chat_id'], $update['message']['decrypted_message']['action']); - return; case 'decryptedMessageActionNotifyLayer': $this->secret_chats[$update['message']['chat_id']]['layer'] = $update['message']['decrypted_message']['action']['layer']; @@ -53,13 +50,10 @@ trait ResponseHandler if ($update['message']['decrypted_message']['action']['layer'] >= 73) { $this->secret_chats[$update['message']['chat_id']]['mtproto'] = 2; } - return; case 'decryptedMessageActionSetMessageTTL': $this->secret_chats[$update['message']['chat_id']]['ttl'] = $update['message']['decrypted_message']['action']['ttl_seconds']; - yield $this->saveUpdate($update); - return; case 'decryptedMessageActionNoop': return; @@ -68,14 +62,13 @@ trait ResponseHandler $update['message']['decrypted_message']['action']['end_seq_no'] -= $this->secret_chats[$update['message']['chat_id']]['out_seq_no_x']; $update['message']['decrypted_message']['action']['start_seq_no'] /= 2; $update['message']['decrypted_message']['action']['end_seq_no'] /= 2; - $this->logger->logger('Resending messages for secret chat '.$update['message']['chat_id'], \danog\MadelineProto\Logger::WARNING); + $this->logger->logger('Resending messages for secret chat ' . $update['message']['chat_id'], \danog\MadelineProto\Logger::WARNING); foreach ($this->secret_chats[$update['message']['chat_id']]['outgoing'] as $seq => $message) { if ($seq >= $update['message']['decrypted_message']['action']['start_seq_no'] && $seq <= $update['message']['decrypted_message']['action']['end_seq_no']) { //throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['resending_unsupported']); yield $this->methodCallAsyncRead('messages.sendEncrypted', ['peer' => $update['message']['chat_id'], 'message' => $update['message']['decrypted_message']], ['datacenter' => $this->datacenter->curdc]); } } - return; default: // yield $this->saveUpdate(['_' => 'updateNewDecryptedMessage', 'peer' => $this->secret_chats[$update['message']['chat_id']]['InputEncryptedChat'], 'in_seq_no' => $this->get_in_seq_no($update['message']['chat_id']), 'out_seq_no' => $this->get_out_seq_no($update['message']['chat_id']), 'message' => $update['message']['decrypted_message']]); @@ -95,11 +88,11 @@ trait ResponseHandler } } $update['message']['decrypted_message'] = $update['message']['decrypted_message']['message']; - yield $this->handleDecryptedUpdate($update); + yield from $this->handleDecryptedUpdate($update); } break; default: - throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['unrecognized_dec_msg'].\var_export($update, true)); + throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['unrecognized_dec_msg'] . \var_export($update, true)); break; } } diff --git a/src/danog/MadelineProto/SecretChats/SeqNoHandler.php b/src/danog/MadelineProto/SecretChats/SeqNoHandler.php index 6dda54c4..ec468655 100644 --- a/src/danog/MadelineProto/SecretChats/SeqNoHandler.php +++ b/src/danog/MadelineProto/SecretChats/SeqNoHandler.php @@ -24,7 +24,7 @@ namespace danog\MadelineProto\SecretChats; */ trait SeqNoHandler { - private function checkSecretInSeqNo($chat_id, $seqno) + private function checkSecretInSeqNo($chat_id, $seqno): \Generator { $seqno = ($seqno - $this->secret_chats[$chat_id]['out_seq_no_x']) / 2; $last = 0; @@ -32,7 +32,6 @@ trait SeqNoHandler if (isset($message['decrypted_message']['in_seq_no'])) { if (($message['decrypted_message']['in_seq_no'] - $this->secret_chats[$chat_id]['out_seq_no_x']) / 2 < $last) { yield $this->discardSecretChat($chat_id); - throw new \danog\MadelineProto\SecurityException('in_seq_no is not increasing'); } $last = ($message['decrypted_message']['in_seq_no'] - $this->secret_chats[$chat_id]['out_seq_no_x']) / 2; @@ -40,14 +39,11 @@ trait SeqNoHandler } if ($seqno > $this->secret_chats[$chat_id]['out_seq_no'] + 1) { yield $this->discardSecretChat($chat_id); - throw new \danog\MadelineProto\SecurityException('in_seq_no is too big'); } - return true; } - - private function checkSecretOutSeqNo($chat_id, $seqno) + private function checkSecretOutSeqNo($chat_id, $seqno): \Generator { $seqno = ($seqno - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2; $C = 0; @@ -55,8 +51,7 @@ trait SeqNoHandler if (isset($message['decrypted_message']['out_seq_no']) && $C < $this->secret_chats[$chat_id]['in_seq_no']) { if (($message['decrypted_message']['out_seq_no'] - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2 !== $C) { yield $this->discardSecretChat($chat_id); - - throw new \danog\MadelineProto\SecurityException('out_seq_no hole: should be '.$C.', is '.($message['decrypted_message']['out_seq_no'] - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2); + throw new \danog\MadelineProto\SecurityException('out_seq_no hole: should be ' . $C . ', is ' . ($message['decrypted_message']['out_seq_no'] - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2); } $C++; } @@ -64,25 +59,20 @@ trait SeqNoHandler //$this->logger->logger($C, $seqno); if ($seqno < $C) { // <= C - $this->logger->logger('WARNING: dropping repeated message with seqno '.$seqno); - + $this->logger->logger('WARNING: dropping repeated message with seqno ' . $seqno); return false; } if ($seqno > $C) { // > C+1 yield $this->discardSecretChat($chat_id); - - throw new \danog\MadelineProto\SecurityException('WARNING: out_seq_no gap detected ('.$seqno.' > '.$C.')!'); + throw new \danog\MadelineProto\SecurityException('WARNING: out_seq_no gap detected (' . $seqno . ' > ' . $C . ')!'); } - return true; } - private function generateSecretInSeqNo($chat) { return $this->secret_chats[$chat]['layer'] > 8 ? $this->secret_chats[$chat]['in_seq_no'] * 2 + $this->secret_chats[$chat]['in_seq_no_x'] : -1; } - private function generateSecretOutSeqNo($chat) { return $this->secret_chats[$chat]['layer'] > 8 ? $this->secret_chats[$chat]['out_seq_no'] * 2 + $this->secret_chats[$chat]['out_seq_no_x'] : -1; diff --git a/src/danog/MadelineProto/Serialization.php b/src/danog/MadelineProto/Serialization.php index bb36adaa..ee4c9874 100644 --- a/src/danog/MadelineProto/Serialization.php +++ b/src/danog/MadelineProto/Serialization.php @@ -27,7 +27,6 @@ class Serialization public static function realpaths($file) { $file = Absolute::absolute($file); - - return ['file' => $file, 'lockfile' => $file.'.lock', 'tempfile' => $file.'.temp.session']; + return ['file' => $file, 'lockfile' => $file . '.lock', 'tempfile' => $file . '.temp.session']; } } diff --git a/src/danog/MadelineProto/Server.php b/src/danog/MadelineProto/Server.php index 53ce99ab..f8cf6988 100644 --- a/src/danog/MadelineProto/Server.php +++ b/src/danog/MadelineProto/Server.php @@ -27,41 +27,34 @@ class Server private $settings; private $pids = []; private $mypid; - public function __construct($settings) { \set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']); \danog\MadelineProto\Logger::constructor(3); - if (!\extension_loaded('sockets')) { throw new Exception(['extension', 'sockets']); } - if (!\extension_loaded('pcntl')) { throw new Exception(['extension', 'pcntl']); } $this->settings = $settings; $this->mypid = \getmypid(); } - public function start() { \pcntl_signal(SIGTERM, [$this, 'sigHandler']); \pcntl_signal(SIGINT, [$this, 'sigHandler']); \pcntl_signal(SIGCHLD, [$this, 'sigHandler']); - $this->sock = new \Socket($this->settings['type'], SOCK_STREAM, $this->settings['protocol']); $this->sock->bind($this->settings['address'], $this->settings['port']); $this->sock->listen(); $this->sock->setBlocking(true); - $timeout = 2; $this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout); $this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout); - \danog\MadelineProto\Logger::log('Server started! Listening on '.$this->settings['address'].':'.$this->settings['port']); + \danog\MadelineProto\Logger::log('Server started! Listening on ' . $this->settings['address'] . ':' . $this->settings['port']); while (true) { \pcntl_signal_dispatch(); - try { if ($sock = $this->sock->accept()) { $this->handle($sock); @@ -70,7 +63,6 @@ class Server } } } - private function handle($socket) { $pid = \pcntl_fork(); @@ -83,29 +75,25 @@ class Server $handler->loop(); die; } - public function __destruct() { if ($this->mypid === \getmypid()) { - \danog\MadelineProto\Logger::log('Shutting main process '.$this->mypid.' down'); + \danog\MadelineProto\Logger::log('Shutting main process ' . $this->mypid . ' down'); unset($this->sock); foreach ($this->pids as $pid) { - \danog\MadelineProto\Logger::log("Waiting for $pid"); + \danog\MadelineProto\Logger::log("Waiting for {$pid}"); \pcntl_wait($pid); } \danog\MadelineProto\Logger::log('Done, closing main process'); - return; } } - public function sigHandler($sig) { switch ($sig) { case SIGTERM: case SIGINT: - exit(); - + exit; case SIGCHLD: \pcntl_waitpid(-1, $status); break; diff --git a/src/danog/MadelineProto/Shutdown.php b/src/danog/MadelineProto/Shutdown.php index 26345eb8..cf2b93e3 100644 --- a/src/danog/MadelineProto/Shutdown.php +++ b/src/danog/MadelineProto/Shutdown.php @@ -1,4 +1,5 @@ <?php + /** * Shutdown module. * diff --git a/src/danog/MadelineProto/Stream/ADNLTransport/ADNLStream.php b/src/danog/MadelineProto/Stream/ADNLTransport/ADNLStream.php index 4fdfd8df..2fe5ea4f 100644 --- a/src/danog/MadelineProto/Stream/ADNLTransport/ADNLStream.php +++ b/src/danog/MadelineProto/Stream/ADNLTransport/ADNLStream.php @@ -1,4 +1,5 @@ <?php + /** * ADNL stream wrapper. * @@ -24,7 +25,6 @@ use danog\MadelineProto\Stream\Async\BufferedStream; use danog\MadelineProto\Stream\BufferedStreamInterface; use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\MTProtoBufferInterface; - use danog\MadelineProto\Stream\RawStreamInterface; use danog\MadelineProto\Tools; @@ -39,7 +39,6 @@ class ADNLStream implements BufferedStreamInterface, MTProtoBufferInterface { use BufferedStream; private $stream; - /** * Connect to stream. * @@ -51,7 +50,6 @@ class ADNLStream implements BufferedStreamInterface, MTProtoBufferInterface { $this->stream = yield $ctx->getStream($header); } - /** * Async close. * @@ -61,7 +59,6 @@ class ADNLStream implements BufferedStreamInterface, MTProtoBufferInterface { return $this->stream->disconnect(); } - /** * Get write buffer asynchronously. * @@ -77,10 +74,8 @@ class ADNLStream implements BufferedStreamInterface, MTProtoBufferInterface $this->stream->startWriteHash(); $this->stream->checkWriteHash($length - 32); yield $buffer->bufferWrite(Tools::random(32)); - return $buffer; } - /** * Get read buffer asynchronously. * @@ -96,10 +91,8 @@ class ADNLStream implements BufferedStreamInterface, MTProtoBufferInterface $this->stream->checkReadHash($length); yield $buffer->bufferRead(32); $length -= 32; - return $buffer; } - /** * {@inheritdoc} * @@ -118,8 +111,6 @@ class ADNLStream implements BufferedStreamInterface, MTProtoBufferInterface { return $this->stream; } - - public static function getName(): string { return __CLASS__; diff --git a/src/danog/MadelineProto/Stream/Async/Buffer.php b/src/danog/MadelineProto/Stream/Async/Buffer.php index f799ea2e..cfe7fcc3 100644 --- a/src/danog/MadelineProto/Stream/Async/Buffer.php +++ b/src/danog/MadelineProto/Stream/Async/Buffer.php @@ -1,4 +1,5 @@ <?php + /** * Buffer helper trait. * @@ -33,7 +34,6 @@ trait Buffer { return \danog\MadelineProto\Tools::call($this->bufferReadGenerator($length)); } - public function bufferWrite(string $data): Promise { return \danog\MadelineProto\Tools::call($this->bufferWriteGenerator($data)); diff --git a/src/danog/MadelineProto/Stream/Async/BufferedStream.php b/src/danog/MadelineProto/Stream/Async/BufferedStream.php index 6693e4f2..5cba6395 100644 --- a/src/danog/MadelineProto/Stream/Async/BufferedStream.php +++ b/src/danog/MadelineProto/Stream/Async/BufferedStream.php @@ -1,4 +1,5 @@ <?php + /** * Buffered stream helper trait. * @@ -30,7 +31,6 @@ use Amp\Promise; trait BufferedStream { use Stream; - /** * Get read buffer asynchronously. * @@ -42,7 +42,6 @@ trait BufferedStream { return \danog\MadelineProto\Tools::call($this->getReadBufferGenerator($length)); } - /** * Get write buffer asynchronously. * diff --git a/src/danog/MadelineProto/Stream/Async/RawStream.php b/src/danog/MadelineProto/Stream/Async/RawStream.php index 8c0c6a39..162943ff 100644 --- a/src/danog/MadelineProto/Stream/Async/RawStream.php +++ b/src/danog/MadelineProto/Stream/Async/RawStream.php @@ -1,4 +1,5 @@ <?php + /** * Raw stream helper trait. * @@ -30,17 +31,14 @@ use Amp\Promise; trait RawStream { use Stream; - public function read(): Promise { return \danog\MadelineProto\Tools::call($this->readGenerator()); } - public function write(string $data): Promise { return \danog\MadelineProto\Tools::call($this->writeGenerator($data)); } - public function end(string $finalData = ''): Promise { return \danog\MadelineProto\Tools::call($this->endGenerator($finalData)); diff --git a/src/danog/MadelineProto/Stream/Async/Stream.php b/src/danog/MadelineProto/Stream/Async/Stream.php index 63b6fe5b..590b79c8 100644 --- a/src/danog/MadelineProto/Stream/Async/Stream.php +++ b/src/danog/MadelineProto/Stream/Async/Stream.php @@ -1,4 +1,5 @@ <?php + /** * Generic stream helper trait. * diff --git a/src/danog/MadelineProto/Stream/BufferInterface.php b/src/danog/MadelineProto/Stream/BufferInterface.php index 723a33bc..047918ff 100644 --- a/src/danog/MadelineProto/Stream/BufferInterface.php +++ b/src/danog/MadelineProto/Stream/BufferInterface.php @@ -1,4 +1,5 @@ <?php + /** * Buffer interface. * @@ -35,7 +36,6 @@ interface BufferInterface * @return Promise */ public function bufferRead(int $length): Promise; - /** * Write data asynchronously. * diff --git a/src/danog/MadelineProto/Stream/BufferedProxyStreamInterface.php b/src/danog/MadelineProto/Stream/BufferedProxyStreamInterface.php index a8907b11..8044d4c3 100644 --- a/src/danog/MadelineProto/Stream/BufferedProxyStreamInterface.php +++ b/src/danog/MadelineProto/Stream/BufferedProxyStreamInterface.php @@ -1,4 +1,5 @@ <?php + /** * Buffered proxy stream interface. * diff --git a/src/danog/MadelineProto/Stream/BufferedStreamInterface.php b/src/danog/MadelineProto/Stream/BufferedStreamInterface.php index 9df0c685..3493938b 100644 --- a/src/danog/MadelineProto/Stream/BufferedStreamInterface.php +++ b/src/danog/MadelineProto/Stream/BufferedStreamInterface.php @@ -1,4 +1,5 @@ <?php + /** * Buffered stream interface. * @@ -35,7 +36,6 @@ interface BufferedStreamInterface extends StreamInterface * @return Promise */ public function getReadBuffer(&$length): Promise; - /** * Get write buffer asynchronously. * @@ -44,7 +44,6 @@ interface BufferedStreamInterface extends StreamInterface * @return Promise */ public function getWriteBuffer(int $length, string $append = ''): Promise; - /** * Get stream name. * diff --git a/src/danog/MadelineProto/Stream/Common/BufferedRawStream.php b/src/danog/MadelineProto/Stream/Common/BufferedRawStream.php index 7f0eb62e..2aac71ea 100644 --- a/src/danog/MadelineProto/Stream/Common/BufferedRawStream.php +++ b/src/danog/MadelineProto/Stream/Common/BufferedRawStream.php @@ -1,4 +1,5 @@ <?php + /** * Buffered raw stream. * @@ -36,14 +37,11 @@ use danog\MadelineProto\Stream\RawStreamInterface; class BufferedRawStream implements BufferedStreamInterface, BufferInterface, RawStreamInterface { use RawStream; - const MAX_SIZE = 10 * 1024 * 1024; - protected $stream; protected $memory_stream; private $append = ''; private $append_after = 0; - /** * Asynchronously connect to a TCP/TLS server. * @@ -55,10 +53,8 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw { $this->stream = yield $ctx->getStream($header); $this->memory_stream = \fopen('php://memory', 'r+'); - return true; } - /** * Async chunked read. * @@ -71,7 +67,6 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw } return $this->stream->read(); } - /** * Async write. * @@ -86,7 +81,6 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw } return $this->stream->write($data); } - /** * Async close. * @@ -103,7 +97,6 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw $this->stream = null; } } - /** * Get read buffer asynchronously. * @@ -128,10 +121,8 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw \fclose($this->memory_stream); $this->memory_stream = $new_memory_stream; } - return new \Amp\Success($this); } - /** * Get write buffer asynchronously. * @@ -145,10 +136,8 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw $this->append = $append; $this->append_after = $length - \strlen($append); } - return new \Amp\Success($this); } - /** * Read data asynchronously. * @@ -169,7 +158,6 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw } return \danog\MadelineProto\Tools::call($this->bufferReadGenerator($length)); } - /** * Read data asynchronously. * @@ -185,22 +173,18 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw if ($buffer_length < $length && $buffer_length) { \fseek($this->memory_stream, $offset + $buffer_length); } - while ($buffer_length < $length) { $chunk = yield $this->read(); if ($chunk === null) { $this->disconnect(); - throw new \danog\MadelineProto\NothingInTheSocketException(); } \fwrite($this->memory_stream, $chunk); $buffer_length += \strlen($chunk); } \fseek($this->memory_stream, $offset); - return \fread($this->memory_stream, $length); } - /** * Async write. * @@ -218,14 +202,11 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw } elseif ($this->append_after < 0) { $this->append_after = 0; $this->append = ''; - throw new Exception('Tried to send too much out of frame data, cannot append'); } } - return $this->write($data); } - /** * {@inheritdoc} * @@ -244,7 +225,6 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw { return $this->stream; } - /** * Get class name. * diff --git a/src/danog/MadelineProto/Stream/Common/CtrStream.php b/src/danog/MadelineProto/Stream/Common/CtrStream.php index 8e52a891..f9cc347e 100644 --- a/src/danog/MadelineProto/Stream/Common/CtrStream.php +++ b/src/danog/MadelineProto/Stream/Common/CtrStream.php @@ -1,4 +1,5 @@ <?php + /** * AES CTR stream wrapper. * @@ -26,7 +27,6 @@ use danog\MadelineProto\Stream\BufferedProxyStreamInterface; use danog\MadelineProto\Stream\BufferInterface; use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\RawStreamInterface; - use tgseclib\Crypt\AES; /** @@ -48,7 +48,6 @@ class CtrStream implements BufferedProxyStreamInterface, BufferInterface private $extra; private $append = ''; private $append_after = 0; - /** * Connect to stream. * @@ -62,15 +61,12 @@ class CtrStream implements BufferedProxyStreamInterface, BufferInterface $this->encrypt->enableContinuousBuffer(); $this->encrypt->setKey($this->extra['encrypt']['key']); $this->encrypt->setIV($this->extra['encrypt']['iv']); - $this->decrypt = new \tgseclib\Crypt\AES('ctr'); $this->decrypt->enableContinuousBuffer(); $this->decrypt->setKey($this->extra['decrypt']['key']); $this->decrypt->setIV($this->extra['decrypt']['iv']); - $this->stream = yield $ctx->getStream($header); } - /** * Async close. * @@ -80,7 +76,6 @@ class CtrStream implements BufferedProxyStreamInterface, BufferInterface { return $this->stream->disconnect(); } - /** * Get write buffer asynchronously. * @@ -95,10 +90,8 @@ class CtrStream implements BufferedProxyStreamInterface, BufferInterface $this->append = $append; $this->append_after = $length - \strlen($append); } - return $this; } - /** * Get read buffer asynchronously. * @@ -109,10 +102,8 @@ class CtrStream implements BufferedProxyStreamInterface, BufferInterface public function getReadBufferGenerator(&$length): \Generator { $this->read_buffer = yield $this->stream->getReadBuffer($length); - return $this; } - /** * Decrypts read data asynchronously. * @@ -126,7 +117,6 @@ class CtrStream implements BufferedProxyStreamInterface, BufferInterface { return @$this->decrypt->encrypt(yield $this->read_buffer->bufferRead($length)); } - /** * Writes data to the stream. * @@ -146,14 +136,11 @@ class CtrStream implements BufferedProxyStreamInterface, BufferInterface } elseif ($this->append_after < 0) { $this->append_after = 0; $this->append = ''; - throw new \danog\MadelineProto\Exception('Tried to send too much out of frame data, cannot append'); } } - return $this->write_buffer->bufferWrite(@$this->encrypt->encrypt($data)); } - /** * Set obfuscation keys/IVs. * @@ -165,7 +152,6 @@ class CtrStream implements BufferedProxyStreamInterface, BufferInterface { $this->extra = $data; } - /** * {@inheritdoc} * @@ -175,7 +161,6 @@ class CtrStream implements BufferedProxyStreamInterface, BufferInterface { return $this->stream->getSocket(); } - /** * {@inheritDoc} * @@ -193,7 +178,6 @@ class CtrStream implements BufferedProxyStreamInterface, BufferInterface { return $this->decrypt; } - public static function getName(): string { return __CLASS__; diff --git a/src/danog/MadelineProto/Stream/Common/HashedBufferedStream.php b/src/danog/MadelineProto/Stream/Common/HashedBufferedStream.php index 9fe74be8..1fddad5a 100644 --- a/src/danog/MadelineProto/Stream/Common/HashedBufferedStream.php +++ b/src/danog/MadelineProto/Stream/Common/HashedBufferedStream.php @@ -1,4 +1,5 @@ <?php + /** * Hash stream wrapper. * @@ -23,7 +24,6 @@ use danog\MadelineProto\Stream\Async\BufferedStream; use danog\MadelineProto\Stream\BufferedProxyStreamInterface; use danog\MadelineProto\Stream\BufferInterface; use danog\MadelineProto\Stream\ConnectionContext; - use danog\MadelineProto\Stream\RawStreamInterface; /** @@ -45,7 +45,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf private $read_check_pos = 0; private $stream; private $rev = false; - /** * Enable read hashing. * @@ -55,7 +54,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf { $this->read_hash = \hash_init($this->hash_name); } - /** * Check the read hash after N bytes are read. * @@ -67,7 +65,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf { $this->read_check_after = $after; } - /** * Stop read hashing and get final hash. * @@ -82,10 +79,8 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf $this->read_hash = null; $this->read_check_after = 0; $this->read_check_pos = 0; - return $hash; } - /** * Check if we are read hashing. * @@ -95,7 +90,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf { return $this->read_hash !== null; } - /** * Enable write hashing. * @@ -105,7 +99,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf { $this->write_hash = \hash_init($this->hash_name); } - /** * Write the write hash after N bytes are read. * @@ -117,7 +110,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf { $this->write_check_after = $after; } - /** * Stop write hashing and get final hash. * @@ -132,10 +124,8 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf $this->write_hash = null; $this->write_check_after = 0; $this->write_check_pos = 0; - return $hash; } - /** * Check if we are write hashing. * @@ -145,7 +135,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf { return $this->write_hash !== null; } - /** * Hashes read data asynchronously. * @@ -167,7 +156,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf if ($hash !== yield $this->read_buffer->bufferRead(\strlen($hash))) { throw new \danog\MadelineProto\Exception('Hash mismatch'); } - return $data; } $data = yield $this->read_buffer->bufferRead($length); @@ -175,10 +163,8 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf if ($this->read_check_after) { $this->read_check_pos += $length; } - return $data; } - /** * Set the hash algorithm. * @@ -196,7 +182,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf } $this->hash_name = $hash; } - /** * Connect to stream. * @@ -212,10 +197,8 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf $this->read_hash = null; $this->read_check_after = 0; $this->read_check_pos = 0; - $this->stream = yield $ctx->getStream($header); } - /** * Async close. * @@ -225,7 +208,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf { return $this->stream->disconnect(); } - /** * Get read buffer asynchronously. * @@ -237,13 +219,10 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf { //if ($this->read_hash) { $this->read_buffer = yield $this->stream->getReadBuffer($length); - return $this; //} - //return yield $this->stream->getReadBuffer($length); } - /** * Get write buffer asynchronously. * @@ -255,13 +234,10 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf { //if ($this->write_hash) { $this->write_buffer = yield $this->stream->getWriteBuffer($length, $append); - return $this; //} - //return yield $this->stream->getWriteBuffer($length, $append); } - /** * Reads data from the stream. * @@ -274,10 +250,8 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf if ($this->read_hash === null) { return $this->read_buffer->bufferRead($length); } - return \danog\MadelineProto\Tools::call($this->bufferReadGenerator($length)); } - /** * Writes data to the stream. * @@ -292,15 +266,13 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf if ($this->write_hash === null) { return $this->write_buffer->bufferWrite($data); } - $length = \strlen($data); if ($this->write_check_after && $length + $this->write_check_pos >= $this->write_check_after) { if ($length + $this->write_check_pos > $this->write_check_after) { throw new \danog\MadelineProto\Exception('Too much out of frame data was sent, cannot check hash'); } \hash_update($this->write_hash, $data); - - return $this->write_buffer->bufferWrite($data.$this->getWriteHash()); + return $this->write_buffer->bufferWrite($data . $this->getWriteHash()); } if ($this->write_check_after) { $this->write_check_pos += $length; @@ -308,10 +280,8 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf if ($this->write_hash) { \hash_update($this->write_hash, $data); } - return $this->write_buffer->bufferWrite($data); } - /** * {@inheritdoc} * @@ -321,7 +291,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf { return $this->stream->getSocket(); } - /** * {@inheritDoc} * diff --git a/src/danog/MadelineProto/Stream/Common/SimpleBufferedRawStream.php b/src/danog/MadelineProto/Stream/Common/SimpleBufferedRawStream.php index ce528f62..ffb350a2 100644 --- a/src/danog/MadelineProto/Stream/Common/SimpleBufferedRawStream.php +++ b/src/danog/MadelineProto/Stream/Common/SimpleBufferedRawStream.php @@ -1,4 +1,5 @@ <?php + /** * Buffered raw stream. * @@ -44,7 +45,6 @@ class SimpleBufferedRawStream extends BufferedRawStream implements BufferedStrea if ($buffer_length < $length && $buffer_length) { \fseek($this->memory_stream, $offset + $buffer_length); } - while ($buffer_length < $length) { $chunk = yield $this->read(); if ($chunk === null) { @@ -55,7 +55,6 @@ class SimpleBufferedRawStream extends BufferedRawStream implements BufferedStrea $buffer_length += \strlen($chunk); } \fseek($this->memory_stream, $offset); - return \fread($this->memory_stream, $length); } /** @@ -67,7 +66,6 @@ class SimpleBufferedRawStream extends BufferedRawStream implements BufferedStrea { return $this->stream; } - /** * Get class name. * diff --git a/src/danog/MadelineProto/Stream/ConnectionContext.php b/src/danog/MadelineProto/Stream/ConnectionContext.php index f026e078..a317cd94 100644 --- a/src/danog/MadelineProto/Stream/ConnectionContext.php +++ b/src/danog/MadelineProto/Stream/ConnectionContext.php @@ -1,4 +1,5 @@ <?php + /** * Connection context. * @@ -107,14 +108,12 @@ class ConnectionContext * @var int */ private $key = 0; - /** * Read callback. * * @var callable */ private $readCallback; - /** * Set the socket context. * @@ -125,10 +124,8 @@ class ConnectionContext public function setSocketContext(ConnectContext $socketContext): self { $this->socketContext = $socketContext; - return $this; } - /** * Get the socket context. * @@ -138,7 +135,6 @@ class ConnectionContext { return $this->socketContext; } - /** * Set the connection URI. * @@ -149,10 +145,8 @@ class ConnectionContext public function setUri($uri): self { $this->uri = $uri instanceof Uri ? $uri : new Uri($uri); - return $this; } - /** * Get the URI as a string. * @@ -162,7 +156,6 @@ class ConnectionContext { return (string) $this->uri; } - /** * Get the URI. * @@ -172,7 +165,6 @@ class ConnectionContext { return $this->uri; } - /** * Set the cancellation token. * @@ -183,10 +175,8 @@ class ConnectionContext public function setCancellationToken($cancellationToken): self { $this->cancellationToken = $cancellationToken; - return $this; } - /** * Get the cancellation token. * @@ -215,10 +205,8 @@ class ConnectionContext public function setTest(bool $test): self { $this->test = $test; - return $this; } - /** * Whether this is a test connection. * @@ -237,7 +225,6 @@ class ConnectionContext { return $this->media; } - /** * Whether this is a CDN connection. * @@ -247,7 +234,6 @@ class ConnectionContext { return $this->cdn; } - /** * Whether this connection context will only be used by the DNS client. * @@ -257,7 +243,6 @@ class ConnectionContext { return $this->isDns; } - /** * Whether this connection context will only be used by the DNS client. * @@ -279,10 +264,8 @@ class ConnectionContext public function secure(bool $secure): self { $this->secure = $secure; - return $this; } - /** * Whether to use TLS with socket connections. * @@ -292,7 +275,6 @@ class ConnectionContext { return $this->secure; } - /** * Set the DC ID. * @@ -304,15 +286,13 @@ class ConnectionContext { $int = \intval($dc); if (!(1 <= $int && $int <= 1000)) { - throw new Exception("Invalid DC id provided: $dc"); + throw new Exception("Invalid DC id provided: {$dc}"); } $this->dc = $dc; $this->media = \strpos($dc, '_media') !== false; $this->cdn = \strpos($dc, '_cdn') !== false; - return $this; } - /** * Get the DC ID. * @@ -322,7 +302,6 @@ class ConnectionContext { return $this->dc; } - /** * Get the int DC ID. * @@ -337,10 +316,8 @@ class ConnectionContext if ($this->media) { $dc = -$dc; } - return $dc; } - /** * Whether to use ipv6. * @@ -351,10 +328,8 @@ class ConnectionContext public function setIpv6(bool $ipv6): self { $this->ipv6 = $ipv6; - return $this; } - /** * Whether to use ipv6. * @@ -364,7 +339,6 @@ class ConnectionContext { return $this->ipv6; } - /** * Add a stream to the stream chain. * @@ -377,10 +351,8 @@ class ConnectionContext { $this->nextStreams[] = [$streamName, $extra]; $this->key = \count($this->nextStreams) - 1; - return $this; } - /** * Set read callback, called every time the socket reads at least a byte. * @@ -392,7 +364,6 @@ class ConnectionContext { $this->readCallback = $callable; } - /** * Check if a read callback is present. * @@ -402,7 +373,6 @@ class ConnectionContext { return $this->readCallback !== null; } - /** * Get read callback. * @@ -412,7 +382,6 @@ class ConnectionContext { return $this->readCallback; } - /** * Get the current stream name from the stream chain. * @@ -422,7 +391,6 @@ class ConnectionContext { return $this->nextStreams[$this->key][0]; } - /** * Check if has stream within stream chain. * @@ -439,7 +407,6 @@ class ConnectionContext } return false; } - /** * Get a stream from the stream chain. * @@ -455,11 +422,8 @@ class ConnectionContext $obj->setExtra($extra); } yield $obj->connect($this, $buffer); - return $obj; } - - /** * Get the inputClientProxy proxy MTProto object. * @@ -499,13 +463,11 @@ class ConnectionContext } $string .= \preg_replace('/.*\\\\/', '', $stream[0]); if ($stream[1] && $stream[0] !== DefaultStream::getName()) { - $string .= ' ('.\json_encode($stream[1]).')'; + $string .= ' (' . \json_encode($stream[1]) . ')'; } } - return $string; } - /** * Returns a representation of the context. * diff --git a/src/danog/MadelineProto/Stream/MTProtoBufferInterface.php b/src/danog/MadelineProto/Stream/MTProtoBufferInterface.php index b2155d78..138bdecb 100644 --- a/src/danog/MadelineProto/Stream/MTProtoBufferInterface.php +++ b/src/danog/MadelineProto/Stream/MTProtoBufferInterface.php @@ -1,4 +1,5 @@ <?php + /** * MTProto buffer interface. * diff --git a/src/danog/MadelineProto/Stream/MTProtoTransport/AbridgedStream.php b/src/danog/MadelineProto/Stream/MTProtoTransport/AbridgedStream.php index cec9de56..e339b03b 100644 --- a/src/danog/MadelineProto/Stream/MTProtoTransport/AbridgedStream.php +++ b/src/danog/MadelineProto/Stream/MTProtoTransport/AbridgedStream.php @@ -1,4 +1,5 @@ <?php + /** * Abridged stream wrapper. * @@ -34,9 +35,7 @@ use danog\MadelineProto\Stream\RawStreamInterface; class AbridgedStream implements BufferedStreamInterface, MTProtoBufferInterface { use BufferedStream; - private $stream; - /** * Connect to stream. * @@ -46,9 +45,8 @@ class AbridgedStream implements BufferedStreamInterface, MTProtoBufferInterface */ public function connectGenerator(ConnectionContext $ctx, string $header = ''): \Generator { - $this->stream = yield $ctx->getStream(\chr(239).$header); + $this->stream = yield $ctx->getStream(\chr(239) . $header); } - /** * Async close. * @@ -58,7 +56,6 @@ class AbridgedStream implements BufferedStreamInterface, MTProtoBufferInterface { return $this->stream->disconnect(); } - /** * Get write buffer asynchronously. * @@ -72,14 +69,12 @@ class AbridgedStream implements BufferedStreamInterface, MTProtoBufferInterface if ($length < 127) { $message = \chr($length); } else { - $message = \chr(127).\substr(\pack('V', $length), 0, 3); + $message = \chr(127) . \substr(\pack('V', $length), 0, 3); } $buffer = yield $this->stream->getWriteBuffer(\strlen($message) + $length, $append); yield $buffer->bufferWrite($message); - return $buffer; } - /** * Get read buffer asynchronously. * @@ -92,13 +87,11 @@ class AbridgedStream implements BufferedStreamInterface, MTProtoBufferInterface $buffer = yield $this->stream->getReadBuffer($l); $length = \ord(yield $buffer->bufferRead(1)); if ($length >= 127) { - $length = \unpack('V', (yield $buffer->bufferRead(3))."\0")[1]; + $length = \unpack('V', yield $buffer->bufferRead(3) . "\0")[1]; } $length <<= 2; - return $buffer; } - /** * {@inheritdoc} * @@ -108,7 +101,6 @@ class AbridgedStream implements BufferedStreamInterface, MTProtoBufferInterface { return $this->stream->getSocket(); } - /** * {@inheritDoc} * diff --git a/src/danog/MadelineProto/Stream/MTProtoTransport/FullStream.php b/src/danog/MadelineProto/Stream/MTProtoTransport/FullStream.php index af06fbe3..a92178d6 100644 --- a/src/danog/MadelineProto/Stream/MTProtoTransport/FullStream.php +++ b/src/danog/MadelineProto/Stream/MTProtoTransport/FullStream.php @@ -1,4 +1,5 @@ <?php + /** * TCP full stream wrapper. * @@ -40,7 +41,6 @@ class FullStream implements BufferedStreamInterface, MTProtoBufferInterface private $stream; private $in_seq_no = -1; private $out_seq_no = -1; - /** * Stream to use as data source. * @@ -54,10 +54,8 @@ class FullStream implements BufferedStreamInterface, MTProtoBufferInterface $this->out_seq_no = -1; $this->stream = new HashedBufferedStream(); $this->stream->setExtra('crc32b_rev'); - return $this->stream->connect($ctx, $header); } - /** * Async close. * @@ -67,7 +65,6 @@ class FullStream implements BufferedStreamInterface, MTProtoBufferInterface { return $this->stream->disconnect(); } - /** * Get write buffer asynchronously. * @@ -82,10 +79,8 @@ class FullStream implements BufferedStreamInterface, MTProtoBufferInterface $buffer = yield $this->stream->getWriteBuffer($length + 12, $append); $this->out_seq_no++; $buffer->bufferWrite(\pack('VV', $length + 12, $this->out_seq_no)); - return $buffer; } - /** * Get read buffer asynchronously. * @@ -105,10 +100,8 @@ class FullStream implements BufferedStreamInterface, MTProtoBufferInterface if ($in_seq_no != $this->in_seq_no) { throw new \danog\MadelineProto\Exception('Incoming seq_no mismatch'); } - return $buffer; } - /** * {@inheritdoc} * @@ -118,7 +111,6 @@ class FullStream implements BufferedStreamInterface, MTProtoBufferInterface { return $this->stream->getSocket(); } - /** * {@inheritDoc} * diff --git a/src/danog/MadelineProto/Stream/MTProtoTransport/HttpStream.php b/src/danog/MadelineProto/Stream/MTProtoTransport/HttpStream.php index 9bd3973e..285da0e7 100644 --- a/src/danog/MadelineProto/Stream/MTProtoTransport/HttpStream.php +++ b/src/danog/MadelineProto/Stream/MTProtoTransport/HttpStream.php @@ -1,4 +1,5 @@ <?php + /** * HTTP stream wrapper. * @@ -45,7 +46,6 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface * @var \Amp\Uri\Uri */ private $uri; - /** * Connect to stream. * @@ -59,7 +59,6 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface $this->stream = yield $ctx->getStream($header); $this->uri = $ctx->getUri(); } - /** * Set proxy data. * @@ -70,10 +69,9 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface public function setExtra($extra) { if (isset($extra['user']) && isset($extra['password'])) { - $this->header = \base64_encode($extra['user'].':'.$extra['password'])."\r\n"; + $this->header = \base64_encode($extra['user'] . ':' . $extra['password']) . "\r\n"; } } - /** * Async close. * @@ -83,7 +81,6 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface { return $this->stream->disconnect(); } - /** * Get write buffer asynchronously. * @@ -93,13 +90,11 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface */ public function getWriteBufferGenerator(int $length, string $append = ''): \Generator { - $headers = 'POST '.$this->uri->getPath()." HTTP/1.1\r\nHost: ".$this->uri->getHost().':'.$this->uri->getPort()."\r\n"."Content-Type: application/x-www-form-urlencoded\r\nConnection: keep-alive\r\nKeep-Alive: timeout=100000, max=10000000\r\nContent-Length: ".$length.$this->header."\r\n\r\n"; + $headers = 'POST ' . $this->uri->getPath() . " HTTP/1.1\r\nHost: " . $this->uri->getHost() . ':' . $this->uri->getPort() . "\r\n" . "Content-Type: application/x-www-form-urlencoded\r\nConnection: keep-alive\r\nKeep-Alive: timeout=100000, max=10000000\r\nContent-Length: " . $length . $this->header . "\r\n\r\n"; $buffer = yield $this->stream->getWriteBuffer(\strlen($headers) + $length, $append); yield $buffer->bufferWrite($headers); - return $buffer; } - /** * Get read buffer asynchronously. * @@ -115,7 +110,8 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface while (true) { $piece = yield $buffer->bufferRead(2); $headers .= $piece; - if ($piece === "\n\r") { // Assume end of headers with \r\n\r\n + if ($piece === "\n\r") { + // Assume end of headers with \r\n\r\n $headers .= yield $buffer->bufferRead(1); break; } @@ -125,7 +121,6 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface $was_crlf = $piece === "\r\n"; } $headers = \explode("\r\n", $headers); - list($protocol, $code, $description) = \explode(' ', $headers[0], 3); list($protocol, $protocol_version) = \explode('/', $protocol); if ($protocol !== 'HTTP') { @@ -133,7 +128,7 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface } $code = (int) $code; unset($headers[0]); - if (\array_pop($headers).\array_pop($headers) !== '') { + if (\array_pop($headers) . \array_pop($headers) !== '') { throw new \danog\MadelineProto\Exception('Wrong last header'); } foreach ($headers as $key => $current_header) { @@ -141,31 +136,24 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface $current_header = \explode(':', $current_header, 2); $headers[\strtolower($current_header[0])] = \trim($current_header[1]); } - $close = $protocol === 'HTTP/1.0'; if (isset($headers['connection'])) { $close = \strtolower($headers['connection']) === 'close'; } - if ($code !== 200) { $read = ''; if (isset($headers['content-length'])) { $read = yield $buffer->bufferRead((int) $headers['content-length']); } - if ($close) { $this->disconnect(); yield $this->connect($this->ctx); } - \danog\MadelineProto\Logger::log($read); - $this->code = \danog\MadelineProto\Tools::packSignedInt(-$code); $length = 4; - return $this; } - if ($close) { $this->stream->disconnect(); yield $this->stream->connect($this->ctx); @@ -173,15 +161,12 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface if (isset($headers['content-length'])) { $length = (int) $headers['content-length']; } - return $buffer; } - public function bufferRead(int $length): Promise { return new Success($this->code); } - /** * {@inheritdoc} * @@ -200,7 +185,6 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface { return $this->stream; } - public static function getName(): string { return __CLASS__; diff --git a/src/danog/MadelineProto/Stream/MTProtoTransport/HttpsStream.php b/src/danog/MadelineProto/Stream/MTProtoTransport/HttpsStream.php index e46c539f..0ce77b05 100644 --- a/src/danog/MadelineProto/Stream/MTProtoTransport/HttpsStream.php +++ b/src/danog/MadelineProto/Stream/MTProtoTransport/HttpsStream.php @@ -1,4 +1,5 @@ <?php + /** * HTTPS stream wrapper. * @@ -20,7 +21,6 @@ namespace danog\MadelineProto\Stream\MTProtoTransport; use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\MTProtoBufferInterface; - use danog\MadelineProto\Stream\RawStreamInterface; /** @@ -41,7 +41,6 @@ class HttpsStream extends HttpStream implements MTProtoBufferInterface { return parent::connectGenerator($ctx->getCtx()->secure(true), $header); } - /** * {@inheritDoc} * diff --git a/src/danog/MadelineProto/Stream/MTProtoTransport/IntermediatePaddedStream.php b/src/danog/MadelineProto/Stream/MTProtoTransport/IntermediatePaddedStream.php index 56d66e12..9940adac 100644 --- a/src/danog/MadelineProto/Stream/MTProtoTransport/IntermediatePaddedStream.php +++ b/src/danog/MadelineProto/Stream/MTProtoTransport/IntermediatePaddedStream.php @@ -1,4 +1,5 @@ <?php + /** * TCP Intermediate stream wrapper. * @@ -24,7 +25,6 @@ use danog\MadelineProto\Stream\Async\BufferedStream; use danog\MadelineProto\Stream\BufferedStreamInterface; use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\MTProtoBufferInterface; - use danog\MadelineProto\Stream\RawStreamInterface; /** @@ -38,7 +38,6 @@ class IntermediatePaddedStream implements BufferedStreamInterface, MTProtoBuffer { use BufferedStream; private $stream; - /** * Connect to stream. * @@ -48,9 +47,8 @@ class IntermediatePaddedStream implements BufferedStreamInterface, MTProtoBuffer */ public function connectGenerator(ConnectionContext $ctx, string $header = ''): \Generator { - $this->stream = yield $ctx->getStream(\str_repeat(\chr(221), 4).$header); + $this->stream = yield $ctx->getStream(\str_repeat(\chr(221), 4) . $header); } - /** * Async close. * @@ -60,7 +58,6 @@ class IntermediatePaddedStream implements BufferedStreamInterface, MTProtoBuffer { return $this->stream->disconnect(); } - /** * Get write buffer asynchronously. * @@ -71,12 +68,10 @@ class IntermediatePaddedStream implements BufferedStreamInterface, MTProtoBuffer public function getWriteBufferGenerator(int $length, string $append = ''): \Generator { $padding_length = \danog\MadelineProto\Tools::randomInt($modulus = 16); - $buffer = yield $this->stream->getWriteBuffer(4 + $length + $padding_length, $append.\danog\MadelineProto\Tools::random($padding_length)); + $buffer = yield $this->stream->getWriteBuffer(4 + $length + $padding_length, $append . \danog\MadelineProto\Tools::random($padding_length)); yield $buffer->bufferWrite(\pack('V', $padding_length + $length)); - return $buffer; } - /** * Get read buffer asynchronously. * @@ -88,10 +83,8 @@ class IntermediatePaddedStream implements BufferedStreamInterface, MTProtoBuffer { $buffer = yield $this->stream->getReadBuffer($l); $length = \unpack('V', yield $buffer->bufferRead(4))[1]; - return $buffer; } - /** * {@inheritdoc} * @@ -110,7 +103,6 @@ class IntermediatePaddedStream implements BufferedStreamInterface, MTProtoBuffer { return $this->stream; } - public static function getName(): string { return __CLASS__; diff --git a/src/danog/MadelineProto/Stream/MTProtoTransport/IntermediateStream.php b/src/danog/MadelineProto/Stream/MTProtoTransport/IntermediateStream.php index 818e426a..3cc8ec11 100644 --- a/src/danog/MadelineProto/Stream/MTProtoTransport/IntermediateStream.php +++ b/src/danog/MadelineProto/Stream/MTProtoTransport/IntermediateStream.php @@ -1,4 +1,5 @@ <?php + /** * TCP Intermediate stream wrapper. * @@ -24,7 +25,6 @@ use danog\MadelineProto\Stream\Async\BufferedStream; use danog\MadelineProto\Stream\BufferedStreamInterface; use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\MTProtoBufferInterface; - use danog\MadelineProto\Stream\RawStreamInterface; /** @@ -38,7 +38,6 @@ class IntermediateStream implements BufferedStreamInterface, MTProtoBufferInterf { use BufferedStream; private $stream; - /** * Connect to stream. * @@ -48,9 +47,8 @@ class IntermediateStream implements BufferedStreamInterface, MTProtoBufferInterf */ public function connectGenerator(ConnectionContext $ctx, string $header = ''): \Generator { - $this->stream = yield $ctx->getStream(\str_repeat(\chr(238), 4).$header); + $this->stream = yield $ctx->getStream(\str_repeat(\chr(238), 4) . $header); } - /** * Async close. * @@ -60,7 +58,6 @@ class IntermediateStream implements BufferedStreamInterface, MTProtoBufferInterf { return $this->stream->disconnect(); } - /** * Get write buffer asynchronously. * @@ -72,10 +69,8 @@ class IntermediateStream implements BufferedStreamInterface, MTProtoBufferInterf { $buffer = yield $this->stream->getWriteBuffer($length + 4, $append); yield $buffer->bufferWrite(\pack('V', $length)); - return $buffer; } - /** * Get read buffer asynchronously. * @@ -87,10 +82,8 @@ class IntermediateStream implements BufferedStreamInterface, MTProtoBufferInterf { $buffer = yield $this->stream->getReadBuffer($l); $length = \unpack('V', yield $buffer->bufferRead(4))[1]; - return $buffer; } - /** * {@inheritdoc} * @@ -109,8 +102,6 @@ class IntermediateStream implements BufferedStreamInterface, MTProtoBufferInterf { return $this->stream; } - - public static function getName(): string { return __CLASS__; diff --git a/src/danog/MadelineProto/Stream/MTProtoTransport/ObfuscatedStream.php b/src/danog/MadelineProto/Stream/MTProtoTransport/ObfuscatedStream.php index e2f6e7c0..c629d5f8 100644 --- a/src/danog/MadelineProto/Stream/MTProtoTransport/ObfuscatedStream.php +++ b/src/danog/MadelineProto/Stream/MTProtoTransport/ObfuscatedStream.php @@ -1,4 +1,5 @@ <?php + /** * Obfuscated2 stream wrapper. * @@ -33,10 +34,8 @@ use danog\MadelineProto\Stream\ConnectionContext; class ObfuscatedStream extends CtrStream implements BufferedProxyStreamInterface { use Stream; - private $stream; private $extra; - /** * Connect to stream. * @@ -48,52 +47,30 @@ class ObfuscatedStream extends CtrStream implements BufferedProxyStreamInterface { if (isset($this->extra['address'])) { $ctx = $ctx->getCtx(); - $ctx->setUri('tcp://'.$this->extra['address'].':'.$this->extra['port']); + $ctx->setUri('tcp://' . $this->extra['address'] . ':' . $this->extra['port']); } - do { $random = \danog\MadelineProto\Tools::random(64); } while (\in_array(\substr($random, 0, 4), ['PVrG', 'GET ', 'POST', 'HEAD', \str_repeat(\chr(238), 4), \str_repeat(\chr(221), 4)]) || $random[0] === \chr(0xef) || \substr($random, 4, 4) === "\0\0\0\0"); - if (\strlen($header) === 1) { $header = \str_repeat($header, 4); } - $random = \substr_replace($random, $header.\substr($random, 56 + \strlen($header)), 56); - $random = \substr_replace($random, \pack('s', $ctx->getIntDc()).\substr($random, 60 + 2), 60); - + $random = \substr_replace($random, $header . \substr($random, 56 + \strlen($header)), 56); + $random = \substr_replace($random, \pack('s', $ctx->getIntDc()) . \substr($random, 60 + 2), 60); $reversed = \strrev($random); - $key = \substr($random, 8, 32); $keyRev = \substr($reversed, 8, 32); - if (isset($this->extra['secret'])) { - $key = \hash('sha256', $key.$this->extra['secret'], true); - $keyRev = \hash('sha256', $keyRev.$this->extra['secret'], true); + $key = \hash('sha256', $key . $this->extra['secret'], true); + $keyRev = \hash('sha256', $keyRev . $this->extra['secret'], true); } - $iv = \substr($random, 40, 16); $ivRev = \substr($reversed, 40, 16); - - parent::setExtra( - [ - 'encrypt' => [ - 'key' => $key, - 'iv' => $iv - ], - 'decrypt' => [ - 'key' => $keyRev, - 'iv' => $ivRev - ] - ] - ); + parent::setExtra(['encrypt' => ['key' => $key, 'iv' => $iv], 'decrypt' => ['key' => $keyRev, 'iv' => $ivRev]]); yield from parent::connectGenerator($ctx); - $random = \substr_replace($random, \substr(@$this->getEncryptor()->encrypt($random), 56, 8), 56, 8); - yield $this->getStream()->write($random); } - - /** * Does nothing. * @@ -111,7 +88,6 @@ class ObfuscatedStream extends CtrStream implements BufferedProxyStreamInterface $extra['secret'] = \substr($extra['secret'], 1, 16); } } - $this->extra = $extra; } public static function getName(): string diff --git a/src/danog/MadelineProto/Stream/Proxy/HttpProxy.php b/src/danog/MadelineProto/Stream/Proxy/HttpProxy.php index 913f9efc..47057048 100644 --- a/src/danog/MadelineProto/Stream/Proxy/HttpProxy.php +++ b/src/danog/MadelineProto/Stream/Proxy/HttpProxy.php @@ -1,4 +1,5 @@ <?php + /** * HTTP proxy stream wrapper. * @@ -25,7 +26,6 @@ use danog\MadelineProto\Stream\Async\RawStream; use danog\MadelineProto\Stream\BufferedProxyStreamInterface; use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\RawProxyStreamInterface; - use danog\MadelineProto\Stream\RawStreamInterface; /** @@ -37,7 +37,6 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface { use RawStream; private $extra; - /** * Connect to stream. * @@ -50,33 +49,28 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface $ctx = $ctx->getCtx(); $uri = $ctx->getUri(); $secure = $ctx->isSecure(); - if ($secure) { $ctx->setSocketContext($ctx->getSocketContext()->withTlsContext(new ClientTlsContext($uri->getHost()))); } - - $ctx->setUri('tcp://'.$this->extra['address'].':'.$this->extra['port'])->secure(false); - + $ctx->setUri('tcp://' . $this->extra['address'] . ':' . $this->extra['port'])->secure(false); $this->stream = yield $ctx->getStream(); $address = $uri->getHost(); $port = $uri->getPort(); - try { if (\strlen(\inet_pton($address) === 16)) { - $address = '['.$address.']'; + $address = '[' . $address . ']'; } } catch (\danog\MadelineProto\Exception $e) { } - - yield $this->stream->write("CONNECT $address:$port HTTP/1.1\r\nHost: $address:$port\r\nAccept: */*\r\n".$this->getProxyAuthHeader()."Connection: keep-Alive\r\n\r\n"); - + yield $this->stream->write("CONNECT {$address}:{$port} HTTP/1.1\r\nHost: {$address}:{$port}\r\nAccept: */*\r\n" . $this->getProxyAuthHeader() . "Connection: keep-Alive\r\n\r\n"); $buffer = yield $this->stream->getReadBuffer($l); $headers = ''; $was_crlf = false; while (true) { $piece = yield $buffer->bufferRead(2); $headers .= $piece; - if ($piece === "\n\r") { // Assume end of headers with \r\n\r\n + if ($piece === "\n\r") { + // Assume end of headers with \r\n\r\n $headers .= yield $buffer->bufferRead(1); break; } @@ -86,7 +80,6 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface $was_crlf = $piece === "\r\n"; } $headers = \explode("\r\n", $headers); - list($protocol, $code, $description) = \explode(' ', $headers[0], 3); list($protocol, $protocol_version) = \explode('/', $protocol); if ($protocol !== 'HTTP') { @@ -94,7 +87,7 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface } $code = (int) $code; unset($headers[0]); - if (\array_pop($headers).\array_pop($headers) !== '') { + if (\array_pop($headers) . \array_pop($headers) !== '') { throw new \danog\MadelineProto\Exception('Wrong last header'); } foreach ($headers as $key => $current_header) { @@ -102,28 +95,22 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface $current_header = \explode(':', $current_header, 2); $headers[\strtolower($current_header[0])] = \trim($current_header[1]); } - $close = $protocol === 'HTTP/1.0'; if (isset($headers['connection'])) { $close = \strtolower($headers['connection']) === 'close'; } - if ($code !== 200) { $read = ''; if (isset($headers['content-length'])) { $read = yield $buffer->bufferRead((int) $headers['content-length']); } - if ($close) { $this->disconnect(); yield $this->connect($ctx); } - \danog\MadelineProto\Logger::log(\trim($read)); - throw new \danog\MadelineProto\Exception($description, $code); } - if ($close) { yield $this->stream->disconnect(); yield $this->stream->connect($ctx); @@ -132,17 +119,14 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface $length = (int) $headers['content-length']; $read = yield $buffer->bufferRead($length); } - if ($secure) { yield $this->getSocket()->setupTls(); } - \danog\MadelineProto\Logger::log('Connected to '.$address.':'.$port.' via http'); - + \danog\MadelineProto\Logger::log('Connected to ' . $address . ':' . $port . ' via http'); if (\strlen($header)) { yield (yield $this->stream->getWriteBuffer(\strlen($header)))->bufferWrite($header); } } - /** * Async close. * @@ -152,7 +136,6 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface { return $this->stream->disconnect(); } - /** * Get write buffer asynchronously. * @@ -164,7 +147,6 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface { return $this->stream->getWriteBuffer($length, $append); } - /** * Get read buffer asynchronously. * @@ -176,26 +158,21 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface { return $this->stream->getReadBuffer($length); } - public function read(): Promise { return $this->stream->read(); } - public function write(string $data): Promise { return $this->stream->write($data); } - private function getProxyAuthHeader() { if (!isset($this->extra['username']) || !isset($this->extra['password'])) { return ''; } - - return 'Proxy-Authorization: Basic '.\base64_encode($this->extra['username'].':'.$this->extra['password'])."\r\n"; + return 'Proxy-Authorization: Basic ' . \base64_encode($this->extra['username'] . ':' . $this->extra['password']) . "\r\n"; } - /** * Sets proxy data. * @@ -207,7 +184,6 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface { $this->extra = $extra; } - /** * {@inheritdoc} * @@ -217,7 +193,6 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface { return $this->stream->getSocket(); } - /** * {@inheritDoc} * diff --git a/src/danog/MadelineProto/Stream/Proxy/SocksProxy.php b/src/danog/MadelineProto/Stream/Proxy/SocksProxy.php index 162a6689..e54a4af2 100644 --- a/src/danog/MadelineProto/Stream/Proxy/SocksProxy.php +++ b/src/danog/MadelineProto/Stream/Proxy/SocksProxy.php @@ -1,4 +1,5 @@ <?php + /** * Socks5 stream wrapper. * @@ -25,7 +26,6 @@ use danog\MadelineProto\Stream\Async\RawStream; use danog\MadelineProto\Stream\BufferedProxyStreamInterface; use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\RawProxyStreamInterface; - use danog\MadelineProto\Stream\RawStreamInterface; /** @@ -35,20 +35,9 @@ use danog\MadelineProto\Stream\RawStreamInterface; */ class SocksProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface { - const REPS = [ - 0 => 'succeeded', - 1 => 'general SOCKS server failure', - 2 => 'connection not allowed by ruleset', - 3 => 'Network unreachable', - 4 => 'Host unreachable', - 5 => 'Connection refused', - 6 => 'TTL expired', - 7 => 'Command not supported', - 8 => 'Address type not supported' - ]; + const REPS = [0 => 'succeeded', 1 => 'general SOCKS server failure', 2 => 'connection not allowed by ruleset', 3 => 'Network unreachable', 4 => 'Host unreachable', 5 => 'Connection refused', 6 => 'TTL expired', 7 => 'Command not supported', 8 => 'Address type not supported']; use RawStream; private $extra; - /** * Connect to stream. * @@ -61,78 +50,61 @@ class SocksProxy implements RawProxyStreamInterface, BufferedProxyStreamInterfac $ctx = $ctx->getCtx(); $uri = $ctx->getUri(); $secure = $ctx->isSecure(); - if ($secure) { $ctx->setSocketContext($ctx->getSocketContext()->withTlsContext(new ClientTlsContext($uri->getHost()))); } - - $ctx->setUri('tcp://'.$this->extra['address'].':'.$this->extra['port'])->secure(false); - + $ctx->setUri('tcp://' . $this->extra['address'] . ':' . $this->extra['port'])->secure(false); $methods = \chr(0); if (isset($this->extra['username']) && isset($this->extra['password'])) { $methods .= \chr(2); } - $this->stream = yield $ctx->getStream(\chr(5).\chr(\strlen($methods)).$methods); - + $this->stream = yield $ctx->getStream(\chr(5) . \chr(\strlen($methods)) . $methods); $l = 2; - $buffer = yield $this->stream->getReadBuffer($l); - $version = \ord(yield $buffer->bufferRead(1)); $method = \ord(yield $buffer->bufferRead(1)); - if ($version !== 5) { - throw new \danog\MadelineProto\Exception("Wrong SOCKS5 version: $version"); + throw new \danog\MadelineProto\Exception("Wrong SOCKS5 version: {$version}"); } if ($method === 2) { - $auth = \chr(1).\chr(\strlen($this->extra['username'])).$this->extra['username'].\chr(\strlen($this->extra['password'])).$this->extra['password']; + $auth = \chr(1) . \chr(\strlen($this->extra['username'])) . $this->extra['username'] . \chr(\strlen($this->extra['password'])) . $this->extra['password']; yield $this->stream->write($auth); - $buffer = yield $this->stream->getReadBuffer($l); - $version = \ord(yield $buffer->bufferRead(1)); $result = \ord(yield $buffer->bufferRead(1)); - if ($version !== 1) { - throw new \danog\MadelineProto\Exception("Wrong authorized SOCKS version: $version"); + throw new \danog\MadelineProto\Exception("Wrong authorized SOCKS version: {$version}"); } if ($result !== 0) { - throw new \danog\MadelineProto\Exception("Wrong authorization status: $version"); + throw new \danog\MadelineProto\Exception("Wrong authorization status: {$version}"); } } elseif ($method !== 0) { - throw new \danog\MadelineProto\Exception("Wrong method: $method"); + throw new \danog\MadelineProto\Exception("Wrong method: {$method}"); } - $payload = \pack('C3', 0x05, 0x01, 0x00); - + $payload = \pack('C3', 0x5, 0x1, 0x0); try { $ip = \inet_pton($uri->getHost()); - $payload .= $ip ? \pack('C1', \strlen($ip) === 4 ? 0x01 : 0x04).$ip : \pack('C2', 0x03, \strlen($uri->getHost())).$uri->getHost(); + $payload .= $ip ? \pack('C1', \strlen($ip) === 4 ? 0x1 : 0x4) . $ip : \pack('C2', 0x3, \strlen($uri->getHost())) . $uri->getHost(); } catch (\danog\MadelineProto\Exception $e) { - $payload .= \pack('C2', 0x03, \strlen($uri->getHost())).$uri->getHost(); + $payload .= \pack('C2', 0x3, \strlen($uri->getHost())) . $uri->getHost(); } - $payload .= \pack('n', $uri->getPort()); yield $this->stream->write($payload); - $l = 4; $buffer = yield $this->stream->getReadBuffer($l); - $version = \ord(yield $buffer->bufferRead(1)); if ($version !== 5) { - throw new \danog\MadelineProto\Exception("Wrong SOCKS5 version: $version"); + throw new \danog\MadelineProto\Exception("Wrong SOCKS5 version: {$version}"); } - $rep = \ord(yield $buffer->bufferRead(1)); if ($rep !== 0) { $rep = self::REPS[$rep] ?? $rep; - throw new \danog\MadelineProto\Exception("Wrong SOCKS5 rep: $rep"); + throw new \danog\MadelineProto\Exception("Wrong SOCKS5 rep: {$rep}"); } - $rsv = \ord(yield $buffer->bufferRead(1)); if ($rsv !== 0) { - throw new \danog\MadelineProto\Exception("Wrong socks5 final RSV: $rsv"); + throw new \danog\MadelineProto\Exception("Wrong socks5 final RSV: {$rsv}"); } - switch (\ord(yield $buffer->bufferRead(1))) { case 1: $buffer = yield $this->stream->getReadBuffer($l); @@ -147,7 +119,6 @@ class SocksProxy implements RawProxyStreamInterface, BufferedProxyStreamInterfac $l = 1; $buffer = yield $this->stream->getReadBuffer($l); $length = \ord(yield $buffer->bufferRead(1)); - $buffer = yield $this->stream->getReadBuffer($length); $ip = yield $buffer->bufferRead($length); break; @@ -155,9 +126,7 @@ class SocksProxy implements RawProxyStreamInterface, BufferedProxyStreamInterfac $l = 2; $buffer = yield $this->stream->getReadBuffer($l); $port = \unpack('n', yield $buffer->bufferRead(2))[1]; - - \danog\MadelineProto\Logger::log(['Connected to '.$ip.':'.$port.' via socks5']); - + \danog\MadelineProto\Logger::log(['Connected to ' . $ip . ':' . $port . ' via socks5']); if ($secure) { yield $this->getSocket()->setupTls(); } @@ -165,7 +134,6 @@ class SocksProxy implements RawProxyStreamInterface, BufferedProxyStreamInterfac yield (yield $this->stream->getWriteBuffer(\strlen($header)))->bufferWrite($header); } } - /** * Async close. * @@ -175,7 +143,6 @@ class SocksProxy implements RawProxyStreamInterface, BufferedProxyStreamInterfac { return $this->stream->disconnect(); } - /** * Get write buffer asynchronously. * @@ -187,7 +154,6 @@ class SocksProxy implements RawProxyStreamInterface, BufferedProxyStreamInterfac { return $this->stream->getWriteBuffer($length, $append); } - /** * Get read buffer asynchronously. * @@ -199,17 +165,14 @@ class SocksProxy implements RawProxyStreamInterface, BufferedProxyStreamInterfac { return $this->stream->getReadBuffer($length); } - public function read(): Promise { return $this->stream->read(); } - public function write(string $data): Promise { return $this->stream->write($data); } - /** * Sets proxy data. * @@ -230,7 +193,6 @@ class SocksProxy implements RawProxyStreamInterface, BufferedProxyStreamInterfac { return $this->stream; } - /** * {@inheritdoc} * @@ -240,7 +202,6 @@ class SocksProxy implements RawProxyStreamInterface, BufferedProxyStreamInterfac { return $this->stream->getSocket(); } - public static function getName(): string { return __CLASS__; diff --git a/src/danog/MadelineProto/Stream/ProxyStreamInterface.php b/src/danog/MadelineProto/Stream/ProxyStreamInterface.php index f948608f..6a90bcdd 100644 --- a/src/danog/MadelineProto/Stream/ProxyStreamInterface.php +++ b/src/danog/MadelineProto/Stream/ProxyStreamInterface.php @@ -1,4 +1,5 @@ <?php + /** * Generic stream proxy interface. * diff --git a/src/danog/MadelineProto/Stream/RawProxyStreamInterface.php b/src/danog/MadelineProto/Stream/RawProxyStreamInterface.php index 48d3d3b8..1b73ddf4 100644 --- a/src/danog/MadelineProto/Stream/RawProxyStreamInterface.php +++ b/src/danog/MadelineProto/Stream/RawProxyStreamInterface.php @@ -1,4 +1,5 @@ <?php + /** * Raw stream proxy interface. * diff --git a/src/danog/MadelineProto/Stream/RawStreamInterface.php b/src/danog/MadelineProto/Stream/RawStreamInterface.php index 1a591181..0eb4ecd8 100644 --- a/src/danog/MadelineProto/Stream/RawStreamInterface.php +++ b/src/danog/MadelineProto/Stream/RawStreamInterface.php @@ -1,4 +1,5 @@ <?php + /** * Raw stream interface. * diff --git a/src/danog/MadelineProto/Stream/StreamInterface.php b/src/danog/MadelineProto/Stream/StreamInterface.php index 4eb7ee1f..ff4edeb6 100644 --- a/src/danog/MadelineProto/Stream/StreamInterface.php +++ b/src/danog/MadelineProto/Stream/StreamInterface.php @@ -1,4 +1,5 @@ <?php + /** * Generic stream interface. * @@ -37,14 +38,12 @@ interface StreamInterface * @return Promise */ public function connect(ConnectionContext $ctx, string $header = ''): Promise; - /** * Disconnect from the server. * * @return void */ public function disconnect(); - /** * Get underlying AMPHP socket resource. * diff --git a/src/danog/MadelineProto/Stream/Transport/DefaultStream.php b/src/danog/MadelineProto/Stream/Transport/DefaultStream.php index 9b81c108..6cd2894e 100644 --- a/src/danog/MadelineProto/Stream/Transport/DefaultStream.php +++ b/src/danog/MadelineProto/Stream/Transport/DefaultStream.php @@ -1,4 +1,5 @@ <?php + /** * Default stream wrapper. * @@ -27,7 +28,6 @@ use Amp\Socket\Socket; use danog\MadelineProto\Stream\Async\RawStream; use danog\MadelineProto\Stream\ProxyStreamInterface; use danog\MadelineProto\Stream\RawStreamInterface; - use function Amp\Socket\connector; /** @@ -37,9 +37,7 @@ use function Amp\Socket\connector; * * @author Daniil Gentili <daniil@daniil.it> */ -class DefaultStream implements - RawStreamInterface, - ProxyStreamInterface +class DefaultStream implements RawStreamInterface, ProxyStreamInterface { use RawStream; /** @@ -48,44 +46,34 @@ class DefaultStream implements * @var EncryptableSocket */ private $stream; - /** * Connector. * * @var Connector */ private $connector; - public function setupTls(?CancellationToken $cancellationToken = null): \Amp\Promise { return $this->stream->setupTls($cancellationToken); } - public function getStream() { return $this->stream; } - public function connectGenerator(\danog\MadelineProto\Stream\ConnectionContext $ctx, string $header = ''): \Generator { $ctx = $ctx->getCtx(); $uri = $ctx->getUri(); $secure = $ctx->isSecure(); if ($secure) { - $ctx->setSocketContext( - $ctx->getSocketContext()->withTlsContext( - new ClientTlsContext($uri->getHost()) - ) - ); + $ctx->setSocketContext($ctx->getSocketContext()->withTlsContext(new ClientTlsContext($uri->getHost()))); } - $this->stream = yield ($this->connector ?? connector())->connect((string) $uri, $ctx->getSocketContext(), $ctx->getCancellationToken()); if ($secure) { yield $this->stream->setupTls(); } yield $this->stream->write($header); } - /** * Async chunked read. * @@ -95,7 +83,6 @@ class DefaultStream implements { return $this->stream ? $this->stream->read() : new \Amp\Success(null); } - /** * Async write. * @@ -110,7 +97,6 @@ class DefaultStream implements } return $this->stream->write($data); } - /** * Close. * @@ -124,10 +110,9 @@ class DefaultStream implements $this->stream = null; } } catch (\Throwable $e) { - \danog\MadelineProto\Logger::log('Got exception while closing stream: '.$e->getMessage()); + \danog\MadelineProto\Logger::log('Got exception while closing stream: ' . $e->getMessage()); } } - /** * Close. * @@ -137,7 +122,6 @@ class DefaultStream implements { $this->disconnect(); } - /** * {@inheritdoc} * @@ -147,12 +131,10 @@ class DefaultStream implements { return $this->stream; } - public function setExtra($extra) { $this->connector = $extra; } - public static function getName(): string { return __CLASS__; diff --git a/src/danog/MadelineProto/Stream/Transport/PremadeStream.php b/src/danog/MadelineProto/Stream/Transport/PremadeStream.php index d1f8ab2a..f6def9c4 100644 --- a/src/danog/MadelineProto/Stream/Transport/PremadeStream.php +++ b/src/danog/MadelineProto/Stream/Transport/PremadeStream.php @@ -1,4 +1,5 @@ <?php + /** * Premade stream wrapper. * @@ -38,29 +39,23 @@ class PremadeStream implements RawStreamInterface, ProxyStreamInterface { use RawStream; private $stream; - public function __construct() { } - public function setupTls(?CancellationToken $cancellationToken = null): \Amp\Promise { return $this->stream->setupTls($cancellationToken); } - - public function getStream() { return $this->stream; } - public function connectGenerator(ConnectionContext $ctx, string $header = ''): \Generator { if ($header !== '') { yield $this->stream->write($header); } } - /** * Async chunked read. * @@ -70,7 +65,6 @@ class PremadeStream implements RawStreamInterface, ProxyStreamInterface { return $this->stream ? $this->stream->read() : new \Amp\Success(null); } - /** * Async write. * @@ -85,7 +79,6 @@ class PremadeStream implements RawStreamInterface, ProxyStreamInterface } return $this->stream->write($data); } - /** * Async close. * @@ -101,15 +94,13 @@ class PremadeStream implements RawStreamInterface, ProxyStreamInterface $this->stream = null; } } catch (\Throwable $e) { - \danog\MadelineProto\Logger::log('Got exception while closing stream: '.$e->getMessage()); + \danog\MadelineProto\Logger::log('Got exception while closing stream: ' . $e->getMessage()); } } - public function close() { $this->disconnect(); } - /** * {@inheritdoc} * @@ -119,7 +110,6 @@ class PremadeStream implements RawStreamInterface, ProxyStreamInterface { return $this->stream; } - /** * {@inheritdoc} */ diff --git a/src/danog/MadelineProto/Stream/Transport/WsStream.php b/src/danog/MadelineProto/Stream/Transport/WsStream.php index f2b64557..32b6d351 100644 --- a/src/danog/MadelineProto/Stream/Transport/WsStream.php +++ b/src/danog/MadelineProto/Stream/Transport/WsStream.php @@ -1,4 +1,5 @@ <?php + /** * Websocket stream wrapper. * @@ -26,7 +27,6 @@ use danog\MadelineProto\Stream\Async\RawStream; use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\ProxyStreamInterface; use danog\MadelineProto\Stream\RawStreamInterface; - use function Amp\Websocket\Client\connector; /** @@ -37,7 +37,6 @@ use function Amp\Websocket\Client\connector; class WsStream implements RawStreamInterface, ProxyStreamInterface { use RawStream; - /** * Websocket stream. * @@ -56,7 +55,6 @@ class WsStream implements RawStreamInterface, ProxyStreamInterface * @var Connector */ private $connector; - /** * Connect to stream. * @@ -69,18 +67,13 @@ class WsStream implements RawStreamInterface, ProxyStreamInterface if (!\class_exists(Connector::class)) { throw new \danog\MadelineProto\Exception('Please install amphp/websocket-client by running "composer require amphp/websocket-client:dev-master"'); } - $this->dc = $ctx->getIntDc(); - $handshake = new Handshake(\str_replace('tcp://', $ctx->isSecure() ? 'wss://' : 'ws://', $ctx->getStringUri())); - $this->stream = yield ($this->connector ?? connector())->connect($handshake, $ctx->getCancellationToken()); - if (\strlen($header)) { yield $this->write($header); } } - /** * Async close. */ @@ -91,7 +84,6 @@ class WsStream implements RawStreamInterface, ProxyStreamInterface } catch (\Throwable $e) { } } - public function readGenerator(): \Generator { try { @@ -107,12 +99,10 @@ class WsStream implements RawStreamInterface, ProxyStreamInterface if ($e->getReason() !== 'Client closed the underlying TCP connection') { throw $e; } - return null; } return $data; } - /** * Async write. * @@ -124,7 +114,6 @@ class WsStream implements RawStreamInterface, ProxyStreamInterface { return $this->stream->sendBinary($data); } - /** * {@inheritdoc} * @@ -140,7 +129,6 @@ class WsStream implements RawStreamInterface, ProxyStreamInterface $this->connector = $extra; } } - public static function getName(): string { return __CLASS__; diff --git a/src/danog/MadelineProto/Stream/Transport/WssStream.php b/src/danog/MadelineProto/Stream/Transport/WssStream.php index 52fe8657..38475d66 100644 --- a/src/danog/MadelineProto/Stream/Transport/WssStream.php +++ b/src/danog/MadelineProto/Stream/Transport/WssStream.php @@ -1,4 +1,5 @@ <?php + /** * Websocket TLS stream wrapper. * @@ -38,7 +39,6 @@ class WssStream extends WsStream { return parent::connectGenerator($ctx->getCtx()->secure(true), $header); } - public static function getName(): string { return __CLASS__; diff --git a/src/danog/MadelineProto/TL/Conversion/BotAPI.php b/src/danog/MadelineProto/TL/Conversion/BotAPI.php index d250f428..0377848f 100644 --- a/src/danog/MadelineProto/TL/Conversion/BotAPI.php +++ b/src/danog/MadelineProto/TL/Conversion/BotAPI.php @@ -27,7 +27,6 @@ trait BotAPI { return \html_entity_decode(\preg_replace('#< *br */? *>#', "\n", $stuff)); } - /** * Get Telegram UTF-8 length of string. * @@ -41,14 +40,12 @@ trait BotAPI $textlength = \strlen($text); for ($x = 0; $x < $textlength; $x++) { $char = \ord($text[$x]); - if (($char & 0xC0) != 0x80) { + if (($char & 0xc0) != 0x80) { $length += 1 + ($char >= 0xf0); } } - return $length; } - /** * Telegram UTF-8 multibyte substring. * @@ -65,7 +62,7 @@ trait BotAPI $offset = $mb_text_length + $offset; } if ($length < 0) { - $length = ($mb_text_length - $offset) + $length; + $length = $mb_text_length - $offset + $length; } elseif ($length === null) { $length = $mb_text_length - $offset; } @@ -75,7 +72,7 @@ trait BotAPI $text_length = \strlen($text); for ($x = 0; $x < $text_length; $x++) { $char = \ord($text[$x]); - if (($char & 0xC0) != 0x80) { + if (($char & 0xc0) != 0x80) { $current_offset += 1 + ($char >= 0xf0); if ($current_offset > $offset) { $current_length += 1 + ($char >= 0xf0); @@ -87,10 +84,8 @@ trait BotAPI } } } - return $new_text; } - /** * Telegram UTF-8 multibyte split. * @@ -106,10 +101,8 @@ trait BotAPI for ($x = 0; $x < $tlength; $x += $length) { $result[] = \mb_substr($text, $x, $length, 'UTF-8'); } - return $result; } - private function parseButtons($rows) { $newrows = []; @@ -145,10 +138,8 @@ trait BotAPI } $key++; } - return $newrows; } - private function parseReplyMarkup($markup) { if (isset($markup['force_reply']) && $markup['force_reply']) { @@ -177,10 +168,8 @@ trait BotAPI $markup['rows'] = $this->parseButtons($markup['inline_keyboard']); unset($markup['inline_keyboard']); } - return $markup; } - /** * Convert MTProto parameters to bot API parameters. * @@ -194,9 +183,8 @@ trait BotAPI $newd = []; if (!isset($data['_'])) { foreach ($data as $key => $element) { - $newd[$key] = yield $this->MTProtoToBotAPI($element, $sent_arguments); + $newd[$key] = (yield from $this->MTProtoToBotAPI($element, $sent_arguments)); } - return $newd; } switch ($data['_']) { @@ -209,16 +197,15 @@ trait BotAPI } $newd['chat'] = yield $this->getPwrChat($sent_arguments['peer']); if (isset($data['entities'])) { - $newd['entities'] = yield $this->MTProtoToBotAPI($data['entities'], $sent_arguments); + $newd['entities'] = (yield from $this->MTProtoToBotAPI($data['entities'], $sent_arguments)); } if (isset($data['media'])) { - $newd = \array_merge($newd, yield $this->MTProtoToBotAPI($data['media'], $sent_arguments)); + $newd = \array_merge($newd, yield from $this->MTProtoToBotAPI($data['media'], $sent_arguments)); } - return $newd; case 'updateNewChannelMessage': case 'updateNewMessage': - return yield $this->MTProtoToBotAPI($data['message']); + return yield from $this->MTProtoToBotAPI($data['message']); case 'message': $newd['message_id'] = $data['id']; $newd['date'] = $data['date']; @@ -230,7 +217,7 @@ trait BotAPI } $newd['chat'] = yield $this->getPwrChat($data['to_id']); if (isset($data['entities'])) { - $newd['entities'] = yield $this->MTProtoToBotAPI($data['entities'], $sent_arguments); + $newd['entities'] = (yield from $this->MTProtoToBotAPI($data['entities'], $sent_arguments)); } if (isset($data['views'])) { $newd['views'] = $data['views']; @@ -254,66 +241,54 @@ trait BotAPI $newd['forward_from_message_id'] = $data['fwd_from']['channel_post']; } if (isset($data['media'])) { - $newd = \array_merge($newd, yield $this->MTProtoToBotAPI($data['media'], $sent_arguments)); + $newd = \array_merge($newd, yield from $this->MTProtoToBotAPI($data['media'], $sent_arguments)); } - return $newd; case 'messageEntityMention': unset($data['_']); $data['type'] = 'mention'; - return $data; case 'messageEntityHashtag': unset($data['_']); $data['type'] = 'hashtag'; - return $data; case 'messageEntityBotCommand': unset($data['_']); $data['type'] = 'bot_command'; - return $data; case 'messageEntityUrl': unset($data['_']); $data['type'] = 'url'; - return $data; case 'messageEntityEmail': unset($data['_']); $data['type'] = 'email'; - return $data; case 'messageEntityBold': unset($data['_']); $data['type'] = 'bold'; - return $data; case 'messageEntityItalic': unset($data['_']); $data['type'] = 'italic'; - return $data; case 'messageEntityCode': unset($data['_']); $data['type'] = 'code'; - return $data; case 'messageEntityPre': unset($data['_']); $data['type'] = 'pre'; - return $data; case 'messageEntityTextUrl': unset($data['_']); $data['type'] = 'text_url'; - return $data; case 'messageEntityMentionName': unset($data['_']); $data['type'] = 'text_mention'; $data['user'] = yield $this->getPwrChat($data['user_id']); unset($data['user_id']); - return $data; case 'messageMediaPhoto': if (isset($data['caption'])) { @@ -325,7 +300,6 @@ trait BotAPI $res['photo'][$key] = yield $this->photosizeToBotAPI($photo, $data['photo']); } } - return $res; case 'messageMediaEmpty': return []; @@ -339,7 +313,7 @@ trait BotAPI switch ($attribute['_']) { case 'documentAttributeFilename': $pathinfo = \pathinfo($attribute['file_name']); - $res['ext'] = isset($pathinfo['extension']) ? '.'.$pathinfo['extension'] : ''; + $res['ext'] = isset($pathinfo['extension']) ? '.' . $pathinfo['extension'] : ''; $res['file_name'] = $pathinfo['filename']; break; case 'documentAttributeAudio': @@ -390,30 +364,28 @@ trait BotAPI if (isset($audio) && isset($audio['title']) && !isset($res['file_name'])) { $res['file_name'] = $audio['title']; if (isset($audio['performer'])) { - $res['file_name'] .= ' - '.$audio['performer']; + $res['file_name'] .= ' - ' . $audio['performer']; } } if (!isset($res['file_name'])) { $res['file_name'] = $data['document']['access_hash']; } - $res['file_name'] .= '_'.$data['document']['id']; + $res['file_name'] .= '_' . $data['document']['id']; if (isset($res['ext'])) { $res['file_name'] .= $res['ext']; unset($res['ext']); } else { $res['file_name'] .= $this->getExtensionFromMime($data['document']['mime_type']); } - $data['document']['_'] = 'bot_'.$type_name; + $data['document']['_'] = 'bot_' . $type_name; $res['file_size'] = $data['document']['size']; $res['mime_type'] = $data['document']['mime_type']; - $res['file_id'] = \danog\MadelineProto\Tools::base64urlEncode(\danog\MadelineProto\Tools::rleEncode((yield $this->TL->serializeObject(['type' => 'File'], $data['document'], 'File')).\chr(2))); - + $res['file_id'] = \danog\MadelineProto\Tools::base64urlEncode(\danog\MadelineProto\Tools::rleEncode(yield $this->TL->serializeObject(['type' => 'File'], $data['document'], 'File') . \chr(2))); return [$type_name => $res, 'caption' => isset($data['caption']) ? $data['caption'] : '']; default: throw new Exception(\sprintf(\danog\MadelineProto\Lang::$current_lang['botapi_conversion_error'], $data['_'])); } } - /** * Convert bot API parameters to MTProto parameters. * @@ -433,13 +405,11 @@ trait BotAPI $arguments['reply_markup'] = $this->parseReplyMarkup($arguments['reply_markup']); } if (isset($arguments['parse_mode'])) { - $arguments = yield $this->parseMode($arguments); + $arguments = (yield from $this->parseMode($arguments)); } - return $arguments; } - - private function parseNode($node, &$entities, &$new_message, &$offset) + private function parseNode($node, &$entities, &$new_message, &$offset): \Generator { switch ($node->nodeName) { case 'br': @@ -450,65 +420,51 @@ trait BotAPI case 'strike': case 'del': $text = $this->htmlEntityDecode($node->textContent); - $length = $this->mbStrlen($text); $entities[] = ['_' => 'messageEntityStrike', 'offset' => $offset, 'length' => $length]; - $new_message .= $text; $offset += $length; break; case 'u': $text = $this->htmlEntityDecode($node->textContent); - $length = $this->mbStrlen($text); $entities[] = ['_' => 'messageEntityUnderline', 'offset' => $offset, 'length' => $length]; - $new_message .= $text; $offset += $length; break; case 'blockquote': $text = $this->htmlEntityDecode($node->textContent); - $length = $this->mbStrlen($text); $entities[] = ['_' => 'messageEntityBlockquote', 'offset' => $offset, 'length' => $length]; - $new_message .= $text; $offset += $length; break; case 'b': case 'strong': $text = $this->htmlEntityDecode($node->textContent); - $length = $this->mbStrlen($text); $entities[] = ['_' => 'messageEntityBold', 'offset' => $offset, 'length' => $length]; - $new_message .= $text; $offset += $length; break; case 'i': case 'em': $text = $this->htmlEntityDecode($node->textContent); - $length = $this->mbStrlen($text); $entities[] = ['_' => 'messageEntityItalic', 'offset' => $offset, 'length' => $length]; - $new_message .= $text; $offset += $length; break; case 'code': $text = $this->htmlEntityDecode($node->textContent); - $length = $this->mbStrlen($text); $entities[] = ['_' => 'messageEntityCode', 'offset' => $offset, 'length' => $length]; - $new_message .= $text; $offset += $length; break; case 'pre': $text = $this->htmlEntityDecode($node->textContent); - $length = $this->mbStrlen($text); - $language = $node->getAttribute('language'); if ($language === null) { $language = ''; @@ -519,14 +475,14 @@ trait BotAPI break; case 'p': foreach ($node->childNodes as $node) { - yield $this->parseNode($node, $entities, $new_message, $offset); + yield from $this->parseNode($node, $entities, $new_message, $offset); } break; case 'a': $text = $this->htmlEntityDecode($node->textContent); $length = $this->mbStrlen($text); $href = $node->getAttribute('href'); - if (\preg_match('|mention:(.*)|', $href, $matches) || \preg_match('|tg://user\?id=(.*)|', $href, $matches)) { + if (\preg_match('|mention:(.*)|', $href, $matches) || \preg_match('|tg://user\\?id=(.*)|', $href, $matches)) { $mention = yield $this->getInfo($matches[1]); if (!isset($mention['InputUser'])) { throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['peer_not_in_db']); @@ -579,9 +535,7 @@ trait BotAPI } if (\stripos($arguments['parse_mode'], 'html') !== false) { $new_message = ''; - $arguments['message'] = \trim($this->htmlFixtags($arguments['message'])); - $dom = new \DOMDocument(); $dom->loadHTML(\mb_convert_encoding($arguments['message'], 'HTML-ENTITIES', 'UTF-8')); if (!isset($arguments['entities'])) { @@ -589,7 +543,7 @@ trait BotAPI } $offset = 0; foreach ($dom->getElementsByTagName('body')->item(0)->childNodes as $node) { - yield $this->parseNode($node, $arguments['entities'], $new_message, $offset); + yield from $this->parseNode($node, $arguments['entities'], $new_message, $offset); } if (isset($arguments['entities']['buttons'])) { $arguments['reply_markup'] = $this->buildRows($arguments['entities']['buttons']); @@ -598,10 +552,8 @@ trait BotAPI unset($arguments['parse_mode']); $arguments['message'] = $new_message; } - return $arguments; } - /** * Split too long message into chunks. * @@ -613,15 +565,13 @@ trait BotAPI */ public function splitToChunks($args): \Generator { - $args = yield $this->parseMode($args); + $args = (yield from $this->parseMode($args)); if (!isset($args['entities'])) { $args['entities'] = []; } - $max_length = isset($args['media']) ? $this->config['caption_length_max'] : $this->config['message_length_max']; $max_entity_length = 100; $max_entity_size = 8110; - $text_arr = []; foreach ($this->multipleExplodeKeepDelimiters(["\n"], $args['message']) as $word) { if (\mb_strlen($word, 'UTF-8') > $max_length) { @@ -632,12 +582,11 @@ trait BotAPI $text_arr[] = $word; } } - $multiple_args_base = \array_merge($args, ['entities' => [], 'parse_mode' => 'text', 'message' => '']); $multiple_args = [$multiple_args_base]; $i = 0; foreach ($text_arr as $word) { - if ($this->mbStrlen($multiple_args[$i]['message'].$word) <= $max_length) { + if ($this->mbStrlen($multiple_args[$i]['message'] . $word) <= $max_length) { $multiple_args[$i]['message'] .= $word; } else { $i++; @@ -645,7 +594,6 @@ trait BotAPI $multiple_args[$i]['message'] .= $word; } } - $i = 0; $offset = 0; for ($k = 0; $k < \count($args['entities']); $k++) { @@ -656,19 +604,16 @@ trait BotAPI $i++; } $entity['offset'] -= $offset; - if ($entity['offset'] + $entity['length'] > $this->mbStrlen($multiple_args[$i]['message'])) { $newentity = $entity; $newentity['length'] = $entity['length'] - ($this->mbStrlen($multiple_args[$i]['message']) - $entity['offset']); $entity['length'] = $this->mbStrlen($multiple_args[$i]['message']) - $entity['offset']; - - $offset += $entity['length']; //$this->mbStrlen($multiple_args[$i]['message']); + $offset += $entity['length']; + //$this->mbStrlen($multiple_args[$i]['message']); $newentity['offset'] = $offset; - $prev_length = $this->mbStrlen($multiple_args[$i]['message']); $multiple_args[$i]['message'] = \rtrim($multiple_args[$i]['message']); $diff = $prev_length - $this->mbStrlen($multiple_args[$i]['message']); - if ($diff) { $entity['length'] -= $diff; foreach ($args['entities'] as $key => &$eentity) { @@ -677,11 +622,9 @@ trait BotAPI } } } - $multiple_args[$i]['entities'][] = $entity; $i++; $entity = $newentity; - continue; } $prev_length = $this->mbStrlen($multiple_args[$i]['message']); @@ -715,12 +658,10 @@ trait BotAPI } } if ($total) { - $this->logger->logger("Too many entities, $total entities will be truncated", Logger::FATAL_ERROR); + $this->logger->logger("Too many entities, {$total} entities will be truncated", Logger::FATAL_ERROR); } - return $multiple_args; } - private function multipleExplodeKeepDelimiters($delimiters, $string) { $initialArray = \explode(\chr(1), \str_replace($delimiters, \chr(1), $string)); @@ -729,57 +670,47 @@ trait BotAPI foreach ($initialArray as $item) { $delimOffset += $this->mbStrlen($item); //if ($this->mbStrlen($item) > 0) { - $finalArray[] = $item.($delimOffset < $this->mbStrlen($string) ? $string[$delimOffset] : ''); + $finalArray[] = $item . ($delimOffset < $this->mbStrlen($string) ? $string[$delimOffset] : ''); //} $delimOffset++; } - return $finalArray; } - private function htmlFixtags($text) { $diff = 0; - \preg_match_all('#(.*?)(<(\bu\b|\bs\b|\ba\b|\bb\b|\bstrong\b|\bblockquote\b|\bstrike\b|\bdel\b|\bem\b|i|\bcode\b|\bpre\b)[^>]*>)(.*?)([<]\s*/\s*\3[>])#is', $text, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE); + \preg_match_all('#(.*?)(<(\\bu\\b|\\bs\\b|\\ba\\b|\\bb\\b|\\bstrong\\b|\\bblockquote\\b|\\bstrike\\b|\\bdel\\b|\\bem\\b|i|\\bcode\\b|\\bpre\\b)[^>]*>)(.*?)([<]\\s*/\\s*\\3[>])#is', $text, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE); if ($matches) { foreach ($matches as $match) { if (\trim($match[1][0]) != '') { $mod = \htmlentities($match[1][0]); - $temp = \substr($text, 0, $match[1][1] + $diff); $temp .= $mod; $temp .= \substr($text, $match[1][1] + $diff + \strlen($match[1][0])); - $diff += \strlen($mod) - \strlen($match[1][0]); - $text = $temp; } $mod = \htmlentities($match[4][0]); - $temp = \substr($text, 0, $match[4][1] + $diff); $temp .= $mod; $temp .= \substr($text, $match[4][1] + $diff + \strlen($match[4][0])); - $diff += \strlen($mod) - \strlen($match[4][0]); $text = $temp; } $diff = 0; - \preg_match_all('#<a\s*href=("|\')(.+?)("|\')\s*>#is', $text, $matches, PREG_OFFSET_CAPTURE); + \preg_match_all('#<a\\s*href=("|\')(.+?)("|\')\\s*>#is', $text, $matches, PREG_OFFSET_CAPTURE); foreach ($matches[2] as $match) { $mod = \htmlentities($match[0]); $temp = \substr($text, 0, $match[1] + $diff); $temp .= $mod; $temp .= \substr($text, $match[1] + $diff + \strlen($match[0])); - $diff += \strlen($mod) - \strlen($match[0]); $text = $temp; } - return $text; } return \htmlentities($text); } - private function buildRows($button_list) { $end = false; @@ -804,7 +735,6 @@ trait BotAPI $row = ['_' => 'keyboardButtonRow', 'buttons' => $buttons]; $rows[] = $row; } - return ['_' => 'replyInlineMarkup', 'rows' => $rows]; } } diff --git a/src/danog/MadelineProto/TL/Conversion/BotAPIFiles.php b/src/danog/MadelineProto/TL/Conversion/BotAPIFiles.php index 35e5599f..599821e0 100644 --- a/src/danog/MadelineProto/TL/Conversion/BotAPIFiles.php +++ b/src/danog/MadelineProto/TL/Conversion/BotAPIFiles.php @@ -27,24 +27,16 @@ trait BotAPIFiles { private function photosizeToBotAPI($photoSize, $photo, $thumbnail = false): \Generator { - $ext = '.jpg';//$this->getExtensionFromLocation(['_' => 'inputFileLocation', 'volume_id' => $photoSize['location']['volume_id'], 'local_id' => $photoSize['location']['local_id'], 'secret' => $photoSize['location']['secret'], 'dc_id' => $photoSize['location']['dc_id']], '.jpg'); + $ext = '.jpg'; + //$this->getExtensionFromLocation(['_' => 'inputFileLocation', 'volume_id' => $photoSize['location']['volume_id'], 'local_id' => $photoSize['location']['local_id'], 'secret' => $photoSize['location']['secret'], 'dc_id' => $photoSize['location']['dc_id']], '.jpg'); $photoSize['location']['access_hash'] = $photo['access_hash'] ?? 0; $photoSize['location']['id'] = $photo['id'] ?? 0; $photoSize['location']['secret'] = $photo['location']['secret'] ?? 0; $photoSize['location']['dc_id'] = $photo['dc_id'] ?? 0; $photoSize['location']['_'] = $thumbnail ? 'bot_thumbnail' : 'bot_photo'; - $data = (yield $this->TL->serializeObject(['type' => 'File'], $photoSize['location'], 'File')).\chr(2); - - return [ - 'file_id' => \danog\MadelineProto\Tools::base64urlEncode(\danog\MadelineProto\Tools::rleEncode($data)), - 'width' => $photoSize['w'], - 'height' => $photoSize['h'], - 'file_size' => isset($photoSize['size']) ? $photoSize['size'] : \strlen($photoSize['bytes']), - 'mime_type' => 'image/jpeg', - 'file_name' => $photoSize['location']['volume_id'].'_'.$photoSize['location']['local_id'].$ext - ]; + $data = yield $this->TL->serializeObject(['type' => 'File'], $photoSize['location'], 'File') . \chr(2); + return ['file_id' => \danog\MadelineProto\Tools::base64urlEncode(\danog\MadelineProto\Tools::rleEncode($data)), 'width' => $photoSize['w'], 'height' => $photoSize['h'], 'file_size' => isset($photoSize['size']) ? $photoSize['size'] : \strlen($photoSize['bytes']), 'mime_type' => 'image/jpeg', 'file_name' => $photoSize['location']['volume_id'] . '_' . $photoSize['location']['local_id'] . $ext]; } - /** * Unpack bot API file ID. * @@ -57,15 +49,14 @@ trait BotAPIFiles $file_id = Tools::rleDecode(Tools::base64urlDecode($file_id)); $version = \ord($file_id[\strlen($file_id) - 1]); $subVersion = $version === 4 ? \ord($file_id[\strlen($file_id) - 2]) : 0; - $this->logger("Got file ID with version $version.$subVersion"); + $this->logger("Got file ID with version {$version}.{$subVersion}"); if (!\in_array($version, [2, 4])) { - throw new Exception("Invalid bot API file ID version $version"); + throw new Exception("Invalid bot API file ID version {$version}"); } $res = \fopen('php://memory', 'rw+b'); \fwrite($res, $file_id); \fseek($res, 0); $file_id = $res; - $deserialized = $this->TL->deserialize($file_id); $res = ['type' => \str_replace('bot_', '', $deserialized['_'])]; if (\in_array($res['type'], ['profile_photo', 'thumbnail', 'photo'])) { @@ -96,134 +87,64 @@ trait BotAPIFiles switch ($deserialized['_']) { case 'bot_profile_photo': if ($deserialized['dialog_id'] < 0) { - $res['Chat'] = [ - '_' => $deserialized['dialog_id'] < -1000000000000 ? 'channel' : 'chat', - 'id' => $deserialized['dialog_id'] < -1000000000000 ? PeerHandler::fromSupergroup($deserialized['dialog_id']) : -$deserialized['dialog_id'], - 'access_hash' => $deserialized['dialog_access_hash'], - 'photo' => [ - '_' => 'chatPhoto', - 'dc_id' => $deserialized['dc_id'], - $deserialized['photo_size'] => [ - '_' => 'fileLocationToBeDeprecated', - 'volume_id' => $deserialized['volume_id'], - 'local_id' => $deserialized['local_id'], - ] - ], - 'min' => true - ]; + $res['Chat'] = ['_' => $deserialized['dialog_id'] < -1000000000000 ? 'channel' : 'chat', 'id' => $deserialized['dialog_id'] < -1000000000000 ? PeerHandler::fromSupergroup($deserialized['dialog_id']) : -$deserialized['dialog_id'], 'access_hash' => $deserialized['dialog_access_hash'], 'photo' => ['_' => 'chatPhoto', 'dc_id' => $deserialized['dc_id'], $deserialized['photo_size'] => ['_' => 'fileLocationToBeDeprecated', 'volume_id' => $deserialized['volume_id'], 'local_id' => $deserialized['local_id']]], 'min' => true]; return $res; } - $res['User'] = [ - '_' => 'user', - 'id' => $deserialized['dialog_id'], - 'access_hash' => $deserialized['dialog_access_hash'], - 'photo' => [ - '_' => 'userProfilePhoto', - 'dc_id' => $deserialized['dc_id'], - 'photo_id' => $deserialized['id'], - $deserialized['photo_size'] => [ - '_' => 'fileLocationToBeDeprecated', - 'volume_id' => $deserialized['volume_id'], - 'local_id' => $deserialized['local_id'], - ] - ], - 'min' => true - ]; + $res['User'] = ['_' => 'user', 'id' => $deserialized['dialog_id'], 'access_hash' => $deserialized['dialog_access_hash'], 'photo' => ['_' => 'userProfilePhoto', 'dc_id' => $deserialized['dc_id'], 'photo_id' => $deserialized['id'], $deserialized['photo_size'] => ['_' => 'fileLocationToBeDeprecated', 'volume_id' => $deserialized['volume_id'], 'local_id' => $deserialized['local_id']]], 'min' => true]; return $res; - case 'bot_thumbnail': - $res['InputFileLocation'] = [ - '_' => $deserialized['file_type'] >= 3 ? 'inputDocumentFileLocation' : 'inputPhotoFileLocation', - 'id' => $deserialized['id'], - 'access_hash' => $deserialized['access_hash'], - 'file_reference' => '', - 'thumb_size' => (string) $deserialized['thumbnail_type'] - ]; - $res['name'] = $deserialized['id'].'_'.$deserialized['thumbnail_type']; + $res['InputFileLocation'] = ['_' => $deserialized['file_type'] >= 3 ? 'inputDocumentFileLocation' : 'inputPhotoFileLocation', 'id' => $deserialized['id'], 'access_hash' => $deserialized['access_hash'], 'file_reference' => '', 'thumb_size' => (string) $deserialized['thumbnail_type']]; + $res['name'] = $deserialized['id'] . '_' . $deserialized['thumbnail_type']; $res['ext'] = 'jpg'; $res['mime'] = 'image/jpeg'; - - $res['InputMedia'] = [ - '_' => $deserialized['file_type'] >= 3 ? 'inputMediaDocument' : 'inputMediaPhoto', - 'id' => [ - '_' => $deserialized['file_type'] >= 3 ? 'inputDocument' : 'inputPhoto', - 'id' => $deserialized['id'], - 'access_hash' => $deserialized['access_hash'], - ] - ]; + $res['InputMedia'] = ['_' => $deserialized['file_type'] >= 3 ? 'inputMediaDocument' : 'inputMediaPhoto', 'id' => ['_' => $deserialized['file_type'] >= 3 ? 'inputDocument' : 'inputPhoto', 'id' => $deserialized['id'], 'access_hash' => $deserialized['access_hash']]]; return $res; - case 'bot_photo': if ($deserialized['photosize_source'] === 0) { $constructor['id'] = $deserialized['id']; $constructor['access_hash'] = $deserialized['access_hash']; unset($deserialized['id'], $deserialized['access_hash']); - $deserialized['_'] = $deserialized['secret'] ? 'fileLocation' : 'fileLocationToBeDeprecated'; $constructor['sizes'][0] = ['_' => 'photoSize', 'type' => '', 'location' => $deserialized]; $res['MessageMedia'] = ['_' => 'messageMediaPhoto', 'photo' => $constructor, 'caption' => '']; - return $res; } - $res['MessageMedia'] = [ - '_' => 'photo', - 'id' => $deserialized['id'], - 'access_hash' => $deserialized['access_hash'], - 'sizes' => [ - [ - '_' => 'photoSize', - 'type' => $deserialized['thumbnail_type'], - 'location' => [ - '_' => 'fileLocationToBeDeprecated', - 'local_id' => $deserialized['local_id'], - 'volume_id' => $deserialized['local_id'], - ] - ] - ], - 'dc_id' => $deserialized['dc_id'] - ]; + $res['MessageMedia'] = ['_' => 'photo', 'id' => $deserialized['id'], 'access_hash' => $deserialized['access_hash'], 'sizes' => [['_' => 'photoSize', 'type' => $deserialized['thumbnail_type'], 'location' => ['_' => 'fileLocationToBeDeprecated', 'local_id' => $deserialized['local_id'], 'volume_id' => $deserialized['local_id']]]], 'dc_id' => $deserialized['dc_id']]; return $res; case 'bot_voice': unset($deserialized['_']); $constructor = \array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => true]]]); $res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => '']; - return $res; case 'bot_video': unset($deserialized['_']); $constructor = \array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeVideo', 'round_message' => false]]]); $res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => '']; - return $res; case 'bot_document': unset($deserialized['_']); $constructor = \array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => []]); $res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => '']; - return $res; case 'bot_sticker': unset($deserialized['_']); $constructor = \array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeSticker']]]); $res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => '']; - return $res; case 'bot_audio': unset($deserialized['_']); $constructor = \array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => false]]]); $res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => '']; - return $res; case 'bot_gif': unset($deserialized['_']); $constructor = \array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeAnimated']]]); $res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => '']; - return $res; case 'bot_video_note': unset($deserialized['_']); $constructor = \array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeVideo', 'round_message' => true]]]); $res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => '']; - return $res; default: throw new Exception(\sprintf(\danog\MadelineProto\Lang::$current_lang['file_type_invalid'], $type)); diff --git a/src/danog/MadelineProto/TL/Conversion/Exception.php b/src/danog/MadelineProto/TL/Conversion/Exception.php index b6e47a74..05e6c622 100644 --- a/src/danog/MadelineProto/TL/Conversion/Exception.php +++ b/src/danog/MadelineProto/TL/Conversion/Exception.php @@ -22,17 +22,14 @@ namespace danog\MadelineProto\TL\Conversion; class Exception extends \Exception { use \danog\MadelineProto\TL\PrettyException; - public function __toString() { - $result = \get_class($this).($this->message !== '' ? ': ' : '').$this->message.PHP_EOL.\danog\MadelineProto\Magic::$revision.PHP_EOL.'TL Trace (YOU ABSOLUTELY MUST READ THE TEXT BELOW):'.PHP_EOL.PHP_EOL.$this->getTLTrace().PHP_EOL; + $result = \get_class($this) . ($this->message !== '' ? ': ' : '') . $this->message . PHP_EOL . \danog\MadelineProto\Magic::$revision . PHP_EOL . 'TL Trace (YOU ABSOLUTELY MUST READ THE TEXT BELOW):' . PHP_EOL . PHP_EOL . $this->getTLTrace() . PHP_EOL; if (PHP_SAPI !== 'cli') { - $result = \str_replace(PHP_EOL, '<br>'.PHP_EOL, $result); + $result = \str_replace(PHP_EOL, '<br>' . PHP_EOL, $result); } - return $result; } - public function __construct($message, $file = '') { parent::__construct($message); diff --git a/src/danog/MadelineProto/TL/Conversion/Extension.php b/src/danog/MadelineProto/TL/Conversion/Extension.php index 0b1557a4..998a07d4 100644 --- a/src/danog/MadelineProto/TL/Conversion/Extension.php +++ b/src/danog/MadelineProto/TL/Conversion/Extension.php @@ -35,10 +35,8 @@ trait Extension if (isset(MTProto::ALL_MIMES[$ext])) { return MTProto::ALL_MIMES[$ext][0]; } - return $default; } - /** * Get extension from mime type. * @@ -50,13 +48,11 @@ trait Extension { foreach (self::ALL_MIMES as $key => $value) { if (\array_search($mime, $value) !== false) { - return '.'.$key; + return '.' . $key; } } - return ''; } - /** * Get extension from file location. * @@ -93,7 +89,6 @@ trait Extension return $default; } } - /** * Get mime type of file. * @@ -104,10 +99,8 @@ trait Extension public static function getMimeFromFile(string $file): string { $finfo = new \finfo(FILEINFO_MIME_TYPE); - return $finfo->file($file); } - /** * Get mime type from buffer. * @@ -118,7 +111,6 @@ trait Extension public static function getMimeFromBuffer(string $buffer): string { $finfo = new \finfo(FILEINFO_MIME_TYPE); - return $finfo->buffer($buffer); } } diff --git a/src/danog/MadelineProto/TL/Conversion/TD.php b/src/danog/MadelineProto/TL/Conversion/TD.php index 1b45b0aa..a26ec164 100644 --- a/src/danog/MadelineProto/TL/Conversion/TD.php +++ b/src/danog/MadelineProto/TL/Conversion/TD.php @@ -36,7 +36,6 @@ trait TD } if (!isset($params['ID'])) { \array_walk($params, [$this, 'tdcliToTd']); - return $params; } foreach ($params as $key => $value) { @@ -48,10 +47,8 @@ trait TD } $params['_'] = \lcfirst($params['ID']); unset($params['ID']); - return $params; } - /** * Convert TD to MTProto parameters. * @@ -81,15 +78,13 @@ trait TD default: $newparams[$mtproto[0]] = isset($params[$td]) ? $params[$td] : null; if (\is_array($newparams[$mtproto[0]])) { - $newparams[$mtproto[0]] = yield $this->MTProtoToTd($newparams[$mtproto[0]]); + $newparams[$mtproto[0]] = (yield from $this->MTProtoToTd($newparams[$mtproto[0]])); } } } } - return $newparams; } - /** * MTProto to TDCLI params. * @@ -99,9 +94,8 @@ trait TD */ public function MTProtoToTdcli($params): \Generator { - return $this->tdToTdcli(yield $this->MTProtoToTd($params)); + return $this->tdToTdcli(yield from $this->MTProtoToTd($params)); } - /** * MTProto to TD params. * @@ -116,7 +110,6 @@ trait TD } if (!isset($params['_'])) { \array_walk($params, [$this, 'mtprotoToTd']); - return $params; } $newparams = ['_' => $params['_']]; @@ -144,7 +137,7 @@ trait TD if (isset($params['fwd_from'])) { $newparams[$td] = ['_' => 'messageForwardedFromUser']; if (isset($params['fwd_from']['channel_id'])) { - $newparams[$td] = ['_' => 'messageForwardedPost', 'chat_id' => '-100'.$params['fwd_from']['channel_id']]; + $newparams[$td] = ['_' => 'messageForwardedPost', 'chat_id' => '-100' . $params['fwd_from']['channel_id']]; } $newparams[$td]['date'] = $params['fwd_from']['date']; if (isset($params['fwd_from']['channel_post'])) { @@ -167,7 +160,7 @@ trait TD if ($params['message'] !== '') { $newparams[$td] = ['_' => 'messageText', 'text' => $params['message']]; if (isset($params['media']['_']) && $params['media']['_'] === 'messageMediaWebPage') { - $newparams[$td]['web_page'] = yield $this->MTProtoToTd($params['media']['webpage']); + $newparams[$td]['web_page'] = (yield from $this->MTProtoToTd($params['media']['webpage'])); } if (isset($params['entities'])) { $newparams[$td]['entities'] = $params['entities']; @@ -183,15 +176,13 @@ trait TD $newparams[$td] = isset($params[$mtproto[0]]) ? $params[$mtproto[0]] : null; } if (\is_array($newparams[$td])) { - $newparams[$td] = yield $this->MTProtoToTd($newparams[$td]); + $newparams[$td] = (yield from $this->MTProtoToTd($newparams[$td])); } } } } - return $newparams; } - /** * Convert TD parameters to tdcli. * @@ -210,12 +201,11 @@ trait TD $newparams['ID'] = \ucfirst($value); } else { if (!\is_numeric($key) && !\preg_match('/_^/', $key)) { - $key = $key.'_'; + $key = $key . '_'; } $newparams[$key] = $this->tdToTdcli($value); } } - return $newparams; } } diff --git a/src/danog/MadelineProto/TL/Exception.php b/src/danog/MadelineProto/TL/Exception.php index 137fda80..54b00517 100644 --- a/src/danog/MadelineProto/TL/Exception.php +++ b/src/danog/MadelineProto/TL/Exception.php @@ -22,17 +22,14 @@ namespace danog\MadelineProto\TL; class Exception extends \Exception { use PrettyException; - public function __toString() { - $result = \get_class($this).($this->message !== '' ? ': ' : '').$this->message.PHP_EOL.\danog\MadelineProto\Magic::$revision.PHP_EOL.'TL Trace (YOU ABSOLUTELY MUST READ THE TEXT BELOW):'.PHP_EOL.PHP_EOL.$this->getTLTrace().PHP_EOL; + $result = \get_class($this) . ($this->message !== '' ? ': ' : '') . $this->message . PHP_EOL . \danog\MadelineProto\Magic::$revision . PHP_EOL . 'TL Trace (YOU ABSOLUTELY MUST READ THE TEXT BELOW):' . PHP_EOL . PHP_EOL . $this->getTLTrace() . PHP_EOL; if (PHP_SAPI !== 'cli') { - $result = \str_replace(PHP_EOL, '<br>'.PHP_EOL, $result); + $result = \str_replace(PHP_EOL, '<br>' . PHP_EOL, $result); } - return $result; } - public function __construct($message, $file = '') { parent::__construct($message); diff --git a/src/danog/MadelineProto/TL/PrettyException.php b/src/danog/MadelineProto/TL/PrettyException.php index 9013a84e..0633b4d8 100644 --- a/src/danog/MadelineProto/TL/PrettyException.php +++ b/src/danog/MadelineProto/TL/PrettyException.php @@ -30,14 +30,12 @@ trait PrettyException * @var string */ public $tl_trace = ''; - /** * Method name. * * @var string */ private $method = ''; - /** * Whether the TL trace was updated. * @@ -67,7 +65,6 @@ trait PrettyException { return $this->tl_trace; } - /** * Generate async trace. * @@ -81,16 +78,15 @@ trait PrettyException $this->method = $init; $previous_trace = $this->tl_trace; $this->tl_trace = ''; - $eol = PHP_EOL; if (PHP_SAPI !== 'cli') { - $eol = '<br>'.PHP_EOL; + $eol = '<br>' . PHP_EOL; } $tl = false; foreach (\array_reverse($trace ?? $this->getTrace()) as $k => $frame) { if (isset($frame['function']) && \in_array($frame['function'], ['serializeParams', 'serializeObject'])) { if (($frame['args'][2] ?? '') !== '') { - $this->tl_trace .= $tl ? "['".$frame['args'][2]."']" : "While serializing: \t".$frame['args'][2]; + $this->tl_trace .= $tl ? "['" . $frame['args'][2] . "']" : "While serializing: \t" . $frame['args'][2]; $tl = true; } } else { @@ -100,20 +96,19 @@ trait PrettyException if (isset($frame['function']) && ($frame['function'] === 'handle_rpc_error' && $k === \count($this->getTrace()) - 1) || $frame['function'] === 'unserialize') { continue; } - $this->tl_trace .= isset($frame['file']) ? \str_pad(\basename($frame['file']).'('.$frame['line'].'):', 20)."\t" : ''; - $this->tl_trace .= isset($frame['function']) ? $frame['function'].'(' : ''; + $this->tl_trace .= isset($frame['file']) ? \str_pad(\basename($frame['file']) . '(' . $frame['line'] . '):', 20) . "\t" : ''; + $this->tl_trace .= isset($frame['function']) ? $frame['function'] . '(' : ''; $this->tl_trace .= isset($frame['args']) ? \substr(\json_encode($frame['args']), 1, -1) : ''; $this->tl_trace .= ')'; $this->tl_trace .= $eol; $tl = false; } } - $this->tl_trace .= $init !== '' ? "['".$init."']" : ''; + $this->tl_trace .= $init !== '' ? "['" . $init . "']" : ''; $this->tl_trace = \implode($eol, \array_reverse(\explode($eol, $this->tl_trace))); - if ($previous_trace) { - $this->tl_trace .= $eol.$eol; - $this->tl_trace .= "Previous TL trace:$eol"; + $this->tl_trace .= $eol . $eol; + $this->tl_trace .= "Previous TL trace:{$eol}"; $this->tl_trace .= $previous_trace; } } diff --git a/src/danog/MadelineProto/TL/TL.php b/src/danog/MadelineProto/TL/TL.php index d268f183..dcb6f1fe 100644 --- a/src/danog/MadelineProto/TL/TL.php +++ b/src/danog/MadelineProto/TL/TL.php @@ -83,7 +83,6 @@ class TL { $this->API = $API; } - /** * Get secret chat layer version. * @@ -93,7 +92,6 @@ class TL { return $this->secretLayer; } - /** * Get constructors. * @@ -105,7 +103,6 @@ class TL { return $td ? $this->tdConstructors : $this->constructors; } - /** * Get methods. * @@ -117,7 +114,6 @@ class TL { return $td ? $this->tdMethods : $this->methods; } - /** * Get TL descriptions. * @@ -127,7 +123,6 @@ class TL { return $this->tdDescriptions; } - /** * Initialize TL parser. * @@ -201,7 +196,7 @@ class TL $type = 'constructors'; continue; } - if (\preg_match('|^===(\d*)===|', $line, $matches)) { + if (\preg_match('|^===(\\d*)===|', $line, $matches)) { $layer = (int) $matches[1]; continue; } @@ -211,7 +206,7 @@ class TL if (\strpos($line, ' ?= ') !== false) { continue; } - $line = \preg_replace(['/[(]([\w\.]+) ([\w\.]+)[)]/', '/\s+/'], ['$1<$2>', ' '], $line); + $line = \preg_replace(['/[(]([\\w\\.]+) ([\\w\\.]+)[)]/', '/\\s+/'], ['$1<$2>', ' '], $line); if (\strpos($line, ';') === false) { $lineBuf .= $line; continue; @@ -220,12 +215,11 @@ class TL $line = $lineBuf; $lineBuf = ''; } - $name = \preg_replace(['/#.*/', '/\\s.*/'], '', $line); if (\in_array($name, ['bytes', 'int128', 'int256', 'int512', 'int', 'long', 'double', 'string', 'bytes', 'object', 'function'])) { /*if (!(\in_array($scheme_type, ['ton_api', 'lite_api']) && $name === 'bytes')) { - continue; - }*/ + continue; + }*/ continue; } if (\in_array($scheme_type, ['ton_api', 'lite_api'])) { @@ -233,9 +227,8 @@ class TL } else { $clean = \preg_replace(['/:bytes /', '/;/', '/#[a-f0-9]+ /', '/ [a-zA-Z0-9_]+\\:flags\\.[0-9]+\\?true/', '/[<]/', '/[>]/', '/ /', '/^ /', '/ $/', '/\\?bytes /', '/{/', '/}/'], [':string ', '', ' ', '', ' ', ' ', ' ', '', '', '?string ', '', ''], $line); } - $id = \hash('crc32b', $clean); - if (\preg_match('/^[^\s]+#([a-f0-9]*)/i', $line, $matches)) { + if (\preg_match('/^[^\\s]+#([a-f0-9]*)/i', $line, $matches)) { $nid = \str_pad($matches[1], 8, '0', \STR_PAD_LEFT); if ($id !== $nid && $scheme_type !== 'botAPI') { $this->API->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['crc32_mismatch'], $id, $nid, $line), \danog\MadelineProto\Logger::ERROR); @@ -269,7 +262,6 @@ class TL $TL_dict[$type][$key]['params'][] = ['name' => $explode[0], 'type' => $explode[1]]; } } - $key++; } } else { @@ -280,9 +272,8 @@ class TL $TL_dict['methods'][$key]['id'] = \danog\MadelineProto\Tools::packSignedInt($TL_dict['methods'][$key]['id']); } } - if (empty($TL_dict) || empty($TL_dict['constructors']) || !isset($TL_dict['methods'])) { - throw new Exception(\danog\MadelineProto\Lang::$current_lang['src_file_invalid'].$file); + throw new Exception(\danog\MadelineProto\Lang::$current_lang['src_file_invalid'] . $file); } $this->API->logger->logger(\danog\MadelineProto\Lang::$current_lang['translating_obj'], \danog\MadelineProto\Logger::ULTRA_VERBOSE); foreach ($TL_dict['constructors'] as $elem) { @@ -325,7 +316,6 @@ class TL } } } - /** * Get TL namespaces. * @@ -338,10 +328,8 @@ class TL $a = \key($pair); $res[$a] = $a; } - return $res; } - /** * Get namespaced methods (method => namespace). * @@ -351,7 +339,6 @@ class TL { return $this->methods->method_namespace; } - /** * Update TL callbacks. * @@ -366,14 +353,7 @@ class TL if (!isset(\class_implements(\get_class($object))[TLCallback::class])) { throw new Exception('Invalid callback object provided!'); } - $new = [ - TLCallback::METHOD_BEFORE_CALLBACK => $object->getMethodBeforeCallbacks(), - TLCallback::METHOD_CALLBACK => $object->getMethodCallbacks(), - TLCallback::CONSTRUCTOR_BEFORE_CALLBACK => $object->getConstructorBeforeCallbacks(), - TLCallback::CONSTRUCTOR_CALLBACK => $object->getConstructorCallbacks(), - TLCallback::CONSTRUCTOR_SERIALIZE_CALLBACK => $object->getConstructorSerializeCallbacks(), - TLCallback::TYPE_MISMATCH_CALLBACK => $object->getTypeMismatchCallbacks(), - ]; + $new = [TLCallback::METHOD_BEFORE_CALLBACK => $object->getMethodBeforeCallbacks(), TLCallback::METHOD_CALLBACK => $object->getMethodCallbacks(), TLCallback::CONSTRUCTOR_BEFORE_CALLBACK => $object->getConstructorBeforeCallbacks(), TLCallback::CONSTRUCTOR_CALLBACK => $object->getConstructorCallbacks(), TLCallback::CONSTRUCTOR_SERIALIZE_CALLBACK => $object->getConstructorSerializeCallbacks(), TLCallback::TYPE_MISMATCH_CALLBACK => $object->getTypeMismatchCallbacks()]; foreach ($new as $type => $values) { foreach ($values as $match => $callback) { if (!isset($this->callbacks[$type][$match])) { @@ -401,10 +381,8 @@ class TL if ($tl_elem === false) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['bool_error']); } - return $tl_elem['predicate'] === 'boolTrue'; } - /** * Serialize TL object. * @@ -426,13 +404,11 @@ class TL throw new Exception(\danog\MadelineProto\Lang::$current_lang['not_numeric']); } } - return \danog\MadelineProto\Tools::packSignedInt($object); case '#': if (!\is_numeric($object)) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['not_numeric']); } - return \danog\MadelineProto\Tools::packUnsignedInt($object); case 'long': if (\is_object($object)) { @@ -447,7 +423,6 @@ class TL if (!\is_numeric($object)) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['not_numeric']); } - return \danog\MadelineProto\Tools::packSignedLong($object); case 'int128': if (\strlen($object) !== 16) { @@ -456,7 +431,6 @@ class TL throw new Exception(\danog\MadelineProto\Lang::$current_lang['long_not_16']); } } - return (string) $object; case 'int256': if (\strlen($object) !== 32) { @@ -465,7 +439,6 @@ class TL throw new Exception(\danog\MadelineProto\Lang::$current_lang['long_not_32']); } } - return (string) $object; case 'int512': if (\strlen($object) !== 64) { @@ -474,7 +447,6 @@ class TL throw new Exception(\danog\MadelineProto\Lang::$current_lang['long_not_64']); } } - return (string) $object; case 'double': return \danog\MadelineProto\Tools::packDouble($object); @@ -488,14 +460,13 @@ class TL if ($l <= 253) { $concat .= \chr($l); $concat .= $object; - $concat .= \pack('@'.\danog\MadelineProto\Tools::posmod(-$l - 1, 4)); + $concat .= \pack('@' . \danog\MadelineProto\Tools::posmod(-$l - 1, 4)); } else { $concat .= \chr(254); $concat .= \substr(\danog\MadelineProto\Tools::packSignedInt($l), 0, 3); $concat .= $object; - $concat .= \pack('@'.\danog\MadelineProto\Tools::posmod(-$l, 4)); + $concat .= \pack('@' . \danog\MadelineProto\Tools::posmod(-$l, 4)); } - return $concat; case 'bytes': if (\is_array($object) && isset($object['_']) && $object['_'] === 'bytes') { @@ -509,14 +480,13 @@ class TL if ($l <= 253) { $concat .= \chr($l); $concat .= $object; - $concat .= \pack('@'.\danog\MadelineProto\Tools::posmod(-$l - 1, 4)); + $concat .= \pack('@' . \danog\MadelineProto\Tools::posmod(-$l - 1, 4)); } else { $concat .= \chr(254); $concat .= \substr(\danog\MadelineProto\Tools::packSignedInt($l), 0, 3); $concat .= $object; - $concat .= \pack('@'.\danog\MadelineProto\Tools::posmod(-$l, 4)); + $concat .= \pack('@' . \danog\MadelineProto\Tools::posmod(-$l, 4)); } - return $concat; case 'Bool': return $this->constructors->findByPredicate((bool) $object ? 'boolTrue' : 'boolFalse')['id']; @@ -529,14 +499,13 @@ class TL throw new Exception(\danog\MadelineProto\Lang::$current_lang['array_invalid']); } if (isset($object['_'])) { - throw new Exception('You must provide an array of '.$type['subtype'].' objects, not a '.$type['subtype']." object. Example: [['_' => ".$type['subtype'].', ... ]]'); + throw new Exception('You must provide an array of ' . $type['subtype'] . ' objects, not a ' . $type['subtype'] . " object. Example: [['_' => " . $type['subtype'] . ', ... ]]'); } $concat = $this->constructors->findByPredicate('vector')['id']; $concat .= \danog\MadelineProto\Tools::packUnsignedInt(\count($object)); foreach ($object as $k => $current_object) { - $concat .= yield $this->serializeObject(['type' => $type['subtype']], $current_object, $k); + $concat .= (yield from $this->serializeObject(['type' => $type['subtype']], $current_object, $k)); } - return $concat; case 'vector': if (!\is_array($object)) { @@ -544,9 +513,8 @@ class TL } $concat = \danog\MadelineProto\Tools::packUnsignedInt(\count($object)); foreach ($object as $k => $current_object) { - $concat .= yield $this->serializeObject(['type' => $type['subtype']], $current_object, $k); + $concat .= (yield from $this->serializeObject(['type' => $type['subtype']], $current_object, $k)); } - return $concat; case 'Object': if (\is_string($object)) { @@ -554,7 +522,6 @@ class TL } } $auto = false; - if ($type['type'] === 'InputMessage' && !\is_array($object)) { $object = ['_' => 'inputMessageID', 'id' => $object]; } elseif (isset($this->callbacks[TLCallback::TYPE_MISMATCH_CALLBACK][$type['type']]) && (!\is_array($object) || isset($object['_']) && $this->constructors->findByPredicate($object['_'])['type'] !== $type['type'])) { @@ -575,29 +542,25 @@ class TL if (isset($this->callbacks[TLCallback::CONSTRUCTOR_SERIALIZE_CALLBACK][$object['_']])) { $object = yield $this->callbacks[TLCallback::CONSTRUCTOR_SERIALIZE_CALLBACK][$object['_']]($object); } - $predicate = $object['_']; $constructorData = $this->constructors->findByPredicate($predicate, $layer); if ($constructorData === false) { $this->API->logger->logger($object, \danog\MadelineProto\Logger::FATAL_ERROR); - throw new Exception(\sprintf(\danog\MadelineProto\Lang::$current_lang['type_extract_error'], $predicate)); } if ($bare = $type['type'] != '' && $type['type'][0] === '%') { $type['type'] = \substr($type['type'], 1); } - if ($predicate === $type['type']) {//} && !$auto) { + if ($predicate === $type['type']) { + //} && !$auto) { $bare = true; } if ($predicate === 'messageEntityMentionName') { $constructorData = $this->constructors->findByPredicate('inputMessageEntityMentionName'); } - $concat = $bare ? '' : $constructorData['id']; - - return $concat.yield $this->serializeParams($constructorData, $object, '', $layer); + return $concat . (yield from $this->serializeParams($constructorData, $object, '', $layer)); } - /** * Serialize method. * @@ -608,16 +571,16 @@ class TL */ public function serializeMethod(string $method, $arguments): \Generator { - if ($method === 'messages.importChatInvite' && isset($arguments['hash']) && \is_string($arguments['hash']) && \preg_match('@(?:t|telegram)\.(?:me|dog)/(joinchat/)?([a-z0-9_-]*)@i', $arguments['hash'], $matches)) { + if ($method === 'messages.importChatInvite' && isset($arguments['hash']) && \is_string($arguments['hash']) && \preg_match('@(?:t|telegram)\\.(?:me|dog)/(joinchat/)?([a-z0-9_-]*)@i', $arguments['hash'], $matches)) { if ($matches[1] === '') { $method = 'channels.joinChannel'; $arguments['channel'] = $matches[2]; } else { $arguments['hash'] = $matches[2]; } - } elseif ($method === 'messages.checkChatInvite' && isset($arguments['hash']) && \is_string($arguments['hash']) && \preg_match('@(?:t|telegram)\.(?:me|dog)/joinchat/([a-z0-9_-]*)@i', $arguments['hash'], $matches)) { + } elseif ($method === 'messages.checkChatInvite' && isset($arguments['hash']) && \is_string($arguments['hash']) && \preg_match('@(?:t|telegram)\\.(?:me|dog)/joinchat/([a-z0-9_-]*)@i', $arguments['hash'], $matches)) { $arguments['hash'] = $matches[1]; - } elseif ($method === 'channels.joinChannel' && isset($arguments['channel']) && \is_string($arguments['channel']) && \preg_match('@(?:t|telegram)\.(?:me|dog)/(joinchat/)?([a-z0-9_-]*)@i', $arguments['channel'], $matches)) { + } elseif ($method === 'channels.joinChannel' && isset($arguments['channel']) && \is_string($arguments['channel']) && \preg_match('@(?:t|telegram)\\.(?:me|dog)/(joinchat/)?([a-z0-9_-]*)@i', $arguments['channel'], $matches)) { if ($matches[1] !== '') { $method = 'messages.importChatInvite'; $arguments['hash'] = $matches[2]; @@ -636,12 +599,7 @@ class TL } } elseif ($method === 'messages.sendEncryptedFile') { if (isset($arguments['file'])) { - if (( - !\is_array($arguments['file']) || - !(isset($arguments['file']['_']) && $this->constructors->findByPredicate($arguments['file']['_']) === 'InputEncryptedFile') - ) && - $this->API->settings['upload']['allow_automatic_upload'] - ) { + if ((!\is_array($arguments['file']) || !(isset($arguments['file']['_']) && $this->constructors->findByPredicate($arguments['file']['_']) === 'InputEncryptedFile')) && $this->API->settings['upload']['allow_automatic_upload']) { $arguments['file'] = yield $this->API->uploadEncrypted($arguments['file']); } if (isset($arguments['file']['key'])) { @@ -676,15 +634,12 @@ class TL $method = 'photos.updateProfilePhoto'; } } - $tl = $this->methods->findByMethod($method); if ($tl === false) { - throw new Exception(\danog\MadelineProto\Lang::$current_lang['method_not_found'].$method); + throw new Exception(\danog\MadelineProto\Lang::$current_lang['method_not_found'] . $method); } - - return $tl['id'].yield $this->serializeParams($tl, $arguments, $method); + return $tl['id'] . (yield from $this->serializeParams($tl, $arguments, $method)); } - /** * Serialize parameters. * @@ -728,11 +683,11 @@ class TL continue; } if ($current_argument['name'] === 'random_bytes') { - $serialized .= yield $this->serializeObject(['type' => 'bytes'], \danog\MadelineProto\Tools::random(15 + 4 * \danog\MadelineProto\Tools::randomInt($modulus = 3)), 'random_bytes'); + $serialized .= (yield from $this->serializeObject(['type' => 'bytes'], \danog\MadelineProto\Tools::random(15 + 4 * \danog\MadelineProto\Tools::randomInt($modulus = 3)), 'random_bytes')); continue; } if ($current_argument['name'] === 'data' && isset($tl['method']) && \in_array($tl['method'], ['messages.sendEncrypted', 'messages.sendEncryptedFile', 'messages.sendEncryptedService']) && isset($arguments['message'])) { - $serialized .= yield $this->serializeObject($current_argument, yield $this->API->encryptSecretMessage($arguments['peer']['chat_id'], $arguments['message']), 'data'); + $serialized .= (yield from $this->serializeObject($current_argument, yield $this->API->encryptSecretMessage($arguments['peer']['chat_id'], $arguments['message']), 'data')); continue; } if ($current_argument['name'] === 'random_id') { @@ -757,7 +712,7 @@ class TL continue; } if ($tl['type'] === 'InputMedia' && $current_argument['name'] === 'mime_type') { - $serialized .= yield $this->serializeObject($current_argument, $arguments['file']['mime_type'], $current_argument['name'], $layer); + $serialized .= (yield from $this->serializeObject($current_argument, $arguments['file']['mime_type'], $current_argument['name'], $layer)); continue; } if ($tl['type'] === 'DocumentAttribute' && \in_array($current_argument['name'], ['w', 'h', 'duration'])) { @@ -768,11 +723,11 @@ class TL $serialized .= \pack('@4'); continue; } - if (($id = $this->constructors->findByPredicate(\lcfirst($current_argument['type']).'Empty', isset($tl['layer']) ? $tl['layer'] : -1)) && $id['type'] === $current_argument['type']) { + if (($id = $this->constructors->findByPredicate(\lcfirst($current_argument['type']) . 'Empty', isset($tl['layer']) ? $tl['layer'] : -1)) && $id['type'] === $current_argument['type']) { $serialized .= $id['id']; continue; } - if (($id = $this->constructors->findByPredicate('input'.$current_argument['type'].'Empty', isset($tl['layer']) ? $tl['layer'] : -1)) && $id['type'] === $current_argument['type']) { + if (($id = $this->constructors->findByPredicate('input' . $current_argument['type'] . 'Empty', isset($tl['layer']) ? $tl['layer'] : -1)) && $id['type'] === $current_argument['type']) { $serialized .= $id['id']; continue; } @@ -781,47 +736,19 @@ class TL case 'vector': $arguments[$current_argument['name']] = []; break; - /* - case 'long': - $serialized .= \danog\MadelineProto\Tools::random(8); - continue 2; - case 'int': - $serialized .= \danog\MadelineProto\Tools::random(4); - continue 2; - case 'string': - case 'bytes': - $arguments[$current_argument['name']] = ''; - break; - case 'Bool': - $arguments[$current_argument['name']] = false; - break; - default: - $arguments[$current_argument['name']] = ['_' => $this->constructors->findByType($current_argument['type'])['predicate']]; - break;*/ } } if (\in_array($current_argument['type'], ['DataJSON', '%DataJSON'])) { $arguments[$current_argument['name']] = ['_' => 'dataJSON', 'data' => \json_encode($arguments[$current_argument['name']])]; } - if (isset($current_argument['subtype']) && \in_array($current_argument['subtype'], ['DataJSON', '%DataJSON'])) { \array_walk($arguments[$current_argument['name']], function (&$arg) { $arg = ['_' => 'dataJSON', 'data' => \json_encode($arg)]; }); } - - if ($current_argument['type'] === 'InputFile' - && ( - !\is_array($arguments[$current_argument['name']]) - || !( - isset($arguments[$current_argument['name']]['_']) - && $this->constructors->findByPredicate($arguments[$current_argument['name']]['_'])['type'] === 'InputFile' - ) - ) - ) { + if ($current_argument['type'] === 'InputFile' && (!\is_array($arguments[$current_argument['name']]) || !(isset($arguments[$current_argument['name']]['_']) && $this->constructors->findByPredicate($arguments[$current_argument['name']]['_'])['type'] === 'InputFile'))) { $arguments[$current_argument['name']] = yield $this->API->upload($arguments[$current_argument['name']]); } - if ($current_argument['type'] === 'InputEncryptedChat' && (!\is_array($arguments[$current_argument['name']]) || isset($arguments[$current_argument['name']]['_']) && $this->constructors->findByPredicate($arguments[$current_argument['name']]['_'])['type'] !== $current_argument['type'])) { if (\is_array($arguments[$current_argument['name']])) { $arguments[$current_argument['name']] = (yield $this->API->getInfo($arguments[$current_argument['name']]))['InputEncryptedChat']; @@ -833,12 +760,10 @@ class TL } } //$this->API->logger->logger('Serializing '.$current_argument['name'].' of type '.$current_argument['type'); - $serialized .= yield $this->serializeObject($current_argument, $arguments[$current_argument['name']], $current_argument['name'], $layer); + $serialized .= (yield from $this->serializeObject($current_argument, $arguments[$current_argument['name']], $current_argument['name'], $layer)); } - return $serialized; } - /** * Get length of TL payload. * @@ -858,11 +783,8 @@ class TL throw new Exception(\danog\MadelineProto\Lang::$current_lang['stream_handle_invalid']); } $this->deserialize($stream, $type); - return \ftell($stream); } - - /** * Deserialize TL object. * @@ -892,7 +814,6 @@ class TL if (isset($type['idstrlong'])) { return \stream_get_contents($stream, 8); } - return \danog\MadelineProto\Magic::$bigint || isset($type['strlong']) ? \stream_get_contents($stream, 8) : \danog\MadelineProto\Tools::unpackSignedLong(\stream_get_contents($stream, 8)); case 'double': return \danog\MadelineProto\Tools::unpackDouble(\stream_get_contents($stream, 8)); @@ -909,7 +830,7 @@ class TL throw new Exception(\danog\MadelineProto\Lang::$current_lang['length_too_big']); } if ($l === 254) { - $long_len = \unpack('V', \stream_get_contents($stream, 3).\chr(0))[1]; + $long_len = \unpack('V', \stream_get_contents($stream, 3) . \chr(0))[1]; $x = \stream_get_contents($stream, $long_len); $resto = \danog\MadelineProto\Tools::posmod(-$long_len, 4); if ($resto > 0) { @@ -925,14 +846,13 @@ class TL if (!\is_string($x)) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['deserialize_not_str']); } - return $type['type'] === 'bytes' ? new Types\Bytes($x) : $x; case 'Vector t': $id = \stream_get_contents($stream, 4); $constructorData = $this->constructors->findById($id); if ($constructorData === false) { $constructorData = $this->methods->findById($id); - $constructorData['predicate'] = 'method_'.$constructorData['method']; + $constructorData['predicate'] = 'method_' . $constructorData['method']; } if ($constructorData === false) { throw new Exception(\sprintf(\danog\MadelineProto\Lang::$current_lang['type_extract_error_id'], $type['type'], \bin2hex(\strrev($id)))); @@ -944,9 +864,9 @@ class TL case 'vector': break; default: - throw new Exception(\danog\MadelineProto\Lang::$current_lang['vector_invalid'].$constructorData['predicate']); + throw new Exception(\danog\MadelineProto\Lang::$current_lang['vector_invalid'] . $constructorData['predicate']); } - // no break + // no break case 'vector': $count = \unpack('V', \stream_get_contents($stream, 4))[1]; $result = []; @@ -954,14 +874,13 @@ class TL for ($i = 0; $i < $count; $i++) { $result[] = $this->deserialize($stream, $type); } - return $result; } if ($type['type'] != '' && $type['type'][0] === '%') { $checkType = \substr($type['type'], 1); $constructorData = $this->constructors->findByType($checkType); if ($constructorData === false) { - throw new Exception(\danog\MadelineProto\Lang::$current_lang['constructor_not_found'].$checkType); + throw new Exception(\danog\MadelineProto\Lang::$current_lang['constructor_not_found'] . $checkType); } } else { $constructorData = $this->constructors->findByPredicate($type['type']); @@ -973,12 +892,11 @@ class TL if ($constructorData === false) { throw new Exception(\sprintf(\danog\MadelineProto\Lang::$current_lang['type_extract_error_id'], $type['type'], \bin2hex(\strrev($id)))); } - $constructorData['predicate'] = 'method_'.$constructorData['method']; + $constructorData['predicate'] = 'method_' . $constructorData['method']; } } } //var_dump($constructorData); - if ($constructorData['predicate'] === 'gzip_packed') { if (!isset($type['subtype'])) { $type['subtype'] = ''; @@ -989,7 +907,6 @@ class TL $constructorData['connection'] = $type['connection']; $constructorData['subtype'] = $type['subtype'] ?? ''; $constructorData['type'] = 'vector'; - return $this->deserialize($stream, $constructorData); } if ($constructorData['predicate'] === 'boolTrue') { @@ -1016,7 +933,7 @@ class TL $x[$arg['name']] = false; continue 2; } - // no break + // no break default: if (($x['flags'] & $arg['pow']) === 0) { continue 2; @@ -1033,17 +950,12 @@ class TL $arg['type'] = 'string'; } if ($x['_'] === 'rpc_result' && $arg['name'] === 'result') { - if (isset($type['connection']->outgoing_messages[$x['req_msg_id']]['_']) - && isset($this->callbacks[TLCallback::METHOD_BEFORE_CALLBACK][$type['connection']->outgoing_messages[$x['req_msg_id']]['_']]) - ) { + if (isset($type['connection']->outgoing_messages[$x['req_msg_id']]['_']) && isset($this->callbacks[TLCallback::METHOD_BEFORE_CALLBACK][$type['connection']->outgoing_messages[$x['req_msg_id']]['_']])) { foreach ($this->callbacks[TLCallback::METHOD_BEFORE_CALLBACK][$type['connection']->outgoing_messages[$x['req_msg_id']]['_']] as $callback) { $callback($type['connection']->outgoing_messages[$x['req_msg_id']]['_']); } } - - if (isset($type['connection']->outgoing_messages[$x['req_msg_id']]['type']) - && \stripos($type['connection']->outgoing_messages[$x['req_msg_id']]['type'], '<') !== false - ) { + if (isset($type['connection']->outgoing_messages[$x['req_msg_id']]['type']) && \stripos($type['connection']->outgoing_messages[$x['req_msg_id']]['type'], '<') !== false) { $arg['subtype'] = \str_replace(['Vector<', '>'], '', $type['connection']->outgoing_messages[$x['req_msg_id']]['type']); } } @@ -1073,26 +985,20 @@ class TL foreach ($x['value'] as $pair) { $res[$pair['key']] = $pair['value']; } - return $res; default: return $x['value']; } } - if (isset($this->callbacks[TLCallback::CONSTRUCTOR_CALLBACK][$x['_']])) { foreach ($this->callbacks[TLCallback::CONSTRUCTOR_CALLBACK][$x['_']] as $callback) { \danog\MadelineProto\Tools::callFork($callback($x)); } - } 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']]['_']]) - ) { + } 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) { $callback($type['connection']->outgoing_messages[$x['req_msg_id']], $x['result']); } } - if ($x['_'] === 'message' && isset($x['reply_markup']['rows'])) { foreach ($x['reply_markup']['rows'] as $key => $row) { foreach ($row['buttons'] as $bkey => $button) { @@ -1100,7 +1006,6 @@ class TL } } } - return $x; } } diff --git a/src/danog/MadelineProto/TL/TLCallback.php b/src/danog/MadelineProto/TL/TLCallback.php index 1102ad8f..a8c3f50a 100644 --- a/src/danog/MadelineProto/TL/TLCallback.php +++ b/src/danog/MadelineProto/TL/TLCallback.php @@ -1,4 +1,5 @@ <?php + /** * TL callback module. * @@ -39,7 +40,6 @@ interface TLCallback * @var int */ const TYPE_MISMATCH_CALLBACK = 5; - /** * Called after serialization of method. * @@ -48,7 +48,6 @@ interface TLCallback * @return array */ public function getMethodCallbacks(): array; - /** * Called right before serialization of method starts. * @@ -57,14 +56,12 @@ interface TLCallback * @return array */ public function getMethodBeforeCallbacks(): array; - /** * Called right after deserialization of object, passing the final object. * * @return array */ public function getConstructorCallbacks(): array; - /** * Called right before deserialization of object. * @@ -73,7 +70,6 @@ interface TLCallback * @return array */ public function getConstructorBeforeCallbacks(): array; - /** * Called right before serialization of constructor. * @@ -82,7 +78,6 @@ interface TLCallback * @return array */ public function getConstructorSerializeCallbacks(): array; - /** * Called if objects of the specified type cannot be serialized. * diff --git a/src/danog/MadelineProto/TL/TLConstructors.php b/src/danog/MadelineProto/TL/TLConstructors.php index 94b7194e..56f5de0c 100644 --- a/src/danog/MadelineProto/TL/TLConstructors.php +++ b/src/danog/MadelineProto/TL/TLConstructors.php @@ -27,21 +27,17 @@ class TLConstructors public $by_id = []; public $by_predicate_and_layer = []; public $layers = []; - public function __sleep() { return ['by_predicate_and_layer', 'by_id', 'layers']; } - public function add($json_dict, $scheme_type) { if (isset($this->by_id[$json_dict['id']]) && (!isset($this->by_id[$json_dict['id']]['layer']) || $this->by_id[$json_dict['id']]['layer'] > $json_dict['layer'])) { return false; } - - $predicate = (string) (($scheme_type === 'mtproto' && $json_dict['predicate'] === 'message' ? 'MT' : '').$json_dict['predicate']); - - $this->by_id[$json_dict['id']] = ['predicate' => $predicate, 'params' => $json_dict['params'], 'type' => ($scheme_type === 'mtproto' && $json_dict['type'] === 'Message' ? 'MT' : '').$json_dict['type']]; + $predicate = (string) (($scheme_type === 'mtproto' && $json_dict['predicate'] === 'message' ? 'MT' : '') . $json_dict['predicate']); + $this->by_id[$json_dict['id']] = ['predicate' => $predicate, 'params' => $json_dict['params'], 'type' => ($scheme_type === 'mtproto' && $json_dict['type'] === 'Message' ? 'MT' : '') . $json_dict['type']]; if ($scheme_type === 'secret') { $this->by_id[$json_dict['id']]['layer'] = $json_dict['layer']; $this->layers[$json_dict['layer']] = $json_dict['layer']; @@ -49,33 +45,29 @@ class TLConstructors } else { $json_dict['layer'] = ''; } - $this->by_predicate_and_layer[$predicate.$json_dict['layer']] = $json_dict['id']; + $this->by_predicate_and_layer[$predicate . $json_dict['layer']] = $json_dict['id']; $this->parseParams($json_dict['id'], $scheme_type === 'mtproto'); } - public function findByType($type) { foreach ($this->by_id as $id => $constructor) { if ($constructor['type'] === $type) { $constructor['id'] = $id; - return $constructor; } } - return false; } - public function findByPredicate($predicate, $layer = -1) { if ($layer !== -1) { foreach ($this->layers as $alayer) { if ($alayer <= $layer) { - if (isset($this->by_predicate_and_layer[$predicate.$alayer])) { - $chosenid = $this->by_predicate_and_layer[$predicate.$alayer]; + if (isset($this->by_predicate_and_layer[$predicate . $alayer])) { + $chosenid = $this->by_predicate_and_layer[$predicate . $alayer]; } } elseif (!isset($chosenid)) { - $chosenid = $this->by_predicate_and_layer[$predicate.$alayer]; + $chosenid = $this->by_predicate_and_layer[$predicate . $alayer]; } } if (!isset($chosenid)) { @@ -83,19 +75,15 @@ class TLConstructors } $constructor = $this->by_id[$chosenid]; $constructor['id'] = $chosenid; - return $constructor; } if (isset($this->by_predicate_and_layer[$predicate])) { $constructor = $this->by_id[$this->by_predicate_and_layer[$predicate]]; $constructor['id'] = $this->by_predicate_and_layer[$predicate]; - return $constructor; } - return false; } - /** * Find constructor by ID. * @@ -108,10 +96,8 @@ class TLConstructors if (isset($this->by_id[$id])) { $constructor = $this->by_id[$id]; $constructor['id'] = $id; - return $constructor; } - return false; } } diff --git a/src/danog/MadelineProto/TL/TLMethods.php b/src/danog/MadelineProto/TL/TLMethods.php index 84eeb23a..cbfe12b6 100644 --- a/src/danog/MadelineProto/TL/TLMethods.php +++ b/src/danog/MadelineProto/TL/TLMethods.php @@ -27,12 +27,10 @@ class TLMethods public $by_id = []; public $by_method = []; public $method_namespace = []; - public function __sleep() { return ['by_id', 'by_method', 'method_namespace']; } - public function add($json_dict) { $this->by_id[$json_dict['id']] = ['method' => $json_dict['method'], 'type' => $json_dict['type'], 'params' => $json_dict['params']]; @@ -43,28 +41,22 @@ class TLMethods } $this->parseParams($json_dict['id']); } - public function findById($id) { if (isset($this->by_id[$id])) { $method = $this->by_id[$id]; $method['id'] = $id; - return $method; } - return false; } - public function findByMethod($method_name) { if (isset($this->by_method[$method_name])) { $method = $this->by_id[$this->by_method[$method_name]]; $method['id'] = $this->by_method[$method_name]; - return $method; } - return false; } } diff --git a/src/danog/MadelineProto/TL/TLParams.php b/src/danog/MadelineProto/TL/TLParams.php index a6100eb1..ce2a353e 100644 --- a/src/danog/MadelineProto/TL/TLParams.php +++ b/src/danog/MadelineProto/TL/TLParams.php @@ -24,17 +24,17 @@ trait TLParams public function parseParams($key, $mtproto = false) { foreach ($this->by_id[$key]['params'] as $kkey => $param) { - if (\preg_match('/(\w*)\.(\d*)\?(.*)/', $param['type'], $matches)) { + if (\preg_match('/(\\w*)\\.(\\d*)\\?(.*)/', $param['type'], $matches)) { $param['pow'] = \pow(2, $matches[2]); $param['type'] = $matches[3]; } - if (\preg_match('/^(v|V)ector\<(.*)\>$/', $param['type'], $matches)) { + if (\preg_match('/^(v|V)ector\\<(.*)\\>$/', $param['type'], $matches)) { $param['type'] = $matches[1] === 'v' ? 'vector' : 'Vector t'; $param['subtype'] = $matches[2]; - $param['subtype'] = ($mtproto && $param['subtype'] === 'Message' ? 'MT' : '').$param['subtype']; + $param['subtype'] = ($mtproto && $param['subtype'] === 'Message' ? 'MT' : '') . $param['subtype']; $param['subtype'] = $mtproto && $param['subtype'] === '%Message' ? '%MTMessage' : $param['subtype']; } - $param['type'] = ($mtproto && $param['type'] === 'Message' ? 'MT' : '').$param['type']; + $param['type'] = ($mtproto && $param['type'] === 'Message' ? 'MT' : '') . $param['type']; $param['type'] = $mtproto && $param['type'] === '%Message' ? '%MTMessage' : $param['type']; $this->by_id[$key]['params'][$kkey] = $param; } diff --git a/src/danog/MadelineProto/TL/Types/Button.php b/src/danog/MadelineProto/TL/Types/Button.php index 6e609d37..1e13caba 100644 --- a/src/danog/MadelineProto/TL/Types/Button.php +++ b/src/danog/MadelineProto/TL/Types/Button.php @@ -25,7 +25,6 @@ class Button implements \JsonSerializable, \ArrayAccess use \danog\MadelineProto\Tools; private $info = []; private $data = []; - public function __magic_construct($API, $message, $button) { $this->data = $button; @@ -33,12 +32,10 @@ class Button implements \JsonSerializable, \ArrayAccess $this->info['id'] = $message['id']; $this->info['API'] = $API; } - public function __sleep() { return ['data', 'info']; } - public function click($donotwait = false, $params = []) { if (\is_array($donotwait)) { @@ -56,26 +53,22 @@ class Button implements \JsonSerializable, \ArrayAccess $res = $this->info['API']->methodCallAsyncRead('messages.sendMessage', ['peer' => $this->info['peer'], 'message' => $this->data['text'], 'reply_to_msg_id' => $this->info['id']], ['datacenter' => $this->info['API']->datacenter->curdc]); break; case 'keyboardButtonCallback': - $res = $this->info['API']->$method('messages.getBotCallbackAnswer', ['peer' => $this->info['peer'], 'msg_id' => $this->info['id'], 'data' => $this->data['data']], ['datacenter' => $this->info['API']->datacenter->curdc]); + $res = $this->info['API']->{$method}('messages.getBotCallbackAnswer', ['peer' => $this->info['peer'], 'msg_id' => $this->info['id'], 'data' => $this->data['data']], ['datacenter' => $this->info['API']->datacenter->curdc]); break; case 'keyboardButtonGame': - $res = $this->info['API']->$method('messages.getBotCallbackAnswer', ['peer' => $this->info['peer'], 'msg_id' => $this->info['id'], 'game' => true], ['datacenter' => $this->info['API']->datacenter->curdc]); + $res = $this->info['API']->{$method}('messages.getBotCallbackAnswer', ['peer' => $this->info['peer'], 'msg_id' => $this->info['id'], 'game' => true], ['datacenter' => $this->info['API']->datacenter->curdc]); break; } - return $async ? $res : \danog\MadelineProto\Tools::wait($res); } - public function __debugInfo() { return ['data' => $this->data, 'info' => ['peer' => $this->info['peer'], 'id' => $this->info['id']]]; } - public function jsonSerialize() { return (array) $this->data; } - public function offsetSet($name, $value) { if ($name === null) { @@ -84,17 +77,14 @@ class Button implements \JsonSerializable, \ArrayAccess $this->data[$name] = $value; } } - public function offsetGet($name) { return $this->data[$name]; } - public function offsetUnset($name) { unset($this->data[$name]); } - public function offsetExists($name) { return isset($this->data[$name]); diff --git a/src/danog/MadelineProto/TL/Types/Bytes.php b/src/danog/MadelineProto/TL/Types/Bytes.php index 658bd4c7..282ce4c6 100644 --- a/src/danog/MadelineProto/TL/Types/Bytes.php +++ b/src/danog/MadelineProto/TL/Types/Bytes.php @@ -23,27 +23,22 @@ class Bytes implements \JsonSerializable, \ArrayAccess { use \danog\Serializable; private $bytes = []; - public function __magic_construct($bytes) { $this->bytes = $bytes; } - public function __sleep() { return ['bytes']; } - public function __toString() { return $this->bytes; } - public function jsonSerialize() { return ['_' => 'bytes', 'bytes' => \base64_encode($this->bytes)]; } - public function offsetSet($name, $value) { if ($name === null) { @@ -52,17 +47,14 @@ class Bytes implements \JsonSerializable, \ArrayAccess $this->bytes[$name] = $value; } } - public function offsetGet($name) { return $this->bytes[$name]; } - public function offsetUnset($name) { unset($this->bytes[$name]); } - public function offsetExists($name) { return isset($this->bytes[$name]); diff --git a/src/danog/MadelineProto/TON/ADNLConnection.php b/src/danog/MadelineProto/TON/ADNLConnection.php index f18a3ead..e5b48070 100644 --- a/src/danog/MadelineProto/TON/ADNLConnection.php +++ b/src/danog/MadelineProto/TON/ADNLConnection.php @@ -83,38 +83,23 @@ class ADNLConnection if ($endpoint['id']['_'] !== 'pub.ed25519') { throw new \InvalidArgumentException('Only ECDH is supported at the moment!'); } - $random = Tools::random(256 - 32 - 64); //$random = strrev(hex2bin(strrev('9E7C27765D12CE634414F0875D55CE5C58E7A9D58CD45C57CAB516D1241B7864691E5B0AFC4ECB54BFF2CEFC2060F1D45F5B5DEB76A9EF6471D75816AAAEC83CD7DE39EE99B9E980B6C0D4565A916D00908613E63657D5539118F89A14FD73ABB8ECD3AC26C287EEBD0FA44F52B315F01DD60F486EFF4C5B4D71EA6F443358FF141E7294BBBB5D7C079F16BD46C28A12507E1948722E7121B94C3B5C7832ADE7'))); $s1 = \substr($random, 0, 32); $s2 = \substr($random, 32, 32); $v1 = \substr($random, 64, 16); $v2 = \substr($random, 80, 16); - - $obf = [ - 'decrypt' => [ - 'key' => $s1, - 'iv' => $v1 - ], - 'encrypt' => [ - 'key' => $s2, - 'iv' => $v2 - ], - ]; + $obf = ['decrypt' => ['key' => $s1, 'iv' => $v1], 'encrypt' => ['key' => $s2, 'iv' => $v2]]; // Generating new private/public params $private = EC::createKey('Ed25519'); - $public = $private->getPublicKey(); $public = \strrev(Tools::getVar($public, 'QA')[1]->toBytes()); - $private = \strrev(Tools::getVar($private, 'dA')->toBytes()); $private = PrivateKey::loadFormat('MontgomeryPrivate', $private); - // Transpose their public $key = $endpoint['id']['key']; $key[31] = $key[31] & \chr(127); - - $curve = new Curve25519; + $curve = new Curve25519(); $modulo = Tools::getVar($curve, "modulo"); $y = new BigInteger(\strrev($key), 256); $y2 = clone $y; @@ -122,41 +107,25 @@ class ADNLConnection $y2 = $y2->subtract(Magic::$one); $y2 = $modulo->subtract($y2)->powMod(Magic::$one, $modulo); $y2 = $y2->modInverse($modulo); - $key = \strrev($y->multiply($y2)->powMod(Magic::$one, $modulo)->toBytes()); $peerPublic = PublicKey::loadFormat('MontgomeryPublic', $key); - // Generate secret $secret = DH::computeSecret($private, $peerPublic); - // Encrypting random with obf keys $digest = \hash('sha256', $random, true); - - $key = \substr($secret, 0, 16).\substr($digest, 16, 16); - $iv = \substr($digest, 0, 4).\substr($secret, 20, 12); - + $key = \substr($secret, 0, 16) . \substr($digest, 16, 16); + $iv = \substr($digest, 0, 4) . \substr($secret, 20, 12); $encryptedRandom = Crypt::ctrEncrypt($random, $key, $iv); - // Generating plaintext init payload $payload = \hash('sha256', yield $this->TL->serializeObject(['type' => ''], $endpoint['id'], 'key'), true); $payload .= $public; $payload .= $digest; $payload .= $encryptedRandom; - $ip = \long2ip(\unpack('V', Tools::packSignedInt($endpoint['ip']))[1]); $port = $endpoint['port']; - $ctx = (new ConnectionContext()) - ->setSocketContext(new ConnectContext) - ->setUri("tcp://$ip:$port") - ->addStream(DefaultStream::getName()) - ->addStream(BufferedRawStream::getName()) - ->addStream(CtrStream::getName(), $obf) - ->addStream(HashedBufferedStream::getName(), 'sha256') - ->addStream(ADNLStream::getName()); - + $ctx = (new ConnectionContext())->setSocketContext(new ConnectContext())->setUri("tcp://{$ip}:{$port}")->addStream(DefaultStream::getName())->addStream(BufferedRawStream::getName())->addStream(CtrStream::getName(), $obf)->addStream(HashedBufferedStream::getName(), 'sha256')->addStream(ADNLStream::getName()); $this->stream = yield $ctx->getStream($payload); - - Tools::callFork((function () { + Tools::callFork((function (): \Generator { //yield Tools::sleep(1); while (true) { $buffer = yield $this->stream->getReadBuffer($length); @@ -164,14 +133,13 @@ class ADNLConnection $data = yield $buffer->bufferRead($length); $data = yield $this->TL->deserialize($data); if ($data['_'] !== 'adnl.message.answer') { - throw new Exception('Wrong answer type: '.$data['_']); + throw new Exception('Wrong answer type: ' . $data['_']); } $this->requests[$data['query_id']]->resolve(yield $this->TL->deserialize((string) $data['answer'])); } } })()); } - /** * Send ADNL query. * @@ -181,18 +149,9 @@ class ADNLConnection */ public function query(string $payload): \Generator { - $data = yield $this->TL->serializeObject( - ['type' => ''], - [ - '_' => 'adnl.message.query', - 'query_id' => $id = Tools::random(32), - 'query' => $payload - ], - '' - ); + $data = yield $this->TL->serializeObject(['type' => ''], ['_' => 'adnl.message.query', 'query_id' => $id = Tools::random(32), 'query' => $payload], ''); (yield $this->stream->getWriteBuffer(\strlen($data)))->bufferWrite($data); - $this->requests[$id] = new Deferred; - + $this->requests[$id] = new Deferred(); return $this->requests[$id]->promise(); } } diff --git a/src/danog/MadelineProto/TON/API.php b/src/danog/MadelineProto/TON/API.php index 5b277ec9..c7694302 100644 --- a/src/danog/MadelineProto/TON/API.php +++ b/src/danog/MadelineProto/TON/API.php @@ -34,7 +34,6 @@ class API extends InternalDoc public function __construct(array $settings) { Magic::classExists(); - $this->API = new Lite($settings); foreach (\get_class_methods($this->API) as $method) { $this->methods[$method] = [$this->API, \strtolower($method)]; diff --git a/src/danog/MadelineProto/TON/APIFactory.php b/src/danog/MadelineProto/TON/APIFactory.php index 34a18525..544fc4be 100644 --- a/src/danog/MadelineProto/TON/APIFactory.php +++ b/src/danog/MadelineProto/TON/APIFactory.php @@ -77,7 +77,6 @@ class APIFactory extends AbstractAPIFactory * @var liteServer */ public $liteServer; - /** * Just proxy async requests to API. * @@ -90,11 +89,10 @@ class APIFactory extends AbstractAPIFactory { $lower_name = \strtolower($name); if ($this->namespace !== '' || !isset($this->methods[$lower_name])) { - $name = $this->namespace.$name; + $name = $this->namespace . $name; $aargs = isset($arguments[1]) && \is_array($arguments[1]) ? $arguments[1] : []; $aargs['apifactory'] = true; $args = isset($arguments[0]) && \is_array($arguments[0]) ? $arguments[0] : []; - return yield $this->API->methodCall($name, $args, $aargs); } return yield $this->methods[$lower_name](...$arguments); diff --git a/src/danog/MadelineProto/TON/Lite.php b/src/danog/MadelineProto/TON/Lite.php index 82c0f6ae..63df6ff4 100644 --- a/src/danog/MadelineProto/TON/Lite.php +++ b/src/danog/MadelineProto/TON/Lite.php @@ -22,7 +22,6 @@ namespace danog\MadelineProto\TON; use danog\MadelineProto\Logger; use danog\MadelineProto\TL\TL; use danog\MadelineProto\Tools; - use function Amp\File\get; /** @@ -70,12 +69,7 @@ class Lite $this->settings = $settings; $this->logger = Logger::getLoggerFromSettings($this->settings); $this->TL = new TL($this); - $this->TL->init( - [ - 'lite_api' => __DIR__.'/schemes/lite_api.tl', - 'ton_api' => __DIR__.'/schemes/ton_api.tl', - ] - ); + $this->TL->init(['lite_api' => __DIR__ . '/schemes/lite_api.tl', 'ton_api' => __DIR__ . '/schemes/ton_api.tl']); } /** * Connect to the lite endpoints specified in the config file. @@ -90,18 +84,10 @@ class Lite $config['_'] = 'liteclient.config.global'; $config = Tools::convertJsonTL($config); $config['validator']['init_block'] = $config['validator']['init_block'] ?? $config['validator']['zero_state']; - - $this->config = yield $this->TL->deserialize( - yield $this->TL->serializeObject( - ['type' => ''], - $config, - 'cleanup' - ) - ); - + $this->config = yield $this->TL->deserialize(yield $this->TL->serializeObject(['type' => ''], $config, 'cleanup')); foreach ($this->config['liteservers'] as $lite) { $this->connections[] = $connection = new ADNLConnection($this->TL); - yield $connection->connect($lite); + yield from $connection->connect($lite); } } /** @@ -118,11 +104,8 @@ class Lite if ($file === null) { $file = \basename(\debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php'); } - isset($this->logger) ? $this->logger->logger($param, $level, $file) : Logger::$default->logger($param, $level, $file); } - - /** * Call lite method. * @@ -137,7 +120,6 @@ class Lite $data = yield $this->TL->serializeMethod('liteServer.query', ['data' => $data]); return yield $this->connections[\rand(0, \count($this->connections) - 1)]->query($data); } - /** * Asynchronously run async callable. * @@ -149,7 +131,6 @@ class Lite { return yield $func(); } - /** * Convert parameters. * @@ -161,7 +142,6 @@ class Lite { return $parameters; } - /** * Get TL method namespaces. * diff --git a/src/danog/MadelineProto/Tools.php b/src/danog/MadelineProto/Tools.php index 42069c83..45e1575e 100644 --- a/src/danog/MadelineProto/Tools.php +++ b/src/danog/MadelineProto/Tools.php @@ -1,4 +1,5 @@ <?php + /** * Tools module. * @@ -25,7 +26,6 @@ use Amp\Loop; use Amp\Promise; use Amp\Success; use tgseclib\Math\BigInteger; - use function Amp\ByteStream\getOutputBufferStream; use function Amp\ByteStream\getStdin; use function Amp\ByteStream\getStdout; @@ -42,7 +42,6 @@ use function Amp\Promise\wait; */ trait Tools { - /** * Sanify TL obtained from JSON for TL serialization. * @@ -83,13 +82,11 @@ trait Tools } else { $hash = 0; foreach ($ints as $int) { - $hash = ((($hash * 20261) & 0x7FFFFFFF) + $int) & 0x7FFFFFFF; + $hash = ($hash * 20261 & 0x7fffffff) + $int & 0x7fffffff; } } - return $hash; } - /** * Get random integer. * @@ -102,7 +99,6 @@ trait Tools if ($modulus === 0) { $modulus = PHP_INT_MAX; } - try { return \random_int(0, PHP_INT_MAX) % $modulus; } catch (\Exception $e) { @@ -115,16 +111,13 @@ trait Tools // random_bytes(), most of the other calls here will fail too, so we'll end up using // the PHP implementation. } - if (Magic::$bigint) { $number = self::unpackSignedInt(self::random(4)); } else { $number = self::unpackSignedLong(self::random(8)); } - return ($number & PHP_INT_MAX) % $modulus; } - /** * Get random string of specified length. * @@ -136,7 +129,6 @@ trait Tools { return $length === 0 ? '' : \tgseclib\Crypt\Random::string($length); } - /** * Positive modulo * Works just like the % (modulus) operator, only returns always a postive number. @@ -149,10 +141,8 @@ trait Tools public static function posmod(int $a, int $b): int { $resto = $a % $b; - return $resto < 0 ? $resto + \abs($b) : $resto; } - /** * Unpack base256 signed int. * @@ -165,10 +155,8 @@ trait Tools if (\strlen($value) !== 4) { throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['length_not_4']); } - return \unpack('l', \danog\MadelineProto\Magic::$BIG_ENDIAN ? \strrev($value) : $value)[1]; } - /** * Unpack base256 signed long. * @@ -181,7 +169,6 @@ trait Tools if (\strlen($value) !== 8) { throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['length_not_8']); } - return \unpack('q', \danog\MadelineProto\Magic::$BIG_ENDIAN ? \strrev($value) : $value)[1]; } /** @@ -199,11 +186,9 @@ trait Tools if (\strlen($value) !== 8) { throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['length_not_8']); } - $big = new BigInteger((string) $value, -256); return (string) $big; } - /** * Convert integer to base256 signed int. * @@ -220,10 +205,8 @@ trait Tools throw new TL\Exception(\sprintf(\danog\MadelineProto\Lang::$current_lang['value_smaller_than_2147483648'], $value)); } $res = \pack('l', $value); - return \danog\MadelineProto\Magic::$BIG_ENDIAN ? \strrev($res) : $res; } - /** * Convert integer to base256 long. * @@ -239,11 +222,9 @@ trait Tools if ($value < -9.223372036854776E+18) { throw new TL\Exception(\sprintf(\danog\MadelineProto\Lang::$current_lang['value_smaller_than_9223372036854775808'], $value)); } - $res = \danog\MadelineProto\Magic::$bigint ? self::packSignedInt($value)."\0\0\0\0" : (\danog\MadelineProto\Magic::$BIG_ENDIAN ? \strrev(\pack('q', $value)) : \pack('q', $value)); - + $res = \danog\MadelineProto\Magic::$bigint ? self::packSignedInt($value) . "\0\0\0\0" : (\danog\MadelineProto\Magic::$BIG_ENDIAN ? \strrev(\pack('q', $value)) : \pack('q', $value)); return $res; } - /** * Convert value to unsigned base256 int. * @@ -259,10 +240,8 @@ trait Tools if ($value < 0) { throw new TL\Exception(\sprintf(\danog\MadelineProto\Lang::$current_lang['value_smaller_than_0'], $value)); } - return \pack('V', $value); } - /** * Convert double to binary version. * @@ -276,10 +255,8 @@ trait Tools if (\strlen($res) !== 8) { throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['encode_double_error']); } - return \danog\MadelineProto\Magic::$BIG_ENDIAN ? \strrev($res) : $res; } - /** * Unpack binary double. * @@ -292,10 +269,8 @@ trait Tools if (\strlen($value) !== 8) { throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['length_not_8']); } - return \unpack('d', \danog\MadelineProto\Magic::$BIG_ENDIAN ? \strrev($value) : $value)[1]; } - /** * Synchronously wait for a promise|generator. * @@ -308,10 +283,9 @@ trait Tools { if ($promise instanceof \Generator) { $promise = new Coroutine($promise); - } elseif (!($promise instanceof Promise)) { + } elseif (!$promise instanceof Promise) { return $promise; } - $exception = null; $value = null; $resolved = false; @@ -329,14 +303,11 @@ trait Tools throw new \Error('Loop exceptionally stopped without resolving the promise', 0, $throwable); } } while (!$resolved && !(Magic::$signaled && !$ignoreSignal)); - if ($exception) { throw $exception; } - return $value; } - /** * 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. @@ -350,10 +321,8 @@ trait Tools foreach ($promises as &$promise) { $promise = self::call($promise); } - return all($promises); } - /** * Returns a promise that is resolved when all promises are resolved. The returned promise will not fail. * @@ -366,10 +335,8 @@ trait Tools foreach ($promises as &$promise) { $promise = self::call($promise); } - return any($promises); } - /** * 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. @@ -383,10 +350,8 @@ trait Tools foreach ($promises as &$promise) { $promise = self::call($promise); } - return some($promises); } - /** * Returns a promise that succeeds when the first promise succeeds, and fails only if all promises fail. * @@ -399,10 +364,8 @@ trait Tools foreach ($promises as &$promise) { $promise = self::call($promise); } - return first($promises); } - /** * Create an artificial timeout for any \Generator or Promise. * @@ -415,7 +378,6 @@ trait Tools { return timeout(self::call($promise), $timeout); } - /** * Convert generator, promise or any other value to a promise. * @@ -427,13 +389,11 @@ trait Tools { if ($promise instanceof \Generator) { $promise = new Coroutine($promise); - } elseif (!($promise instanceof Promise)) { + } elseif (!$promise instanceof Promise) { return new Success($promise); } - return $promise; } - /** * Call promise in background. * @@ -471,10 +431,8 @@ trait Tools } }); } - return $promise; } - /** * Call promise in background, deferring execution. * @@ -486,7 +444,6 @@ trait Tools { Loop::defer([__CLASS__, 'callFork'], $promise); } - /** * Rethrow error catched in strand. * @@ -500,12 +457,11 @@ trait Tools $zis = isset($this) ? $this : null; $logger = isset($zis->logger) ? $zis->logger : Logger::$default; if ($file) { - $file = " started @ $file"; + $file = " started @ {$file}"; } if ($logger) { - $logger->logger("Got the following exception within a forked strand$file, trying to rethrow"); + $logger->logger("Got the following exception within a forked strand{$file}, trying to rethrow"); } - if ($e->getMessage() === "Cannot get return value of a generator that hasn't returned") { $logger->logger("Well you know, this might actually not be the actual exception, scroll up in the logs to see the actual exception"); if (!$zis || !$zis->destructing) { @@ -515,11 +471,9 @@ trait Tools if ($logger) { $logger->logger($e); } - Promise\rethrow(new Failure($e)); } } - /** * Call promise $b after promise $a. * @@ -554,7 +508,6 @@ trait Tools $deferred->resolve($res); }); }); - return $deferred->promise(); } /** @@ -573,7 +526,6 @@ trait Tools \http_response_code($status); return self::echo($message); } - /** * Asynchronously lock a file * Resolves with a callbable that MUST eventually be called in order to release the lock. @@ -581,7 +533,7 @@ trait Tools * @param string $file File to lock * @param integer $operation Locking mode * @param float $polling Polling interval - * + * * @return Promise */ public static function flock(string $file, int $operation, float $polling = 0.1): Promise @@ -613,7 +565,6 @@ trait Tools yield self::sleep($polling); } } while (!$result); - return static function () use (&$res) { if ($res) { \flock($res, LOCK_UN); @@ -633,7 +584,6 @@ trait Tools { return new \Amp\Delayed($time * 1000); } - /** * Asynchronously read line. * @@ -669,7 +619,6 @@ trait Tools } return \array_shift($lines); } - /** * Asynchronously write to stdout/browser. * @@ -690,12 +639,8 @@ trait Tools */ public static function isArrayOrAlike($var): bool { - return \is_array($var) || - ($var instanceof \ArrayAccess && - $var instanceof \Traversable && - $var instanceof \Countable); + return \is_array($var) || $var instanceof \ArrayAccess && $var instanceof \Traversable && $var instanceof \Countable; } - /** * Convert to camelCase. * @@ -721,10 +666,8 @@ trait Tools foreach ($ret as &$match) { $match = $match == \strtoupper($match) ? \strtolower($match) : \lcfirst($match); } - return \implode('_', $ret); } - /** * Create array. * @@ -758,7 +701,6 @@ trait Tools { return \rtrim(\strtr(\base64_encode($data), '+/', '-_'), '='); } - /** * null-byte RLE decode. * @@ -780,11 +722,9 @@ trait Tools $last = $cur; } } - $string = $new.$last; - + $string = $new . $last; return $string; } - /** * null-byte RLE encode. * @@ -802,16 +742,14 @@ trait Tools $count++; } else { if ($count > 0) { - $new .= $null.\chr($count); + $new .= $null . \chr($count); $count = 0; } $new .= $cur; } } - return $new; } - /** * Get final element of array. * @@ -823,7 +761,6 @@ trait Tools { return \end($what); } - /** * Escape string for markdown. * @@ -835,7 +772,6 @@ trait Tools { return \str_replace('_', '\\_', $hwat); } - /** * Whether this is altervista. * @@ -845,8 +781,6 @@ trait Tools { return Magic::$altervista; } - - /** * Accesses a private variable from an object. * diff --git a/src/danog/MadelineProto/VoIP/AuthKeyHandler.php b/src/danog/MadelineProto/VoIP/AuthKeyHandler.php index 04cca6b3..3201d6d7 100644 --- a/src/danog/MadelineProto/VoIP/AuthKeyHandler.php +++ b/src/danog/MadelineProto/VoIP/AuthKeyHandler.php @@ -28,7 +28,6 @@ namespace danog\MadelineProto\VoIP; trait AuthKeyHandler { private $calls = []; - /** * Request call (synchronous). * @@ -42,7 +41,6 @@ trait AuthKeyHandler { return \danog\MadelineProto\Tools::wait($this->requestCallAsync($user)); } - /** * Accept call (synchronous). * @@ -56,7 +54,6 @@ trait AuthKeyHandler { return \danog\MadelineProto\Tools::wait($this->acceptCallAsync($user)); } - /** * Discard call (synchronous). * @@ -71,7 +68,6 @@ trait AuthKeyHandler { \danog\MadelineProto\Tools::wait($this->discardCallAsync($call, $reason, $rating, $need_debug)); } - /** * Request VoIP call. * @@ -102,10 +98,8 @@ trait AuthKeyHandler $controller->setCall($res['phone_call']); $this->calls[$res['phone_call']['id']] = $controller; yield $this->updaters[false]->resume(); - return $controller; } - /** * Accept call. * @@ -120,7 +114,6 @@ trait AuthKeyHandler } if ($this->callStatus($call['id']) !== \danog\MadelineProto\VoIP::CALL_STATE_ACCEPTED) { $this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['call_error_1'], $call['id'])); - return false; } $this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['accepting_call'], $this->calls[$call['id']]->getOtherID()), \danog\MadelineProto\Logger::VERBOSE); @@ -129,30 +122,24 @@ trait AuthKeyHandler $b = \tgseclib\Math\BigInteger::randomRange(\danog\MadelineProto\Magic::$two, $dh_config['p']->subtract(\danog\MadelineProto\Magic::$two)); $g_b = $dh_config['g']->powMod($b, $dh_config['p']); $this->checkG($g_b, $dh_config['p']); - try { $res = yield $this->methodCallAsyncRead('phone.acceptCall', ['peer' => $call, 'g_b' => $g_b->toBytes(), 'protocol' => ['_' => 'phoneCallProtocol', 'udp_reflector' => true, 'udp_p2p' => true, 'min_layer' => 65, 'max_layer' => \danog\MadelineProto\VoIP::getConnectionMaxLayer()]], ['datacenter' => $this->datacenter->curdc]); } catch (\danog\MadelineProto\RPCErrorException $e) { if ($e->rpc === 'CALL_ALREADY_ACCEPTED') { $this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['call_already_accepted'], $call['id'])); - return true; } if ($e->rpc === 'CALL_ALREADY_DECLINED') { $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['call_already_declined']); - yield $this->discardCallAsync($call['id'], 'phoneCallDiscardReasonHangup'); - + yield from $this->discardCallAsync($call['id'], 'phoneCallDiscardReasonHangup'); return false; } - throw $e; } $this->calls[$res['phone_call']['id']]->storage['b'] = $b; yield $this->updaters[false]->resume(); - return true; } - /** * Confirm call. * @@ -167,7 +154,6 @@ trait AuthKeyHandler } if ($this->callStatus($params['id']) !== \danog\MadelineProto\VoIP::CALL_STATE_REQUESTED) { $this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['call_error_2'], $params['id'])); - return false; } $this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['call_confirming'], $this->calls[$params['id']]->getOtherID()), \danog\MadelineProto\Logger::VERBOSE); @@ -180,35 +166,28 @@ trait AuthKeyHandler } catch (\danog\MadelineProto\RPCErrorException $e) { if ($e->rpc === 'CALL_ALREADY_ACCEPTED') { $this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['call_already_accepted'], $call['id'])); - return true; } if ($e->rpc === 'CALL_ALREADY_DECLINED') { $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['call_already_declined']); - yield $this->discardCallAsync($call['id'], 'phoneCallDiscardReasonHangup'); - + yield from $this->discardCallAsync($call['id'], 'phoneCallDiscardReasonHangup'); return false; } - throw $e; } - $visualization = []; $length = new \tgseclib\Math\BigInteger(\count(\danog\MadelineProto\Magic::$emojis)); - foreach (\str_split(\hash('sha256', $key.\str_pad($this->calls[$params['id']]->storage['g_a'], 256, \chr(0), \STR_PAD_LEFT), true), 8) as $number) { + foreach (\str_split(\hash('sha256', $key . \str_pad($this->calls[$params['id']]->storage['g_a'], 256, \chr(0), \STR_PAD_LEFT), true), 8) as $number) { $number[0] = \chr(\ord($number[0]) & 0x7f); $visualization[] = \danog\MadelineProto\Magic::$emojis[(int) (new \tgseclib\Math\BigInteger($number, 256))->divide($length)[1]->toString()]; } $this->calls[$params['id']]->setVisualization($visualization); - $this->calls[$params['id']]->configuration['endpoints'] = \array_merge($res['connections'], $this->calls[$params['id']]->configuration['endpoints']); $this->calls[$params['id']]->configuration = \array_merge(['recv_timeout' => $this->config['call_receive_timeout_ms'] / 1000, 'init_timeout' => $this->config['call_connect_timeout_ms'] / 1000, 'data_saving' => \danog\MadelineProto\VoIP::DATA_SAVING_NEVER, 'enable_NS' => true, 'enable_AEC' => true, 'enable_AGC' => true, 'auth_key' => $key, 'auth_key_id' => \substr(\sha1($key, true), -8), 'call_id' => \substr(\hash('sha256', $key, true), -16), 'network_type' => \danog\MadelineProto\VoIP::NET_TYPE_ETHERNET], $this->calls[$params['id']]->configuration); $this->calls[$params['id']]->parseConfig(); $res = $this->calls[$params['id']]->startTheMagic(); - return $res; } - /** * Complete call handshake. * @@ -223,7 +202,6 @@ trait AuthKeyHandler } if ($this->callStatus($params['id']) !== \danog\MadelineProto\VoIP::CALL_STATE_ACCEPTED || !isset($this->calls[$params['id']]->storage['b'])) { $this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['call_error_3'], $params['id'])); - return false; } $this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['call_completing'], $this->calls[$params['id']]->getOtherID()), \danog\MadelineProto\Logger::VERBOSE); @@ -239,7 +217,7 @@ trait AuthKeyHandler } $visualization = []; $length = new \tgseclib\Math\BigInteger(\count(\danog\MadelineProto\Magic::$emojis)); - foreach (\str_split(\hash('sha256', $key.\str_pad($params['g_a_or_b']->toBytes(), 256, \chr(0), \STR_PAD_LEFT), true), 8) as $number) { + foreach (\str_split(\hash('sha256', $key . \str_pad($params['g_a_or_b']->toBytes(), 256, \chr(0), \STR_PAD_LEFT), true), 8) as $number) { $number[0] = \chr(\ord($number[0]) & 0x7f); $visualization[] = \danog\MadelineProto\Magic::$emojis[(int) (new \tgseclib\Math\BigInteger($number, 256))->divide($length)[1]->toString()]; } @@ -247,10 +225,8 @@ trait AuthKeyHandler $this->calls[$params['id']]->configuration['endpoints'] = \array_merge($params['connections'], $this->calls[$params['id']]->configuration['endpoints']); $this->calls[$params['id']]->configuration = \array_merge(['recv_timeout' => $this->config['call_receive_timeout_ms'] / 1000, 'init_timeout' => $this->config['call_connect_timeout_ms'] / 1000, 'data_saving' => \danog\MadelineProto\VoIP::DATA_SAVING_NEVER, 'enable_NS' => true, 'enable_AEC' => true, 'enable_AGC' => true, 'auth_key' => $key, 'auth_key_id' => \substr(\sha1($key, true), -8), 'call_id' => \substr(\hash('sha256', $key, true), -16), 'network_type' => \danog\MadelineProto\VoIP::NET_TYPE_ETHERNET], $this->calls[$params['id']]->configuration); $this->calls[$params['id']]->parseConfig(); - return $this->calls[$params['id']]->startTheMagic(); } - /** * Get call status. * @@ -266,10 +242,8 @@ trait AuthKeyHandler if (isset($this->calls[$id])) { return $this->calls[$id]->getCallState(); } - return \danog\MadelineProto\VoIP::CALL_STATE_NONE; } - /** * Get call info. * @@ -282,10 +256,8 @@ trait AuthKeyHandler if (!\class_exists('\\danog\\MadelineProto\\VoIP')) { throw \danog\MadelineProto\Exception::extension('libtgvoip'); } - return $this->calls[$call]; } - /** * Discard call. * @@ -305,7 +277,6 @@ trait AuthKeyHandler return; } $this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['call_discarding'], $call['id']), \danog\MadelineProto\Logger::VERBOSE); - try { $res = yield $this->methodCallAsyncRead('phone.discardCall', ['peer' => $call, 'duration' => \time() - $this->calls[$call['id']]->whenCreated(), 'connection_id' => $this->calls[$call['id']]->getPreferredRelayID(), 'reason' => $reason], ['datacenter' => $this->datacenter->curdc]); } catch (\danog\MadelineProto\RPCErrorException $e) { diff --git a/src/danog/MadelineProto/VoIPServerConfig.php b/src/danog/MadelineProto/VoIPServerConfig.php index 45701098..7232f571 100644 --- a/src/danog/MadelineProto/VoIPServerConfig.php +++ b/src/danog/MadelineProto/VoIPServerConfig.php @@ -1,4 +1,5 @@ <?php + /** * VoIPServerConfig. * @@ -36,7 +37,6 @@ if (\class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal')) { * @var array */ private static $_configDefault = []; - /** * Update shared call settings. * @@ -49,7 +49,6 @@ if (\class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal')) { self::$_config = $config; self::updateInternal(self::getFinal()); } - /** * Get shared call settings. * @@ -59,7 +58,6 @@ if (\class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal')) { { return self::$_config; } - /** * Update default shared call settings. * @@ -72,7 +70,6 @@ if (\class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal')) { self::$_configDefault = $configDefault; self::updateInternal(self::getFinal()); } - /** * Get default shared call settings. * @@ -82,7 +79,6 @@ if (\class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal')) { { return self::$_configDefault; } - /** * Get final settings. * diff --git a/src/danog/MadelineProto/Wrappers/ApiStart.php b/src/danog/MadelineProto/Wrappers/ApiStart.php index c0d68ea9..44657e63 100644 --- a/src/danog/MadelineProto/Wrappers/ApiStart.php +++ b/src/danog/MadelineProto/Wrappers/ApiStart.php @@ -20,7 +20,6 @@ namespace danog\MadelineProto\Wrappers; use danog\MadelineProto\Tools; - use function Amp\ByteStream\getStdout; /** @@ -28,12 +27,12 @@ use function Amp\ByteStream\getStdout; */ trait ApiStart { - public function APIStart($settings) + public function APIStart($settings): \Generator { if (PHP_SAPI === 'cli') { $stdout = getStdout(); yield $stdout->write('You did not define a valid API ID/API hash. Do you want to define it now manually, or automatically? (m/a) -Note that you can also provide the API parameters directly in the code using the settings: https://docs.madelineproto.xyz/docs/SETTINGS.html#settingsapp_infoapi_id'.PHP_EOL); +Note that you can also provide the API parameters directly in the code using the settings: https://docs.madelineproto.xyz/docs/SETTINGS.html#settingsapp_infoapi_id' . PHP_EOL); if (\strpos(yield Tools::readLine('Your choice (m/a): '), 'm') !== false) { yield $stdout->write('1) Login to my.telegram.org 2) Go to API development tools @@ -42,10 +41,9 @@ Note that you can also provide the API parameters directly in the code using the URL: your app/website\'s URL, or t.me/yourusername Platform: anything Description: Describe your app here -4) Click on create application'.PHP_EOL); +4) Click on create application' . PHP_EOL); $app['api_id'] = yield Tools::readLine('5) Enter your API ID: '); $app['api_hash'] = yield Tools::readLine('6) Enter your API hash: '); - return $app; } $this->my_telegram_org_wrapper = new \danog\MadelineProto\MyTelegramOrgWrapper($settings); @@ -60,7 +58,6 @@ Note that you can also provide the API parameters directly in the code using the } else { $app = yield $this->my_telegram_org_wrapper->getApp(); } - return $app; } $this->getting_api_id = true; @@ -69,16 +66,15 @@ Note that you can also provide the API parameters directly in the code using the $app['api_id'] = (int) $_POST['api_id']; $app['api_hash'] = $_POST['api_hash']; $this->getting_api_id = false; - return $app; } elseif (isset($_POST['phone_number'])) { - yield $this->webAPIPhoneLogin($settings); + yield from $this->webAPIPhoneLogin($settings); } else { yield $this->webAPIEcho(); } } elseif (!$this->my_telegram_org_wrapper->loggedIn()) { if (isset($_POST['code'])) { - yield $this->webAPICompleteLogin(); + yield from $this->webAPICompleteLogin(); if (yield $this->my_telegram_org_wrapper->hasApp()) { return yield $this->my_telegram_org_wrapper->getApp(); } @@ -87,19 +83,17 @@ Note that you can also provide the API parameters directly in the code using the $app['api_id'] = (int) $_POST['api_id']; $app['api_hash'] = $_POST['api_hash']; $this->getting_api_id = false; - return $app; } elseif (isset($_POST['phone_number'])) { - yield $this->webAPIPhoneLogin($settings); + yield from $this->webAPIPhoneLogin($settings); } else { $this->my_telegram_org_wrapper = null; yield $this->webAPIEcho(); } } else { if (isset($_POST['app_title'], $_POST['app_shortname'], $_POST['app_url'], $_POST['app_platform'], $_POST['app_desc'])) { - $app = yield $this->webAPICreateApp(); + $app = (yield from $this->webAPICreateApp()); $this->getting_api_id = false; - return $app; } yield $this->webAPIEcho("You didn't provide all of the required parameters!"); @@ -107,41 +101,37 @@ Note that you can also provide the API parameters directly in the code using the $this->asyncInitPromise = null; exit; } - - private function webAPIPhoneLogin($settings) + private function webAPIPhoneLogin($settings): \Generator { try { $this->my_telegram_org_wrapper = new \danog\MadelineProto\MyTelegramOrgWrapper($settings); yield $this->my_telegram_org_wrapper->login($_POST['phone_number']); yield $this->webAPIEcho(); } catch (\Throwable $e) { - yield $this->webAPIEcho('ERROR: '.$e->getMessage().'. Try again.'); + yield $this->webAPIEcho('ERROR: ' . $e->getMessage() . '. Try again.'); } } - - private function webAPICompleteLogin() + private function webAPICompleteLogin(): \Generator { try { yield $this->my_telegram_org_wrapper->completeLogin($_POST['code']); } catch (\danog\MadelineProto\RPCErrorException $e) { - yield $this->webAPIEcho('ERROR: '.$e->getMessage().'. Try again.'); + yield $this->webAPIEcho('ERROR: ' . $e->getMessage() . '. Try again.'); } catch (\danog\MadelineProto\Exception $e) { - yield $this->webAPIEcho('ERROR: '.$e->getMessage().'. Try again.'); + yield $this->webAPIEcho('ERROR: ' . $e->getMessage() . '. Try again.'); } } - - private function webAPICreateApp() + private function webAPICreateApp(): \Generator { try { $params = $_POST; unset($params['creating_app']); $app = yield $this->my_telegram_org_wrapper->createApp($params); - return $app; } catch (\danog\MadelineProto\RPCErrorException $e) { - yield $this->webAPIEcho('ERROR: '.$e->getMessage().' Try again.'); + yield $this->webAPIEcho('ERROR: ' . $e->getMessage() . ' Try again.'); } catch (\danog\MadelineProto\Exception $e) { - yield $this->webAPIEcho('ERROR: '.$e->getMessage().' Try again.'); + yield $this->webAPIEcho('ERROR: ' . $e->getMessage() . ' Try again.'); } } } diff --git a/src/danog/MadelineProto/Wrappers/ApiTemplates.php b/src/danog/MadelineProto/Wrappers/ApiTemplates.php index dc5eb723..c92c8ae7 100644 --- a/src/danog/MadelineProto/Wrappers/ApiTemplates.php +++ b/src/danog/MadelineProto/Wrappers/ApiTemplates.php @@ -37,12 +37,10 @@ trait ApiTemplates </form> </body> </html>'; - private function webAPIEchoTemplate($message, $form) { return \sprintf($this->web_api_template, $message, $form); } - /** * Get web API login HTML template string. * @@ -52,7 +50,6 @@ trait ApiTemplates { return $this->web_template; } - /** * Set web API login HTML template string. * @@ -62,14 +59,13 @@ trait ApiTemplates { $this->web_template = $template; } - - private function webAPIEcho(string $message = '') + private function webAPIEcho(string $message = ''): \Generator { $stdout = getOutputBufferStream(); if (!isset($this->my_telegram_org_wrapper)) { if (isset($_POST['type'])) { if ($_POST['type'] === 'manual') { - yield $stdout->write($this->webAPIEchoTemplate('Enter your API ID and API hash<br><b>'.$message.'</b><ol> + yield $stdout->write($this->webAPIEchoTemplate('Enter your API ID and API hash<br><b>' . $message . '</b><ol> <li>Login to my.telegram.org</li> <li>Go to API development tools</li> <li> @@ -83,21 +79,19 @@ trait ApiTemplates <li>Click on create application</li> </ol>', '<input type="string" name="api_id" placeholder="API ID" required/><input type="string" name="api_hash" placeholder="API hash" required/>')); } else { - yield $stdout->write($this->webAPIEchoTemplate('Enter a phone number that is <b>already registered</b> on telegram to get the API ID<br><b>'.$message.'</b>', '<input type="text" name="phone_number" placeholder="Phone number" required/>')); + yield $stdout->write($this->webAPIEchoTemplate('Enter a phone number that is <b>already registered</b> on telegram to get the API ID<br><b>' . $message . '</b>', '<input type="text" name="phone_number" placeholder="Phone number" required/>')); } } else { if ($message) { - $message = '<br><br>'.$message; + $message = '<br><br>' . $message; } - yield $stdout->write($this->webAPIEchoTemplate('Do you want to enter the API id and the API hash manually or automatically?<br>Note that you can also provide it directly in the code using the <a href="https://docs.madelineproto.xyz/docs/SETTINGS.html#settingsapp_infoapi_id">settings</a>.<b>'.$message.'</b>', '<select name="type"><option value="automatic">Automatically</option><option value="manual">Manually</option></select>')); + yield $stdout->write($this->webAPIEchoTemplate('Do you want to enter the API id and the API hash manually or automatically?<br>Note that you can also provide it directly in the code using the <a href="https://docs.madelineproto.xyz/docs/SETTINGS.html#settingsapp_infoapi_id">settings</a>.<b>' . $message . '</b>', '<select name="type"><option value="automatic">Automatically</option><option value="manual">Manually</option></select>')); } } else { if (!$this->my_telegram_org_wrapper->loggedIn()) { - yield $stdout->write($this->webAPIEchoTemplate('Enter your code<br><b>'.$message.'</b>', '<input type="text" name="code" placeholder="Code" required/>')); + yield $stdout->write($this->webAPIEchoTemplate('Enter your code<br><b>' . $message . '</b>', '<input type="text" name="code" placeholder="Code" required/>')); } else { - yield $stdout->write($this->webAPIEchoTemplate( - 'Enter the API info<br><b>'.$message.'</b>', - '<input type="hidden" name="creating_app" value="yes" required/> + yield $stdout->write($this->webAPIEchoTemplate('Enter the API info<br><b>' . $message . '</b>', '<input type="hidden" name="creating_app" value="yes" required/> Enter the app name, can be anything: <br><input type="text" name="app_title" required/><br> <br>Enter the app's short name, alphanumeric, 5-32 chars: <br><input type="text" name="app_shortname" required/><br> <br>Enter the app/website URL, or https://t.me/yourusername: <br><input type="text" name="app_url" required/><br> @@ -127,8 +121,7 @@ trait ApiTemplates <input type="radio" name="app_platform" value="other"> Other (specify in description) </label> <br><br>Enter the app description, can be anything: <br><textarea name="app_desc" required></textarea><br><br> - ' - )); + ')); } } } diff --git a/src/danog/MadelineProto/Wrappers/DialogHandler.php b/src/danog/MadelineProto/Wrappers/DialogHandler.php index de1c505e..6e9ec09e 100644 --- a/src/danog/MadelineProto/Wrappers/DialogHandler.php +++ b/src/danog/MadelineProto/Wrappers/DialogHandler.php @@ -35,17 +35,14 @@ trait DialogHandler foreach ($this->chats as $chat) { $res[] = $this->genAll($chat)['Peer']; } - return $res; } $res = []; - foreach (yield $this->getFullDialogs($force) as $dialog) { + foreach (yield from $this->getFullDialogs($force) as $dialog) { $res[] = $dialog['peer']; } - return $res; } - /** * Get full info of all dialogs. * @@ -64,7 +61,6 @@ trait DialogHandler $res = ['dialogs' => [0], 'count' => 1]; $datacenter = $this->datacenter->curdc; $dialogs = []; - $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['getting_dialogs']); while ($this->dialog_params['count'] < $res['count']) { $res = yield $this->methodCallAsyncRead('messages.getDialogs', $this->dialog_params, ['datacenter' => $datacenter, 'FloodWaitLimit' => 100]); @@ -104,7 +100,6 @@ trait DialogHandler break; } } - return $dialogs; } } diff --git a/src/danog/MadelineProto/Wrappers/Events.php b/src/danog/MadelineProto/Wrappers/Events.php index 209a3bc9..c0d30cf7 100644 --- a/src/danog/MadelineProto/Wrappers/Events.php +++ b/src/danog/MadelineProto/Wrappers/Events.php @@ -44,7 +44,6 @@ trait Events * @var array<string> */ private $event_handler_methods = []; - /** * Set event handler. * @@ -54,13 +53,11 @@ trait Events */ public function setEventHandler($event_handler): void { - if (!\class_exists($event_handler) || !\is_subclass_of($event_handler, '\danog\MadelineProto\EventHandler')) { + if (!\class_exists($event_handler) || !\is_subclass_of($event_handler, '\\danog\\MadelineProto\\EventHandler')) { throw new \danog\MadelineProto\Exception('Wrong event handler was defined'); } - $this->event_handler = $event_handler; - - if (!($this->event_handler_instance instanceof $this->event_handler)) { + if (!$this->event_handler_instance instanceof $this->event_handler) { $class_name = $this->event_handler; $this->event_handler_instance = new $class_name($this->wrapper); } elseif ($this->wrapper) { @@ -81,7 +78,6 @@ trait Events $this->event_handler_methods[$method_name] = [$this->event_handler_instance, $method]; } } - $this->settings['updates']['callback'] = [$this, 'eventUpdateHandler']; $this->settings['updates']['handle_updates'] = true; $this->settings['updates']['run_callback'] = true; @@ -89,7 +85,6 @@ trait Events $this->startUpdateSystem(); } } - /** * Get event handler. * @@ -99,7 +94,6 @@ trait Events { return $this->event_handler_instance; } - /** * Event update handler. * diff --git a/src/danog/MadelineProto/Wrappers/Login.php b/src/danog/MadelineProto/Wrappers/Login.php index 4474c4f1..de9fcfb2 100644 --- a/src/danog/MadelineProto/Wrappers/Login.php +++ b/src/danog/MadelineProto/Wrappers/Login.php @@ -27,7 +27,6 @@ use danog\MadelineProto\MTProtoTools\PasswordCalculator; */ trait Login { - /** * Log out currently logged in user. * @@ -39,10 +38,8 @@ trait Login $this->resetSession(); $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['logout_ok'], \danog\MadelineProto\Logger::NOTICE); $this->startUpdateSystem(); - return true; } - /** * Login as bot. * @@ -54,11 +51,10 @@ trait Login { if ($this->authorized === self::LOGGED_IN) { $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['already_loggedIn'], \danog\MadelineProto\Logger::NOTICE); - yield $this->logout(); + yield from $this->logout(); } $callbacks = [$this, $this->referenceDatabase]; $this->TL->updateCallbacks($callbacks); - $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_bot'], \danog\MadelineProto\Logger::NOTICE); $this->authorization = yield $this->methodCallAsyncRead('auth.importBotAuthorization', ['bot_auth_token' => $token, 'api_id' => $this->settings['app_info']['api_id'], 'api_hash' => $this->settings['app_info']['api_hash']], ['datacenter' => $this->datacenter->curdc]); $this->authorized = self::LOGGED_IN; @@ -68,12 +64,9 @@ trait Login $this->updates_key = 0; yield $this->initAuthorization(); $this->startUpdateSystem(); - $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_ok'], \danog\MadelineProto\Logger::NOTICE); - return $this->authorization; } - /** * Login as user. * @@ -86,7 +79,7 @@ trait Login { if ($this->authorized === self::LOGGED_IN) { $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['already_loggedIn'], \danog\MadelineProto\Logger::NOTICE); - yield $this->logout(); + yield from $this->logout(); } $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_code_sending'], \danog\MadelineProto\Logger::NOTICE); $this->authorization = yield $this->methodCallAsyncRead('auth.sendCode', ['settings' => ['_' => 'codeSettings'], 'phone_number' => $number, 'sms_type' => $sms_type, 'api_id' => $this->settings['app_info']['api_id'], 'api_hash' => $this->settings['app_info']['api_hash'], 'lang_code' => $this->settings['app_info']['lang_code']], ['datacenter' => $this->datacenter->curdc]); @@ -97,10 +90,8 @@ trait Login $this->updates = []; $this->updates_key = 0; $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_code_sent'], \danog\MadelineProto\Logger::NOTICE); - return $this->authorization; } - /** * Complet user login using login code. * @@ -115,7 +106,6 @@ trait Login } $this->authorized = self::NOT_LOGGED_IN; $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_user'], \danog\MadelineProto\Logger::NOTICE); - try { $authorization = yield $this->methodCallAsyncRead('auth.signIn', ['phone_number' => $this->authorization['phone_number'], 'phone_code_hash' => $this->authorization['phone_code_hash'], 'phone_code' => (string) $code], ['datacenter' => $this->datacenter->curdc]); } catch (\danog\MadelineProto\RPCErrorException $e) { @@ -126,24 +116,20 @@ trait Login $this->authorization['hint'] = ''; } $this->authorized = self::WAITING_PASSWORD; - return $this->authorization; } if ($e->rpc === 'PHONE_NUMBER_UNOCCUPIED') { $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_need_signup'], \danog\MadelineProto\Logger::NOTICE); $this->authorized = self::WAITING_SIGNUP; $this->authorization['phone_code'] = $code; - return ['_' => 'account.needSignup']; } - throw $e; } if ($authorization['_'] === 'auth.authorizationSignUpRequired') { $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_need_signup'], \danog\MadelineProto\Logger::NOTICE); $this->authorized = self::WAITING_SIGNUP; $this->authorization['phone_code'] = $code; - $authorization['_'] = 'account.needSignup'; return $authorization; } @@ -153,12 +139,9 @@ trait Login yield $this->initAuthorization(); yield $this->getPhoneConfig(); $this->startUpdateSystem(); - $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_ok'], \danog\MadelineProto\Logger::NOTICE); - return $this->authorization; } - /** * Import authorization. * @@ -170,7 +153,7 @@ trait Login { if ($this->authorized === self::LOGGED_IN) { $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['already_loggedIn'], \danog\MadelineProto\Logger::NOTICE); - yield $this->logout(); + yield from $this->logout(); } $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_auth_key'], \danog\MadelineProto\Logger::NOTICE); list($dc_id, $auth_key) = $authorization; @@ -178,7 +161,6 @@ trait Login $auth_key = ['auth_key' => $auth_key]; } $auth_key = new PermAuthKey($auth_key); - $this->authorized_dc = $dc_id; $dataCenterConnection = $this->datacenter->getDataCenterConnection($dc_id); $dataCenterConnection->resetSession(); @@ -187,20 +169,15 @@ trait Login $this->authorized = self::LOGGED_IN; yield $this->initAuthorization(); yield $this->getPhoneConfig(); - $res = yield $this->getSelf(); - $callbacks = [$this, $this->referenceDatabase]; if (!($this->authorization['user']['bot'] ?? false)) { - $callbacks []= $this->minDatabase; + $callbacks[] = $this->minDatabase; } $this->TL->updateCallbacks($callbacks); - $this->startUpdateSystem(); - return $res; } - /** * Export authorization. * @@ -213,10 +190,8 @@ trait Login } yield $this->getSelf(); $this->authorized_dc = $this->datacenter->curdc; - return [$this->datacenter->curdc, $this->datacenter->getDataCenterConnection($this->datacenter->curdc)->getPermAuthKey()->getAuthKey()]; } - /** * Complete signup to Telegram. * @@ -237,13 +212,10 @@ trait Login $this->datacenter->getDataCenterConnection($this->datacenter->curdc)->authorized(true); yield $this->initAuthorization(); yield $this->getPhoneConfig(); - $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['signup_ok'], \danog\MadelineProto\Logger::NOTICE); $this->startUpdateSystem(); - return $this->authorization; } - /** * Complete 2FA login. * @@ -267,10 +239,8 @@ trait Login $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_ok'], \danog\MadelineProto\Logger::NOTICE); yield $this->getPhoneConfig(); $this->startUpdateSystem(); - return $this->authorization; } - /** * Update the 2FA password. * @@ -284,7 +254,6 @@ trait Login { $hasher = new PasswordCalculator($this->logger); $hasher->addInfo(yield $this->methodCallAsyncRead('account.getPassword', [], ['datacenter' => $this->datacenter->curdc])); - return yield $this->methodCallAsyncRead('account.updatePasswordSettings', $hasher->getPassword($params), ['datacenter' => $this->datacenter->curdc]); } } diff --git a/src/danog/MadelineProto/Wrappers/Loop.php b/src/danog/MadelineProto/Wrappers/Loop.php index db2e6414..cb2b7f49 100644 --- a/src/danog/MadelineProto/Wrappers/Loop.php +++ b/src/danog/MadelineProto/Wrappers/Loop.php @@ -35,7 +35,6 @@ trait Loop * @var boolean */ private $stopLoop = false; - /** * Set loop callback (DEPRECATED). * @@ -47,7 +46,6 @@ trait Loop { $this->loop_callback = $callback; } - /** * Start MadelineProto's update handling loop, or run the provided async callable. * @@ -55,47 +53,41 @@ trait Loop * * @return mixed */ - public function loop($callback = null) + public function loop($callback = null): \Generator { if (\is_callable($callback)) { $this->logger->logger('Running async callable'); - return yield $callback(); } if ($callback instanceof Promise) { $this->logger->logger('Resolving async promise'); - return yield $callback; } if (!$this->authorized) { $this->logger->logger('Not authorized, not starting event loop', \danog\MadelineProto\Logger::FATAL_ERROR); - return false; } if (\in_array($this->settings['updates']['callback'], [['danog\\MadelineProto\\API', 'getUpdatesUpdateHandler'], 'getUpdatesUpdateHandler'])) { $this->logger->logger('Getupdates event handler is enabled, exiting from loop', \danog\MadelineProto\Logger::FATAL_ERROR); - return false; } $this->logger->logger('Starting event loop'); - if (!\is_callable($this->loop_callback) || (\is_array($this->loop_callback) && $this->loop_callback[1] === 'onLoop' && !\method_exists(...$this->loop_callback))) { + if (!\is_callable($this->loop_callback) || \is_array($this->loop_callback) && $this->loop_callback[1] === 'onLoop' && !\method_exists(...$this->loop_callback)) { $this->loop_callback = null; } if (PHP_SAPI !== 'cli') { $needs_restart = true; - try { \set_time_limit(-1); } catch (\danog\MadelineProto\Exception $e) { $needs_restart = true; } if (isset($_REQUEST['MadelineSelfRestart'])) { - $this->logger->logger("Self-restarted, restart token ".$_REQUEST['MadelineSelfRestart']); + $this->logger->logger("Self-restarted, restart token " . $_REQUEST['MadelineSelfRestart']); } $this->logger->logger($needs_restart ? 'Will self-restart' : 'Will not self-restart'); - $backtrace = \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); - $lockfile = \dirname(\end($backtrace)['file']).'/bot'.$this->authorization['user']['id'].'.lock'; + $lockfile = \dirname(\end($backtrace)['file']) . '/bot' . $this->authorization['user']['id'] . '.lock'; unset($backtrace); $try_locking = true; if (!\file_exists($lockfile)) { @@ -121,43 +113,32 @@ trait Loop } } } - Shutdown::addCallback(static function () use ($lock) { \flock($lock, LOCK_UN); \fclose($lock); }); if ($needs_restart) { - $logger = &$this->logger; + $logger =& $this->logger; Shutdown::addCallback(static function () use (&$logger) { - $address = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] ? 'tls' : 'tcp').'://'.$_SERVER['SERVER_NAME']; + $address = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] ? 'tls' : 'tcp') . '://' . $_SERVER['SERVER_NAME']; $port = $_SERVER['SERVER_PORT']; - $uri = $_SERVER['REQUEST_URI']; - $params = $_GET; $params['MadelineSelfRestart'] = Tools::randomInt(); - $url = \explode('?', $uri, 2)[0] ?? ''; - $query = \http_build_query($params); $uri = \implode('?', [$url, $query]); - - $payload = $_SERVER['REQUEST_METHOD'].' '.$uri.' '.$_SERVER['SERVER_PROTOCOL']."\r\n".'Host: '.$_SERVER['SERVER_NAME']."\r\n\r\n"; - - $logger->logger("Connecting to $address:$port"); + $payload = $_SERVER['REQUEST_METHOD'] . ' ' . $uri . ' ' . $_SERVER['SERVER_PROTOCOL'] . "\r\n" . 'Host: ' . $_SERVER['SERVER_NAME'] . "\r\n\r\n"; + $logger->logger("Connecting to {$address}:{$port}"); $a = \fsockopen($address, $port); - $logger->logger("Sending self-restart payload"); $logger->logger($payload); \fwrite($a, $payload); - $logger->logger("Payload sent with token {$params['MadelineSelfRestart']}, waiting for self-restart"); - \sleep(10); \fclose($a); }, 'restarter'); } - $this->closeConnection('Bot was started'); } if (!$this->settings['updates']['handle_updates']) { @@ -167,9 +148,7 @@ trait Loop $this->settings['updates']['run_callback'] = true; } $this->startUpdateSystem(); - $this->logger->logger('Started update loop', \danog\MadelineProto\Logger::NOTICE); - $this->stopLoop = false; do { $updates = $this->updates; @@ -181,7 +160,6 @@ trait Loop } } $updates = []; - if ($this->loop_callback !== null) { $callback = $this->loop_callback; Tools::callForkDefer($callback()); @@ -200,7 +178,6 @@ trait Loop $this->stopLoop = true; $this->signalUpdate(); } - /** * Close connection with client, connected via web. * @@ -214,17 +191,13 @@ trait Loop return; } $this->logger->logger($message); - $buffer = @\ob_get_clean() ?: ''; - $buffer .= '<html><body><h1>'.\htmlentities($message).'</h1></body></html>'; - + $buffer .= '<html><body><h1>' . \htmlentities($message) . '</h1></body></html>'; \ignore_user_abort(true); \header('Connection: close'); \header('Content-Type: text/html'); - echo $buffer; \flush(); - $GLOBALS['exited'] = true; if (\function_exists(\fastcgi_finish_request::class)) { \fastcgi_finish_request(); diff --git a/src/danog/MadelineProto/Wrappers/Noop.php b/src/danog/MadelineProto/Wrappers/Noop.php index 5e22d9de..fb699119 100644 --- a/src/danog/MadelineProto/Wrappers/Noop.php +++ b/src/danog/MadelineProto/Wrappers/Noop.php @@ -33,7 +33,6 @@ trait Noop $this->settings['updates']['handle_updates'] = true; $this->startUpdateSystem(); } - /** * Noop update handler. * diff --git a/src/danog/MadelineProto/Wrappers/Start.php b/src/danog/MadelineProto/Wrappers/Start.php index 2275d3b2..df9e5bb1 100644 --- a/src/danog/MadelineProto/Wrappers/Start.php +++ b/src/danog/MadelineProto/Wrappers/Start.php @@ -43,108 +43,101 @@ trait Start yield $this->phoneLogin(yield Tools::readLine('Enter your phone number: ')); $authorization = yield $this->completePhoneLogin(yield Tools::readLine('Enter the phone code: ')); if ($authorization['_'] === 'account.password') { - $authorization = yield $this->complete2faLogin(yield Tools::readLine('Please enter your password (hint '.$authorization['hint'].'): ')); + $authorization = yield $this->complete2faLogin(yield Tools::readLine('Please enter your password (hint ' . $authorization['hint'] . '): ')); } if ($authorization['_'] === 'account.needSignup') { $authorization = yield $this->completeSignup(yield Tools::readLine('Please enter your first name: '), yield Tools::readLine('Please enter your last name (can be empty): ')); } } $this->serialize(); - return yield $this->getSelf(); } if ($this->authorized === self::NOT_LOGGED_IN) { if (isset($_POST['phone_number'])) { - yield $this->webPhoneLogin(); + yield from $this->webPhoneLogin(); } elseif (isset($_POST['token'])) { - yield $this->webBotLogin(); + yield from $this->webBotLogin(); } else { yield $this->webEcho(); } } elseif ($this->authorized === self::WAITING_CODE) { if (isset($_POST['phone_code'])) { - yield $this->webCompletePhoneLogin(); + yield from $this->webCompletePhoneLogin(); } else { yield $this->webEcho("You didn't provide a phone code!"); } } elseif ($this->authorized === self::WAITING_PASSWORD) { if (isset($_POST['password'])) { - yield $this->webComplete2faLogin(); + yield from $this->webComplete2faLogin(); } else { yield $this->webEcho("You didn't provide the password!"); } } elseif ($this->authorized === self::WAITING_SIGNUP) { if (isset($_POST['first_name'])) { - yield $this->webCompleteSignup(); + yield from $this->webCompleteSignup(); } else { yield $this->webEcho("You didn't provide the first name!"); } } if ($this->authorized === self::LOGGED_IN) { $this->serialize(); - return yield $this->getSelf(); } exit; } - - private function webPhoneLogin() + private function webPhoneLogin(): \Generator { try { yield $this->phoneLogin($_POST['phone_number']); yield $this->webEcho(); } catch (\danog\MadelineProto\RPCErrorException $e) { - yield $this->webEcho('ERROR: '.$e->getMessage().'. Try again.'); + yield $this->webEcho('ERROR: ' . $e->getMessage() . '. Try again.'); } catch (\danog\MadelineProto\Exception $e) { - yield $this->webEcho('ERROR: '.$e->getMessage().'. Try again.'); + yield $this->webEcho('ERROR: ' . $e->getMessage() . '. Try again.'); } } - - private function webCompletePhoneLogin() + private function webCompletePhoneLogin(): \Generator { try { yield $this->completePhoneLogin($_POST['phone_code']); yield $this->webEcho(); } catch (\danog\MadelineProto\RPCErrorException $e) { - yield $this->webEcho('ERROR: '.$e->getMessage().'. Try again.'); + yield $this->webEcho('ERROR: ' . $e->getMessage() . '. Try again.'); } catch (\danog\MadelineProto\Exception $e) { - yield $this->webEcho('ERROR: '.$e->getMessage().'. Try again.'); + yield $this->webEcho('ERROR: ' . $e->getMessage() . '. Try again.'); } } - - private function webComplete2faLogin() + private function webComplete2faLogin(): \Generator { try { yield $this->complete2faLogin($_POST['password']); yield $this->webEcho(); } catch (\danog\MadelineProto\RPCErrorException $e) { - yield $this->webEcho('ERROR: '.$e->getMessage().'. Try again.'); + yield $this->webEcho('ERROR: ' . $e->getMessage() . '. Try again.'); } catch (\danog\MadelineProto\Exception $e) { - yield $this->webEcho('ERROR: '.$e->getMessage().'. Try again.'); + yield $this->webEcho('ERROR: ' . $e->getMessage() . '. Try again.'); } } - - private function webCompleteSignup() + private function webCompleteSignup(): \Generator { try { yield $this->completeSignup($_POST['first_name'], isset($_POST['last_name']) ? $_POST['last_name'] : ''); yield $this->webEcho(); } catch (\danog\MadelineProto\RPCErrorException $e) { - yield $this->webEcho('ERROR: '.$e->getMessage().'. Try again.'); + yield $this->webEcho('ERROR: ' . $e->getMessage() . '. Try again.'); } catch (\danog\MadelineProto\Exception $e) { - yield $this->webEcho('ERROR: '.$e->getMessage().'. Try again.'); + yield $this->webEcho('ERROR: ' . $e->getMessage() . '. Try again.'); } } - - private function webBotLogin() + private function webBotLogin(): \Generator { try { yield $this->botLogin($_POST['token']); yield $this->webEcho(); } catch (\danog\MadelineProto\RPCErrorException $e) { - yield $this->webEcho('ERROR: '.$e->getMessage().'. Try again.'); + yield $this->webEcho('ERROR: ' . $e->getMessage() . '. Try again.'); } catch (\danog\MadelineProto\Exception $e) { - yield $this->webEcho('ERROR: '.$e->getMessage().'. Try again.'); + yield $this->webEcho('ERROR: ' . $e->getMessage() . '. Try again.'); } } } diff --git a/src/danog/MadelineProto/Wrappers/TOS.php b/src/danog/MadelineProto/Wrappers/TOS.php index 2206f193..d2732a5c 100644 --- a/src/danog/MadelineProto/Wrappers/TOS.php +++ b/src/danog/MadelineProto/Wrappers/TOS.php @@ -37,7 +37,6 @@ trait TOS $this->tos = yield $this->methodCallAsyncRead('help.getTermsOfServiceUpdate', [], ['datacenter' => $this->datacenter->curdc]); $this->tos['accepted'] = $this->tos['_'] === 'help.termsOfServiceUpdateEmpty'; } - if (!$this->tos['accepted']) { $this->logger->logger('Telegram has updated their Terms Of Service', \danog\MadelineProto\Logger::ERROR); $this->logger->logger('Accept the TOS before proceeding by calling $MadelineProto->acceptTos().', \danog\MadelineProto\Logger::ERROR); @@ -45,12 +44,10 @@ trait TOS $this->logger->logger('By declining the TOS, the currently logged in account will be PERMANENTLY DELETED.', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger('Read the following TOS very carefully: ', \danog\MadelineProto\Logger::ERROR); $this->logger->logger($this->tos); - throw new \danog\MadelineProto\Exception('TOS action required, check the logs', 0, null, 'MadelineProto', 1); } } } - /** * Accept terms of service update. * @@ -65,7 +62,6 @@ trait TOS throw new \danog\MadelineProto\Exception('An error occurred while accepting the TOS'); } } - /** * Decline terms of service update. * diff --git a/src/danog/MadelineProto/Wrappers/Templates.php b/src/danog/MadelineProto/Wrappers/Templates.php index 7f60d8da..4d0232b6 100644 --- a/src/danog/MadelineProto/Wrappers/Templates.php +++ b/src/danog/MadelineProto/Wrappers/Templates.php @@ -23,36 +23,32 @@ use function Amp\ByteStream\getOutputBufferStream; trait Templates { - private function webEcho(string $message = '') + private function webEcho(string $message = ''): \Generator { $stdout = getOutputBufferStream(); switch ($this->authorized) { case self::NOT_LOGGED_IN: - if (isset($_POST['type'])) { - if ($_POST['type'] === 'phone') { - yield $stdout->write($this->webEchoTemplate('Enter your phone number<br><b>'.$message.'</b>', '<input type="text" name="phone_number" placeholder="Phone number" required/>')); + if (isset($_POST['type'])) { + if ($_POST['type'] === 'phone') { + yield $stdout->write($this->webEchoTemplate('Enter your phone number<br><b>' . $message . '</b>', '<input type="text" name="phone_number" placeholder="Phone number" required/>')); + } else { + yield $stdout->write($this->webEchoTemplate('Enter your bot token<br><b>' . $message . '</b>', '<input type="text" name="token" placeholder="Bot token" required/>')); + } } else { - yield $stdout->write($this->webEchoTemplate('Enter your bot token<br><b>'.$message.'</b>', '<input type="text" name="token" placeholder="Bot token" required/>')); + yield $stdout->write($this->webEchoTemplate('Do you want to login as user or bot?<br><b>' . $message . '</b>', '<select name="type"><option value="phone">User</option><option value="bot">Bot</option></select>')); } - } else { - yield $stdout->write($this->webEchoTemplate('Do you want to login as user or bot?<br><b>'.$message.'</b>', '<select name="type"><option value="phone">User</option><option value="bot">Bot</option></select>')); - } - break; - + break; case self::WAITING_CODE: - yield $stdout->write($this->webEchoTemplate('Enter your code<br><b>'.$message.'</b>', '<input type="text" name="phone_code" placeholder="Phone code" required/>')); - break; - + yield $stdout->write($this->webEchoTemplate('Enter your code<br><b>' . $message . '</b>', '<input type="text" name="phone_code" placeholder="Phone code" required/>')); + break; case self::WAITING_PASSWORD: - yield $stdout->write($this->webEchoTemplate('Enter your password<br><b>'.$message.'</b>', '<input type="password" name="password" placeholder="Hint: '.$this->authorization['hint'].'" required/>')); - break; - + yield $stdout->write($this->webEchoTemplate('Enter your password<br><b>' . $message . '</b>', '<input type="password" name="password" placeholder="Hint: ' . $this->authorization['hint'] . '" required/>')); + break; case self::WAITING_SIGNUP: - yield $stdout->write($this->webEchoTemplate('Sign up please<br><b>'.$message.'</b>', '<input type="text" name="first_name" placeholder="First name" required/><input type="text" name="last_name" placeholder="Last name"/>')); - break; + yield $stdout->write($this->webEchoTemplate('Sign up please<br><b>' . $message . '</b>', '<input type="text" name="first_name" placeholder="First name" required/><input type="text" name="last_name" placeholder="Last name"/>')); + break; } } - private $web_template = '<!DOCTYPE html> <html> <head> @@ -67,12 +63,10 @@ trait Templates <p>%s</p> </body> </html>'; - private function webEchoTemplate($message, $form): string { return \sprintf($this->web_template, $form, $message); } - /** * Get web template. * @@ -82,7 +76,6 @@ trait Templates { return $this->web_template; } - /** * Set web template. * diff --git a/src/polyfill.php b/src/polyfill.php index fe8db311..bc009ae3 100644 --- a/src/polyfill.php +++ b/src/polyfill.php @@ -1,4 +1,5 @@ <?php + // Polyfill for some PHP 5 functions function callMe($allable, ...$args) { @@ -17,7 +18,7 @@ function __destructure($list, $value) $res = []; foreach ($list as $key) { if (\is_string($key)) { - $res []= $value[$key]; + $res[] = $value[$key]; } else { $res = \array_merge($res, __destructure($key, $value[$key])); } @@ -36,7 +37,6 @@ if (!\function_exists('error_clear_last')) { @\trigger_error(""); } } - if (!\defined('MADELINEPROTO_TEST')) { \define('MADELINEPROTO_TEST', 'NOT PONY'); }