1
0
mirror of https://github.com/danog/MadelineProto.git synced 2024-11-30 04:08:59 +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:
- 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.

View File

@ -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;

View File

@ -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();

View File

@ -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

View File

@ -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') {

View File

@ -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 = [];
[

View File

@ -56,6 +56,12 @@ trait Events
* @var array<string, callable>
*/
private array $eventHandlerMethods = [];
/**
* Event handler handler list.
*
* @var array<string, callable>
*/
private array $eventHandlerHandlers = [];
/** @var array<class-string<EventHandler>, 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();
}