Save
This commit is contained in:
parent
ea2b28dbb1
commit
0f7ffc2da7
@ -71,7 +71,7 @@ class Connection extends Session
|
|||||||
*
|
*
|
||||||
* @var Stream
|
* @var Stream
|
||||||
*/
|
*/
|
||||||
private $stream;
|
public $stream;
|
||||||
/**
|
/**
|
||||||
* Connection context.
|
* Connection context.
|
||||||
*
|
*
|
||||||
@ -126,30 +126,18 @@ class Connection extends Session
|
|||||||
protected $datacenter;
|
protected $datacenter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the socket is reading data.
|
* Connection ID
|
||||||
*
|
*
|
||||||
* @var boolean
|
* @var int
|
||||||
*/
|
*/
|
||||||
private $reading = false;
|
private $id = 0;
|
||||||
/**
|
|
||||||
* Whether the socket is writing data.
|
|
||||||
*
|
|
||||||
* @var boolean
|
|
||||||
*/
|
|
||||||
private $writing = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writing callback.
|
* DC ID and connection ID concatenated
|
||||||
*
|
*
|
||||||
* @var callable
|
* @var
|
||||||
*/
|
*/
|
||||||
private $writingCallback;
|
private $datacenterId = '';
|
||||||
/**
|
|
||||||
* Reading callback.
|
|
||||||
*
|
|
||||||
* @var callable
|
|
||||||
*/
|
|
||||||
private $readingCallback;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the socket is writing stuff.
|
* Check if the socket is writing stuff.
|
||||||
@ -178,8 +166,7 @@ class Connection extends Session
|
|||||||
*/
|
*/
|
||||||
public function writing(bool $writing)
|
public function writing(bool $writing)
|
||||||
{
|
{
|
||||||
$this->writing = $writing;
|
$this->shared->writing($writing, $this->id);
|
||||||
($this->writingCallback)($writing);
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Set reading boolean.
|
* Set reading boolean.
|
||||||
@ -190,8 +177,7 @@ class Connection extends Session
|
|||||||
*/
|
*/
|
||||||
public function reading(bool $reading)
|
public function reading(bool $reading)
|
||||||
{
|
{
|
||||||
$this->reading = $reading;
|
$this->shared->reading($reading, $this->id);
|
||||||
($this->readingCallback)($writing);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -250,6 +236,25 @@ class Connection extends Session
|
|||||||
return $this->httpReqCount;
|
return $this->httpReqCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get connection ID
|
||||||
|
*
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public function getID(): int
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get datacenter concatenated with connection ID
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getDatacenterID(): string
|
||||||
|
{
|
||||||
|
return $this->datacenterId;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get connection context.
|
* Get connection context.
|
||||||
@ -276,6 +281,7 @@ class Connection extends Session
|
|||||||
|
|
||||||
$this->ctx = $ctx->getCtx();
|
$this->ctx = $ctx->getCtx();
|
||||||
$this->datacenter = $ctx->getDc();
|
$this->datacenter = $ctx->getDc();
|
||||||
|
$this->datacenterId = $this->datacenter.'.'.$this->id;
|
||||||
$this->stream = yield $ctx->getStream();
|
$this->stream = yield $ctx->getStream();
|
||||||
if (isset($this->old)) {
|
if (isset($this->old)) {
|
||||||
unset($this->old);
|
unset($this->old);
|
||||||
@ -395,17 +401,15 @@ class Connection extends Session
|
|||||||
/**
|
/**
|
||||||
* Connect main instance.
|
* Connect main instance.
|
||||||
*
|
*
|
||||||
* @param DataCenterConnection $extra Extra
|
* @param DataCenterConnection $extra Shared instance
|
||||||
* @param callable $readingCallback Read callback
|
* @param int $id Connection ID
|
||||||
* @param callable $writingCallback Write callback
|
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setExtra(DataCenterConnection $extra, $readingCallback, $writingCallback)
|
public function setExtra(DataCenterConnection $extra, int $id)
|
||||||
{
|
{
|
||||||
$this->shared = $extra;
|
$this->shared = $extra;
|
||||||
$this->readingCallback = $readingCallback;
|
$this->id = $id;
|
||||||
$this->writingCallback = $writingCallback;
|
|
||||||
$this->API = $extra->getExtra();
|
$this->API = $extra->getExtra();
|
||||||
$this->logger = $this->API->logger;
|
$this->logger = $this->API->logger;
|
||||||
}
|
}
|
||||||
@ -420,6 +424,16 @@ class Connection extends Session
|
|||||||
return $this->API;
|
return $this->API;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get shared connection instance.
|
||||||
|
*
|
||||||
|
* @return DataCenterConnection
|
||||||
|
*/
|
||||||
|
public function getShared(): DataCenterConnection
|
||||||
|
{
|
||||||
|
return $this->shared;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disconnect from DC.
|
* Disconnect from DC.
|
||||||
*
|
*
|
||||||
@ -427,7 +441,7 @@ class Connection extends Session
|
|||||||
*/
|
*/
|
||||||
public function disconnect()
|
public function disconnect()
|
||||||
{
|
{
|
||||||
$this->API->logger->logger("Disconnecting from DC {$this->datacenter}");
|
$this->API->logger->logger("Disconnecting from DC {$this->datacenterId}");
|
||||||
$this->old = true;
|
$this->old = true;
|
||||||
foreach (['reader', 'writer', 'checker', 'waiter', 'updater'] as $loop) {
|
foreach (['reader', 'writer', 'checker', 'waiter', 'updater'] as $loop) {
|
||||||
if (isset($this->{$loop}) && $this->{$loop}) {
|
if (isset($this->{$loop}) && $this->{$loop}) {
|
||||||
@ -441,7 +455,7 @@ class Connection extends Session
|
|||||||
$this->API->logger->logger($e);
|
$this->API->logger->logger($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->API->logger->logger("Disconnected from DC {$this->datacenter}");
|
$this->API->logger->logger("Disconnected from DC {$this->datacenterId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -451,7 +465,7 @@ class Connection extends Session
|
|||||||
*/
|
*/
|
||||||
public function reconnect(): \Generator
|
public function reconnect(): \Generator
|
||||||
{
|
{
|
||||||
$this->API->logger->logger("Reconnecting DC {$this->datacenter}");
|
$this->API->logger->logger("Reconnecting DC {$this->datacenterId}");
|
||||||
$this->disconnect();
|
$this->disconnect();
|
||||||
yield $this->API->datacenter->dcConnectAsync($this->ctx->getDc());
|
yield $this->API->datacenter->dcConnectAsync($this->ctx->getDc());
|
||||||
if ($this->API->hasAllAuth() && !$this->hasPendingCalls()) {
|
if ($this->API->hasAllAuth() && !$this->hasPendingCalls()) {
|
||||||
@ -474,16 +488,4 @@ class Connection extends Session
|
|||||||
{
|
{
|
||||||
return __CLASS__;
|
return __CLASS__;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sleep function.
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function __sleep()
|
|
||||||
{
|
|
||||||
return ['peer_tag', 'temp_auth_key', 'auth_key', 'session_id', 'session_out_seq_no', 'session_in_seq_no', 'max_incoming_id', 'max_outgoing_id', 'authorized', 'ack_queue'];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -879,6 +879,26 @@ class DataCenter
|
|||||||
{
|
{
|
||||||
return isset($this->sockets[$dc]);
|
return isset($this->sockets[$dc]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if connected to datacenter using HTTP
|
||||||
|
*
|
||||||
|
* @param string $datacenter DC ID
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function isHttp(string $datacenter)
|
||||||
|
{
|
||||||
|
return $this->sockets[$datacenter]->isHttp();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all DCs
|
||||||
|
*
|
||||||
|
* @param boolean $all
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public function get_dcs($all = true)
|
public function get_dcs($all = true)
|
||||||
{
|
{
|
||||||
$test = $this->settings['all']['test_mode'] ? 'test' : 'main';
|
$test = $this->settings['all']['test_mode'] ? 'test' : 'main';
|
||||||
|
@ -22,6 +22,8 @@ use danog\MadelineProto\AuthKey\AuthKey;
|
|||||||
use danog\MadelineProto\AuthKey\PermAuthKey;
|
use danog\MadelineProto\AuthKey\PermAuthKey;
|
||||||
use danog\MadelineProto\AuthKey\TempAuthKey;
|
use danog\MadelineProto\AuthKey\TempAuthKey;
|
||||||
use danog\MadelineProto\Stream\ConnectionContext;
|
use danog\MadelineProto\Stream\ConnectionContext;
|
||||||
|
use danog\MadelineProto\Stream\MTProtoTransport\HttpsStream;
|
||||||
|
use danog\MadelineProto\Stream\MTProtoTransport\HttpStream;
|
||||||
use JsonSerializable;
|
use JsonSerializable;
|
||||||
|
|
||||||
class DataCenterConnection implements JsonSerializable
|
class DataCenterConnection implements JsonSerializable
|
||||||
@ -87,6 +89,19 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
*/
|
*/
|
||||||
private $robinLoop;
|
private $robinLoop;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrement roundrobin weight by this value if busy reading.
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
private $decRead = 1;
|
||||||
|
/**
|
||||||
|
* Decrement roundrobin weight by this value if busy writing.
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
private $decWrite = 10;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get auth key.
|
* Get auth key.
|
||||||
*
|
*
|
||||||
@ -294,15 +309,7 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
for ($x = 0; $x < $count; $x++) {
|
for ($x = 0; $x < $count; $x++) {
|
||||||
$this->availableConnections[$x] = 0;
|
$this->availableConnections[$x] = 0;
|
||||||
$this->connections[$x] = new Connection();
|
$this->connections[$x] = new Connection();
|
||||||
$this->connections[$x]->setExtra(
|
$this->connections[$x]->setExtra($this, $x);
|
||||||
$this,
|
|
||||||
function (bool $reading) use ($x, $incRead) {
|
|
||||||
$this->availableConnections[$x] += $reading ? -$incRead : $incRead;
|
|
||||||
},
|
|
||||||
function (bool $writing) use ($x) {
|
|
||||||
$this->availableConnections[$x] += $writing ? -10 : 10;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
yield $this->connections[$x]->connect($ctx);
|
yield $this->connections[$x]->connect($ctx);
|
||||||
$ctx = $this->ctx->getCtx();
|
$ctx = $this->ctx->getCtx();
|
||||||
}
|
}
|
||||||
@ -380,6 +387,32 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicate that one of the sockets is busy reading.
|
||||||
|
*
|
||||||
|
* @param boolean $reading Whether we're busy reading
|
||||||
|
* @param int $x Connection ID
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function reading(bool $reading, int $x)
|
||||||
|
{
|
||||||
|
$this->availableConnections[$x] += $reading ? -$this->decRead : $this->decRead;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Indicate that one of the sockets is busy writing.
|
||||||
|
*
|
||||||
|
* @param boolean $writing Whether we're busy writing
|
||||||
|
* @param int $x Connection ID
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function writing(bool $writing, int $x)
|
||||||
|
{
|
||||||
|
$this->availableConnections[$x] += $writing ? -$this->decWrite : $this->decWrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set main instance.
|
* Set main instance.
|
||||||
*
|
*
|
||||||
@ -401,6 +434,28 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
{
|
{
|
||||||
return $this->API;
|
return $this->API;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if is an HTTP connection.
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function isHttp()
|
||||||
|
{
|
||||||
|
return \in_array($this->ctx->getStreamName(), [HttpStream::getName(), HttpsStream::getName()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get DC-specific settings
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getSettings(): array
|
||||||
|
{
|
||||||
|
$dc_config_number = isset($this->API->settings['connection_settings'][$this->datacenter]) ? $this->datacenter : 'all';
|
||||||
|
return $this->API->settings['connection_settings'][$dc_config_number];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JSON serialize function.
|
* JSON serialize function.
|
||||||
*
|
*
|
||||||
|
@ -32,7 +32,7 @@ class CheckLoop extends ResumableSignalLoop
|
|||||||
/**
|
/**
|
||||||
* Connection instance.
|
* Connection instance.
|
||||||
*
|
*
|
||||||
* @var \danog\Madelineproto\Connection
|
* @var \danog\MadelineProto\Connection
|
||||||
*/
|
*/
|
||||||
protected $connection;
|
protected $connection;
|
||||||
/**
|
/**
|
||||||
@ -42,12 +42,18 @@ class CheckLoop extends ResumableSignalLoop
|
|||||||
*/
|
*/
|
||||||
protected $datacenter;
|
protected $datacenter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DataCenterConnection instance.
|
||||||
|
*
|
||||||
|
* @var \danog\MadelineProto\DataCenterConnection
|
||||||
|
*/
|
||||||
|
protected $datacenterConnection;
|
||||||
public function __construct(Connection $connection)
|
public function __construct(Connection $connection)
|
||||||
{
|
{
|
||||||
$this->connection = $connection;
|
$this->connection = $connection;
|
||||||
$this->API = $connection->getExtra();
|
$this->API = $connection->getExtra();
|
||||||
$ctx = $connection->getCtx();
|
$this->datacenter = $connection->getDatacenterID();
|
||||||
$this->datacenter = $ctx->getDc();
|
$this->datacenterConnection = $connection->getShared();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loop()
|
public function loop()
|
||||||
@ -55,10 +61,9 @@ class CheckLoop extends ResumableSignalLoop
|
|||||||
$API = $this->API;
|
$API = $this->API;
|
||||||
$datacenter = $this->datacenter;
|
$datacenter = $this->datacenter;
|
||||||
$connection = $this->connection;
|
$connection = $this->connection;
|
||||||
|
$shared = $this->datacenterConnection;
|
||||||
|
|
||||||
$dc_config_number = isset($API->settings['connection_settings'][$datacenter]) ? $datacenter : 'all';
|
$timeout = $shared->getSettings()['timeout'];
|
||||||
|
|
||||||
$timeout = $API->settings['connection_settings'][$dc_config_number]['timeout'];
|
|
||||||
while (true) {
|
while (true) {
|
||||||
while (empty($connection->new_outgoing)) {
|
while (empty($connection->new_outgoing)) {
|
||||||
if (yield $this->waitSignal($this->pause())) {
|
if (yield $this->waitSignal($this->pause())) {
|
||||||
@ -70,7 +75,7 @@ class CheckLoop extends ResumableSignalLoop
|
|||||||
$last_msgid = $connection->get_max_id(true);
|
$last_msgid = $connection->get_max_id(true);
|
||||||
$last_chunk = $connection->getLastChunk();
|
$last_chunk = $connection->getLastChunk();
|
||||||
|
|
||||||
if ($connection->temp_auth_key !== null) {
|
if ($shared->hasTempAuthKey()) {
|
||||||
$full_message_ids = $connection->getPendingCalls(); //array_values($connection->new_outgoing);
|
$full_message_ids = $connection->getPendingCalls(); //array_values($connection->new_outgoing);
|
||||||
foreach (\array_chunk($full_message_ids, 8192) as $message_ids) {
|
foreach (\array_chunk($full_message_ids, 8192) as $message_ids) {
|
||||||
$deferred = new Deferred();
|
$deferred = new Deferred();
|
||||||
@ -124,7 +129,7 @@ class CheckLoop extends ResumableSignalLoop
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($reply) {
|
if ($reply) {
|
||||||
$this->callFork($API->object_call_async('msg_resend_ans_req', ['msg_ids' => $reply], ['datacenter' => $datacenter, 'postpone' => true]));
|
$this->callFork($connection->object_call_async('msg_resend_ans_req', ['msg_ids' => $reply], ['postpone' => true]));
|
||||||
}
|
}
|
||||||
$connection->writer->resume();
|
$connection->writer->resume();
|
||||||
}
|
}
|
||||||
@ -135,7 +140,7 @@ class CheckLoop extends ResumableSignalLoop
|
|||||||
$list .= $connection->outgoing_messages[$message_id]['_'].', ';
|
$list .= $connection->outgoing_messages[$message_id]['_'].', ';
|
||||||
}
|
}
|
||||||
$API->logger->logger("Still missing $list on DC $datacenter, sending state request", \danog\MadelineProto\Logger::ERROR);
|
$API->logger->logger("Still missing $list on DC $datacenter, sending state request", \danog\MadelineProto\Logger::ERROR);
|
||||||
yield $API->object_call_async('msgs_state_req', ['msg_ids' => $message_ids], ['datacenter' => $datacenter, 'promise' => $deferred]);
|
yield $connection->object_call_async('msgs_state_req', ['msg_ids' => $message_ids], ['promise' => $deferred]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
foreach ($connection->new_outgoing as $message_id) {
|
foreach ($connection->new_outgoing as $message_id) {
|
||||||
|
@ -33,7 +33,7 @@ class HttpWaitLoop extends ResumableSignalLoop
|
|||||||
/**
|
/**
|
||||||
* Connection instance.
|
* Connection instance.
|
||||||
*
|
*
|
||||||
* @var \danog\Madelineproto\Connection
|
* @var \danog\MadelineProto\Connection
|
||||||
*/
|
*/
|
||||||
protected $connection;
|
protected $connection;
|
||||||
/**
|
/**
|
||||||
@ -43,12 +43,20 @@ class HttpWaitLoop extends ResumableSignalLoop
|
|||||||
*/
|
*/
|
||||||
protected $datacenter;
|
protected $datacenter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DataCenterConnection instance.
|
||||||
|
*
|
||||||
|
* @var \danog\MadelineProto\DataCenterConnection
|
||||||
|
*/
|
||||||
|
protected $datacenterConnection;
|
||||||
|
|
||||||
public function __construct(Connection $connection)
|
public function __construct(Connection $connection)
|
||||||
{
|
{
|
||||||
$this->connection = $connection;
|
$this->connection = $connection;
|
||||||
$this->API = $connection->getExtra();
|
$this->API = $connection->getExtra();
|
||||||
$ctx = $connection->getCtx();
|
$ctx = $connection->getCtx();
|
||||||
$this->datacenter = $ctx->getDc();
|
$this->datacenter = $connection->getDatacenterID();
|
||||||
|
$this->datacenterConnection = $connection->getShared();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loop()
|
public function loop()
|
||||||
@ -56,12 +64,12 @@ class HttpWaitLoop extends ResumableSignalLoop
|
|||||||
$API = $this->API;
|
$API = $this->API;
|
||||||
$datacenter = $this->datacenter;
|
$datacenter = $this->datacenter;
|
||||||
$connection = $this->connection;
|
$connection = $this->connection;
|
||||||
|
$shared = $this->datacenterConnection;
|
||||||
|
|
||||||
if (!\in_array($connection->getCtx()->getStreamName(), [HttpStream::getName(), HttpsStream::getName()])) {
|
if (!$shared->isHttp()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$timeout = $API->settings['connection_settings'][isset($API->settings['connection_settings'][$datacenter]) ? $datacenter : 'all']['timeout'];
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (yield $this->waitSignal($this->pause())) {
|
if (yield $this->waitSignal($this->pause())) {
|
||||||
return;
|
return;
|
||||||
@ -69,7 +77,7 @@ class HttpWaitLoop extends ResumableSignalLoop
|
|||||||
if (!\in_array($connection->getCtx()->getStreamName(), [HttpStream::getName(), HttpsStream::getName()])) {
|
if (!\in_array($connection->getCtx()->getStreamName(), [HttpStream::getName(), HttpsStream::getName()])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while ($connection->temp_auth_key === null) {
|
while (!$shared->hasTempAuthKey()) {
|
||||||
if (yield $this->waitSignal($this->pause())) {
|
if (yield $this->waitSignal($this->pause())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -42,9 +42,15 @@ class ReadLoop extends SignalLoop
|
|||||||
/**
|
/**
|
||||||
* Connection instance.
|
* Connection instance.
|
||||||
*
|
*
|
||||||
* @var \danog\Madelineproto\Connection
|
* @var \danog\MadelineProto\Connection
|
||||||
*/
|
*/
|
||||||
protected $connection;
|
protected $connection;
|
||||||
|
/**
|
||||||
|
* DataCenterConnection instance.
|
||||||
|
*
|
||||||
|
* @var \danog\MadelineProto\DataCenterConnection
|
||||||
|
*/
|
||||||
|
protected $datacenterConnection;
|
||||||
/**
|
/**
|
||||||
* DC ID.
|
* DC ID.
|
||||||
*
|
*
|
||||||
@ -57,7 +63,8 @@ class ReadLoop extends SignalLoop
|
|||||||
$this->connection = $connection;
|
$this->connection = $connection;
|
||||||
$this->API = $connection->getExtra();
|
$this->API = $connection->getExtra();
|
||||||
$ctx = $connection->getCtx();
|
$ctx = $connection->getCtx();
|
||||||
$this->datacenter = $ctx->getDc();
|
$this->datacenter = $connection->getDatacenterID();
|
||||||
|
$this->datacenterConnection = $connection->getShared();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loop()
|
public function loop()
|
||||||
@ -65,8 +72,8 @@ class ReadLoop extends SignalLoop
|
|||||||
$API = $this->API;
|
$API = $this->API;
|
||||||
$datacenter = $this->datacenter;
|
$datacenter = $this->datacenter;
|
||||||
$connection = $this->connection;
|
$connection = $this->connection;
|
||||||
|
$shared = $this->datacenterConnection;
|
||||||
|
|
||||||
//$timeout = $API->settings['connection_settings'][isset($API->settings['connection_settings'][$datacenter]) ? $datacenter : 'all']['timeout'];
|
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
$error = yield $this->waitSignal($this->readMessage());
|
$error = yield $this->waitSignal($this->readMessage());
|
||||||
@ -84,14 +91,14 @@ class ReadLoop extends SignalLoop
|
|||||||
$this->exitedLoop();
|
$this->exitedLoop();
|
||||||
|
|
||||||
if ($error === -404) {
|
if ($error === -404) {
|
||||||
if ($connection->temp_auth_key !== null) {
|
if ($shared->getTemp) {
|
||||||
$API->logger->logger("WARNING: Resetting auth key in DC {$datacenter}...", \danog\MadelineProto\Logger::WARNING);
|
$API->logger->logger("WARNING: Resetting auth key in DC {$datacenter}...", \danog\MadelineProto\Logger::WARNING);
|
||||||
$connection->temp_auth_key = null;
|
$shared->setTempAuthKey(null);
|
||||||
$connection->session_id = null;
|
$connection->session_id = null;
|
||||||
foreach ($connection->new_outgoing as $message_id) {
|
foreach ($connection->new_outgoing as $message_id) {
|
||||||
$connection->outgoing_messages[$message_id]['sent'] = 0;
|
$connection->outgoing_messages[$message_id]['sent'] = 0;
|
||||||
}
|
}
|
||||||
yield $connection->reconnect();
|
yield $shared->reconnect();
|
||||||
yield $API->init_authorization_async();
|
yield $API->init_authorization_async();
|
||||||
} else {
|
} else {
|
||||||
yield $connection->reconnect();
|
yield $connection->reconnect();
|
||||||
@ -115,7 +122,7 @@ class ReadLoop extends SignalLoop
|
|||||||
|
|
||||||
Loop::defer([$connection, 'handle_messages']);
|
Loop::defer([$connection, 'handle_messages']);
|
||||||
|
|
||||||
if ($this->API->is_http($datacenter)) {
|
if ($shared->isHttp()) {
|
||||||
Loop::defer([$connection->waiter, 'resume']);
|
Loop::defer([$connection->waiter, 'resume']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,6 +133,8 @@ class ReadLoop extends SignalLoop
|
|||||||
$API = $this->API;
|
$API = $this->API;
|
||||||
$datacenter = $this->datacenter;
|
$datacenter = $this->datacenter;
|
||||||
$connection = $this->connection;
|
$connection = $this->connection;
|
||||||
|
$shared = $this->datacenterConnection;
|
||||||
|
|
||||||
if (isset($this->connection->old)) {
|
if (isset($this->connection->old)) {
|
||||||
$API->logger->logger('Not reading because connection is old');
|
$API->logger->logger('Not reading because connection is old');
|
||||||
|
|
||||||
@ -152,84 +161,89 @@ class ReadLoop extends SignalLoop
|
|||||||
|
|
||||||
return $payload;
|
return $payload;
|
||||||
}
|
}
|
||||||
$auth_key_id = yield $buffer->bufferRead(8);
|
|
||||||
|
|
||||||
if ($auth_key_id === "\0\0\0\0\0\0\0\0") {
|
$connection->reading(true);
|
||||||
$message_id = yield $buffer->bufferRead(8);
|
try {
|
||||||
if (!\in_array($message_id, [1, 0])) {
|
$auth_key_id = yield $buffer->bufferRead(8);
|
||||||
$connection->check_message_id($message_id, ['outgoing' => false, 'container' => false]);
|
|
||||||
}
|
if ($auth_key_id === "\0\0\0\0\0\0\0\0") {
|
||||||
$message_length = \unpack('V', yield $buffer->bufferRead(4))[1];
|
$message_id = yield $buffer->bufferRead(8);
|
||||||
$message_data = yield $buffer->bufferRead($message_length);
|
if (!\in_array($message_id, [1, 0])) {
|
||||||
$left = $payload_length - $message_length - 4 - 8 - 8;
|
$connection->check_message_id($message_id, ['outgoing' => false, 'container' => false]);
|
||||||
if ($left) {
|
|
||||||
$API->logger->logger('Padded unencrypted message', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
|
||||||
if ($left < (-$message_length & 15)) {
|
|
||||||
$API->logger->logger('Protocol padded unencrypted message', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
|
||||||
}
|
}
|
||||||
yield $buffer->bufferRead($left);
|
$message_length = \unpack('V', yield $buffer->bufferRead(4))[1];
|
||||||
}
|
$message_data = yield $buffer->bufferRead($message_length);
|
||||||
$connection->incoming_messages[$message_id] = [];
|
$left = $payload_length - $message_length - 4 - 8 - 8;
|
||||||
} elseif ($auth_key_id === $connection->temp_auth_key['id']) {
|
if ($left) {
|
||||||
$message_key = yield $buffer->bufferRead(16);
|
$API->logger->logger('Padded unencrypted message', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $connection->temp_auth_key['auth_key'], false);
|
if ($left < (-$message_length & 15)) {
|
||||||
$encrypted_data = yield $buffer->bufferRead($payload_length - 24);
|
$API->logger->logger('Protocol padded unencrypted message', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
|
}
|
||||||
|
yield $buffer->bufferRead($left);
|
||||||
|
}
|
||||||
|
$connection->incoming_messages[$message_id] = [];
|
||||||
|
} elseif ($auth_key_id === $shared->getTempAuthKey()->getID()) {
|
||||||
|
$message_key = yield $buffer->bufferRead(16);
|
||||||
|
list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $shared->getTempAuthKey()->getAuthKey(), false);
|
||||||
|
$encrypted_data = yield $buffer->bufferRead($payload_length - 24);
|
||||||
|
|
||||||
$protocol_padding = \strlen($encrypted_data) % 16;
|
$protocol_padding = \strlen($encrypted_data) % 16;
|
||||||
if ($protocol_padding) {
|
if ($protocol_padding) {
|
||||||
$encrypted_data = \substr($encrypted_data, 0, -$protocol_padding);
|
$encrypted_data = \substr($encrypted_data, 0, -$protocol_padding);
|
||||||
}
|
}
|
||||||
$decrypted_data = $this->ige_decrypt($encrypted_data, $aes_key, $aes_iv);
|
$decrypted_data = $this->ige_decrypt($encrypted_data, $aes_key, $aes_iv);
|
||||||
/*
|
/*
|
||||||
$server_salt = substr($decrypted_data, 0, 8);
|
$server_salt = substr($decrypted_data, 0, 8);
|
||||||
if ($server_salt != $connection->temp_auth_key['server_salt']) {
|
if ($server_salt != $shared->getTempAuthKey()->getServerSalt()) {
|
||||||
$API->logger->logger('WARNING: Server salt mismatch (my server salt '.$connection->temp_auth_key['server_salt'].' is not equal to server server salt '.$server_salt.').', \danog\MadelineProto\Logger::WARNING);
|
$API->logger->logger('WARNING: Server salt mismatch (my server salt '.$shared->getTempAuthKey()->getServerSalt().' is not equal to server server salt '.$server_salt.').', \danog\MadelineProto\Logger::WARNING);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
$session_id = \substr($decrypted_data, 8, 8);
|
$session_id = \substr($decrypted_data, 8, 8);
|
||||||
if ($session_id != $connection->session_id) {
|
if ($session_id != $connection->session_id) {
|
||||||
throw new \danog\MadelineProto\Exception('Session id mismatch.');
|
throw new \danog\MadelineProto\Exception('Session id mismatch.');
|
||||||
}
|
}
|
||||||
$message_id = \substr($decrypted_data, 16, 8);
|
$message_id = \substr($decrypted_data, 16, 8);
|
||||||
$connection->check_message_id($message_id, ['outgoing' => false, 'container' => false]);
|
$connection->check_message_id($message_id, ['outgoing' => false, 'container' => false]);
|
||||||
$seq_no = \unpack('V', \substr($decrypted_data, 24, 4))[1];
|
$seq_no = \unpack('V', \substr($decrypted_data, 24, 4))[1];
|
||||||
|
|
||||||
$message_data_length = \unpack('V', \substr($decrypted_data, 28, 4))[1];
|
$message_data_length = \unpack('V', \substr($decrypted_data, 28, 4))[1];
|
||||||
if ($message_data_length > \strlen($decrypted_data)) {
|
if ($message_data_length > \strlen($decrypted_data)) {
|
||||||
throw new \danog\MadelineProto\SecurityException('message_data_length is too big');
|
throw new \danog\MadelineProto\SecurityException('message_data_length is too big');
|
||||||
}
|
}
|
||||||
if (\strlen($decrypted_data) - 32 - $message_data_length < 12) {
|
if (\strlen($decrypted_data) - 32 - $message_data_length < 12) {
|
||||||
throw new \danog\MadelineProto\SecurityException('padding is too small');
|
throw new \danog\MadelineProto\SecurityException('padding is too small');
|
||||||
}
|
}
|
||||||
if (\strlen($decrypted_data) - 32 - $message_data_length > 1024) {
|
if (\strlen($decrypted_data) - 32 - $message_data_length > 1024) {
|
||||||
throw new \danog\MadelineProto\SecurityException('padding is too big');
|
throw new \danog\MadelineProto\SecurityException('padding is too big');
|
||||||
}
|
}
|
||||||
if ($message_data_length < 0) {
|
if ($message_data_length < 0) {
|
||||||
throw new \danog\MadelineProto\SecurityException('message_data_length not positive');
|
throw new \danog\MadelineProto\SecurityException('message_data_length not positive');
|
||||||
}
|
}
|
||||||
if ($message_data_length % 4 != 0) {
|
if ($message_data_length % 4 != 0) {
|
||||||
throw new \danog\MadelineProto\SecurityException('message_data_length not divisible by 4');
|
throw new \danog\MadelineProto\SecurityException('message_data_length not divisible by 4');
|
||||||
}
|
}
|
||||||
$message_data = \substr($decrypted_data, 32, $message_data_length);
|
$message_data = \substr($decrypted_data, 32, $message_data_length);
|
||||||
if ($message_key != \substr(\hash('sha256', \substr($connection->temp_auth_key['auth_key'], 96, 32).$decrypted_data, true), 8, 16)) {
|
if ($message_key != \substr(\hash('sha256', \substr($shared->getTempAuthKey()->getAuthKey(), 96, 32).$decrypted_data, true), 8, 16)) {
|
||||||
throw new \danog\MadelineProto\SecurityException('msg_key mismatch');
|
throw new \danog\MadelineProto\SecurityException('msg_key mismatch');
|
||||||
}
|
}
|
||||||
$connection->incoming_messages[$message_id] = ['seq_no' => $seq_no];
|
$connection->incoming_messages[$message_id] = ['seq_no' => $seq_no];
|
||||||
} else {
|
} else {
|
||||||
$API->logger->logger('Got unknown auth_key id', \danog\MadelineProto\Logger::ERROR);
|
$API->logger->logger('Got unknown auth_key id', \danog\MadelineProto\Logger::ERROR);
|
||||||
|
|
||||||
return -404;
|
return -404;
|
||||||
|
}
|
||||||
|
$deserialized = $API->deserialize($message_data, ['type' => '', 'connection' => $connection]);
|
||||||
|
$API->referenceDatabase->reset();
|
||||||
|
|
||||||
|
$connection->incoming_messages[$message_id]['content'] = $deserialized;
|
||||||
|
$connection->incoming_messages[$message_id]['response'] = -1;
|
||||||
|
$connection->new_incoming[$message_id] = $message_id;
|
||||||
|
//$connection->last_http_wait = 0;
|
||||||
|
|
||||||
|
$API->logger->logger('Received payload from DC '.$datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
|
} finally {
|
||||||
|
$connection->reading(false);
|
||||||
}
|
}
|
||||||
$deserialized = $API->deserialize($message_data, ['type' => '', 'datacenter' => $datacenter]);
|
|
||||||
$API->referenceDatabase->reset();
|
|
||||||
|
|
||||||
$connection->incoming_messages[$message_id]['content'] = $deserialized;
|
|
||||||
$connection->incoming_messages[$message_id]['response'] = -1;
|
|
||||||
$connection->new_incoming[$message_id] = $message_id;
|
|
||||||
//$connection->last_http_wait = 0;
|
|
||||||
|
|
||||||
$API->logger->logger('Received payload from DC '.$datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,9 +39,15 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
/**
|
/**
|
||||||
* Connection instance.
|
* Connection instance.
|
||||||
*
|
*
|
||||||
* @var \danog\Madelineproto\Connection
|
* @var \danog\MadelineProto\Connection
|
||||||
*/
|
*/
|
||||||
protected $connection;
|
protected $connection;
|
||||||
|
/**
|
||||||
|
* DataCenterConnection instance.
|
||||||
|
*
|
||||||
|
* @var \danog\MadelineProto\DataCenterConnection
|
||||||
|
*/
|
||||||
|
protected $datacenterConnection;
|
||||||
/**
|
/**
|
||||||
* DC ID.
|
* DC ID.
|
||||||
*
|
*
|
||||||
@ -52,15 +58,17 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
public function __construct(Connection $connection)
|
public function __construct(Connection $connection)
|
||||||
{
|
{
|
||||||
$this->connection = $connection;
|
$this->connection = $connection;
|
||||||
|
$this->datacenterConnection = $connection->getShared();
|
||||||
$this->API = $connection->getExtra();
|
$this->API = $connection->getExtra();
|
||||||
$ctx = $connection->getCtx();
|
$ctx = $connection->getCtx();
|
||||||
$this->datacenter = $ctx->getDc();
|
$this->datacenter = $connection->getDatacenterID();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loop(): \Generator
|
public function loop(): \Generator
|
||||||
{
|
{
|
||||||
$API = $this->API;
|
$API = $this->API;
|
||||||
$connection = $this->connection;
|
$connection = $this->connection;
|
||||||
|
$shared = $this->datacenterConnection;
|
||||||
$datacenter = $this->datacenter;
|
$datacenter = $this->datacenter;
|
||||||
|
|
||||||
$please_wait = false;
|
$please_wait = false;
|
||||||
@ -74,8 +82,9 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
$API->logger->logger("Done waiting in $this", Logger::ULTRA_VERBOSE);
|
$API->logger->logger("Done waiting in $this", Logger::ULTRA_VERBOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$connection->writing(true);
|
||||||
try {
|
try {
|
||||||
$please_wait = yield $this->{$connection->temp_auth_key === null ? 'unencryptedWriteLoopAsync' : 'encryptedWriteLoopAsync'}();
|
$please_wait = yield $this->{$shared->hasTempAuthKey() ? 'encryptedWriteLoopAsync' : 'unencryptedWriteLoopAsync'}();
|
||||||
} catch (StreamException $e) {
|
} catch (StreamException $e) {
|
||||||
if (isset($connection->old)) {
|
if (isset($connection->old)) {
|
||||||
return;
|
return;
|
||||||
@ -84,6 +93,8 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
$API->logger->logger("Got nothing in the socket in DC {$datacenter}, reconnecting...", Logger::ERROR);
|
$API->logger->logger("Got nothing in the socket in DC {$datacenter}, reconnecting...", Logger::ERROR);
|
||||||
yield $connection->reconnect();
|
yield $connection->reconnect();
|
||||||
continue;
|
continue;
|
||||||
|
} finally {
|
||||||
|
$connection->writing(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//$connection->waiter->resume();
|
//$connection->waiter->resume();
|
||||||
@ -95,11 +106,12 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
$API = $this->API;
|
$API = $this->API;
|
||||||
$datacenter = $this->datacenter;
|
$datacenter = $this->datacenter;
|
||||||
$connection = $this->connection;
|
$connection = $this->connection;
|
||||||
|
$shared = $this->datacenterConnection;
|
||||||
|
|
||||||
while ($connection->pending_outgoing) {
|
while ($connection->pending_outgoing) {
|
||||||
$skipped_all = true;
|
$skipped_all = true;
|
||||||
foreach ($connection->pending_outgoing as $k => $message) {
|
foreach ($connection->pending_outgoing as $k => $message) {
|
||||||
if ($connection->temp_auth_key !== null) {
|
if ($shared->hasTempAuthKey()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!$message['unencrypted']) {
|
if (!$message['unencrypted']) {
|
||||||
@ -146,13 +158,13 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
$API = $this->API;
|
$API = $this->API;
|
||||||
$datacenter = $this->datacenter;
|
$datacenter = $this->datacenter;
|
||||||
$connection = $this->connection;
|
$connection = $this->connection;
|
||||||
$dc_config_number = isset($API->settings['connection_settings'][$datacenter]) ? $datacenter : 'all';
|
$shared = $this->datacenterConnection;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if ($connection->temp_auth_key === null) {
|
if (!$shared->hasTempAuthKey()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($this->API->is_http($datacenter) && empty($connection->pending_outgoing)) {
|
if ($shared->isHttp() && empty($connection->pending_outgoing)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (\count($to_ack = $connection->ack_queue)) {
|
if (\count($to_ack = $connection->ack_queue)) {
|
||||||
@ -172,7 +184,7 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($API->is_http($datacenter) && !$has_http_wait) {
|
if ($shared->isHttp() && !$has_http_wait) {
|
||||||
$connection->pending_outgoing[$connection->pending_outgoing_key++] = ['_' => 'http_wait', 'serialized_body' => yield $this->API->serialize_object_async(['type' => ''], ['_' => 'http_wait', 'max_wait' => 30000, 'wait_after' => 0, 'max_delay' => 0], 'http_wait'), 'content_related' => true, 'unencrypted' => false, 'method' => true];
|
$connection->pending_outgoing[$connection->pending_outgoing_key++] = ['_' => 'http_wait', 'serialized_body' => yield $this->API->serialize_object_async(['type' => ''], ['_' => 'http_wait', 'max_wait' => 30000, 'wait_after' => 0, 'max_delay' => 0], 'http_wait'), 'content_related' => true, 'unencrypted' => false, 'method' => true];
|
||||||
$connection->pending_outgoing_key %= Connection::PENDING_MAX;
|
$connection->pending_outgoing_key %= Connection::PENDING_MAX;
|
||||||
$has_http_wait = true;
|
$has_http_wait = true;
|
||||||
@ -190,7 +202,7 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
unset($connection->pending_outgoing[$k]);
|
unset($connection->pending_outgoing[$k]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($API->settings['connection_settings'][$dc_config_number]['pfs'] && !isset($connection->temp_auth_key['bound']) && !\strpos($datacenter, 'cdn') && !\in_array($message['_'], ['http_wait', 'auth.bindTempAuthKey']) && $message['method']) {
|
if ($shared->getSettings()['pfs'] && !$shared->getTempAuthKey()->isBound() && !$shared->getCtx()->isCDN() && !\in_array($message['_'], ['http_wait', 'auth.bindTempAuthKey']) && $message['method']) {
|
||||||
$API->logger->logger("Skipping {$message['_']} due to unbound keys in DC {$datacenter}");
|
$API->logger->logger("Skipping {$message['_']} due to unbound keys in DC {$datacenter}");
|
||||||
$skipped = true;
|
$skipped = true;
|
||||||
continue;
|
continue;
|
||||||
@ -202,14 +214,14 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$message_id = isset($message['msg_id']) ? $message['msg_id'] : $connection->generate_message_id($datacenter);
|
$message_id = isset($message['msg_id']) ? $message['msg_id'] : $connection->generate_message_id();
|
||||||
|
|
||||||
$API->logger->logger("Sending {$message['_']} as encrypted message to DC {$datacenter}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$API->logger->logger("Sending {$message['_']} as encrypted message to DC {$datacenter}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
|
|
||||||
$MTmessage = ['_' => 'MTmessage', 'msg_id' => $message_id, 'body' => $message['serialized_body'], 'seqno' => $connection->generate_out_seq_no($message['content_related'])];
|
$MTmessage = ['_' => 'MTmessage', 'msg_id' => $message_id, 'body' => $message['serialized_body'], 'seqno' => $connection->generate_out_seq_no($message['content_related'])];
|
||||||
|
|
||||||
if (isset($message['method']) && $message['method'] && $message['_'] !== 'http_wait') {
|
if (isset($message['method']) && $message['method'] && $message['_'] !== 'http_wait') {
|
||||||
if ((!isset($connection->temp_auth_key['connection_inited']) || $connection->temp_auth_key['connection_inited'] === false) && $message['_'] !== 'auth.bindTempAuthKey') {
|
if (!$shared->getTempAuthKey()->isInited() && $message['_'] !== 'auth.bindTempAuthKey') {
|
||||||
$API->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['write_client_info'], $message['_']), \danog\MadelineProto\Logger::NOTICE);
|
$API->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['write_client_info'], $message['_']), \danog\MadelineProto\Logger::NOTICE);
|
||||||
$MTmessage['body'] = yield $API->serialize_method_async(
|
$MTmessage['body'] = yield $API->serialize_method_async(
|
||||||
'invokeWithLayer',
|
'invokeWithLayer',
|
||||||
@ -220,8 +232,8 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
[
|
[
|
||||||
'api_id' => $API->settings['app_info']['api_id'],
|
'api_id' => $API->settings['app_info']['api_id'],
|
||||||
'api_hash' => $API->settings['app_info']['api_hash'],
|
'api_hash' => $API->settings['app_info']['api_hash'],
|
||||||
'device_model' => \strpos($datacenter, 'cdn') === false ? $API->settings['app_info']['device_model'] : 'n/a',
|
'device_model' => !$connection->getCtx()->isCDN() ? $API->settings['app_info']['device_model'] : 'n/a',
|
||||||
'system_version' => \strpos($datacenter, 'cdn') === false ? $API->settings['app_info']['system_version'] : 'n/a',
|
'system_version' => !$connection->getCtx()->isCDN() ? $API->settings['app_info']['system_version'] : 'n/a',
|
||||||
'app_version' => $API->settings['app_info']['app_version'],
|
'app_version' => $API->settings['app_info']['app_version'],
|
||||||
'system_lang_code' => $API->settings['app_info']['lang_code'],
|
'system_lang_code' => $API->settings['app_info']['lang_code'],
|
||||||
'lang_code' => $API->settings['app_info']['lang_code'],
|
'lang_code' => $API->settings['app_info']['lang_code'],
|
||||||
@ -274,7 +286,7 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
if ($count > 1) {
|
if ($count > 1) {
|
||||||
$API->logger->logger("Wrapping in msg_container ($count messages of total size $total_length) as encrypted message for DC {$datacenter}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$API->logger->logger("Wrapping in msg_container ($count messages of total size $total_length) as encrypted message for DC {$datacenter}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
|
|
||||||
$message_id = $connection->generate_message_id($datacenter);
|
$message_id = $connection->generate_message_id();
|
||||||
$connection->pending_outgoing[$connection->pending_outgoing_key] = ['_' => 'msg_container', 'container' => \array_values($keys), 'content_related' => false, 'method' => false, 'unencrypted' => false];
|
$connection->pending_outgoing[$connection->pending_outgoing_key] = ['_' => 'msg_container', 'container' => \array_values($keys), 'content_related' => false, 'method' => false, 'unencrypted' => false];
|
||||||
|
|
||||||
//var_dumP("container ".bin2hex($message_id));
|
//var_dumP("container ".bin2hex($message_id));
|
||||||
@ -299,19 +311,19 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
|
|
||||||
unset($messages);
|
unset($messages);
|
||||||
|
|
||||||
$plaintext = $connection->temp_auth_key['server_salt'].$connection->session_id.$message_id.\pack('VV', $seq_no, $message_data_length).$message_data;
|
$plaintext = $shared->getTempAuthKey()->getServerSalt().$connection->session_id.$message_id.\pack('VV', $seq_no, $message_data_length).$message_data;
|
||||||
$padding = $this->posmod(-\strlen($plaintext), 16);
|
$padding = $this->posmod(-\strlen($plaintext), 16);
|
||||||
if ($padding < 12) {
|
if ($padding < 12) {
|
||||||
$padding += 16;
|
$padding += 16;
|
||||||
}
|
}
|
||||||
$padding = $this->random($padding);
|
$padding = $this->random($padding);
|
||||||
$message_key = \substr(\hash('sha256', \substr($connection->temp_auth_key['auth_key'], 88, 32).$plaintext.$padding, true), 8, 16);
|
$message_key = \substr(\hash('sha256', \substr($shared->getTempAuthKey()->getAuthKey(), 88, 32).$plaintext.$padding, true), 8, 16);
|
||||||
list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $connection->temp_auth_key['auth_key']);
|
list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $shared->getTempAuthKey()->getAuthKey());
|
||||||
$message = $connection->temp_auth_key['id'].$message_key.$this->ige_encrypt($plaintext.$padding, $aes_key, $aes_iv);
|
$message = $shared->getTempAuthKey()->getID().$message_key.$this->ige_encrypt($plaintext.$padding, $aes_key, $aes_iv);
|
||||||
|
|
||||||
$buffer = yield $connection->stream->getWriteBuffer($len = \strlen($message));
|
$buffer = yield $connection->stream->getWriteBuffer($len = \strlen($message));
|
||||||
|
|
||||||
$t = \microtime(true);
|
//$t = \microtime(true);
|
||||||
yield $buffer->bufferWrite($message);
|
yield $buffer->bufferWrite($message);
|
||||||
|
|
||||||
$connection->httpSent();
|
$connection->httpSent();
|
||||||
|
@ -1147,9 +1147,16 @@ class MTProto extends AsyncConstruct implements TLCallback
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function is_http($datacenter)
|
/**
|
||||||
|
* Check if connected to datacenter using HTTP
|
||||||
|
*
|
||||||
|
* @param string $datacenter DC ID
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function isHttp(string $datacenter)
|
||||||
{
|
{
|
||||||
return \in_array($this->datacenter->getDataCenterConection($datacenter)->getCtx()->getStreamName(), [HttpStream::getName(), HttpsStream::getName()]);
|
return $this->datacenter->isHttp($datacenter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connects to all datacenters and if necessary creates authorization keys, binds them and writes client info
|
// Connects to all datacenters and if necessary creates authorization keys, binds them and writes client info
|
||||||
|
@ -16,14 +16,14 @@
|
|||||||
* @link https://docs.madelineproto.xyz MadelineProto documentation
|
* @link https://docs.madelineproto.xyz MadelineProto documentation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace danog\MadelineProto\AuthKey;
|
namespace danog\MadelineProto\MTProto;
|
||||||
|
|
||||||
use JsonSerializable;
|
use JsonSerializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MTProto auth key.
|
* MTProto auth key.
|
||||||
*/
|
*/
|
||||||
abstract class AuthKey extends JsonSerializable
|
abstract class AuthKey implements JsonSerializable
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Auth key.
|
* Auth key.
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
* @link https://docs.madelineproto.xyz MadelineProto documentation
|
* @link https://docs.madelineproto.xyz MadelineProto documentation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace danog\MadelineProto\AuthKey;
|
namespace danog\MadelineProto\MTProto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MTProto permanent auth key.
|
* MTProto permanent auth key.
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
* @link https://docs.madelineproto.xyz MadelineProto documentation
|
* @link https://docs.madelineproto.xyz MadelineProto documentation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace danog\MadelineProto\AuthKey;
|
namespace danog\MadelineProto\MTProto;
|
||||||
|
|
||||||
use JsonSerializable;
|
use JsonSerializable;
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ namespace danog\MadelineProto\MTProtoSession;
|
|||||||
*/
|
*/
|
||||||
trait AckHandler
|
trait AckHandler
|
||||||
{
|
{
|
||||||
public function ack_outgoing_message_id($message_id)
|
public function ack_outgoing_message_id($message_id): bool
|
||||||
{
|
{
|
||||||
// The server acknowledges that it received my message
|
// The server acknowledges that it received my message
|
||||||
if (!isset($this->outgoing_messages[$message_id])) {
|
if (!isset($this->outgoing_messages[$message_id])) {
|
||||||
@ -43,7 +43,7 @@ trait AckHandler
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function got_response_for_outgoing_message_id($message_id)
|
public function got_response_for_outgoing_message_id($message_id): bool
|
||||||
{
|
{
|
||||||
// The server acknowledges that it received my message
|
// The server acknowledges that it received my message
|
||||||
if (!isset($this->outgoing_messages[$message_id])) {
|
if (!isset($this->outgoing_messages[$message_id])) {
|
||||||
@ -64,7 +64,7 @@ trait AckHandler
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function ack_incoming_message_id($message_id)
|
public function ack_incoming_message_id($message_id): bool
|
||||||
{
|
{
|
||||||
// I let the server know that I received its message
|
// I let the server know that I received its message
|
||||||
if (!isset($this->incoming_messages[$message_id])) {
|
if (!isset($this->incoming_messages[$message_id])) {
|
||||||
@ -83,26 +83,23 @@ trait AckHandler
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if there are some pending calls
|
* Check if there are some pending calls.
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function hasPendingCalls()
|
public function hasPendingCalls(): bool
|
||||||
{
|
{
|
||||||
$API = $this->API;
|
$settings = $this->shared->getSettings();
|
||||||
$datacenter = $this->datacenter;
|
$timeout = $settings['timeout'];
|
||||||
|
$pfs = $settings['pfs'];
|
||||||
$dc_config_number = isset($API->settings['connection_settings'][$datacenter]) ? $datacenter : 'all';
|
|
||||||
$timeout = $API->settings['connection_settings'][$dc_config_number]['timeout'];
|
|
||||||
$pfs = $API->settings['connection_settings'][$dc_config_number]['pfs'];
|
|
||||||
|
|
||||||
foreach ($this->new_outgoing as $message_id) {
|
foreach ($this->new_outgoing as $message_id) {
|
||||||
if (isset($this->outgoing_messages[$message_id]['sent'])
|
if (isset($this->outgoing_messages[$message_id]['sent'])
|
||||||
&& $this->outgoing_messages[$message_id]['sent'] + $timeout < \time()
|
&& $this->outgoing_messages[$message_id]['sent'] + $timeout < \time()
|
||||||
&& ($this->temp_auth_key === null) === $this->outgoing_messages[$message_id]['unencrypted']
|
&& $this->shared->hasTempAuthKey() === !$this->outgoing_messages[$message_id]['unencrypted']
|
||||||
&& $this->outgoing_messages[$message_id]['_'] !== 'msgs_state_req'
|
&& $this->outgoing_messages[$message_id]['_'] !== 'msgs_state_req'
|
||||||
) {
|
) {
|
||||||
if ($pfs && !isset($this->temp_auth_key['bound']) && $this->outgoing_messages[$message_id]['_'] !== 'auth.bindTempAuthKey') {
|
if ($pfs && !$this->shared->getTempAuthKey()->bound() && $this->outgoing_messages[$message_id]['_'] !== 'auth.bindTempAuthKey') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,27 +111,24 @@ trait AckHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all pending calls
|
* Get all pending calls.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getPendingCalls()
|
public function getPendingCalls(): array
|
||||||
{
|
{
|
||||||
$API = $this->API;
|
$settings = $this->shared->getSettings();
|
||||||
$datacenter = $this->datacenter;
|
$timeout = $settings['timeout'];
|
||||||
|
$pfs = $settings['pfs'];
|
||||||
$dc_config_number = isset($API->settings['connection_settings'][$datacenter]) ? $datacenter : 'all';
|
|
||||||
$timeout = $API->settings['connection_settings'][$dc_config_number]['timeout'];
|
|
||||||
$pfs = $API->settings['connection_settings'][$dc_config_number]['pfs'];
|
|
||||||
|
|
||||||
$result = [];
|
$result = [];
|
||||||
foreach ($this->new_outgoing as $message_id) {
|
foreach ($this->new_outgoing as $message_id) {
|
||||||
if (isset($this->outgoing_messages[$message_id]['sent'])
|
if (isset($this->outgoing_messages[$message_id]['sent'])
|
||||||
&& $this->outgoing_messages[$message_id]['sent'] + $timeout < \time()
|
&& $this->outgoing_messages[$message_id]['sent'] + $timeout < \time()
|
||||||
&& ($this->temp_auth_key === null) === $this->outgoing_messages[$message_id]['unencrypted']
|
&& $this->shared->hasTempAuthKey() === !$this->outgoing_messages[$message_id]['unencrypted']
|
||||||
&& $this->outgoing_messages[$message_id]['_'] !== 'msgs_state_req'
|
&& $this->outgoing_messages[$message_id]['_'] !== 'msgs_state_req'
|
||||||
) {
|
) {
|
||||||
if ($pfs && !isset($this->temp_auth_key['bound']) && $this->outgoing_messages[$message_id]['_'] !== 'auth.bindTempAuthKey') {
|
if ($pfs && !$this->shared->getTempAuthKey()->bound() && $this->outgoing_messages[$message_id]['_'] !== 'auth.bindTempAuthKey') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,5 +138,4 @@ trait AckHandler
|
|||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -184,7 +184,7 @@ trait CallHandler
|
|||||||
$aargs,
|
$aargs,
|
||||||
[
|
[
|
||||||
'_' => $method,
|
'_' => $method,
|
||||||
'type' => $this->methods->find_by_method($method)['type'],
|
'type' => $this->API->methods->find_by_method($method)['type'],
|
||||||
'content_related' => $this->content_related($method),
|
'content_related' => $this->content_related($method),
|
||||||
'promise' => $deferred,
|
'promise' => $deferred,
|
||||||
'method' => true,
|
'method' => true,
|
||||||
|
@ -257,7 +257,7 @@ trait ResponseHandler
|
|||||||
$this->check_in_seq_no($current_msg_id);
|
$this->check_in_seq_no($current_msg_id);
|
||||||
$this->ack_incoming_message_id($current_msg_id);
|
$this->ack_incoming_message_id($current_msg_id);
|
||||||
// Acknowledge that I received the server's response
|
// Acknowledge that I received the server's response
|
||||||
$response_type = $this->constructors->find_by_predicate($this->incoming_messages[$current_msg_id]['content']['_'])['type'];
|
$response_type = $this->API->constructors->find_by_predicate($this->incoming_messages[$current_msg_id]['content']['_'])['type'];
|
||||||
|
|
||||||
switch ($response_type) {
|
switch ($response_type) {
|
||||||
case 'Updates':
|
case 'Updates':
|
||||||
@ -568,7 +568,7 @@ trait ResponseHandler
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$botAPI = isset($request['botAPI']) && $request['botAPI'];
|
$botAPI = isset($request['botAPI']) && $request['botAPI'];
|
||||||
if (isset($response['_']) && \strpos($this->datacenter, 'cdn') === false && $this->constructors->find_by_predicate($response['_'])['type'] === 'Updates') {
|
if (isset($response['_']) && \strpos($this->datacenter, 'cdn') === false && $this->API->constructors->find_by_predicate($response['_'])['type'] === 'Updates') {
|
||||||
$response['request'] = $request;
|
$response['request'] = $request;
|
||||||
$this->callForkDefer($this->API->handle_updates_async($response));
|
$this->callForkDefer($this->API->handle_updates_async($response));
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
namespace danog\MadelineProto\MTProtoSession;
|
namespace danog\MadelineProto\MTProtoSession;
|
||||||
|
|
||||||
|
use danog\MadelineProto\MTProto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages sequence number.
|
* Manages sequence number.
|
||||||
*/
|
*/
|
||||||
|
@ -714,7 +714,6 @@ trait AuthKeyHandler
|
|||||||
$cdn = \strpos($id, 'cdn');
|
$cdn = \strpos($id, 'cdn');
|
||||||
$media = \strpos($id, 'media');
|
$media = \strpos($id, 'media');
|
||||||
if (!$socket->hasTempAuthKey() || !$socket->hasPermAuthKey()) {
|
if (!$socket->hasTempAuthKey() || !$socket->hasPermAuthKey()) {
|
||||||
$dc_config_number = isset($this->settings['connection_settings'][$id]) ? $id : 'all';
|
|
||||||
if (!$socket->hasPermAuthKey() && !$cdn && !$media) {
|
if (!$socket->hasPermAuthKey() && !$cdn && !$media) {
|
||||||
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['gen_perm_auth_key'], $id), \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['gen_perm_auth_key'], $id), \danog\MadelineProto\Logger::NOTICE);
|
||||||
$socket->setPermAuthKey(yield $this->create_auth_key_async(-1, $id));
|
$socket->setPermAuthKey(yield $this->create_auth_key_async(-1, $id));
|
||||||
@ -723,7 +722,7 @@ trait AuthKeyHandler
|
|||||||
if ($media) {
|
if ($media) {
|
||||||
$socket->link(\intval($id));
|
$socket->link(\intval($id));
|
||||||
}
|
}
|
||||||
if ($this->settings['connection_settings'][$dc_config_number]['pfs']) {
|
if ($this->datacenter->getDataCenterConnection($id)->getSettings()['pfs']) {
|
||||||
if (!$cdn) {
|
if (!$cdn) {
|
||||||
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['gen_temp_auth_key'], $id), \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['gen_temp_auth_key'], $id), \danog\MadelineProto\Logger::NOTICE);
|
||||||
|
|
||||||
|
@ -744,7 +744,7 @@ trait TL
|
|||||||
}
|
}
|
||||||
switch ($constructorData['predicate']) {
|
switch ($constructorData['predicate']) {
|
||||||
case 'gzip_packed':
|
case 'gzip_packed':
|
||||||
return $this->deserialize(gzdecode($this->deserialize($stream, ['type' => 'bytes', 'datacenter' => $type['datacenter']])), ['type' => '', 'datacenter' => $type['datacenter']]);
|
return $this->deserialize(gzdecode($this->deserialize($stream, ['type' => 'bytes', 'connection' => $type['connection']])), ['type' => '', 'connection' => $type['connection']]);
|
||||||
case 'Vector t':
|
case 'Vector t':
|
||||||
case 'vector':
|
case 'vector':
|
||||||
break;
|
break;
|
||||||
@ -786,10 +786,10 @@ trait TL
|
|||||||
$type['subtype'] = '';
|
$type['subtype'] = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->deserialize(gzdecode($this->deserialize($stream, ['type' => 'bytes'])), ['type' => '', 'datacenter' => $type['datacenter'], 'subtype' => $type['subtype']]);
|
return $this->deserialize(gzdecode($this->deserialize($stream, ['type' => 'bytes'])), ['type' => '', 'connection' => $type['connection'], 'subtype' => $type['subtype']]);
|
||||||
}
|
}
|
||||||
if ($constructorData['type'] === 'Vector t') {
|
if ($constructorData['type'] === 'Vector t') {
|
||||||
$constructorData['datacenter'] = $type['datacenter'];
|
$constructorData['connection'] = $type['connection'];
|
||||||
$constructorData['subtype'] = isset($type['subtype']) ? $type['subtype'] : '';
|
$constructorData['subtype'] = isset($type['subtype']) ? $type['subtype'] : '';
|
||||||
$constructorData['type'] = 'vector';
|
$constructorData['type'] = 'vector';
|
||||||
|
|
||||||
@ -835,18 +835,18 @@ trait TL
|
|||||||
$arg['type'] = 'string';
|
$arg['type'] = 'string';
|
||||||
}
|
}
|
||||||
if ($x['_'] === 'rpc_result' && $arg['name'] === 'result') {
|
if ($x['_'] === 'rpc_result' && $arg['name'] === 'result') {
|
||||||
if (isset($this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['_'])
|
if (isset($type['connection']->outgoing_messages[$x['req_msg_id']]['_'])
|
||||||
&& isset($this->tl_callbacks[TLCallback::METHOD_BEFORE_CALLBACK][$this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['_']])
|
&& isset($this->tl_callbacks[TLCallback::METHOD_BEFORE_CALLBACK][$type['connection']->outgoing_messages[$x['req_msg_id']]['_']])
|
||||||
) {
|
) {
|
||||||
foreach ($this->tl_callbacks[TLCallback::METHOD_BEFORE_CALLBACK][$this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['_']] as $callback) {
|
foreach ($this->tl_callbacks[TLCallback::METHOD_BEFORE_CALLBACK][$type['connection']->outgoing_messages[$x['req_msg_id']]['_']] as $callback) {
|
||||||
$callback($this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['_']);
|
$callback($type['connection']->outgoing_messages[$x['req_msg_id']]['_']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['type'])
|
if (isset($type['connection']->outgoing_messages[$x['req_msg_id']]['type'])
|
||||||
&& stripos($this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['type'], '<') !== false
|
&& stripos($type['connection']->outgoing_messages[$x['req_msg_id']]['type'], '<') !== false
|
||||||
) {
|
) {
|
||||||
$arg['subtype'] = str_replace(['Vector<', '>'], '', $this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['type']);
|
$arg['subtype'] = str_replace(['Vector<', '>'], '', $type['connection']->outgoing_messages[$x['req_msg_id']]['type']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isset($type['datacenter'])) {
|
if (isset($type['datacenter'])) {
|
||||||
@ -888,11 +888,11 @@ trait TL
|
|||||||
$this->callFork($callback($x));
|
$this->callFork($callback($x));
|
||||||
}
|
}
|
||||||
} elseif ($x['_'] === 'rpc_result'
|
} elseif ($x['_'] === 'rpc_result'
|
||||||
&& isset($this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['_'])
|
&& isset($type['connection']->outgoing_messages[$x['req_msg_id']]['_'])
|
||||||
&& isset($this->tl_callbacks[TLCallback::METHOD_CALLBACK][$this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['_']])
|
&& isset($this->tl_callbacks[TLCallback::METHOD_CALLBACK][$type['connection']->outgoing_messages[$x['req_msg_id']]['_']])
|
||||||
) {
|
) {
|
||||||
foreach ($this->tl_callbacks[TLCallback::METHOD_CALLBACK][$this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['_']] as $callback) {
|
foreach ($this->tl_callbacks[TLCallback::METHOD_CALLBACK][$type['connection']->outgoing_messages[$x['req_msg_id']]['_']] as $callback) {
|
||||||
$callback($this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']], $x['result']);
|
$callback($type['connection']->outgoing_messages[$x['req_msg_id']], $x['result']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user