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,7 +19,12 @@
* @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
*/
if (\file_exists('vendor/autoload.php')) {
@ -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.

File diff suppressed because one or more lines are too long

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']) {
@ -212,7 +212,7 @@ trait Files
yield $stream->seek(0, \SEEK_END);
$size = yield $stream->tell();
yield $stream->seek(0);
} else if (!$size) {
} elseif (!$size) {
$this->logger->logger("No content length for stream, caching first");
$body = $stream;
$stream = new BlockingFile(\fopen('php://temp', 'r+b'), 'php://temp', 'r+b');

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,10 +739,10 @@ trait Tools
return $new;
}
/**
* Inflate stripped photosize to full JPG payload
* Inflate stripped photosize to full JPG payload.
*
* @param string $stripped Stripped photosize
*
*
* @return string JPG payload
*/
public static function inflateStripped(string $stripped): string

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;
@ -86,12 +87,12 @@ trait Events
}
}
/**
* 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
*/
* 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->event_handler = null;
@ -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);
@ -83,11 +75,11 @@ trait Loop
$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)) {
@ -120,7 +112,7 @@ trait Loop
if ($needs_restart) {
$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;
@ -128,7 +120,7 @@ trait Loop
$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";
$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");
@ -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.
@ -203,14 +203,14 @@ trait Loop
}
$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)) {
if (\function_exists('fastcgi_finish_request')) {
\fastcgi_finish_request();
}
}