From 379cd0f2478062063cc966f7e8d72b00334aea4a Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Fri, 31 Jan 2020 18:03:23 +0100 Subject: [PATCH] Proper async traces --- src/danog/MadelineProto/Coroutine.php | 96 +++++++++++++------ .../MTProtoSession/ResponseHandler.php | 2 +- src/danog/MadelineProto/Trace.php | 75 --------------- 3 files changed, 69 insertions(+), 104 deletions(-) delete mode 100644 src/danog/MadelineProto/Trace.php diff --git a/src/danog/MadelineProto/Coroutine.php b/src/danog/MadelineProto/Coroutine.php index 1cf2f863..e63f5d70 100644 --- a/src/danog/MadelineProto/Coroutine.php +++ b/src/danog/MadelineProto/Coroutine.php @@ -58,20 +58,15 @@ final class Coroutine implements Promise, \ArrayAccess /** @var mixed Promise success value when executing next coroutine step, null at all other times. */ private $value; - /** - * Generator trace. - * - * @var Trace - */ - private $trace; + /** @var ?self Reference to coroutine that started this coroutine */ + private $parentCoroutine; /** * @param \Generator $generator */ - public function __construct(\Generator $generator, Trace $trace = null) + public function __construct(\Generator $generator) { $this->generator = $generator; - //$this->trace = $trace ?? new Trace(\debug_backtrace()); try { $yielded = $this->generator->current(); @@ -92,24 +87,13 @@ final class Coroutine implements Promise, \ArrayAccess return; } if ($yielded instanceof \Generator) { - /*if ($this->generator->valid()) { - $reflection = new ReflectionGenerator($this->generator); - $trace = new Trace( - [[ - 'file' => $reflection->getExecutingFile(), - 'line' => $reflection->getExecutingLine(), - 'function' => $reflection->getFunction()->getName(), - ]], - $this->trace - ); - } else { - $trace = $this->trace; - } - $yielded = new self($yielded, $trace);*/ $yielded = new self($yielded); } else { $yielded = $this->generator->send($yielded); } + if ($yielded instanceof self) { + $yielded->parentCoroutine = $this; + } } } catch (\Throwable $exception) { $this->fail($exception); @@ -133,7 +117,7 @@ final class Coroutine implements Promise, \ArrayAccess do { if ($this->exception) { // Throw exception at current execution point. - $yielded = $this->generator->throw($this->exception); + $yielded = $this->throw($this->exception); } else { // Send the new value and execute to next yield statement. $yielded = $this->generator->send($this->value); @@ -163,6 +147,9 @@ final class Coroutine implements Promise, \ArrayAccess $yielded = $this->generator->send($yielded); } } + if ($yielded instanceof self) { + $yielded->parentCoroutine = $this; + } $this->immediate = false; $yielded->onResolve($this->onResolve); } while ($this->immediate); @@ -178,14 +165,32 @@ final class Coroutine implements Promise, \ArrayAccess $yielded->onResolve($this->onResolve); } + /** + * 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')) { + $reason->updateTLTrace($this->getTrace()); + } else { + $reason->yieldedFrames = $this->getTrace(); + } + } + $this->generator->throw($reason); + } + /** * @param \Throwable $reason Failure reason. */ public function fail(\Throwable $reason) { - //if (isset(\class_uses($reason)[TL\PrettyException::class])) { - //$reason->updateTLTrace($this->getTrace()); - //} $this->resolve(new Failure($reason)); } @@ -246,13 +251,48 @@ final class Coroutine implements Promise, \ArrayAccess return $result->{$name}($arguments); })()); } + /** - * Get stacktrace from when the generator was started. + * Get current stack trace for running coroutine. * * @return array */ public function getTrace(): array { - return $this->trace->getTrace(); + $frames = []; + try { + $reflector = new ReflectionGenerator($this->generator); + $frames = $reflector->getTrace(); + $frames []= \array_merge( + $this->parentCoroutine ? $this->parentCoroutine->getFrame() : [], + [ + 'function' => $reflector->getFunction()->getName(), + 'args' => [] + ] + ); + } catch (\Throwable $e) { + } + if ($this->parentCoroutine) { + $frames = \array_merge($frames, $this->parentCoroutine->getTrace()); + } + return $frames; + } + + /** + * Get current execution frame + * + * @return array + */ + public function getFrame(): array + { + try { + $reflector = new ReflectionGenerator($this->generator); + return [ + 'file' => $reflector->getExecutingFile(), + 'line' => $reflector->getExecutingLine(), + ]; + } catch (\Throwable $e) { + } + return []; } } diff --git a/src/danog/MadelineProto/MTProtoSession/ResponseHandler.php b/src/danog/MadelineProto/MTProtoSession/ResponseHandler.php index b75c4fa7..7fb8b399 100644 --- a/src/danog/MadelineProto/MTProtoSession/ResponseHandler.php +++ b/src/danog/MadelineProto/MTProtoSession/ResponseHandler.php @@ -392,7 +392,7 @@ trait ResponseHandler return; } - if (\in_array($response['error_message'], ['MSGID_DECREASE_RETRY', 'RPC_CALL_FAIL', 'PERSISTENT_TIMESTAMP_OUTDATED', 'RPC_MCGET_FAIL', 'no workers running', 'No workers running'])) { + 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, ]); return; } diff --git a/src/danog/MadelineProto/Trace.php b/src/danog/MadelineProto/Trace.php deleted file mode 100644 index 30a3c6b7..00000000 --- a/src/danog/MadelineProto/Trace.php +++ /dev/null @@ -1,75 +0,0 @@ -. - * - * @author Daniil Gentili - * @copyright 2016-2019 Daniil Gentili - * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 - * - * @link https://docs.madelineproto.xyz MadelineProto documentation - */ - -namespace danog\MadelineProto; - -/** - * Represents a piece of a coroutine stack trace. - */ -class Trace -{ - /** - * Next piece of the stack trace. - * - * @var Trace - */ - private $next; - /** - * Current stack trace frames. - * - * @var array - */ - private $frames = []; - /** - * Create trace. - * - * @param array $frames Current frames - * @param self $next Next trace - */ - public function __construct(array $frames, self $next = null) - { - $this->frames = $frames; - $this->next = $next; - } - - /** - * Get stack trace. - * - * @return array - */ - public function getTrace(): array - { - return \iterator_to_array($this->getTraceGenerator()); - } - - /** - * Get stack trace. - * - * @return \Generator - */ - private function getTraceGenerator(): \Generator - { - foreach ($this->frames as $frame) { - yield $frame; - } - if ($this->next) { - yield from $this->next->getTraceGenerator(); - } - } -}