From e2392db86c21018351acabb8c11fd60f8adcb7cb Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Sun, 29 Jan 2023 16:48:18 +0100 Subject: [PATCH] Fetch entire update history when using getDialogs with bots --- src/Ipc/Runner/ProcessRunner.php | 2 +- src/MTProto.php | 2 + src/MTProtoTools/UpdateHandler.php | 9 ++--- src/Wrappers/DialogHandler.php | 60 ++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 6 deletions(-) diff --git a/src/Ipc/Runner/ProcessRunner.php b/src/Ipc/Runner/ProcessRunner.php index 0aeb72153..d82e6f372 100644 --- a/src/Ipc/Runner/ProcessRunner.php +++ b/src/Ipc/Runner/ProcessRunner.php @@ -138,7 +138,7 @@ final class ProcessRunner extends RunnerAbstract { $executable = \strncasecmp(PHP_OS, 'WIN', 3) === 0 ? 'php.exe' : 'php'; - $paths = \array_filter(\explode(PATH_SEPARATOR, \getenv('PATH'))); + $paths = \array_filter(\explode(PATH_SEPARATOR, \getenv('PATH') ?: '')); $paths[] = PHP_BINDIR; $paths = \array_unique($paths); diff --git a/src/MTProto.php b/src/MTProto.php index 0bbeff6b2..3bbab897a 100644 --- a/src/MTProto.php +++ b/src/MTProto.php @@ -687,6 +687,8 @@ final class MTProto implements TLCallback, LoggerGetter 'tmpDbPrefix', // Misc caching + 'botDialogsUpdatesState', + 'cachedAllBotUsers', 'dialog_params', 'last_stored', 'qres', diff --git a/src/MTProtoTools/UpdateHandler.php b/src/MTProtoTools/UpdateHandler.php index f3c837be6..872b34301 100644 --- a/src/MTProtoTools/UpdateHandler.php +++ b/src/MTProtoTools/UpdateHandler.php @@ -495,6 +495,10 @@ trait UpdateHandler } else { $this->refreshPeerCache($update); } + } catch (Exception $e) { + if ($e->getMessage() !== 'This peer is not present in the internal peer database') { + throw $e; + } } catch (RPCErrorException $e) { if ($e->rpc !== 'CHANNEL_PRIVATE') { throw $e; @@ -569,11 +573,6 @@ trait UpdateHandler $this->secretFeeders[$update['message']['chat_id']]->resume(); return; } - /* - if ($update['_'] === 'updateEncryptedChatTyping') { - $update = ['_' => 'updateUserTyping', 'user_id' => $this->encrypted_chats[$update['chat_id']]['user_id'], 'action' => ['_' => 'sendMessageTypingAction']]; - } - */ if ($update['_'] === 'updateEncryption') { switch ($update['chat']['_']) { case 'encryptedChatRequested': diff --git a/src/Wrappers/DialogHandler.php b/src/Wrappers/DialogHandler.php index c0ac4e70b..30735fe45 100644 --- a/src/Wrappers/DialogHandler.php +++ b/src/Wrappers/DialogHandler.php @@ -20,6 +20,7 @@ declare(strict_types=1); namespace danog\MadelineProto\Wrappers; +use Amp\Sync\LocalMutex; use danog\MadelineProto\MTProto; use danog\MadelineProto\Settings; use Throwable; @@ -31,6 +32,13 @@ use Throwable; */ trait DialogHandler { + private array $botDialogsUpdatesState = [ + 'qts' => 1, + 'pts' => 1, + 'date' => 1, + ]; + private bool $cachedAllBotUsers = false; + private ?LocalMutex $cachingAllBotUsers = null; /** * Get dialog peers. * @@ -40,6 +48,58 @@ trait DialogHandler public function getDialogs(bool $force = true): array { if ($this->authorization['user']['bot']) { + if (!$this->cachedAllBotUsers) { + $this->cachingAllBotUsers ??= new LocalMutex; + $lock = $this->cachingAllBotUsers->acquire(); + try { + while (true) { + $this->logger($this->botDialogsUpdatesState); + $result = $this->methodCallAsyncRead( + 'updates.getDifference', + [ + ...$this->botDialogsUpdatesState, + 'pts_total_limit' => 2147483647 + ] + ); + switch ($result['_']) { + case 'updates.differenceEmpty': + break 2; + case 'updates.difference': + $this->botDialogsUpdatesState = $result['state']; + break; + case 'updates.differenceSlice': + $this->botDialogsUpdatesState = $result['intermediate_state']; + break; + case 'updates.differenceTooLong': + // Binary search for working PTS + $bottom = $this->botDialogsUpdatesState['pts']; + $top = $result['pts']; + $state = $this->botDialogsUpdatesState; + $state['pts_total_limit'] = 2147483647; + while ($bottom <= $top) { + $state['pts'] = ($bottom+$top)>>1; + $result = $this->methodCallAsyncRead( + 'updates.getDifference', + $state + )['_']; + $this->logger("$bottom, {$state['pts']}, $top"); + $this->logger($result); + if ($result === 'updates.differenceTooLong') { + $bottom = $state['pts']+1; + } else { + $top = $state['pts']-1; + } + } + $this->botDialogsUpdatesState['pts'] = $bottom; + $this->logger("Found PTS $bottom"); + break; + } + } + $this->cachedAllBotUsers = true; + } finally { + $lock->release(); + } + } $res = []; foreach ($this->chats as $chat) { try {