. * * @author Daniil Gentili * @copyright 2016-2023 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\MTProtoSession; use danog\MadelineProto\Logger; use danog\MadelineProto\MTProto\IncomingMessage; use danog\MadelineProto\MTProto\OutgoingMessage; use danog\MadelineProto\Tools; use function time; /** * Manages MTProto session-specific data. * * @extends Connection */ trait Session { use AuthKeyHandler; use AckHandler; use ResponseHandler; use SeqNoHandler; use CallHandler; use Reliable; /** * Incoming message array. * * @var array */ public array $incoming_messages = []; /** * Outgoing message array. * * @var array */ public array $outgoing_messages = []; /** * New incoming message ID array. * * @var array */ public array $new_incoming = []; /** * New outgoing message array. * * @var array */ public array $new_outgoing = []; /** * Pending outgoing messages. * * @var array */ public array $pendingOutgoing = []; /** * Pending outgoing key. * */ public int $pendingOutgoingKey = 0; /** * Time delta with server. * */ public int $time_delta = 0; /** * Call queue. * */ public array $call_queue = []; /** * Ack queue. * */ public array $ack_queue = []; /** * Message ID handler. * */ public MsgIdHandler $msgIdHandler; /** * Reset MTProto session. */ public function resetSession(): void { $this->API->logger->logger("Resetting session in DC {$this->datacenterId}...", Logger::WARNING); $this->session_id = Tools::random(8); $this->session_in_seq_no = 0; $this->session_out_seq_no = 0; $this->msgIdHandler ??= new MsgIdHandler($this); foreach ($this->outgoing_messages as &$msg) { if ($msg->hasMsgId()) { $msg->setMsgId(null); } if ($msg->hasSeqNo()) { $msg->setSeqNo(null); } } } /** * Cleanup incoming and outgoing messages. */ public function cleanupSession(): void { $count = 0; $incoming = []; foreach ($this->incoming_messages as $key => $message) { if ($message->canGarbageCollect()) { $count++; } else { $this->API->logger->logger("Can't garbage collect $message in DC {$this->datacenter}, not handled yet!", Logger::VERBOSE); $incoming[$key] = $message; } } $this->incoming_messages = $incoming; $total = \count($this->incoming_messages); if ($count+$total) { $this->API->logger->logger("Garbage collected $count incoming messages in DC {$this->datacenter}, $total left", Logger::VERBOSE); } $count = 0; $outgoing = []; foreach ($this->outgoing_messages as $key => $message) { if ($message->canGarbageCollect()) { $count++; } else { $ago = \time() - $message->getSent(); if ($ago > 2) { $this->API->logger->logger("Can't garbage collect $message in DC {$this->datacenter}, no response has been received or it wasn't yet handled!", Logger::VERBOSE); } $outgoing[$key] = $message; } } $this->outgoing_messages = $outgoing; $total = \count($this->outgoing_messages); if ($count+$total) { $this->API->logger->logger("Garbage collected $count outgoing messages in DC {$this->datacenter}, $total left", Logger::VERBOSE); } } /** * Create MTProto session if needed. */ public function createSession(): void { if ($this->session_id === null) { $this->resetSession(); } } /** * Backup eventual unsent messages before session deletion. * * @return array */ public function backupSession(): array { $pending = \array_values($this->pendingOutgoing); return \array_merge($pending, $this->new_outgoing); } }