From cc4a99d598276349c170c336390bf3a08297568a Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Sat, 8 Jul 2023 21:42:18 +0200 Subject: [PATCH] Improve performance --- CHANGELOG.md | 4 +- examples/downloadRenameBot.php | 11 +--- src/EventHandler.php | 91 ++++++++---------------------- src/EventHandler/Message.php | 2 +- src/MTProtoTools/PeerHandler.php | 4 +- src/MTProtoTools/UpdateHandler.php | 23 +++++--- src/Wrappers/Events.php | 9 ++- 7 files changed, 55 insertions(+), 89 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8402ca826..70759547a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ MadelineProto was updated (8.0.0-beta100)! Features: - Thanks to the many translation contributors @ https://weblate.madelineproto.xyz/, MadelineProto is now fully localized in Hebrew, Persian, Kurdish, Uzbek and Italian, with WIP translations in Russian and French! -- You can now use callFork to fork a new green thread! +- You can now use `Tools::callFork` to fork a new green thread! - The `waveform` attribute of `Voice` objects is now automatically encoded and decoded to an array of 100 integer values! - Added a custom PeerNotInDbException class for "This peer is not present in the internal peer database" errors - Added a `label` property to the Button class, directly indicating the button label (instead of manually fetching it as an array key). @@ -13,7 +13,7 @@ Features: Fixes: -- Fixed file uploads with uv +- Fixed file uploads with ext-uv! - Many performance improvements and bugfixes! - Improve background broadcasting with the broadcast API using a pre-defined list of `whitelist` IDs! - Broadcast IDs are now unique across multiple broadcasts, even if previous broadcasts already completed their ID will never be re-used. diff --git a/examples/downloadRenameBot.php b/examples/downloadRenameBot.php index 3192562e1..d1d7fcef4 100755 --- a/examples/downloadRenameBot.php +++ b/examples/downloadRenameBot.php @@ -18,16 +18,11 @@ * @link https://docs.madelineproto.xyz MadelineProto documentation */ -use Amp\Http\Server\HttpServer; -use danog\MadelineProto\API; -use danog\MadelineProto\APIWrapper; use danog\MadelineProto\EventHandler; use danog\MadelineProto\FileCallback; use danog\MadelineProto\Logger; -use danog\MadelineProto\MTProtoTools\Files; use danog\MadelineProto\RPCErrorException; use danog\MadelineProto\Settings; -use danog\MadelineProto\Tools; use League\Uri\Contracts\UriException; /* @@ -79,7 +74,7 @@ class MyEventHandler extends EventHandler * @var array */ private $states = []; - public function onStart() + public function onStart(): void { $this->adminId = $this->getInfo(self::ADMIN)['bot_api_id']; } @@ -88,7 +83,7 @@ class MyEventHandler extends EventHandler * * @param array $update Update */ - public function onUpdateNewChannelMessage(array $update) + public function onUpdateNewChannelMessage(array $update): void { //$this->onUpdateNewMessage($update); } @@ -154,7 +149,7 @@ class MyEventHandler extends EventHandler $url = new FileCallback( $url, - function ($progress, $speed, $time) use ($peerId, $id) { + function ($progress, $speed, $time) use ($peerId, $id): void { $this->logger("Upload progress: $progress%"); static $prev = 0; diff --git a/src/EventHandler.php b/src/EventHandler.php index ab6ec6f27..73db32389 100644 --- a/src/EventHandler.php +++ b/src/EventHandler.php @@ -23,6 +23,7 @@ namespace danog\MadelineProto; use Amp\DeferredFuture; use Amp\Future; use Amp\Sync\LocalMutex; +use Closure; use danog\MadelineProto\Db\DbPropertiesTrait; use danog\MadelineProto\EventHandler\Filter\Combinator\FiltersAnd; use danog\MadelineProto\EventHandler\Filter\Filter; @@ -123,15 +124,26 @@ abstract class EventHandler extends AbstractAPI $methods = []; $handlers = []; $has_any = false; + $basic_handler = static function (array $update, Closure $closure): void { + $r = $closure($update); + if ($r instanceof Generator) { + Tools::consumeGenerator($r); + } + }; foreach ((new ReflectionClass($this))->getMethods(ReflectionMethod::IS_PUBLIC) as $methodRefl) { $method = $methodRefl->getName(); if ($method === 'onAny') { $has_any = true; continue; } + $closure = $this->$method(...); $method_name = \lcfirst(\substr($method, 2)); if (($constructor = $constructors->findByPredicate($method_name)) && $constructor['type'] === 'Update') { - $methods[$method_name] = $this->$method(...); + $methods[$method_name] = [ + function (array $update) use ($basic_handler, $closure): void { + $basic_handler($update, $closure); + } + ]; continue; } if (!($handler = $methodRefl->getAttributes(Handler::class))) { @@ -149,61 +161,17 @@ abstract class EventHandler extends AbstractAPI Filter::fromReflectionType($methodRefl->getParameters()[0]->getType()) ); $filter = $filter->initialize($this) ?? $filter; - $handlers []= [ - $method, - $handler, - $filter - ]; - } - $prevClosure = null; - /** @var Filter $filter */ - foreach ($handlers as [$method, $handler, $filter]) { - $closure = $this->$method(...); - if ($prevClosure) { - $prevClosure = function (Update $update) use ($prevClosure, $closure, $filter): void { - if ($filter->apply($update)) { - EventLoop::queue($closure, $update); - } - $prevClosure(); - }; - } else { - $prevClosure = function (Update $update) use ($closure, $filter): void { - if ($filter->apply($update)) { - EventLoop::queue($closure, $update); - } - }; - } - } - if ($prevClosure) { - foreach (['updateNewMessage', 'updateNewChannelMessage'] as $update) { - if (isset($methods[$update])) { - $old = $methods[$update]; - $methods[$update] = function (array $update) use ($old, $prevClosure): void { - $obj = $this->wrapUpdate($update); - if ($obj === null) { - $r = $old($update); - if ($r instanceof Generator) { - Tools::consumeGenerator($r); - } - } else { - $prevClosure($obj); - } - }; - } else { - $methods[$update] = function (array $update) use ($prevClosure): void { - $obj = $this->wrapUpdate($update); - if ($obj !== null) { - $prevClosure($obj); - } - }; + $handlers []= function (Update $update) use ($closure, $filter): void { + if ($filter->apply($update)) { + EventLoop::queue($closure, $update); } - } + }; } if ($has_any) { $onAny = $this->onAny(...); foreach ($constructors->by_id as $constructor) { if ($constructor['type'] === 'Update' && !isset($methods[$constructor['predicate']])) { - $methods[$constructor['predicate']] = $onAny; + $methods[$constructor['predicate']] = [$onAny]; } } } @@ -213,27 +181,16 @@ abstract class EventHandler extends AbstractAPI foreach ($plugins as $class => $_) { $plugin = $pluginsPrev[$class] ?? $pluginsNew[$class] ?? new $class; $pluginsNew[$class] = $plugin; - foreach ($plugin->internalStart($MadelineProto, $pluginsPrev, $pluginsNew, false) ?? [] as $update => $method) { - if (isset($methods[$update])) { - $oldMethod = $methods[$update]; - $methods[$update] = function (array $update) use ($oldMethod, $method): void { - EventLoop::queue(function () use ($update, $method): void { - $r = $method($update); - if ($r instanceof Generator) { - Tools::consumeGenerator($r); - } - }); - $r = $oldMethod($update); - if ($r instanceof Generator) { - Tools::consumeGenerator($r); - } - }; - } + [$newMethods, $newHandlers] = $plugin->internalStart($MadelineProto, $pluginsPrev, $pluginsNew, false) ?? []; + foreach ($newMethods as $update => $method) { + $methods[$update] ??= []; + $methods[$update][] = $method; } + $handlers = \array_merge($handler, $newHandlers); } $this->startedInternal = true; - return $methods; + return [$methods, $handlers]; } finally { $this->startDeferred = null; $startDeferred->complete(); diff --git a/src/EventHandler/Message.php b/src/EventHandler/Message.php index 4a654c5e0..f5aaa30f4 100644 --- a/src/EventHandler/Message.php +++ b/src/EventHandler/Message.php @@ -63,7 +63,7 @@ abstract class Message extends AbstractMessage public readonly bool $imported; /** For Public Service Announcement messages, the PSA type */ - public readonly string $psaType; + public readonly ?string $psaType; // Todo media (photosizes, thumbs), albums, reactions, replies, games eventually diff --git a/src/MTProtoTools/PeerHandler.php b/src/MTProtoTools/PeerHandler.php index 78c97d47b..15b2c9945 100644 --- a/src/MTProtoTools/PeerHandler.php +++ b/src/MTProtoTools/PeerHandler.php @@ -590,7 +590,7 @@ trait PeerHandler * type: string * } : ($type is API::INFO_TYPE_TYPE ? string : ($type is \danog\MadelineProto\API::INFO_TYPE_ID ? int : array{_: string, user_id?: int, access_hash?: int, min?: bool, chat_id?: int, channel_id?: int}|array{_: string, user_id?: int, access_hash?: int, min?: bool}|array{_: string, channel_id: int, access_hash: int, min: bool}))) */ - public function getInfo(mixed $id, int $type = \danog\MadelineProto\API::INFO_TYPE_ALL): array|int + public function getInfo(mixed $id, int $type = \danog\MadelineProto\API::INFO_TYPE_ALL): array|int|string { if (\is_array($id)) { switch ($id['_']) { @@ -722,7 +722,7 @@ trait PeerHandler * type: string * }&array) : array|int) */ - private function genAll($constructor, $folder_id, int $type): array|int + private function genAll($constructor, $folder_id, int $type): array|int|string { if ($type === \danog\MadelineProto\API::INFO_TYPE_CONSTRUCTOR) { if ($constructor['_'] === 'user') { diff --git a/src/MTProtoTools/UpdateHandler.php b/src/MTProtoTools/UpdateHandler.php index 17a7e4bf3..7b5a50c03 100644 --- a/src/MTProtoTools/UpdateHandler.php +++ b/src/MTProtoTools/UpdateHandler.php @@ -49,10 +49,8 @@ use danog\MadelineProto\RPCErrorException; use danog\MadelineProto\Settings; use danog\MadelineProto\TL\TL; use danog\MadelineProto\TL\Types\Button; -use danog\MadelineProto\Tools; use danog\MadelineProto\UpdateHandlerType; use danog\MadelineProto\VoIP; -use Generator; use Revolt\EventLoop; use Throwable; use Webmozart\Assert\Assert; @@ -87,6 +85,7 @@ trait UpdateHandler $this->event_handler = null; $this->event_handler_instance = null; $this->eventHandlerMethods = []; + $this->eventHandlerHandlers = []; $this->pluginInstances = []; $this->startUpdateSystem(); } @@ -109,6 +108,7 @@ trait UpdateHandler $this->event_handler = null; $this->event_handler_instance = null; $this->eventHandlerMethods = []; + $this->eventHandlerHandlers = []; $this->pluginInstances = []; $this->startUpdateSystem(); } @@ -124,7 +124,7 @@ trait UpdateHandler $update = $update['progress']; } if ($f = $this->event_handler_instance->waitForInternalStart()) { - $this->logger->logger("Postponing update handling, onStart is still running (if stuck here for too long, make sure to fork long-running tasks in onStart using EventLoop::queue to fix this)...", Logger::NOTICE); + $this->logger->logger("Postponing update handling, onStart is still running (if stuck here for too long, make sure to fork long-running tasks in onStart using \$this->callFork(function () { ... }) to fix this)...", Logger::NOTICE); $this->updates[$this->updates_key++] = $update; $f->map(function (): void { \array_map($this->handleUpdate(...), $this->updates); @@ -133,12 +133,18 @@ trait UpdateHandler }); return; } - if (!isset($this->eventHandlerMethods[$update['_']])) { - return; + if (isset($this->eventHandlerMethods[$update['_']])) { + foreach ($this->eventHandlerMethods[$update['_']] as $closure) { + $closure($update); + } } - $r = $this->eventHandlerMethods[$update['_']]($update); - if ($r instanceof Generator) { - Tools::consumeGenerator($r); + if (\count($this->eventHandlerHandlers) !== 0) { + $update = $this->wrapUpdate($update); + if ($update !== null) { + foreach ($this->eventHandlerHandlers as $closure) { + $closure($update); + } + } } } @@ -204,6 +210,7 @@ trait UpdateHandler $this->event_handler = null; $this->event_handler_instance = null; $this->eventHandlerMethods = []; + $this->eventHandlerHandlers = []; $this->pluginInstances = []; [ diff --git a/src/Wrappers/Events.php b/src/Wrappers/Events.php index 1a1a80e04..40cc87099 100644 --- a/src/Wrappers/Events.php +++ b/src/Wrappers/Events.php @@ -56,6 +56,12 @@ trait Events * @var array */ private array $eventHandlerMethods = []; + /** + * Event handler handler list. + * + * @var array + */ + private array $eventHandlerHandlers = []; /** @var array, EventHandler> */ private array $pluginInstances = []; @@ -87,7 +93,7 @@ trait Events // Already started event handler return; } - $this->eventHandlerMethods = $methods; + [$this->eventHandlerMethods, $this->eventHandlerHandlers] = $methods; $this->pluginInstances = $pluginsNew; $this->updateHandlerType = UpdateHandlerType::EVENT_HANDLER; @@ -130,6 +136,7 @@ trait Events $this->event_handler = null; $this->event_handler_instance = null; $this->eventHandlerMethods = []; + $this->eventHandlerHandlers = []; $this->pluginInstances = []; $this->setNoop(); }