Add native error reporting functions and slash boilerplate

This commit is contained in:
Daniil Gentili 2020-02-23 19:28:42 +01:00
parent 0aa75af3e4
commit c3270a5c63
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
14 changed files with 448 additions and 172 deletions

View File

@ -19,6 +19,11 @@
* @link https://docs.madelineproto.xyz MadelineProto documentation
*/
use danog\MadelineProto\API;
use danog\MadelineProto\EventHandler;
use danog\MadelineProto\Exception;
use danog\MadelineProto\RPCErrorException;
/*
* Various ways to load MadelineProto
*/
@ -34,13 +39,40 @@ if (\file_exists('vendor/autoload.php')) {
/**
* Event handler class.
*/
class EventHandler extends \danog\MadelineProto\EventHandler
class MyEventHandler extends EventHandler
{
public function onUpdateNewChannelMessage($update)
/**
* @var int|string Username or ID of bot admin
*/
const ADMIN = "danogentili"; // Change this
/**
* Get peer(s) where to report errors.
*
* @return int|string|array
*/
public function getReportPeers()
{
yield $this->onUpdateNewMessage($update);
return [self::ADMIN];
}
public function onUpdateNewMessage($update)
/**
* Handle updates from supergroups and channels.
*
* @param array $update Update
*
* @return void
*/
public function onUpdateNewChannelMessage(array $update): \Generator
{
return $this->onUpdateNewMessage($update);
}
/**
* Handle updates from users.
*
* @param array $update Update
*
* @return \Generator
*/
public function onUpdateNewMessage(array $update): \Generator
{
if ($update['message']['_'] === 'messageEmpty' || $update['message']['out'] ?? false) {
return;
@ -51,21 +83,13 @@ class EventHandler extends \danog\MadelineProto\EventHandler
yield $this->messages->sendMessage(['peer' => $update, 'message' => "<code>$res</code>", 'reply_to_msg_id' => isset($update['message']['id']) ? $update['message']['id'] : null, 'parse_mode' => 'HTML']);
if (isset($update['message']['media']) && $update['message']['media']['_'] !== 'messageMediaGame') {
yield $this->messages->sendMedia(['peer' => $update, 'message' => $update['message']['message'], 'media' => $update]);
/* '_' => 'inputMediaUploadedDocument',
'file' => $update,
'attributes' => [
['_' => 'documentAttributeFilename', 'file_name' => 'document.txt']
]
],]);*/
//yield $this->downloadToDir($update, '/tmp');
}
} catch (\danog\MadelineProto\RPCErrorException $e) {
$this->logger((string) $e, \danog\MadelineProto\Logger::FATAL_ERROR);
} catch (\danog\MadelineProto\Exception $e) {
} catch (RPCErrorException $e) {
$this->report("Surfaced: $e");
} catch (Exception $e) {
if (\stripos($e->getMessage(), 'invalid constructor given') === false) {
$this->logger((string) $e, \danog\MadelineProto\Logger::FATAL_ERROR);
$this->report("Surfaced: $e");
}
//$this->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]);
}
}
}
@ -78,11 +102,8 @@ $settings = [
],
];
$MadelineProto = new \danog\MadelineProto\API('bot.madeline', $settings);
$MadelineProto->async(true);
$MadelineProto->loop(function () use ($MadelineProto) {
yield $MadelineProto->start();
yield $MadelineProto->setEventHandler('\EventHandler');
});
$MadelineProto = new API('bot.madeline', $settings);
$MadelineProto->loop();
// Reduce boilerplate with new wrapper method.
// Also initializes error reporting, catching and reporting all errors surfacing from the event loop.
$MadelineProto->startAndLoop(MyEventHandler::class);

View File

