Handle some pts errors
This commit is contained in:
parent
1f33dc9e33
commit
f1eecff25d
@ -44,7 +44,9 @@ use ReflectionGenerator;
|
||||
*/
|
||||
final class Coroutine implements Promise, \ArrayAccess
|
||||
{
|
||||
use Internal\Placeholder;
|
||||
use Internal\Placeholder {
|
||||
fail as internalFail;
|
||||
}
|
||||
/** @var \Generator */
|
||||
private $generator;
|
||||
/** @var callable(\Throwable|null $exception, mixed $value): void */
|
||||
@ -56,41 +58,20 @@ final class Coroutine implements Promise, \ArrayAccess
|
||||
/** @var mixed Promise success value when executing next coroutine step, null at all other times. */
|
||||
private $value;
|
||||
|
||||
private $frames = [];
|
||||
/**
|
||||
* Generator trace.
|
||||
*
|
||||
* @var Trace
|
||||
*/
|
||||
private $trace;
|
||||
|
||||
/**
|
||||
* @param \Generator $generator
|
||||
*/
|
||||
public function __construct(\Generator $generator)
|
||||
public function __construct(\Generator $generator, Trace $trace = null)
|
||||
{
|
||||
/*
|
||||
$this->generator = new class($generator) {
|
||||
private $s = '';
|
||||
private $g;
|
||||
private $trace;
|
||||
public function __construct($g) {
|
||||
$this->g = $g;
|
||||
$this->s .= spl_object_hash($this).', ';
|
||||
}
|
||||
public function __call($a, $args) {
|
||||
$this->s .= "$a, ";
|
||||
try {
|
||||
$res = $this->g->{$a}(...$args);
|
||||
if (is_array($res) && isset($res['my_trace'])) {
|
||||
$this->trace = $res;
|
||||
$res = $this->g->{$a}(...$args);
|
||||
}
|
||||
return $res;
|
||||
} catch (\Throwable $e) {
|
||||
$this->s .= $e->getMessage();
|
||||
$this->s .= ', ';
|
||||
var_dump($this->s, $this->trace);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
//public function __destruct() { var_dump($this->s); }
|
||||
};*/
|
||||
$this->generator = $generator;
|
||||
//$this->trace = $trace ?? new Trace(\debug_backtrace());
|
||||
|
||||
try {
|
||||
$yielded = $this->generator->current();
|
||||
@ -111,6 +92,20 @@ 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);
|
||||
@ -183,6 +178,17 @@ final class Coroutine implements Promise, \ArrayAccess
|
||||
$yielded->onResolve($this->onResolve);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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));
|
||||
}
|
||||
|
||||
public function offsetExists($offset): bool
|
||||
{
|
||||
throw new Exception('Not supported!');
|
||||
@ -214,12 +220,10 @@ final class Coroutine implements Promise, \ArrayAccess
|
||||
/**
|
||||
* Get stacktrace from when the generator was started.
|
||||
*
|
||||
* @param integer $options Backtrace options
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTrace(int $options = \DEBUG_BACKTRACE_PROVIDE_OBJECT): array
|
||||
public function getTrace(): array
|
||||
{
|
||||
return (new ReflectionGenerator($this->generator))->getTrace($options);
|
||||
return $this->trace->getTrace();
|
||||
}
|
||||
}
|
||||
|
@ -93,9 +93,12 @@ 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());
|
||||
|
@ -21,6 +21,7 @@ namespace danog\MadelineProto\MTProtoSession;
|
||||
|
||||
use Amp\Loop;
|
||||
use danog\MadelineProto\MTProto;
|
||||
use danog\MadelineProto\TL\PrettyException;
|
||||
|
||||
/**
|
||||
* Manages responses.
|
||||
@ -307,7 +308,15 @@ trait ResponseHandler
|
||||
return $only_updates;
|
||||
}
|
||||
|
||||
public function handle_reject(&$request, $data)
|
||||
/**
|
||||
* Reject request with exception
|
||||
*
|
||||
* @param array $request Request
|
||||
* @param \Throwable $data Exception
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle_reject(array &$request, \Throwable $data)
|
||||
{
|
||||
if (isset($request['promise']) && \is_object($request['promise'])) {
|
||||
Loop::defer(function () use (&$request, $data) {
|
||||
@ -350,12 +359,15 @@ trait ResponseHandler
|
||||
$this->shared->getTempAuthKey()->init(true);
|
||||
}
|
||||
|
||||
if (\in_array($response['error_message'], ['PERSISTENT_TIMESTAMP_EMPTY', 'PERSISTENT_TIMESTAMP_OUTDATED', 'PERSISTENT_TIMESTAMP_INVALID'])) {
|
||||
if (\in_array($response['error_message'], ['PERSISTENT_TIMESTAMP_EMPTY', 'PERSISTENT_TIMESTAMP_INVALID'])) {
|
||||
$this->got_response_for_outgoing_message_id($request_id);
|
||||
$this->handle_reject($request, new \danog\MadelineProto\PTSException($response['error_message']));
|
||||
|
||||
return;
|
||||
}
|
||||
if ($response['error_message'] === 'PERSISTENT_TIMESTAMP_OUTDATED') {
|
||||
$response['error_code'] = 500;
|
||||
}
|
||||
if (\strpos($response['error_message'], 'FILE_REFERENCE_') === 0) {
|
||||
$this->logger->logger("Got {$response['error_message']}, refreshing file reference and repeating method call...");
|
||||
|
||||
@ -377,7 +389,7 @@ trait ResponseHandler
|
||||
|
||||
return;
|
||||
}
|
||||
if (\in_array($response['error_message'], ['MSGID_DECREASE_RETRY', 'RPC_CALL_FAIL', 'RPC_MCGET_FAIL', 'no workers running'])) {
|
||||
if (\in_array($response['error_message'], ['MSGID_DECREASE_RETRY', 'RPC_CALL_FAIL', 'PERSISTENT_TIMESTAMP_OUTDATED', 'RPC_MCGET_FAIL', 'no workers running'])) {
|
||||
Loop::delay(1 * 1000, [$this, 'method_recall'], ['message_id' => $request_id, ]);
|
||||
return;
|
||||
}
|
||||
|
@ -19,23 +19,77 @@
|
||||
|
||||
namespace danog\MadelineProto\TL;
|
||||
|
||||
use danog\MadelineProto\Tools;
|
||||
|
||||
/**
|
||||
* Handle async stack traces.
|
||||
*/
|
||||
trait PrettyException
|
||||
{
|
||||
public $tl_trace;
|
||||
/**
|
||||
* TL trace.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $tl_trace = '';
|
||||
|
||||
public function getTLTrace()
|
||||
/**
|
||||
* Method name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $method = '';
|
||||
|
||||
/**
|
||||
* Whether the TL trace was updated.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
private $updated = false;
|
||||
/**
|
||||
* Update TL trace.
|
||||
*
|
||||
* @param array $trace
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function updateTLTrace(array $trace)
|
||||
{
|
||||
if (!$this->updated) {
|
||||
$this->updated = true;
|
||||
$this->prettify_tl($this->method, $trace);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get TL trace.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTLTrace(): string
|
||||
{
|
||||
return $this->tl_trace;
|
||||
}
|
||||
|
||||
public function prettify_tl($init = '')
|
||||
/**
|
||||
* Generate async trace.
|
||||
*
|
||||
* @param string $init Method name
|
||||
* @param array $trace Async trace
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function prettify_tl(string $init = '', array $trace = null)
|
||||
{
|
||||
$this->method = $init;
|
||||
$previous_trace = $this->tl_trace;
|
||||
$this->tl_trace = '';
|
||||
|
||||
$eol = PHP_EOL;
|
||||
if (PHP_SAPI !== 'cli') {
|
||||
$eol = '<br>'.PHP_EOL;
|
||||
}
|
||||
$tl = false;
|
||||
foreach (\array_reverse($this->getTrace()) as $k => $frame) {
|
||||
foreach (\array_reverse($trace ?? $this->getTrace()) as $k => $frame) {
|
||||
if (isset($frame['function']) && \in_array($frame['function'], ['serialize_params', 'serialize_object'])) {
|
||||
if ($frame['args'][2] !== '') {
|
||||
$this->tl_trace .= $tl ? "['".$frame['args'][2]."']" : "While serializing: \t".$frame['args'][2];
|
||||
@ -58,5 +112,11 @@ trait PrettyException
|
||||
}
|
||||
$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 .= $previous_trace;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -448,46 +448,4 @@ trait Tools
|
||||
$var instanceof Traversable &&
|
||||
$var instanceof Countable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom backtrace for working with generators.
|
||||
*
|
||||
* @param boolean $ignoreArgs Whether to ignore method arguments
|
||||
* @param array $trace Trace to work with
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function backtrace(bool $ignoreArgs = false, array $trace = []): array
|
||||
{
|
||||
return \iterator_to_array(self::backtraceGenerator($ignoreArgs, $trace));
|
||||
}
|
||||
/**
|
||||
* Custom backtrace for working with generators.
|
||||
*
|
||||
* @param boolean $ignoreArgs Whether to ignore method arguments
|
||||
* @param array $trace Trace to work with
|
||||
*
|
||||
* @return \Generator
|
||||
*/
|
||||
public static function backtraceGenerator(bool $ignoreArgs = false, array $trace = []): \Generator
|
||||
{
|
||||
$flags = DEBUG_BACKTRACE_PROVIDE_OBJECT;
|
||||
if ($ignoreArgs) {
|
||||
$flags |= DEBUG_BACKTRACE_IGNORE_ARGS;
|
||||
}
|
||||
if (!$trace) {
|
||||
$trace = \debug_backtrace($flags);
|
||||
\array_shift($trace);
|
||||
}
|
||||
|
||||
foreach ($trace as $frame) {
|
||||
if (isset($frame['object']) && $frame['object'] instanceof Coroutine) {
|
||||
yield from self::backtrace($ignoreArgs, $frame['object']->getTrace($flags));
|
||||
return;
|
||||
}
|
||||
//var_dump(get_class($frame['object'] ?? new class {}));
|
||||
unset($frame['object']);
|
||||
yield $frame;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
75
src/danog/MadelineProto/Trace.php
Normal file
75
src/danog/MadelineProto/Trace.php
Normal file
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* ResponseHandler module.
|
||||
*
|
||||
* This file is part of MadelineProto.
|
||||
* MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
* MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Affero General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License along with MadelineProto.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
* @copyright 2016-2019 Daniil Gentili <daniil@daniil.it>
|
||||
* @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();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user