diff --git a/src/danog/MadelineProto/MTProto.php b/src/danog/MadelineProto/MTProto.php index 815cee54..7d62ffa0 100644 --- a/src/danog/MadelineProto/MTProto.php +++ b/src/danog/MadelineProto/MTProto.php @@ -142,8 +142,6 @@ class MTProto implements TLCallback public $setdem = false; public $storage = []; private $postpone_updates = false; - private $postpone_pwrchat = false; - private $pending_pwrchat = []; private $altervista = false; private $supportUser = 0; public $referenceDatabase; @@ -210,7 +208,7 @@ class MTProto implements TLCallback public function __sleep() { - return ['supportUser', 'referenceDatabase', 'channel_participants', 'event_handler', 'event_handler_instance', 'loop_callback', 'web_template', 'encrypted_layer', 'settings', 'config', 'authorization', 'authorized', 'rsa_keys', 'last_recv', 'dh_config', 'chats', 'last_stored', 'qres', 'pending_updates', 'pending_pwrchat', 'postpone_pwrchat', 'updates_state', 'got_state', 'channels_state', 'updates', 'updates_key', 'full_chats', 'msg_ids', 'dialog_params', 'datacenter', 'v', 'constructors', 'td_constructors', 'methods', 'td_methods', 'td_descriptions', 'tl_callbacks', 'temp_requested_secret_chats', 'temp_rekeyed_secret_chats', 'secret_chats', 'hook_url', 'storage', 'authorized_dc', 'tos']; + return ['supportUser', 'referenceDatabase', 'channel_participants', 'event_handler', 'event_handler_instance', 'loop_callback', 'web_template', 'encrypted_layer', 'settings', 'config', 'authorization', 'authorized', 'rsa_keys', 'last_recv', 'dh_config', 'chats', 'last_stored', 'qres', 'pending_updates', 'updates_state', 'got_state', 'channels_state', 'updates', 'updates_key', 'full_chats', 'msg_ids', 'dialog_params', 'datacenter', 'v', 'constructors', 'td_constructors', 'methods', 'td_methods', 'td_descriptions', 'tl_callbacks', 'temp_requested_secret_chats', 'temp_rekeyed_secret_chats', 'secret_chats', 'hook_url', 'storage', 'authorized_dc', 'tos']; } public function isAltervista() @@ -277,7 +275,6 @@ class MTProto implements TLCallback $this->channels_state[$key]['sync_loading'] = false; } $this->postpone_updates = false; - $this->postpone_pwrchat = false; if ($this->event_handler && class_exists($this->event_handler) && is_subclass_of($this->event_handler, '\danog\MadelineProto\EventHandler')) { $this->setEventHandler($this->event_handler); } diff --git a/src/danog/MadelineProto/MTProtoTools/CallHandler.php b/src/danog/MadelineProto/MTProtoTools/CallHandler.php index c51eda73..9bdaa221 100644 --- a/src/danog/MadelineProto/MTProtoTools/CallHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/CallHandler.php @@ -257,6 +257,9 @@ trait CallHandler if (isset($aargs['botAPI'])) { $message['botAPI'] = $aargs['botAPI']; } + if (isset($aargs['FloodWaitLimit'])) { + $message['FloodWaitLimit'] = $aargs['FloodWaitLimit']; + } if (($method === 'users.getUsers' && $args === ['id' => [['_' => 'inputUserSelf']]]) || $method === 'auth.exportAuthorization' || $method === 'updates.getDifference') { $message['user_related'] = true; } diff --git a/src/danog/MadelineProto/MTProtoTools/PeerHandler.php b/src/danog/MadelineProto/MTProtoTools/PeerHandler.php index 405e52da..3055150d 100644 --- a/src/danog/MadelineProto/MTProtoTools/PeerHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/PeerHandler.php @@ -26,6 +26,10 @@ use Amp\Loop; */ trait PeerHandler { + public $caching_simple = []; + public $caching_simple_username = []; + public $caching_possible_username = []; + public function to_supergroup($id) { return -($id + pow(10, (int) floor(log($id, 10) + 3))); @@ -43,51 +47,30 @@ trait PeerHandler return ($log - intval($log)) * 1000 < 10; } - public function handle_pending_pwrchat() - { - if ($this->postpone_pwrchat || empty($this->pending_pwrchat)) { - return false; - } - $this->postpone_pwrchat = true; - - try { - $this->logger->logger('Handling pending pwrchat queries...', \danog\MadelineProto\Logger::VERBOSE); - foreach ($this->pending_pwrchat as $query => $params) { - unset($this->pending_pwrchat[$query]); - - try { - $this->get_pwr_chat($query, ...$params); - } catch (\danog\MadelineProto\Exception $e) { - $this->logger->logger($e->getMessage(), \danog\MadelineProto\Logger::WARNING); - } catch (\danog\MadelineProto\RPCErrorException $e) { - $this->logger->logger($e->getMessage(), \danog\MadelineProto\Logger::WARNING); - } - } - } finally { - $this->postpone_pwrchat = false; - } - } - public function add_support($support) { $this->supportUser = $support['user']['id']; } - public function add_users($users) - { - foreach ($users as $user) { - $this->add_user($user); - } - } - public function add_user($user) { if (!isset($user['access_hash'])) { - $this->logger->logger("No access hash with user {$user['id']}, trying to fetch by ID..."); - $this->cache_pwr_chat($user['id'], false, true); - if (isset($user['username']) && !isset($this->chats[$user['id']])) { + /*if (isset($this->chats[$user['id']]['access_hash']) && $this->chats[$user['id']]['access_hash']) { + $this->logger->logger("No access hash with user {$user['id']}, using backup"); + $user['access_hash'] = $this->chats[$user['id']]['access_hash']; + } else { + $this->logger->logger("No access hash with user {$user['id']}, not trying to fetch it"); + $user['access_hash'] = 0; + }*/ + if (!isset($this->caching_simple[$user['id']]) && !(isset($user['username']) && isset($this->caching_simple_username[$user['username']]))) { + $this->logger->logger("No access hash with user {$user['id']}, trying to fetch by ID..."); + if (isset($user['username']) && !isset($this->caching_simple_username[$user['username']])) $this->caching_possible_username[$user['id']] = $user['username']; + $this->cache_pwr_chat($user['id'], false, true); + } else if (isset($user['username']) && !isset($this->chats[$user['id']]) && !isset($this->caching_simple_username[$user['username']])) { $this->logger->logger("No access hash with user {$user['id']}, trying to fetch by username..."); $this->cache_pwr_chat($user['username'], false, true); + } else { + $this->logger->logger("No access hash with user {$user['id']}, tried and failed to fetch data..."); } return; @@ -107,13 +90,6 @@ trait PeerHandler } } - public function add_chats($chats) - { - foreach ($chats as $chat) { - $this->add_chat($chat); - } - } - public function add_chat($chat) { switch ($chat['_']) { @@ -132,13 +108,17 @@ trait PeerHandler case 'channelForbidden': $bot_api_id = $this->to_supergroup($chat['id']); if (!isset($chat['access_hash'])) { - $this->logger->logger("Chat $bot_api_id does not have access hash, fetching by ID..."); - $this->cache_pwr_chat($bot_api_id, $this->settings['peer']['full_fetch'], true); - if (isset($chat['username']) && !isset($this->chats[$bot_api_id])) { - $this->logger->logger("Chat $bot_api_id does not have access hash, fetching by username..."); - $this->cache_pwr_chat($chat['username'], $this->settings['peer']['full_fetch'], true); - } + if (!isset($this->caching_simple[$bot_api_id]) && !(isset($chat['username']) && isset($this->caching_simple_username[$chat['username']]))) { + $this->logger->logger("No access hash with {$chat['_']} {$bot_api_id}, trying to fetch by ID..."); + if (isset($chat['username']) && !isset($this->caching_simple_username[$chat['username']])) $this->caching_possible_username[$bot_api_id] = $chat['username']; + $this->cache_pwr_chat($bot_api_id, false, true); + } else if (isset($chat['username']) && !isset($this->chats[$bot_api_id]) && !isset($this->caching_simple_username[$chat['username']])) { + $this->logger->logger("No access hash with {$chat['_']} {$bot_api_id}, trying to fetch by username..."); + $this->cache_pwr_chat($chat['username'], false, true); + } else { + $this->logger->logger("No access hash with {$chat['_']} {$bot_api_id}, tried and failed to fetch data..."); + } return; } if (!isset($this->chats[$bot_api_id]) || $this->chats[$bot_api_id] !== $chat) { @@ -159,19 +139,15 @@ trait PeerHandler public function cache_pwr_chat($id, $full_fetch, $send) { - if ($this->postpone_pwrchat) { - $this->pending_pwrchat[$id] = [$full_fetch, $send]; - } else { Loop::defer(function () use ($id, $full_fetch, $send) { try { $this->get_pwr_chat($id, $full_fetch, $send); } catch (\danog\MadelineProto\Exception $e) { - $this->logger->logger($e->getMessage(), \danog\MadelineProto\Logger::WARNING); + $this->logger->logger("While caching: ".$e->getMessage(), \danog\MadelineProto\Logger::WARNING); } catch (\danog\MadelineProto\RPCErrorException $e) { - $this->logger->logger($e->getMessage(), \danog\MadelineProto\Logger::WARNING); + $this->logger->logger("While caching: ".$e->getMessage(), \danog\MadelineProto\Logger::WARNING); } }); - } } public function peer_isset($id) @@ -370,9 +346,12 @@ trait PeerHandler $try_id = $this->get_id($id); if ($try_id !== false) $id = $try_id; + $tried_simple = false; + if (is_numeric($id)) { if (!isset($this->chats[$id])) { try { + $this->caching_simple[$id] = true; if ($id < 0) { if ($this->is_supergroup($id)) { $this->method_call('channels.getChannels', ['id' => [['access_hash' => 0, 'channel_id' => $this->from_supergroup($id), '_' => 'inputChannel']]], ['datacenter' => $this->datacenter->curdc]); @@ -386,6 +365,9 @@ trait PeerHandler $this->logger->logger($e->getMessage(), \danog\MadelineProto\Logger::WARNING); } catch (\danog\MadelineProto\RPCErrorException $e) { $this->logger->logger($e->getMessage(), \danog\MadelineProto\Logger::WARNING); + } finally { + if (isset($this->caching_simple[$id])) unset($this->caching_simple[$id]); + $tried_simple = true; } } if (isset($this->chats[$id])) { @@ -407,7 +389,13 @@ trait PeerHandler return $this->get_info($id, false); } } + if ($tried_simple && isset($this->caching_possible_username[$id])) { + $this->logger->logger("No access hash with $id, trying to fetch by username..."); + $user = $this->caching_possible_username[$id]; + unset($this->caching_possible_username[$id]); + return $this->get_info($user); + } throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database'); } if (preg_match('@(?:t|telegram)\.(?:me|dog)/(joinchat/)?([a-z0-9_-]*)@i', $id, $matches)) { @@ -860,6 +848,7 @@ trait PeerHandler public function resolve_username($username) { try { + $this->caching_simple_username[$username] = true; $res = $this->method_call('contacts.resolveUsername', ['username' => str_replace('@', '', $username)], ['datacenter' => $this->datacenter->curdc]); } catch (\danog\MadelineProto\RPCErrorException $e) { $this->logger->logger('Username resolution failed with error '.$e->getMessage(), \danog\MadelineProto\Logger::ERROR); @@ -868,6 +857,8 @@ trait PeerHandler } return false; + } finally { + if (isset($this->caching_simple_username[$username])) unset($this->caching_simple_username[$username]); } if ($res['_'] === 'contacts.resolvedPeer') { return $res; diff --git a/src/danog/MadelineProto/MTProtoTools/ResponseHandler.php b/src/danog/MadelineProto/MTProtoTools/ResponseHandler.php index 1296a2e2..9e7741c8 100644 --- a/src/danog/MadelineProto/MTProtoTools/ResponseHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/ResponseHandler.php @@ -469,9 +469,12 @@ trait ResponseHandler return; case 420: $seconds = preg_replace('/[^0-9]+/', '', $response['error_message']); - $limit = isset($aargs['FloodWaitLimit']) ? $aargs['FloodWaitLimit'] : $this->settings['flood_timeout']['wait_if_lt']; + $limit = isset($request['FloodWaitLimit']) ? $request['FloodWaitLimit'] : $this->settings['flood_timeout']['wait_if_lt']; if (is_numeric($seconds) && $seconds < $limit) { + //$this->got_response_for_outgoing_message_id($request_id, $datacenter); + $this->logger->logger('Flood, waiting '.$seconds.' seconds before repeating async call...', \danog\MadelineProto\Logger::NOTICE); + $request['sent'] += $seconds; Loop::delay($seconds * 1000, [$this, 'method_recall'], ['message_id' => $request_id, 'datacenter' => $datacenter]); return; diff --git a/src/danog/MadelineProto/MTProtoTools/UpdateHandler.php b/src/danog/MadelineProto/MTProtoTools/UpdateHandler.php index fcf2ee56..d5010029 100644 --- a/src/danog/MadelineProto/MTProtoTools/UpdateHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/UpdateHandler.php @@ -632,7 +632,7 @@ trait UpdateHandler if (isset($update['message']['from_id']) && $update['message']['from_id'] === $this->authorization['user']['id']) { $update['message']['out'] = true; } - $this->logger->logger('Saving an update of type '.$update['_'].'...', \danog\MadelineProto\Logger::VERBOSE); + //$this->logger->logger('Saving an update of type '.$update['_'].'...', \danog\MadelineProto\Logger::ULTRA_VERBOSE); if (isset($this->settings['pwr']['strict']) && $this->settings['pwr']['strict'] && isset($this->settings['pwr']['update_handler'])) { $this->pwr_update_handler($update); } elseif ($this->settings['updates']['run_callback']) { diff --git a/src/danog/MadelineProto/Wrappers/DialogHandler.php b/src/danog/MadelineProto/Wrappers/DialogHandler.php index 3ad9ad74..30e67ee4 100644 --- a/src/danog/MadelineProto/Wrappers/DialogHandler.php +++ b/src/danog/MadelineProto/Wrappers/DialogHandler.php @@ -22,9 +22,13 @@ namespace danog\MadelineProto\Wrappers; trait DialogHandler { public function get_dialogs($force = true) + { + return $this->wait($this->get_dialogs_async($force)); + } + public function get_dialogs_async($force = true) { if ($force || !isset($this->dialog_params['offset_date']) || is_null($this->dialog_params['offset_date']) || !isset($this->dialog_params['offset_id']) || is_null($this->dialog_params['offset_id']) || !isset($this->dialog_params['offset_peer']) || is_null($this->dialog_params['offset_peer']) || !isset($this->dialog_params['count']) || is_null($this->dialog_params['count'])) { - $this->dialog_params = ['limit' => 100, 'offset_date' => 0, 'offset_id' => 0, 'offset_peer' => ['_' => 'inputPeerEmpty'], 'count' => 0]; + $this->dialog_params = ['limit' => 100, 'offset_date' => 0, 'offset_id' => 0, 'offset_peer' => ['_' => 'inputPeerEmpty'], 'count' => 0, 'hash' => 0]; } if (!isset($this->dialog_params['hash'])) { $this->dialog_params['hash'] = 0; @@ -36,18 +40,40 @@ trait DialogHandler $this->postpone_updates = true; try { + $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['getting_dialogs']); while ($this->dialog_params['count'] < $res['count']) { - $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['getting_dialogs']); - $res = $this->method_call('messages.getDialogs', $this->dialog_params, ['datacenter' => $datacenter, 'FloodWaitLimit' => 100]); - foreach ($res['dialogs'] as $dialog) { + $res = yield $this->method_call_async_read('messages.getDialogs', $this->dialog_params, ['datacenter' => $datacenter, 'FloodWaitLimit' => 100]); + $last_peer = []; + $last_date = 0; + $last_id = 0; + $res['messages'] = array_reverse($res['messages']); + foreach (array_reverse($res['dialogs']) as $dialog) { if (!in_array($dialog['peer'], $peers)) { $peers[] = $dialog['peer']; } + if (!$last_date) { + if (!$last_peer) { + $last_peer = $dialog['peer']; + } + if (!$last_id) { + $last_id = $dialog['top_message']; + } + foreach ($res['messages'] as $message) { + if (yield $this->get_info($message)['Peer'] === $last_peer && $last_id === $message['id']) { + $last_date = $message['date']; + break; + } + } + } + } + if ($last_date) { + $this->dialog_params['offset_date'] = $last_date; + $this->dialog_params['offset_peer'] = $last_peer; + $this->dialog_params['offset_id'] = $last_id; + $this->dialog_params['count'] = count($peers); + } else { + break; } - $this->dialog_params['count'] += count($res['dialogs']); - $this->dialog_params['offset_date'] = end($res['messages'])['date']; - $this->dialog_params['offset_peer'] = end($res['dialogs'])['peer']; - $this->dialog_params['offset_id'] = end($res['messages'])['id'] & 4294967296; if (!isset($res['count'])) { break; }