@ -19,7 +19,12 @@
* @link https://docs.madelineproto.xyz MadelineProto documentation
*/
\set_include_path(\get_include_path().':'.\realpath(\dirname(__FILE__).'/MadelineProto/'));
use danog\MadelineProto\API;
use danog\MadelineProto\EventHandler;
use danog\MadelineProto\Exception;
use danog\MadelineProto\Logger;
use danog\MadelineProto\RPCErrorException;
use danog\MadelineProto\Tools;
/*
* Various ways to load MadelineProto
@ -34,54 +39,89 @@ if (\file_exists(__DIR__.'/vendor/autoload.php')) {
}
/**
* Combined event handler class.
* Event handler class.
*/
class EventHandler extends \danog\MadelineProto\CombinedEventHandler
class MyEventHandler extends EventHandler
{
public function onUpdateNewChannelMessage($update, $path)
/**
* @var int|string Username or ID of bot admin
*/
const ADMIN = "danogentili"; // Change this
/**
* Get peer(s) where to report errors.
*
* @return int|string|array
*/
public function getReportPeers()
{
yield $this->onUpdateNewMessage($update, $path);
return [self::ADMIN];
}
public function onUpdateNewMessage($update, $path)
/**
* Handle updates from supergroups and channels.
*
* @param array $update Update
*
* @return void
*/
public function onUpdateNewChannelMessage(array $update): \Generator
{
if (isset($update['message']['out']) && $update['message']['out']) {
return $this->onUpdateNewMessage($update);
}
/**
* Handle updates from users.
*
* @param array $update Update
*
* @return \Generator
*/
public function onUpdateNewMessage(array $update): \Generator
{
if ($update['message']['_'] === 'messageEmpty' || $update['message']['out'] ?? false) {
return;
}
$MadelineProto = $this->{$path};
if (isset($update['message']['media'])) {
yield $MadelineProto->messages->sendMedia(['peer' => $update, 'message' => $update['message']['message'], 'media' => $update]);
}
$res = \json_encode($update, JSON_PRETTY_PRINT);
if ($res == '') {
$res = \var_export($update, true);
}
yield $MadelineProto->sleep(3);
try {
yield $MadelineProto->messages->sendMessage(['peer' => $update, 'message' => "<code>$res</code>\n\nDopo 3 secondi, in modo asincrono", 'reply_to_msg_id' => isset($update['message']['id']) ? $update['message']['id'] : null, 'parse_mode' => 'HTML']); //'entities' => [['_' => 'messageEntityPre', 'offset' => 0, 'length' => strlen($res), 'language' => 'json']]]);
} catch (\danog\MadelineProto\RPCErrorException $e) {
\danog\MadelineProto\Logger::log((string) $e, \danog\MadelineProto\Logger::FATAL_ERROR);
} catch (\danog\MadelineProto\Exception $e) {
\danog\MadelineProto\Logger::log((string) $e, \danog\MadelineProto\Logger::FATAL_ERROR);
//$MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]);
yield $this->messages->sendMessage(['peer' => $update, 'message' => "<code>$res</code>", 'reply_to_msg_id' => isset($update['message']['id']) ? $update['message']['id'] : null, 'parse_mode' => 'HTML']);
if (isset($update['message']['media']) && $update['message']['media']['_'] !== 'messageMediaGame') {
yield $this->messages->sendMedia(['peer' => $update, 'message' => $update['message']['message'], 'media' => $update]);
}
} catch (RPCErrorException $e) {
$this->report("Surfaced: $e");
} catch (Exception $e) {
if (\stripos($e->getMessage(), 'invalid constructor given') === false) {
$this->report("Surfaced: $e");
}
}
}
}
$settings = ['logger' => ['logger_level' => 5]];
$CombinedMadelineProto = new \danog\MadelineProto\CombinedAPI('combined_session.madeline', ['bot.madeline' => $settings, 'user.madeline' => $settings]);
$MadelineProtos = [];
foreach ([
'bot.madeline' => 'Bot Login',
'user.madeline' => 'Userbot login',
'user2.madeline' => 'Userbot login (2)'
] as $session => $message) {
Logger::log($message, Logger::WARNING);
$MadelineProto = new API($session);
$MadelineProto->async(true);
$MadelineProto->loop(function () use ($MadelineProto) {
yield $MadelineProto->start();
yield $MadelineProto->setEventHandler(MyEventHandler::class);
});
$MadelineProtos []= $MadelineProto->loopFork();
}
\danog\MadelineProto\Logger::log('Bot login', \danog\MadelineProto\Logger::WARNING);
$CombinedMadelineProto->instances['bot.madeline']->start();
\danog\MadelineProto\Logger::log('Userbot login');
$CombinedMadelineProto->instances['user.madeline']->start();
$CombinedMadelineProto->setEventHandler('\EventHandler');
$CombinedMadelineProto->loop();
$CombinedMadelineProto->async(true);
$CombinedMadelineProto->setEventHandler('\EventHandler');
$CombinedMadelineProto->loop();
do {
$thrown = false;
try {
Tools::wait(Tools::all($MadelineProtos));
} catch (\Throwable $e) {
$thrown = true;
try {
$MadelineProto->report("Surfaced: $e");
} catch (\Throwable $e) {
$MadelineProto->logger((string) $e, \danog\MadelineProto\Logger::FATAL_ERROR);
}
}
} while ($thrown);

View File

@ -21,7 +21,6 @@
use Amp\Http\Server\HttpServer;
use danog\MadelineProto\API;
use danog\MadelineProto\Logger;
use danog\MadelineProto\MTProtoTools\Files;
use danog\MadelineProto\RPCErrorException;
use danog\MadelineProto\Tools;
@ -49,7 +48,21 @@ class EventHandler extends \danog\MadelineProto\EventHandler
"Usage: `https://example.com file name.ext`\n\n".
"I can also rename Telegram files, just send me any file and I will rename it!\n\n".
"Max 1.5GB, parallel upload and download powered by @MadelineProto.";
const ADMIN = 'danogentili';
/**
* @var int|string Username or ID of bot admin
*/
const ADMIN = 'danogentili'; // Change this
/**
* Get peer(s) where to report errors.
*
* @return int|string|array
*/
public function getReportPeers()
{
return [self::ADMIN];
}
/**
* Whether to allow uploads.
@ -65,26 +78,32 @@ class EventHandler extends \danog\MadelineProto\EventHandler
/**
* Constructor.
*
* @param API $API API
* @param ?API $API API
*/
public function __construct($API)
public function __construct(?API $API)
{
$this->UPLOAD = \class_exists(HttpServer::class);
parent::__construct($API);
}
public function onUpdateNewChannelMessage($update)
/**
* Handle updates from channels and supergroups.
*
* @param array $update Update
*
* @return \Generator
*/
public function onUpdateNewChannelMessage(array $update)
{
//yield $this->onUpdateNewMessage($update);
}
public function report(string $message)
{
try {
$this->messages->sendMessage(['peer' => self::ADMIN, 'message' => $message]);
} catch (\Throwable $e) {
$this->logger("While reporting: $e", Logger::FATAL_ERROR);
}
}
public function onUpdateNewMessage($update)
/**
* Handle updates from users.
*
* @param array $update Update
*
* @return \Generator
*/
public function onUpdateNewMessage(array $update): \Generator
{
if ($update['message']['out'] ?? false) {
return;
@ -111,7 +130,7 @@ class EventHandler extends \danog\MadelineProto\EventHandler
unset($this->states[$peerId]);
$update = Files::extractBotAPIFile(yield $this->MTProtoToBotAPI($update));
$file = [$update['file_size'], $update['mime_type']];
\var_dump($update['file_id'].'.'.Tools::base64urlEncode(json_encode($file))."/".$update['file_name']);
\var_dump($update['file_id'].'.'.Tools::base64urlEncode(\json_encode($file))."/".$update['file_name']);
return;
}
yield $this->messages->sendMessage(['peer' => $peerId, 'message' => 'Give me a new name for this file: ', 'reply_to_msg_id' => $messageId]);
@ -220,19 +239,7 @@ $settings = [
];
$MadelineProto = new \danog\MadelineProto\API(($argv[1] ?? 'bot').'.madeline', $settings);
$MadelineProto->async(true);
while (true) {
try {
$MadelineProto->loop(function () use ($MadelineProto) {
yield $MadelineProto->start();
yield $MadelineProto->setEventHandler('\EventHandler');
});
$MadelineProto->loop();
} catch (\Throwable $e) {
try {
$MadelineProto->logger("Surfaced: $e");
$MadelineProto->getEventHandler(['async' => false])->report("Surfaced: $e");
} catch (\Throwable $e) {
}
}
}
// Reduce boilerplate with new wrapper method.
// Also initializes error reporting, catching and reporting all errors surfacing from the event loop.
$MadelineProto->startAndLoop(MyEventHandler::class);

View File

@ -33,11 +33,48 @@ if (\file_exists(__DIR__.'/../vendor/autoload.php')) {
include 'madeline.php';
}
class EventHandler extends \danog\MadelineProto\EventHandler
class SecretHandler extends \danog\MadelineProto\EventHandler
{
private $sent = [-440592694 => true];
public function onUpdateNewEncryptedMessage($update)
public function __construct($API)
{
parent::__construct($API);
$this->sent = [];
}
/**
* @var int|string Username or ID of bot admin
*/
const ADMIN = "danogentili"; // Change this
/**
* Get peer(s) where to report errors.
*
* @return int|string|array
*/
public function getReportPeers()
{
return [self::ADMIN];
}
/**
* Handle updates from users.
*
* @param array $update Update
*
* @return \Generator
*/
public function onUpdateNewMessage(array $update): \Generator
{
if ($update['message']['message'] === 'request') {
yield $this->requestSecretChat($update);
}
}
/**
* Handle secret chat messages.
*
* @param array $update Update
*
* @return \Generator
*/
public function onUpdateNewEncryptedMessage(array $update): \Generator
{
try {
if (isset($update['message']['decrypted_message']['media'])) {
@ -72,14 +109,14 @@ class EventHandler extends \danog\MadelineProto\EventHandler
$secret_media['voice'] = ['peer' => $update, 'file' => 'tests/mosconi.mp3', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => \file_get_contents('tests/faust.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => \mime_content_type('tests/mosconi.mp3'), 'caption' => 'test', 'file_name' => 'mosconi.mp3', 'size' => \filesize('tests/mosconi.mp3'), 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => true, 'duration' => 1, 'title' => 'AH NON LO SO IO', 'performer' => 'IL DIO GERMANO MOSCONI']]]]];
foreach ($secret_media as $type => $smessage) {
yield $this->messages->sendEncryptedFile($smessage);
$promises = $this->messages->sendEncryptedFile($smessage);
}
yield $promises;
$i = 0;
while ($i < 10) {
$this->logger("SENDING MESSAGE $i TO ".$update['message']['chat_id']);
// You can also use the sendEncrypted parameter for more options in secret chats
//yield $this->messages->sendEncrypted(['peer' => $update, 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => (string) ($i++)]]);
yield $this->messages->sendMessage(['peer' => $update, 'message' => (string) ($i++)]);
}
$this->sent[$update['message']['chat_id']] = true;
@ -102,7 +139,5 @@ $settings = \json_decode(\getenv('MTPROTO_SETTINGS'), true) ?: [];
$MadelineProto = new \danog\MadelineProto\API('s.madeline', $settings);
$MadelineProto->start();
$MadelineProto->setEventHandler('\EventHandler');
$MadelineProto->async(true);
$MadelineProto->loop();
// Reduce boilerplate with new wrapper method
$MadelineProto->startAndLoop(MyEventHandler::class);

View File

@ -405,4 +405,35 @@ class API extends InternalDoc
return $wrote;
})());
}
/**
* Start MadelineProto and the event handler (enables async).
*
* Also initializes error reporting, catching and reporting all errors surfacing from the event loop.
*
* @param string $eventHandler Event handler class name
*
* @return void
*/
public function startAndLoop(string $eventHandler): void
{
$this->async(true);
do {
$thrown = false;
try {
$this->loop(function () use ($eventHandler) {
yield $this->start();
yield $this->setEventHandler($eventHandler);
});
$this->loop();
} catch (\Throwable $e) {
$thrown = true;
try {
$this->report("Surfaced: $e");
} catch (\Throwable $e) {
$this->logger((string) $e, Logger::FATAL_ERROR);
}
}
} while ($thrown);
}
}

View File

@ -97,15 +97,15 @@ abstract class AbstractAPIFactory extends AsyncConstruct
public function __call(string $name, array $arguments)
{
$yielded = Tools::call($this->__call_async($name, $arguments));
$async = !$this->lua && ((is_array(\end($arguments)) ? \end($arguments) : [])['async'] ?? ($this->async && $name !== 'loop'));
$async = !$this->lua && ((\is_array(\end($arguments)) ? \end($arguments) : [])['async'] ?? ($this->async && $name !== 'loop'));
if ($async) {
return $yielded;
}
$yielded = Tools::wait($yielded);
if (!$this->lua) {
return Tools::wait($yielded);
return $yielded;
}
try {
$yielded = Tools::wait($yielded);
Lua::convertObjects($yielded);
return $yielded;
} catch (\Throwable $e) {
@ -128,9 +128,6 @@ abstract class AbstractAPIFactory extends AsyncConstruct
yield from $this->initAsynchronously();
$this->API->logger->logger('Finished init asynchronously');
}
if (Magic::isFork() && !Magic::$processed_fork) {
throw new Exception('Forking not supported, use async logic, instead: https://docs.madelineproto.xyz/docs/ASYNC.html');
}
if (!$this->API) {
throw new Exception('API did not init!');
}
@ -160,7 +157,7 @@ abstract class AbstractAPIFactory extends AsyncConstruct
$args = isset($arguments[0]) && \is_array($arguments[0]) ? $arguments[0] : [];
return yield from $this->API->methodCallAsyncRead($name, $args, $aargs);
}
$res = yield $this->methods[$lower_name](...$arguments);
$res = $this->methods[$lower_name](...$arguments);
return $res instanceof \Generator ? yield from $res : yield $res;
}
/**

View File

@ -41,4 +41,13 @@ class EventHandler extends InternalDoc
$this->{$namespace} = new APIFactory($namespace, $this->API, $this->async);
}
}
/**
* Get peers where to send error reports.
*
* @return array|string|int
*/
public function getReportPeers()
{
return [];
}
}

View File

@ -4215,6 +4215,37 @@ class InternalDoc extends APIFactory
{
return $this->__call(__FUNCTION__, [$extra]);
}
/**
* Check if has report peers.
*
* @return boolean
*/
public function hasReportPeers(): bool
{
return $this->API->hasReportPeers();
}
/**
* Set peer(s) where to send errors occurred in the event loop.
*
* @param int|string $userOrId Username(s) or peer ID(s)
*
* @return \Generator
*/
public function setReportPeers($userOrId, array $extra = [])
{
return $this->__call(__FUNCTION__, [$userOrId, $extra]);
}
/**
* Report an error to the previously set peer.
*
* @param string $message Error to report
*
* @return \Generator
*/
public function report(string $message, array $extra = [])
{
return $this->__call(__FUNCTION__, [$message, $extra]);
}
/**
* Call method and wait asynchronously for response.
*
@ -5293,6 +5324,17 @@ class InternalDoc extends APIFactory
{
return \danog\MadelineProto\MTProto::rleEncode($string);
}
/**
* Inflate stripped photosize to full JPG payload.
*
* @param string $stripped Stripped photosize
*
* @return string JPG payload
*/
public function inflateStripped(string $stripped): string
{
return \danog\MadelineProto\MTProto::inflateStripped($stripped);
}
/**
* Get final element of array.
*
@ -5460,6 +5502,17 @@ class InternalDoc extends APIFactory
{
$this->API->setEventHandler($event_handler);
}
/**
* Unset event handler.
*
* @param bool $disableUpdateHandling Whether to also disable internal update handling (will cause errors, otherwise will simply use the NOOP handler)
*
* @return void
*/
public function unsetEventHandler(bool $disableUpdateHandling = false): void
{
$this->API->unsetEventHandler($disableUpdateHandling);
}
/**
* Get event handler.
*
@ -5469,6 +5522,15 @@ class InternalDoc extends APIFactory
{
return $this->API->getEventHandler();
}
/**
* Check if an event handler instance is present.
*
* @return boolean
*/
public function hasEventHandler(): bool
{
return $this->API->hasEventHandler();
}
/**
* Set webhook update handler.
*
@ -5591,17 +5653,6 @@ class InternalDoc extends APIFactory
{
return $this->__call(__FUNCTION__, [$params, $extra]);
}
/**
* Set loop callback (DEPRECATED).
*
* @param callable $callback Callback
*
* @return void
*/
public function setLoopCallback($callback): void
{
$this->API->setLoopCallback($callback);
}
/**
* Start MadelineProto's update handling loop, or run the provided async callable.
*
@ -5623,15 +5674,22 @@ class InternalDoc extends APIFactory
$this->API->stop();
}
/**
* Start MadelineProto's update handling loop in background, or run the provided async callable.
* Restart update loop.
*
* @param callable $callback Async callable to run
*
* @return mixed
* @return void
*/
public function loopFork($callback = null): void
public function restart(): void
{
$this->API->loopFork($callback);
$this->API->restart();
}
/**
* Start MadelineProto's update handling loop in background.
*
* @return Promise
*/
public function loopFork(array $extra = [])
{
return $this->__call(__FUNCTION__, [$extra]);
}
/**
* Close connection with client, connected via web.

View File

@ -493,12 +493,14 @@ 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',
@ -506,34 +508,47 @@ class MTProto extends AsyncConstruct implements TLCallback
'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',
// Report URI
'reportDest'
];
}
/**
@ -1651,6 +1666,58 @@ class MTProto extends AsyncConstruct implements TLCallback
}
return $this->authorization['user'];
}
/**
* IDs of peers where to report errors.
*
* @var int[]
*/
private $reportDest = [];
/**
* Check if has report peers.
*
* @return boolean
*/
public function hasReportPeers(): bool
{
return (bool) $this->reportDest;
}
/**
* Set peer(s) where to send errors occurred in the event loop.
*
* @param int|string $userOrId Username(s) or peer ID(s)
*
* @return \Generator
*/
public function setReportPeers($userOrId): \Generator
{
if (!(\is_array($userOrId) && !isset($userOrId['_']) && !isset($userOrId['id']))) {
$userOrId = [$userOrId];
}
foreach ($userOrId as &$peer) {
$peer = yield from $this->getInfo($userOrId)['bot_api_id'];
}
$this->reportDest = $userOrId;
}
/**
* Report an error to the previously set peer.
*
* @param string $message Error to report
*
* @return \Generator
*/
public function report(string $message): \Generator
{
if (!$this->reportDest) {
return;
}
foreach ($this->reportDest as $id) {
try {
yield from $this->methodCallAsyncRead('messages.sendMessage', ['peer' => $id, 'message' => $message]);
} catch (\Throwable $e) {
$this->logger("While reporting to $id: $e", Logger::FATAL_ERROR);
}
}
}
/**
* Called right before serialization of method starts.
*

View File

@ -79,7 +79,7 @@ trait Files
} elseif (\is_array($file)) {
return yield from $this->uploadFromTgfile($file, $cb, $encrypted);
}
if (\is_resource($file) || (is_object($file) && $file instanceof InputStream)) {
if (\is_resource($file) || (\is_object($file) && $file instanceof InputStream)) {
return yield from $this->uploadFromStream($file, 0, '', $fileName, $cb, $encrypted);
}
if (!$this->settings['upload']['allow_automatic_upload']) {

View File

@ -240,7 +240,8 @@ trait BotAPI
if (isset($data['fwd_from']['channel_id'])) {
try {
$newd['forward_from_chat'] = yield from $this->getPwrChat(PeerHandler::toSupergroup($data['fwd_from']['channel_id']));
} catch (\Throwable $e) {}
} catch (\Throwable $e) {
}
}
if (isset($data['fwd_from']['date'])) {
$newd['forward_date'] = $data['fwd_from']['date'];

View File

@ -739,7 +739,7 @@ trait Tools
return $new;
}
/**
* Inflate stripped photosize to full JPG payload
* Inflate stripped photosize to full JPG payload.
*
* @param string $stripped Stripped photosize
*

View File

@ -19,7 +19,7 @@
namespace danog\MadelineProto\Wrappers;
use EventHandler;
use danog\MadelineProto\EventHandler;
/**
* Event handler.
@ -35,7 +35,7 @@ trait Events
/**
* Event handler instance.
*
* @var \danog\MadelineProto\EventHandler
* @var EventHandler
*/
private $event_handler_instance;
/**
@ -78,6 +78,7 @@ trait Events
$this->event_handler_methods[$method_name] = [$this->event_handler_instance, $method];
}
}
$this->setReportPeers($this->event_handler_instance->getReportPeers());
$this->settings['updates']['callback'] = [$this, 'eventUpdateHandler'];
$this->settings['updates']['handle_updates'] = true;
$this->settings['updates']['run_callback'] = true;
@ -107,10 +108,19 @@ trait Events
*
* @return EventHandler
*/
public function getEventHandler(): \danog\MadelineProto\EventHandler
public function getEventHandler(): EventHandler
{
return $this->event_handler_instance;
}
/**
* Check if an event handler instance is present.
*
* @return boolean
*/
public function hasEventHandler(): bool
{
return isset($this->event_handler_instance);
}
/**
* Event update handler.
*

View File

@ -35,17 +35,7 @@ trait Loop
* @var boolean
*/
private $stopLoop = false;
/**
* Set loop callback (DEPRECATED).
*
* @param callable $callback Callback
*
* @return void
*/
public function setLoopCallback($callback): void
{
$this->loop_callback = $callback;
}
/**
* Start MadelineProto's update handling loop, or run the provided async callable.
*
@ -75,7 +65,9 @@ trait Loop
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') {
static $inited = false;
if (PHP_SAPI !== 'cli' && !$inited) {
$needs_restart = true;
try {
\set_time_limit(-1);
@ -140,6 +132,7 @@ trait Loop
}, 'restarter');
}
$this->closeConnection('Bot was started');
$inited = true;
}
if (!$this->settings['updates']['handle_updates']) {
$this->settings['updates']['handle_updates'] = true;
@ -179,15 +172,22 @@ trait Loop
$this->signalUpdate();
}
/**
* Start MadelineProto's update handling loop in background, or run the provided async callable.
* Restart update loop.
*
* @param callable $callback Async callable to run
*
* @return mixed
* @return void
*/
public function loopFork($callback = null): void
public function restart(): void
{
Tools::callFork($this->loop($callback));
$this->stop();
}
/**
* Start MadelineProto's update handling loop in background.
*
* @return Promise
*/
public function loopFork(): Promise
{
return Tools::callFork($this->loop());
}
/**
* Close connection with client, connected via web.
@ -210,7 +210,7 @@ trait Loop
echo $buffer;
\flush();
$GLOBALS['exited'] = true;
if (\function_exists(\fastcgi_finish_request::class)) {
if (\function_exists('fastcgi_finish_request')) {
\fastcgi_finish_request();
}
}