diff --git a/composer.json b/composer.json index b487ab16..860f883a 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,8 @@ }, "require-dev": { "phpdocumentor/reflection-docblock": "^3.1", - "ennexa/amp-update-cache": "dev-master" + "ennexa/amp-update-cache": "dev-master", + "phpunit/phpunit": "^8" }, "suggest": { "ext-libtgvoip": "Install the php-libtgvoip extension to make phone calls (https://github.com/danog/php-libtgvoip)", diff --git a/docs b/docs index 55b64aaf..8dee62b1 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit 55b64aaf627fceb0fae839c3008ffae25d53541d +Subproject commit 8dee62b19a4e2c8d03f5602711587403b5f14d75 diff --git a/src/danog/MadelineProto/API.php b/src/danog/MadelineProto/API.php index 5f8dde69..5c2f7273 100644 --- a/src/danog/MadelineProto/API.php +++ b/src/danog/MadelineProto/API.php @@ -69,6 +69,10 @@ class API extends APIFactory if ($e->getFile() === 'MadelineProto' && $e->getLine() === 1) { throw $e; } + if (defined('MADELINEPROTO_TEST') && MADELINEPROTO_TEST === 'pony') { + throw $e; + } + class_exists('\\Volatile'); $tounserialize = str_replace('O:26:"danog\\MadelineProto\\Button":', 'O:35:"danog\\MadelineProto\\TL\\Types\\Button":', $tounserialize); foreach (['RSA', 'TL\\TLMethod', 'TL\\TLConstructor', 'MTProto', 'API', 'DataCenter', 'Connection', 'TL\\Types\\Button', 'TL\\Types\\Bytes', 'APIFactory'] as $class) { diff --git a/src/danog/MadelineProto/APIFactory.php b/src/danog/MadelineProto/APIFactory.php index 0a317764..3693ea91 100644 --- a/src/danog/MadelineProto/APIFactory.php +++ b/src/danog/MadelineProto/APIFactory.php @@ -213,7 +213,6 @@ class APIFactory public function __mtproto_call($name, $arguments) { $aargs = isset($arguments[1]) && is_array($arguments[1]) ? $arguments[1] : []; - $aargs['datacenter'] = $this->API->datacenter->curdc; $aargs['apifactory'] = true; $args = isset($arguments[0]) && is_array($arguments[0]) ? $arguments[0] : []; @@ -224,6 +223,7 @@ class APIFactory return $this->call(function () use ($name, $args, $aargs) { yield $this->API->asyncInitPromise; $this->API->asyncInitPromise = null; + $aargs['datacenter'] = $this->API->datacenter->curdc; return yield $this->API->method_call_async_read($name, $args, $aargs); ; }); @@ -232,6 +232,7 @@ class APIFactory $this->API->asyncInitPromise = null; } } + $aargs['datacenter'] = $this->API->datacenter->curdc; $res = $this->API->method_call_async_read($name, $args, $aargs); if ($async) { diff --git a/src/danog/MadelineProto/Async/Parameters.php b/src/danog/MadelineProto/Async/Parameters.php index cfa458d3..400792a2 100644 --- a/src/danog/MadelineProto/Async/Parameters.php +++ b/src/danog/MadelineProto/Async/Parameters.php @@ -30,7 +30,6 @@ use function Amp\call; */ abstract class Parameters { - private $fetched = false; private $params = []; /** @@ -51,7 +50,7 @@ abstract class Parameters public function fetchParametersAsync(): \Generator { $refetchable = $this->isRefetchable(); - if ($this->fetched && !$refetchable) { + if ($this->params && !$refetchable) { return $this->params; } $params = yield call([$this, 'getParameters']); diff --git a/src/danog/MadelineProto/Connection.php b/src/danog/MadelineProto/Connection.php index 7a40cb58..c3295394 100644 --- a/src/danog/MadelineProto/Connection.php +++ b/src/danog/MadelineProto/Connection.php @@ -198,6 +198,7 @@ class Connection $this->API->referenceDatabase->refreshNext(false); } $message['serialized_body'] = $body; + unset($body); } $message['send_promise'] = $deferred; diff --git a/src/danog/MadelineProto/DataCenter.php b/src/danog/MadelineProto/DataCenter.php index 535dc8ba..e3c49e27 100644 --- a/src/danog/MadelineProto/DataCenter.php +++ b/src/danog/MadelineProto/DataCenter.php @@ -97,6 +97,9 @@ class DataCenter return true; } catch (\Throwable $e) { + if (defined('MADELINEPROTO_TEST') && MADELINEPROTO_TEST === 'pony') { + throw $e; + } $this->API->logger->logger('Connection failed: ' . $e->getMessage(), \danog\MadelineProto\Logger::ERROR); } catch (\Exception $e) { $this->API->logger->logger('Connection failed: ' . $e->getMessage(), \danog\MadelineProto\Logger::ERROR); @@ -313,6 +316,9 @@ class DataCenter $this->API->logger->logger("No info for DC $dc_number", \danog\MadelineProto\Logger::ERROR); } + if (defined('MADELINEPROTO_TEST') && MADELINEPROTO_TEST === 'pony') { + return [$ctxs[0]]; + } return $ctxs; } diff --git a/src/danog/MadelineProto/Loop/Connection/CheckLoop.php b/src/danog/MadelineProto/Loop/Connection/CheckLoop.php index 619d8cbc..fc05acb7 100644 --- a/src/danog/MadelineProto/Loop/Connection/CheckLoop.php +++ b/src/danog/MadelineProto/Loop/Connection/CheckLoop.php @@ -83,10 +83,11 @@ class CheckLoop extends ResumableSignalLoop case 2: case 3: if ($connection->outgoing_messages[$message_id]['_'] === 'msgs_state_req') { + $API->got_response_for_outgoing_message_id($message_id, $datacenter); break; } $API->logger->logger('Message '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.($message_id).' not received by server, resending...', \danog\MadelineProto\Logger::ERROR); - $API->method_recall('', ['message_id' => $message_id, 'datacenter' => $datacenter, 'postpone' => true]); + $API->method_recall('watcherId', ['message_id' => $message_id, 'datacenter' => $datacenter, 'postpone' => true]); break; case 4: if ($chr & 32) { diff --git a/src/danog/MadelineProto/Loop/Connection/ReadLoop.php b/src/danog/MadelineProto/Loop/Connection/ReadLoop.php index bc2c328e..b613aebf 100644 --- a/src/danog/MadelineProto/Loop/Connection/ReadLoop.php +++ b/src/danog/MadelineProto/Loop/Connection/ReadLoop.php @@ -103,7 +103,7 @@ class ReadLoop extends SignalLoop } $this->startedLoop(); //var_dump(count($connection->incoming_messages)); -// Loop::defer(function () use ($datacenter) { + // Loop::defer(function () use ($datacenter) { if ($this->API->is_http($datacenter)) { $this->API->datacenter->sockets[$datacenter]->waiter->resume(); } // }); diff --git a/src/danog/MadelineProto/Loop/Connection/WriteLoop.php b/src/danog/MadelineProto/Loop/Connection/WriteLoop.php index a3c04b1b..5deb7b52 100644 --- a/src/danog/MadelineProto/Loop/Connection/WriteLoop.php +++ b/src/danog/MadelineProto/Loop/Connection/WriteLoop.php @@ -309,6 +309,7 @@ class WriteLoop extends ResumableSignalLoop foreach ($keys as $key => $message_id) { $connection->outgoing_messages[$message_id] = &$connection->pending_outgoing[$key]; + if (isset($connection->outgoing_messages[$message_id]['promise'])) { $connection->new_outgoing[$message_id] = $message_id; $connection->outgoing_messages[$message_id]['sent'] = $sent; diff --git a/src/danog/MadelineProto/MTProto.php b/src/danog/MadelineProto/MTProto.php index cbaaf9f8..cf2312a3 100644 --- a/src/danog/MadelineProto/MTProto.php +++ b/src/danog/MadelineProto/MTProto.php @@ -228,9 +228,10 @@ class MTProto implements TLCallback public function __wakeup() { - $this->asyncInitPromise = $this->call($this->__async_wakeup()); + $backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 3); + $this->asyncInitPromise = $this->call($this->__async_wakeup($backtrace)); } - public function __async_wakeup() + public function __async_wakeup($backtrace) { set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']); set_exception_handler(['\\danog\\MadelineProto\\Serialization', 'serialize_all']); @@ -289,14 +290,13 @@ class MTProto implements TLCallback } $force = false; $this->reset_session(); - - $backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 3); if (isset($backtrace[2]['function']) && isset($backtrace[2]['class']) && isset($backtrace[2]['args']) && $backtrace[2]['class'] === 'danog\\MadelineProto\\API' && $backtrace[2]['function'] === '__magic_construct') { if (count($backtrace[2]['args']) === 2) { $this->parse_settings(array_replace_recursive($this->settings, $backtrace[2]['args'][1])); } } + if (isset($this->settings['tl_schema']['src']['botAPI']) && $this->settings['tl_schema']['src']['botAPI'] !== __DIR__ . '/TL_botAPI.tl') { unset($this->v); } @@ -676,8 +676,8 @@ class MTProto implements TLCallback 'response' => 5, ], 'flood_timeout' => ['wait_if_lt' => 20], 'msg_array_limit' => [ // How big should be the arrays containing the incoming and outgoing messages? - 'incoming' => 200, - 'outgoing' => 200, + 'incoming' => 100, + 'outgoing' => 100, 'call_queue' => 200, ], 'peer' => [ 'full_info_cache_time' => 3600, diff --git a/src/danog/MadelineProto/MTProtoTools/AckHandler.php b/src/danog/MadelineProto/MTProtoTools/AckHandler.php index eb090333..1478dfae 100644 --- a/src/danog/MadelineProto/MTProtoTools/AckHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/AckHandler.php @@ -54,6 +54,9 @@ trait AckHandler if (isset($this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['body'])) { unset($this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['body']); } + if (isset($this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['serialized_body'])) { + unset($this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['serialized_body']); + } if (isset($this->datacenter->sockets[$datacenter]->new_outgoing[$message_id])) { unset($this->datacenter->sockets[$datacenter]->new_outgoing[$message_id]); } diff --git a/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php b/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php index f17228be..32dc11d0 100644 --- a/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php @@ -559,7 +559,7 @@ trait AuthKeyHandler return $this->init_authorization_socket($id, $socket); }; } - yield array_shift($dcs)(); + if ($dcs) yield array_shift($dcs)(); foreach ($dcs as $id => &$dc) { $dc = $dc(); } diff --git a/src/danog/MadelineProto/MTProtoTools/CallHandler.php b/src/danog/MadelineProto/MTProtoTools/CallHandler.php index 4c3e0780..e3b19f8e 100644 --- a/src/danog/MadelineProto/MTProtoTools/CallHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/CallHandler.php @@ -30,107 +30,6 @@ use function Amp\Promise\all; */ trait CallHandler { - public function has_pending_calls() - { - $result = []; - foreach ($this->datacenter->sockets as $id => $socket) { - $result[$id] = $this->has_pending_calls_dc($id); - } - - return $result; - } - - public function has_pending_calls_dc($datacenter) - { - //$result = 0; - $dc_config_number = isset($this->settings['connection_settings'][$datacenter]) ? $datacenter : 'all'; - foreach ($this->datacenter->sockets[$datacenter]->new_outgoing as $message_id) { - if (isset($this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['sent']) && ($this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['sent'] + $this->settings['connection_settings'][$dc_config_number]['timeout'] < time()) && ($this->datacenter->sockets[$datacenter]->temp_auth_key === null) === (isset($this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['unencrypted']) && $this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['unencrypted']) && $this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['_'] !== 'msgs_state_req') { - return true; - //$result |= 1; - } - } - - return false; //(bool) $result; - } - - public function check_pending_calls() - { - foreach ($this->datacenter->sockets as $datacenter => $socket) { - $this->check_pending_calls_dc($datacenter); - } - } - - public function check_pending_calls_dc($datacenter) - { - if (!empty($this->datacenter->sockets[$datacenter]->new_outgoing)) { - if ($this->has_pending_calls_dc($datacenter)) { - if ($this->datacenter->sockets[$datacenter]->temp_auth_key !== null) { - $message_ids = array_values($this->datacenter->sockets[$datacenter]->new_outgoing); - $deferred = new \danog\MadelineProto\ImmediatePromise(); - $deferred->then( - function ($result) use ($datacenter, $message_ids) { - $reply = []; - foreach (str_split($result['info']) as $key => $chr) { - $message_id = $message_ids[$key]; - if (!isset($this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id])) { - $this->logger->logger('Already got response for and forgot about message ID '.$this->unpack_signed_long($message_id)); - continue; - } - if (!isset($this->datacenter->sockets[$datacenter]->new_outgoing[$message_id])) { - $this->logger->logger('Already got response for '.$this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['_'].' with message ID '.$this->unpack_signed_long($message_id)); - continue; - } - $chr = ord($chr); - switch ($chr & 7) { - case 0: - $this->logger->logger('Wrong message status 0 for '.$this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['_'], \danog\MadelineProto\Logger::FATAL_ERROR); - break; - case 1: - case 2: - case 3: - $this->logger->logger('Message '.$this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['_'].' with message ID '.$this->unpack_signed_long($message_id).' not received by server, resending...', \danog\MadelineProto\Logger::ERROR); - $this->method_recall($message_id, $datacenter, false, true); - break; - case 4: - if ($chr & 32) { - $this->logger->logger('Message '.$this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['_'].' with message ID '.$this->unpack_signed_long($message_id).' received by server and is being processed, waiting...', \danog\MadelineProto\Logger::ERROR); - } elseif ($chr & 64) { - $this->logger->logger('Message '.$this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['_'].' with message ID '.$this->unpack_signed_long($message_id).' received by server and was already processed, requesting reply...', \danog\MadelineProto\Logger::ERROR); - $reply[] = $message_id; - } elseif ($chr & 128) { - $this->logger->logger('Message '.$this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['_'].' with message ID '.$this->unpack_signed_long($message_id).' received by server and was already sent, requesting reply...', \danog\MadelineProto\Logger::ERROR); - $reply[] = $message_id; - } else { - $this->logger->logger('Message '.$this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['_'].' with message ID '.$this->unpack_signed_long($message_id).' received by server, requesting reply...', \danog\MadelineProto\Logger::ERROR); - $reply[] = $message_id; - } - } - } - if ($reply) { - $this->object_call('msg_resend_ans_req', ['msg_ids' => $reply], ['datacenter' => $datacenter, 'postpone' => true]); - } - $this->send_messages($datacenter); - }, - function ($error) use ($datacenter) { - throw $error; - } - ); - $this->logger->logger("Still missing something on DC $datacenter, sending state request", \danog\MadelineProto\Logger::ERROR); - $this->object_call('msgs_state_req', ['msg_ids' => $message_ids], ['datacenter' => $datacenter, 'promise' => $deferred]); - } else { - $dc_config_number = isset($this->settings['connection_settings'][$datacenter]) ? $datacenter : 'all'; - foreach ($this->datacenter->sockets[$datacenter]->new_outgoing as $message_id) { - if (isset($this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['sent']) && $this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['sent'] + $this->settings['connection_settings'][$dc_config_number]['timeout'] < time() && $this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['unencrypted']) { - $this->logger->logger('Still missing '.$this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['_'].' with message id '.$this->unpack_signed_long($message_id)." on DC $datacenter, resending", \danog\MadelineProto\Logger::ERROR); - $this->method_recall($message_id, $datacenter, false, true); - } - } - } - } - } - } - public function method_recall($watcherId, $args) { $message_id = $args['message_id']; @@ -289,7 +188,8 @@ trait CallHandler /* $message = [ // only in outgoing messages -'body' => 'serialized body', (optional if container) +'body' => deserialized body, (optional if container) +'serialized_body' => 'serialized body', (optional if container) 'content_related' => bool, '_' => 'predicate', 'promise' => deferred promise that gets resolved when a response to the message is received (optional), diff --git a/src/danog/MadelineProto/MTProtoTools/Files.php b/src/danog/MadelineProto/MTProtoTools/Files.php index 0e31fb90..0e45e907 100644 --- a/src/danog/MadelineProto/MTProtoTools/Files.php +++ b/src/danog/MadelineProto/MTProtoTools/Files.php @@ -97,7 +97,10 @@ trait Files static function () use ($file_id, $part_num, $part_total_num, $part_size, $f, $ctx, $ige, $seekable) { if ($seekable) { fseek($f, $part_num * $part_size); + } else if (ftell($f) !== $part_num * $part_size) { + throw new \danog\MadelineProto\Exception('Wrong position!'); } + $bytes = stream_get_contents($f, $part_size); if ($ige) { $bytes = $ige->encrypt(str_pad($bytes, $part_size, chr(0))); diff --git a/src/danog/MadelineProto/MTProtoTools/ResponseHandler.php b/src/danog/MadelineProto/MTProtoTools/ResponseHandler.php index 9e7741c8..a943f16f 100644 --- a/src/danog/MadelineProto/MTProtoTools/ResponseHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/ResponseHandler.php @@ -28,28 +28,29 @@ trait ResponseHandler { public function send_msgs_state_info($req_msg_id, $msg_ids, $datacenter) { - // TODO REWRITE + $this->logger->logger("Sending state info for ".count($msg_ids)." message IDs"); $info = ''; foreach ($msg_ids as $msg_id) { $cur_info = 0; if (!isset($this->datacenter->sockets[$datacenter]->incoming_messages[$msg_id])) { $msg_id = new \phpseclib\Math\BigInteger(strrev($msg_id), 256); if ((new \phpseclib\Math\BigInteger(time() + $this->datacenter->sockets[$datacenter]->time_delta + 30))->bitwise_leftShift(32)->compare($msg_id) < 0) { + $this->logger->logger("Do not know anything about $msg_id and it is too small"); $cur_info |= 3; } elseif ((new \phpseclib\Math\BigInteger(time() + $this->datacenter->sockets[$datacenter]->time_delta - 300))->bitwise_leftShift(32)->compare($msg_id) > 0) { + $this->logger->logger("Do not know anything about $msg_id and it is too big"); $cur_info |= 1; } else { + $this->logger->logger("Do not know anything about $msg_id"); $cur_info |= 2; } } else { + $this->logger->logger("Know about $msg_id"); $cur_info |= 4; - if ($this->datacenter->sockets[$datacenter]->incoming_messages[$msg_id]['ack']) { - $cur_info |= 8; - } } $info .= chr($cur_info); } - $this->datacenter->sockets[$datacenter]->outgoing_messages[$this->object_call('msgs_state_info', ['req_msg_id' => $req_msg_id, 'info' => $info], ['datacenter' => $datacenter])]['response'] = $req_msg_id; + $this->datacenter->sockets[$datacenter]->outgoing_messages[yield $this->object_call_async('msgs_state_info', ['req_msg_id' => $req_msg_id, 'info' => $info], ['datacenter' => $datacenter])]['response'] = $req_msg_id; } public $n = 0; @@ -59,8 +60,6 @@ trait ResponseHandler if ($actual_datacenter) { $datacenter = $actual_datacenter; } - - //$n = $this->n++; $only_updates = true; foreach ($this->datacenter->sockets[$datacenter]->new_incoming as $current_msg_id) { $this->logger->logger((isset($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['from_container']) ? 'Inside of container, received ' : 'Received ').$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['_'].' from DC '.$datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE); @@ -74,58 +73,55 @@ trait ResponseHandler $this->ack_outgoing_message_id($msg_id, $datacenter); // Acknowledge that the server received my message } + + unset($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']); break; case 'rpc_result': unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); $this->ack_incoming_message_id($current_msg_id, $datacenter); + $only_updates = false; // Acknowledge that the server received my request $req_msg_id = $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['req_msg_id']; $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content'] = $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['result']; $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); $this->handle_response($req_msg_id, $current_msg_id, $datacenter); + break; - $only_updates = false; - break; case 'future_salts': - unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); - $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); - $only_updates = false; - $this->handle_response($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['req_msg_id'], $current_msg_id, $datacenter); - break; + case 'msgs_state_info': + $msg_id_type = 'req_msg_id'; case 'bad_server_salt': case 'bad_msg_notification': - $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); - $only_updates = false; - unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); - $this->handle_response($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['bad_msg_id'], $current_msg_id, $datacenter); - break; + $msg_id_type = isset($msg_id_type) ? $msg_id_type : 'bad_msg_id'; case 'pong': + $msg_id_type = isset($msg_id_type) ? $msg_id_type : 'msg_id'; + unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); $only_updates = false; - unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); - $this->handle_response($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_id'], $current_msg_id, $datacenter); + + $this->handle_response($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content'][$msg_id_type], $current_msg_id, $datacenter); break; + case 'new_session_created': + unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); $only_updates = false; + $this->datacenter->sockets[$datacenter]->temp_auth_key['server_salt'] = $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['server_salt']; - unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); $this->ack_incoming_message_id($current_msg_id, $datacenter); // Acknowledge that I received the server's response if ($this->authorized === self::LOGGED_IN && !$this->initing_authorization && $this->datacenter->sockets[$this->datacenter->curdc]->temp_auth_key !== null) { Loop::defer([$this, 'get_updates_difference']); } - //foreach ($this->datacenter->sockets[$datacenter]->new_outgoing as $message_id) { - // $this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['sent'] = 0; - //} -// Loop::defer([$this->datacenter->sockets[$datacenter]->checker, 'resume']); unset($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']); break; case 'msg_container': unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); + $only_updates = false; + foreach ($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['messages'] as $message) { $this->datacenter->sockets[$datacenter]->check_message_id($message['msg_id'], ['outgoing' => false, 'container' => true]); $this->datacenter->sockets[$datacenter]->incoming_messages[$message['msg_id']] = ['seq_no' => $message['seqno'], 'content' => $message['body'], 'from_container' => true]; @@ -133,57 +129,63 @@ trait ResponseHandler $this->handle_messages($datacenter); } $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); - $only_updates = false; + unset($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']); break; case 'msg_copy': + unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); $only_updates = false; + $this->ack_incoming_message_id($current_msg_id, $datacenter); // Acknowledge that I received the server's response if (isset($this->datacenter->sockets[$datacenter]->incoming_messages[$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['orig_message']['msg_id']])) { $this->ack_incoming_message_id($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['orig_message']['msg_id'], $datacenter); - // Acknowledge that I received the server's response + // Acknowledge that I received the server's response } else { + $message = $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']; $this->datacenter->sockets[$datacenter]->check_message_id($message['orig_message']['msg_id'], ['outgoing' => false, 'container' => true]); $this->datacenter->sockets[$datacenter]->incoming_messages[$message['orig_message']['msg_id']] = ['content' => $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['orig_message']]; $this->datacenter->sockets[$datacenter]->new_incoming[$message['orig_message']['msg_id']] = $message['orig_message']['msg_id']; $this->handle_messages($datacenter); } - unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); + unset($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']); break; + case 'http_wait': + unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); $only_updates = false; + $this->logger->logger($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content'], \danog\MadelineProto\Logger::NOTICE); - unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); + unset($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']); break; - case 'msgs_state_info': - $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); - $only_updates = false; - unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); - $this->handle_response($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['req_msg_id'], $current_msg_id, $datacenter); - break; + case 'msgs_state_req': $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); $only_updates = false; unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); - $this->send_msgs_state_info($current_msg_id, $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_ids'], $datacenter); + + $this->call($this->send_msgs_state_info($current_msg_id, $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_ids'], $datacenter)); + unset($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']); break; case 'msgs_all_info': $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); $only_updates = false; unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); + foreach ($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_ids'] as $key => $msg_id) { + $info = ord($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['info'][$key]); $msg_id = new \phpseclib\Math\BigInteger(strrev($msg_id), 256); $status = 'Status for message id '.$msg_id.': '; - if (($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['info'][$key] & 4) !== 0) { - $this->got_response_for_outgoing_message_id($msg_id, $datacenter); - } + /*if ($info & 4) { + *$this->got_response_for_outgoing_message_id($msg_id, $datacenter); + *} + */ foreach (self::MSGS_INFO_FLAGS as $flag => $description) { - if (($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['info'][$key] & $flag) !== 0) { + if (($info & $flag) !== 0) { $status .= $description; } } @@ -195,27 +197,29 @@ trait ResponseHandler $only_updates = false; if (isset($this->datacenter->sockets[$datacenter]->outgoing_messages[$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_id']])) { if (isset($this->datacenter->sockets[$datacenter]->incoming_messages[$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['answer_msg_id']])) { - $this->datacenter->sockets[$datacenter]->outgoing_messages[$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_id']]['response'] = $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['answer_msg_id']; - unset($this->datacenter->sockets[$datacenter]->new_outgoing[$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_id']]); + $this->handle_response($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_id'], $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['answer_msg_id'], $datacenter); } else { - $this->object_call('msg_resend_req', ['msg_ids' => [$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['answer_msg_id']]], ['datacenter' => $datacenter]); + $this->call($this->object_call_async('msg_resend_req', ['msg_ids' => [$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['answer_msg_id']]], ['datacenter' => $datacenter])); } } + break; case 'msg_new_detailed_info': $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); $only_updates = false; + unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); + if (isset($this->datacenter->sockets[$datacenter]->incoming_messages[$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['answer_msg_id']])) { $this->ack_incoming_message_id($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['answer_msg_id'], $datacenter); } else { - $this->object_call('msg_resend_req', ['msg_ids' => [$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['answer_msg_id']]], ['datacenter' => $datacenter]); + $this->call($this->object_call_async('msg_resend_req', ['msg_ids' => [$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['answer_msg_id']]], ['datacenter' => $datacenter])); } - unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); break; case 'msg_resend_req': $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); $only_updates = false; - $ok = true; unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); + + $ok = true; foreach ($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_ids'] as $msg_id) { if (!isset($this->datacenter->sockets[$datacenter]->outgoing_messages[$msg_id]) || isset($this->datacenter->sockets[$datacenter]->incoming_messages[$msg_id])) { $ok = false; @@ -223,20 +227,21 @@ trait ResponseHandler } if ($ok) { foreach ($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_ids'] as $msg_id) { - $this->object_call($this->datacenter->sockets[$datacenter]->outgoing_messages[$msg_id]['content']['method'], $this->datacenter->sockets[$datacenter]->outgoing_messages[$msg_id]['content']['args'], ['datacenter' => $datacenter]); + $this->method_recall('', ['message_id' => $msg_id, 'datacenter' => $datacenter]); } } else { - $this->send_msgs_state_info($current_msg_id, $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_ids'], $datacenter); + $this->call($this->send_msgs_state_info($current_msg_id, $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_ids'], $datacenter)); } break; case 'msg_resend_ans_req': $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); $only_updates = false; unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); - $this->send_msgs_state_info($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_ids'], $datacenter); + + $this->call($this->send_msgs_state_info($current_msg_id, $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_ids'], $datacenter)); foreach ($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_ids'] as $msg_id) { - if (isset($this->datacenter->sockets[$datacenter]->incoming_messages[$msg_id]) && isset($this->datacenter->sockets[$datacenter]->outgoing_messages[$this->datacenter->sockets[$datacenter]->incoming_messages[$msg_id]['response']])) { - $this->object_call($this->datacenter->sockets[$datacenter]->outgoing_messages[$this->datacenter->sockets[$datacenter]->incoming_messages[$msg_id]['response']]['method'], $this->datacenter->sockets[$datacenter]->outgoing_messages[$this->datacenter->sockets[$datacenter]->incoming_messages[$msg_id]['response']]['args'], ['datacenter' => $datacenter]); + if (isset($this->datacenter->sockets[$datacenter]->incoming_messages[$msg_id]['response']) && isset($this->datacenter->sockets[$datacenter]->outgoing_messages[$this->datacenter->sockets[$datacenter]->incoming_messages[$msg_id]['response']])) { + $this->call($this->object_call_async($this->datacenter->sockets[$datacenter]->outgoing_messages[$this->datacenter->sockets[$datacenter]->incoming_messages[$msg_id]['response']]['_'], $this->datacenter->sockets[$datacenter]->outgoing_messages[$this->datacenter->sockets[$datacenter]->incoming_messages[$msg_id]['response']]['body'], ['datacenter' => $datacenter])); } } break; @@ -263,8 +268,11 @@ trait ResponseHandler $this->logger->logger('Trying to assign a response of type '.$response_type.' to its request...', \danog\MadelineProto\Logger::VERBOSE); foreach ($this->datacenter->sockets[$datacenter]->new_outgoing as $key => $expecting_msg_id) { $expecting = $this->datacenter->sockets[$datacenter]->outgoing_messages[$expecting_msg_id]; + if (!isset($expecting['type'])) { + continue; + } - $this->logger->logger('Does the request of return type '.(isset($expecting['type']) ? $expecting['type'] : json_encode($expecting)).' match?', \danog\MadelineProto\Logger::VERBOSE); + $this->logger->logger('Does the request of return type '.$expecting['type'].' match?', \danog\MadelineProto\Logger::VERBOSE); if ($response_type === $expecting['type']) { $this->logger->logger('Yes', \danog\MadelineProto\Logger::VERBOSE); unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); diff --git a/src/danog/MadelineProto/Stream/ConnectionContext.php b/src/danog/MadelineProto/Stream/ConnectionContext.php index 8047e07f..27b3dae0 100644 --- a/src/danog/MadelineProto/Stream/ConnectionContext.php +++ b/src/danog/MadelineProto/Stream/ConnectionContext.php @@ -361,6 +361,7 @@ class ConnectionContext if ($this->isSecure()) { $string .= ' (TLS)'; } + $string .= $this->isTest() ? ' test' : ' main'; $string .= ' DC '; $string .= $this->getDc(); $string .= ', via '; diff --git a/src/danog/MadelineProto/VoIP/AuthKeyHandler.php b/src/danog/MadelineProto/VoIP/AuthKeyHandler.php index 96a31f72..d5f4ae52 100644 --- a/src/danog/MadelineProto/VoIP/AuthKeyHandler.php +++ b/src/danog/MadelineProto/VoIP/AuthKeyHandler.php @@ -136,7 +136,7 @@ trait AuthKeyHandler $visualization[] = \danog\MadelineProto\Magic::$emojis[(int) (new \phpseclib\Math\BigInteger($number, 256))->divide($length)[1]->toString()]; } $this->calls[$params['id']]->setVisualization($visualization); - + $this->calls[$params['id']]->configuration['endpoints'] = array_merge([$res['connection']], $res['alternative_connections'], $this->calls[$params['id']]->configuration['endpoints']); $this->calls[$params['id']]->configuration = array_merge(['recv_timeout' => $this->config['call_receive_timeout_ms'] / 1000, 'init_timeout' => $this->config['call_connect_timeout_ms'] / 1000, 'data_saving' => \danog\MadelineProto\VoIP::DATA_SAVING_NEVER, 'enable_NS' => true, 'enable_AEC' => true, 'enable_AGC' => true, 'auth_key' => $key, 'auth_key_id' => substr(sha1($key, true), -8), 'call_id' => substr(hash('sha256', $key, true), -16), 'network_type' => \danog\MadelineProto\VoIP::NET_TYPE_ETHERNET], $this->calls[$params['id']]->configuration); $this->calls[$params['id']]->parseConfig(); @@ -238,8 +238,7 @@ trait AuthKeyHandler $this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['call_set_rating'], $call['id']), \danog\MadelineProto\Logger::VERBOSE); $this->method_call('phone.setCallRating', ['peer' => $call, 'rating' => $rating['rating'], 'comment' => $rating['comment']], ['datacenter' => $this->datacenter->curdc]); } - if ($need_debug) { - //} && isset($this->calls[$call['id']]->storage['not_modified'])) { + if ($need_debug && isset($this->calls[$call['id']])) { $this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['call_debug_saving'], $call['id']), \danog\MadelineProto\Logger::VERBOSE); $this->method_call('phone.saveCallDebug', ['peer' => $call, 'debug' => $this->calls[$call['id']]->getDebugLog()], ['datacenter' => $this->datacenter->curdc]); } diff --git a/tests/testing.php b/tests/testing.php index 9739b576..48adb2de 100755 --- a/tests/testing.php +++ b/tests/testing.php @@ -42,7 +42,6 @@ $settings = json_decode(getenv('MTPROTO_SETTINGS'), true) ?: []; * Load MadelineProto */ echo 'Loading MadelineProto...'.PHP_EOL; - $MadelineProto = new \danog\MadelineProto\API(getcwd().'/testing.madeline', $settings); try {