1
0
mirror of https://github.com/danog/MadelineProto.git synced 2024-12-02 12:17:47 +01:00

Improve performance

This commit is contained in:
Daniil Gentili 2023-07-08 21:42:18 +02:00
parent c5b7a06641
commit cc4a99d598
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
7 changed files with 55 additions and 89 deletions

View File

@ -2,7 +2,7 @@ MadelineProto was updated (8.0.0-beta100)!
Features: 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! - 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! - 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 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). - 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: Fixes:
- Fixed file uploads with uv - Fixed file uploads with ext-uv!
- Many performance improvements and bugfixes! - Many performance improvements and bugfixes!
- Improve background broadcasting with the broadcast API using a pre-defined list of `whitelist` IDs! - 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. - Broadcast IDs are now unique across multiple broadcasts, even if previous broadcasts already completed their ID will never be re-used.

View File

@ -18,16 +18,11 @@
* @link https://docs.madelineproto.xyz MadelineProto documentation * @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\EventHandler;
use danog\MadelineProto\FileCallback; use danog\MadelineProto\FileCallback;
use danog\MadelineProto\Logger; use danog\MadelineProto\Logger;
use danog\MadelineProto\MTProtoTools\Files;
use danog\MadelineProto\RPCErrorException; use danog\MadelineProto\RPCErrorException;
use danog\MadelineProto\Settings; use danog\MadelineProto\Settings;
use danog\MadelineProto\Tools;
use League\Uri\Contracts\UriException; use League\Uri\Contracts\UriException;
/* /*
@ -79,7 +74,7 @@ class MyEventHandler extends EventHandler
* @var array * @var array
*/ */
private $states = []; private $states = [];
public function onStart() public function onStart(): void
{ {
$this->adminId = $this->getInfo(self::ADMIN)['bot_api_id']; $this->adminId = $this->getInfo(self::ADMIN)['bot_api_id'];
} }
@ -88,7 +83,7 @@ class MyEventHandler extends EventHandler
* *
* @param array $update Update * @param array $update Update
*/ */
public function onUpdateNewChannelMessage(array $update) public function onUpdateNewChannelMessage(array $update): void
{ {
//$this->onUpdateNewMessage($update); //$this->onUpdateNewMessage($update);
} }
@ -154,7 +149,7 @@ class MyEventHandler extends EventHandler
$url = new FileCallback( $url = new FileCallback(
$url, $url,
function ($progress, $speed, $time) use ($peerId, $id) { function ($progress, $speed, $time) use ($peerId, $id): void {
$this->logger("Upload progress: $progress%"); $this->logger("Upload progress: $progress%");
static $prev = 0; static $prev = 0;

View File

@ -23,6 +23,7 @@ namespace danog\MadelineProto;
use Amp\DeferredFuture; use Amp\DeferredFuture;
use Amp\Future; use Amp\Future;
use Amp\Sync\LocalMutex; use Amp\Sync\LocalMutex;
use Closure;
use danog\MadelineProto\Db\DbPropertiesTrait; use danog\MadelineProto\Db\DbPropertiesTrait;
use danog\MadelineProto\EventHandler\Filter\Combinator\FiltersAnd; use danog\MadelineProto\EventHandler\Filter\Combinator\FiltersAnd;
use danog\MadelineProto\EventHandler\Filter\Filter; use danog\MadelineProto\EventHandler\Filter\Filter;
@ -123,15 +124,26 @@ abstract class EventHandler extends AbstractAPI
$methods = []; $methods = [];
$handlers = []; $handlers = [];
$has_any = false; $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) { foreach ((new ReflectionClass($this))->getMethods(ReflectionMethod::IS_PUBLIC) as $methodRefl) {
$method = $methodRefl->getName(); $method = $methodRefl->getName();
if ($method === 'onAny') { if ($method === 'onAny') {
$has_any = true; $has_any = true;
continue; continue;
} }
$closure = $this->$method(...);
$method_name = \lcfirst(\substr($method, 2)); $method_name = \lcfirst(\substr($method, 2));
if (($constructor = $constructors->findByPredicate($method_name)) && $constructor['type'] === 'Update') { 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; continue;
} }
if (!($handler = $methodRefl->getAttributes(Handler::class))) { if (!($handler = $methodRefl->getAttributes(Handler::class))) {
@ -149,61 +161,17 @@ abstract class EventHandler extends AbstractAPI
Filter::fromReflectionType($methodRefl->getParameters()[0]->getType()) Filter::fromReflectionType($methodRefl->getParameters()[0]->getType())
); );
$filter = $filter->initialize($this) ?? $filter; $filter = $filter->initialize($this) ?? $filter;
$handlers []= [ $handlers []= function (Update $update) use ($closure, $filter): void {
$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)) { if ($filter->apply($update)) {
EventLoop::queue($closure, $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);
}
};
}
}
}
if ($has_any) { if ($has_any) {
$onAny = $this->onAny(...); $onAny = $this->onAny(...);
foreach ($constructors->by_id as $constructor) { foreach ($constructors->by_id as $constructor) {
if ($constructor['type'] === 'Update' && !isset($methods[$constructor['predicate']])) { 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 => $_) { foreach ($plugins as $class => $_) {
$plugin = $pluginsPrev[$class] ?? $pluginsNew[$class] ?? new $class; $plugin = $pluginsPrev[$class] ?? $pluginsNew[$class] ?? new $class;
$pluginsNew[$class] = $plugin; $pluginsNew[$class] = $plugin;
foreach ($plugin->internalStart($MadelineProto, $pluginsPrev, $pluginsNew, false) ?? [] as $update => $method) { [$newMethods, $newHandlers] = $plugin->internalStart($MadelineProto, $pluginsPrev, $pluginsNew, false) ?? [];
if (isset($methods[$update])) { foreach ($newMethods as $update => $method) {
$oldMethod = $methods[$update]; $methods[$update] ??= [];
$methods[$update] = function (array $update) use ($oldMethod, $method): void { $methods[$update][] = $method;
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);
}
};
}
} }
$handlers = \array_merge($handler, $newHandlers);
} }
$this->startedInternal = true; $this->startedInternal = true;
return $methods; return [$methods, $handlers];
} finally { } finally {
$this->startDeferred = null; $this->startDeferred = null;
$startDeferred->complete(); $startDeferred->complete();

View File

@ -63,7 +63,7 @@ abstract class Message extends AbstractMessage
public readonly bool $imported; public readonly bool $imported;
/** For Public Service Announcement messages, the PSA type */ /** 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 // Todo media (photosizes, thumbs), albums, reactions, replies, games eventually

View File

@ -590,7 +590,7 @@ trait PeerHandler
* type: string * 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}))) * } : ($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)) { if (\is_array($id)) {
switch ($id['_']) { switch ($id['_']) {
@ -722,7 +722,7 @@ trait PeerHandler
* type: string * type: string
* }&array) : array|int) * }&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 ($type === \danog\MadelineProto\API::INFO_TYPE_CONSTRUCTOR) {
if ($constructor['_'] === 'user') { if ($constructor['_'] === 'user') {

View File

@ -49,10 +49,8 @@ use danog\MadelineProto\RPCErrorException;
use danog\MadelineProto\Settings; use danog\MadelineProto\Settings;
use danog\MadelineProto\TL\TL; use danog\MadelineProto\TL\TL;
use danog\MadelineProto\TL\Types\Button; use danog\MadelineProto\TL\Types\Button;
use danog\MadelineProto\Tools;
use danog\MadelineProto\UpdateHandlerType; use danog\MadelineProto\UpdateHandlerType;
use danog\MadelineProto\VoIP; use danog\MadelineProto\VoIP;
use Generator;
use Revolt\EventLoop; use Revolt\EventLoop;
use Throwable; use Throwable;
use Webmozart\Assert\Assert; use Webmozart\Assert\Assert;
@ -87,6 +85,7 @@ trait UpdateHandler
$this->event_handler = null; $this->event_handler = null;
$this->event_handler_instance = null; $this->event_handler_instance = null;
$this->eventHandlerMethods = []; $this->eventHandlerMethods = [];
$this->eventHandlerHandlers = [];
$this->pluginInstances = []; $this->pluginInstances = [];
$this->startUpdateSystem(); $this->startUpdateSystem();
} }
@ -109,6 +108,7 @@ trait UpdateHandler
$this->event_handler = null; $this->event_handler = null;
$this->event_handler_instance = null; $this->event_handler_instance = null;
$this->eventHandlerMethods = []; $this->eventHandlerMethods = [];
$this->eventHandlerHandlers = [];
$this->pluginInstances = []; $this->pluginInstances = [];
$this->startUpdateSystem(); $this->startUpdateSystem();
} }
@ -124,7 +124,7 @@ trait UpdateHandler
$update = $update['progress']; $update = $update['progress'];
} }
if ($f = $this->event_handler_instance->waitForInternalStart()) { 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; $this->updates[$this->updates_key++] = $update;
$f->map(function (): void { $f->map(function (): void {
\array_map($this->handleUpdate(...), $this->updates); \array_map($this->handleUpdate(...), $this->updates);
@ -133,12 +133,18 @@ trait UpdateHandler
}); });
return; return;
} }
if (!isset($this->eventHandlerMethods[$update['_']])) { if (isset($this->eventHandlerMethods[$update['_']])) {
return; foreach ($this->eventHandlerMethods[$update['_']] as $closure) {
$closure($update);
}
}
if (\count($this->eventHandlerHandlers) !== 0) {
$update = $this->wrapUpdate($update);
if ($update !== null) {
foreach ($this->eventHandlerHandlers as $closure) {
$closure($update);
}
} }
$r = $this->eventHandlerMethods[$update['_']]($update);
if ($r instanceof Generator) {
Tools::consumeGenerator($r);
} }
} }
@ -204,6 +210,7 @@ trait UpdateHandler
$this->event_handler = null; $this->event_handler = null;
$this->event_handler_instance = null; $this->event_handler_instance = null;
$this->eventHandlerMethods = []; $this->eventHandlerMethods = [];
$this->eventHandlerHandlers = [];
$this->pluginInstances = []; $this->pluginInstances = [];
[ [

View File

@ -56,6 +56,12 @@ trait Events
* @var array<string, callable> * @var array<string, callable>
*/ */
private array $eventHandlerMethods = []; private array $eventHandlerMethods = [];
/**
* Event handler handler list.
*
* @var array<string, callable>
*/
private array $eventHandlerHandlers = [];
/** @var array<class-string<EventHandler>, EventHandler> */ /** @var array<class-string<EventHandler>, EventHandler> */
private array $pluginInstances = []; private array $pluginInstances = [];
@ -87,7 +93,7 @@ trait Events
// Already started event handler // Already started event handler
return; return;
} }
$this->eventHandlerMethods = $methods; [$this->eventHandlerMethods, $this->eventHandlerHandlers] = $methods;
$this->pluginInstances = $pluginsNew; $this->pluginInstances = $pluginsNew;
$this->updateHandlerType = UpdateHandlerType::EVENT_HANDLER; $this->updateHandlerType = UpdateHandlerType::EVENT_HANDLER;
@ -130,6 +136,7 @@ trait Events
$this->event_handler = null; $this->event_handler = null;
$this->event_handler_instance = null; $this->event_handler_instance = null;
$this->eventHandlerMethods = []; $this->eventHandlerMethods = [];
$this->eventHandlerHandlers = [];
$this->pluginInstances = []; $this->pluginInstances = [];
$this->setNoop(); $this->setNoop();
} }