Yield from all the things
This commit is contained in:
parent
b842c8f7e5
commit
000839a1b5
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
namespace phpseclib\Math;
|
namespace phpseclib\Math;
|
||||||
|
|
||||||
if (PHP_MAJOR_VERSION < 7 && !((\class_exists(\Phar::class) && \Phar::running()) || \defined('TESTING_VERSIONS'))) {
|
if (PHP_MAJOR_VERSION < 7 && !(\class_exists(\Phar::class) && \Phar::running() || \defined('TESTING_VERSIONS'))) {
|
||||||
throw new \Exception('MadelineProto requires php 7 to run natively, use phar.madelineproto.xyz to run on PHP 5.6');
|
throw new \Exception('MadelineProto requires php 7 to run natively, use phar.madelineproto.xyz to run on PHP 5.6');
|
||||||
}
|
}
|
||||||
if (\defined('HHVM_VERSION')) {
|
if (\defined('HHVM_VERSION')) {
|
||||||
@ -32,7 +32,6 @@ if (\defined('HHVM_VERSION')) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BigIntegor
|
class BigIntegor
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,8 @@ if (!\class_exists('ReflectionGenerator')) {
|
|||||||
}
|
}
|
||||||
public function getFunction(): ReflectionFunctionAbstract
|
public function getFunction(): ReflectionFunctionAbstract
|
||||||
{
|
{
|
||||||
return new ReflectionFunction(function () {});
|
return new ReflectionFunction(function () {
|
||||||
|
});
|
||||||
}
|
}
|
||||||
public function getThis(): object
|
public function getThis(): object
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Yield return value PHP5 polyfill.
|
* Yield return value PHP5 polyfill.
|
||||||
*
|
*
|
||||||
@ -18,12 +19,10 @@
|
|||||||
class YieldReturnValue
|
class YieldReturnValue
|
||||||
{
|
{
|
||||||
private $value;
|
private $value;
|
||||||
|
|
||||||
public function __construct($value)
|
public function __construct($value)
|
||||||
{
|
{
|
||||||
$this->value = $value;
|
$this->value = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getReturn()
|
public function getReturn()
|
||||||
{
|
{
|
||||||
return $this->value;
|
return $this->value;
|
||||||
|
@ -21,7 +21,6 @@ namespace danog\MadelineProto;
|
|||||||
|
|
||||||
use Amp\Deferred;
|
use Amp\Deferred;
|
||||||
use Amp\Promise;
|
use Amp\Promise;
|
||||||
|
|
||||||
use function Amp\File\exists;
|
use function Amp\File\exists;
|
||||||
use function Amp\File\get;
|
use function Amp\File\get;
|
||||||
use function Amp\File\put;
|
use function Amp\File\put;
|
||||||
@ -67,7 +66,6 @@ class API extends InternalDoc
|
|||||||
public $asyncAPIPromise;
|
public $asyncAPIPromise;
|
||||||
private $oldInstance = false;
|
private $oldInstance = false;
|
||||||
private $destructing = false;
|
private $destructing = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Magic constructor function.
|
* Magic constructor function.
|
||||||
*
|
*
|
||||||
@ -94,7 +92,6 @@ class API extends InternalDoc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Async constructor function.
|
* Async constructor function.
|
||||||
*
|
*
|
||||||
@ -108,29 +105,25 @@ class API extends InternalDoc
|
|||||||
{
|
{
|
||||||
if (\is_string($params)) {
|
if (\is_string($params)) {
|
||||||
Logger::constructorFromSettings($settings);
|
Logger::constructorFromSettings($settings);
|
||||||
|
|
||||||
$realpaths = Serialization::realpaths($params);
|
$realpaths = Serialization::realpaths($params);
|
||||||
$this->session = $realpaths['file'];
|
$this->session = $realpaths['file'];
|
||||||
|
|
||||||
if (yield exists($realpaths['file'])) {
|
if (yield exists($realpaths['file'])) {
|
||||||
Logger::log('Waiting for shared lock of serialization lockfile...');
|
Logger::log('Waiting for shared lock of serialization lockfile...');
|
||||||
$unlock = yield Tools::flock($realpaths['lockfile'], LOCK_SH);
|
$unlock = yield Tools::flock($realpaths['lockfile'], LOCK_SH);
|
||||||
Logger::log('Shared lock acquired, deserializing...');
|
Logger::log('Shared lock acquired, deserializing...');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$tounserialize = yield get($realpaths['file']);
|
$tounserialize = yield get($realpaths['file']);
|
||||||
} finally {
|
} finally {
|
||||||
$unlock();
|
$unlock();
|
||||||
}
|
}
|
||||||
\danog\MadelineProto\Magic::classExists();
|
\danog\MadelineProto\Magic::classExists();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$unserialized = \unserialize($tounserialize);
|
$unserialized = \unserialize($tounserialize);
|
||||||
} catch (\danog\MadelineProto\Bug74586Exception $e) {
|
} catch (\danog\MadelineProto\Bug74586Exception $e) {
|
||||||
\class_exists('\\Volatile');
|
\class_exists('\\Volatile');
|
||||||
$tounserialize = \str_replace('O:26:"danog\\MadelineProto\\Button":', 'O:35:"danog\\MadelineProto\\TL\\Types\\Button":', $tounserialize);
|
$tounserialize = \str_replace('O:26:"danog\\MadelineProto\\Button":', 'O:35:"danog\\MadelineProto\\TL\\Types\\Button":', $tounserialize);
|
||||||
foreach (['RSA', 'TL\\TLMethods', 'TL\\TLConstructors', 'MTProto', 'API', 'DataCenter', 'Connection', 'TL\\Types\\Button', 'TL\\Types\\Bytes', 'APIFactory'] as $class) {
|
foreach (['RSA', 'TL\\TLMethods', 'TL\\TLConstructors', 'MTProto', 'API', 'DataCenter', 'Connection', 'TL\\Types\\Button', 'TL\\Types\\Bytes', 'APIFactory'] as $class) {
|
||||||
\class_exists('\\danog\\MadelineProto\\'.$class);
|
\class_exists('\\danog\\MadelineProto\\' . $class);
|
||||||
}
|
}
|
||||||
$unserialized = \danog\Serialization::unserialize($tounserialize);
|
$unserialized = \danog\Serialization::unserialize($tounserialize);
|
||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
@ -142,7 +135,7 @@ class API extends InternalDoc
|
|||||||
}
|
}
|
||||||
\class_exists('\\Volatile');
|
\class_exists('\\Volatile');
|
||||||
foreach (['RSA', 'TL\\TLMethods', 'TL\\TLConstructors', 'MTProto', 'API', 'DataCenter', 'Connection', 'TL\\Types\\Button', 'TL\\Types\\Bytes', 'APIFactory'] as $class) {
|
foreach (['RSA', 'TL\\TLMethods', 'TL\\TLConstructors', 'MTProto', 'API', 'DataCenter', 'Connection', 'TL\\Types\\Button', 'TL\\Types\\Bytes', 'APIFactory'] as $class) {
|
||||||
\class_exists('\\danog\\MadelineProto\\'.$class);
|
\class_exists('\\danog\\MadelineProto\\' . $class);
|
||||||
}
|
}
|
||||||
$changed = false;
|
$changed = false;
|
||||||
if (\strpos($tounserialize, 'O:26:"danog\\MadelineProto\\Button":') !== false) {
|
if (\strpos($tounserialize, 'O:26:"danog\\MadelineProto\\Button":') !== false) {
|
||||||
@ -165,12 +158,10 @@ class API extends InternalDoc
|
|||||||
$tounserialize = \str_replace('C:26:"phpseclib3\\Math\\BigInteger"', 'C:24:"tgseclib\\Math\\BigInteger"', $tounserialize);
|
$tounserialize = \str_replace('C:26:"phpseclib3\\Math\\BigInteger"', 'C:24:"tgseclib\\Math\\BigInteger"', $tounserialize);
|
||||||
$changed = true;
|
$changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::log((string) $e, Logger::ERROR);
|
Logger::log((string) $e, Logger::ERROR);
|
||||||
if (!$changed) {
|
if (!$changed) {
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$unserialized = \danog\Serialization::unserialize($tounserialize);
|
$unserialized = \danog\Serialization::unserialize($tounserialize);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
@ -189,7 +180,6 @@ class API extends InternalDoc
|
|||||||
$this->web_api_template = $unserialized->web_api_template;
|
$this->web_api_template = $unserialized->web_api_template;
|
||||||
$this->my_telegram_org_wrapper = $unserialized->my_telegram_org_wrapper;
|
$this->my_telegram_org_wrapper = $unserialized->my_telegram_org_wrapper;
|
||||||
$this->getting_api_id = $unserialized->getting_api_id;
|
$this->getting_api_id = $unserialized->getting_api_id;
|
||||||
|
|
||||||
if (isset($unserialized->API)) {
|
if (isset($unserialized->API)) {
|
||||||
$this->API = $unserialized->API;
|
$this->API = $unserialized->API;
|
||||||
$this->APIFactory();
|
$this->APIFactory();
|
||||||
@ -208,7 +198,6 @@ class API extends InternalDoc
|
|||||||
$params = $settings;
|
$params = $settings;
|
||||||
}
|
}
|
||||||
Logger::constructorFromSettings($settings);
|
Logger::constructorFromSettings($settings);
|
||||||
|
|
||||||
if (!isset($params['app_info']['api_id']) || !$params['app_info']['api_id']) {
|
if (!isset($params['app_info']['api_id']) || !$params['app_info']['api_id']) {
|
||||||
$app = yield $this->APIStart($params);
|
$app = yield $this->APIStart($params);
|
||||||
$params['app_info']['api_id'] = $app['api_id'];
|
$params['app_info']['api_id'] = $app['api_id'];
|
||||||
@ -226,7 +215,6 @@ class API extends InternalDoc
|
|||||||
//\danog\MadelineProto\Logger::log('Pong: '.$pong['ping_id'], Logger::ULTRA_VERBOSE);
|
//\danog\MadelineProto\Logger::log('Pong: '.$pong['ping_id'], Logger::ULTRA_VERBOSE);
|
||||||
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['madelineproto_ready'], Logger::NOTICE);
|
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['madelineproto_ready'], Logger::NOTICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable or disable async.
|
* Enable or disable async.
|
||||||
*
|
*
|
||||||
@ -237,14 +225,12 @@ class API extends InternalDoc
|
|||||||
public function async(bool $async): void
|
public function async(bool $async): void
|
||||||
{
|
{
|
||||||
$this->async = $async;
|
$this->async = $async;
|
||||||
|
|
||||||
if ($this->API) {
|
if ($this->API) {
|
||||||
if ($this->API->event_handler && \class_exists($this->API->event_handler) && \is_subclass_of($this->API->event_handler, '\danog\MadelineProto\EventHandler')) {
|
if ($this->API->event_handler && \class_exists($this->API->event_handler) && \is_subclass_of($this->API->event_handler, '\\danog\\MadelineProto\\EventHandler')) {
|
||||||
$this->API->setEventHandler($this->API->event_handler);
|
$this->API->setEventHandler($this->API->event_handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destruct function.
|
* Destruct function.
|
||||||
*
|
*
|
||||||
@ -270,7 +256,6 @@ class API extends InternalDoc
|
|||||||
}
|
}
|
||||||
//restore_error_handler();
|
//restore_error_handler();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sleep function.
|
* Sleep function.
|
||||||
*
|
*
|
||||||
@ -282,8 +267,6 @@ class API extends InternalDoc
|
|||||||
{
|
{
|
||||||
return ['API', 'web_api_template', 'getting_api_id', 'my_telegram_org_wrapper'];
|
return ['API', 'web_api_template', 'getting_api_id', 'my_telegram_org_wrapper'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom fast getSelf.
|
* Custom fast getSelf.
|
||||||
*
|
*
|
||||||
@ -295,7 +278,6 @@ class API extends InternalDoc
|
|||||||
{
|
{
|
||||||
return isset($this->API) && isset($this->API->authorization['user']) ? $this->API->authorization['user'] : false;
|
return isset($this->API) && isset($this->API->authorization['user']) ? $this->API->authorization['user'] : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Init API wrapper.
|
* Init API wrapper.
|
||||||
*
|
*
|
||||||
@ -322,7 +304,6 @@ class API extends InternalDoc
|
|||||||
$this->methods = [];
|
$this->methods = [];
|
||||||
foreach ($methods as $method) {
|
foreach ($methods as $method) {
|
||||||
$actual_method = $method;
|
$actual_method = $method;
|
||||||
|
|
||||||
if ($method == 'methodCallAsyncRead') {
|
if ($method == 'methodCallAsyncRead') {
|
||||||
$method = 'methodCall';
|
$method = 'methodCall';
|
||||||
} elseif (\stripos($method, 'async') !== false) {
|
} elseif (\stripos($method, 'async') !== false) {
|
||||||
@ -340,14 +321,12 @@ class API extends InternalDoc
|
|||||||
$this->methods[\strtolower(Tools::fromCamelCase($method))] = $actual_method;
|
$this->methods[\strtolower(Tools::fromCamelCase($method))] = $actual_method;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->API->wrapper = $this;
|
$this->API->wrapper = $this;
|
||||||
if ($this->API->event_handler && \class_exists($this->API->event_handler) && \is_subclass_of($this->API->event_handler, '\danog\MadelineProto\EventHandler')) {
|
if ($this->API->event_handler && \class_exists($this->API->event_handler) && \is_subclass_of($this->API->event_handler, '\\danog\\MadelineProto\\EventHandler')) {
|
||||||
$this->API->setEventHandler($this->API->event_handler);
|
$this->API->setEventHandler($this->API->event_handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get full list of MTProto and API methods.
|
* Get full list of MTProto and API methods.
|
||||||
*
|
*
|
||||||
@ -362,10 +341,8 @@ class API extends InternalDoc
|
|||||||
foreach ($this->API->methods->by_id as $method) {
|
foreach ($this->API->methods->by_id as $method) {
|
||||||
$methods[] = $method['method'];
|
$methods[] = $method['method'];
|
||||||
}
|
}
|
||||||
|
|
||||||
return \array_merge($methods, \get_class_methods($this->API));
|
return \array_merge($methods, \get_class_methods($this->API));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serialize session.
|
* Serialize session.
|
||||||
*
|
*
|
||||||
@ -377,12 +354,11 @@ class API extends InternalDoc
|
|||||||
*/
|
*/
|
||||||
public function serialize(string $filename = ''): Promise
|
public function serialize(string $filename = ''): Promise
|
||||||
{
|
{
|
||||||
return Tools::callFork((function () use ($filename) {
|
return Tools::callFork((function () use ($filename): \Generator {
|
||||||
if (empty($filename)) {
|
if (empty($filename)) {
|
||||||
$filename = $this->session;
|
$filename = $this->session;
|
||||||
}
|
}
|
||||||
//Logger::log(\danog\MadelineProto\Lang::$current_lang['serializing_madelineproto']);
|
//Logger::log(\danog\MadelineProto\Lang::$current_lang['serializing_madelineproto']);
|
||||||
|
|
||||||
if ($filename == '') {
|
if ($filename == '') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -399,11 +375,8 @@ class API extends InternalDoc
|
|||||||
$this->serialized = \time();
|
$this->serialized = \time();
|
||||||
$realpaths = Serialization::realpaths($filename);
|
$realpaths = Serialization::realpaths($filename);
|
||||||
//Logger::log('Waiting for exclusive lock of serialization lockfile...');
|
//Logger::log('Waiting for exclusive lock of serialization lockfile...');
|
||||||
|
|
||||||
$unlock = yield Tools::flock($realpaths['lockfile'], LOCK_EX);
|
$unlock = yield Tools::flock($realpaths['lockfile'], LOCK_EX);
|
||||||
|
|
||||||
//Logger::log('Lock acquired, serializing');
|
//Logger::log('Lock acquired, serializing');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!$this->getting_api_id) {
|
if (!$this->getting_api_id) {
|
||||||
$update_closure = $this->API->settings['updates']['callback'];
|
$update_closure = $this->API->settings['updates']['callback'];
|
||||||
@ -425,7 +398,6 @@ class API extends InternalDoc
|
|||||||
$unlock();
|
$unlock();
|
||||||
}
|
}
|
||||||
//Logger::log('Done serializing');
|
//Logger::log('Done serializing');
|
||||||
|
|
||||||
return $wrote;
|
return $wrote;
|
||||||
})());
|
})());
|
||||||
}
|
}
|
||||||
|
@ -26,10 +26,9 @@ class Absolute
|
|||||||
{
|
{
|
||||||
public static function absolute($file)
|
public static function absolute($file)
|
||||||
{
|
{
|
||||||
if (($file[0] !== '/') && ($file[1] !== ':') && !\in_array(\substr($file, 0, 4), ['phar', 'http'])) {
|
if ($file[0] !== '/' && $file[1] !== ':' && !\in_array(\substr($file, 0, 4), ['phar', 'http'])) {
|
||||||
$file = Magic::getcwd().'/'.$file;
|
$file = Magic::getcwd() . '/' . $file;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $file;
|
return $file;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,21 +61,18 @@ abstract class AbstractAPIFactory extends AsyncConstruct
|
|||||||
* @var Promise
|
* @var Promise
|
||||||
*/
|
*/
|
||||||
public $asyncAPIPromise;
|
public $asyncAPIPromise;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method list.
|
* Method list.
|
||||||
*
|
*
|
||||||
* @var string[]
|
* @var string[]
|
||||||
*/
|
*/
|
||||||
protected $methods = [];
|
protected $methods = [];
|
||||||
|
|
||||||
public function __construct($namespace, &$API, &$async)
|
public function __construct($namespace, &$API, &$async)
|
||||||
{
|
{
|
||||||
$this->namespace = $namespace.'.';
|
$this->namespace = $namespace . '.';
|
||||||
$this->API = &$API;
|
$this->API =& $API;
|
||||||
$this->async = &$async;
|
$this->async =& $async;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable or disable async.
|
* Enable or disable async.
|
||||||
*
|
*
|
||||||
@ -87,7 +84,6 @@ abstract class AbstractAPIFactory extends AsyncConstruct
|
|||||||
{
|
{
|
||||||
$this->async = $async;
|
$this->async = $async;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call async wrapper function.
|
* Call async wrapper function.
|
||||||
*
|
*
|
||||||
@ -101,25 +97,21 @@ abstract class AbstractAPIFactory extends AsyncConstruct
|
|||||||
public function __call(string $name, array $arguments)
|
public function __call(string $name, array $arguments)
|
||||||
{
|
{
|
||||||
$yielded = Tools::call($this->__call_async($name, $arguments));
|
$yielded = Tools::call($this->__call_async($name, $arguments));
|
||||||
$async = $this->lua === false && (\is_array(\end($arguments)) && isset(\end($arguments)['async']) ? \end($arguments)['async'] : ($this->async && $name !== 'loop'));
|
$async = $this->lua === false && (\is_array(\end($arguments)) && isset(\end($arguments)['async']) ? \end($arguments)['async'] : $this->async && $name !== 'loop');
|
||||||
|
|
||||||
if ($async) {
|
if ($async) {
|
||||||
return $yielded;
|
return $yielded;
|
||||||
}
|
}
|
||||||
if (!$this->lua) {
|
if (!$this->lua) {
|
||||||
return Tools::wait($yielded);
|
return Tools::wait($yielded);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$yielded = Tools::wait($yielded);
|
$yielded = Tools::wait($yielded);
|
||||||
Lua::convertObjects($yielded);
|
Lua::convertObjects($yielded);
|
||||||
|
|
||||||
return $yielded;
|
return $yielded;
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return ['error_code' => $e->getCode(), 'error' => $e->getMessage()];
|
return ['error_code' => $e->getCode(), 'error' => $e->getMessage()];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call async wrapper function.
|
* Call async wrapper function.
|
||||||
*
|
*
|
||||||
@ -159,20 +151,17 @@ abstract class AbstractAPIFactory extends AsyncConstruct
|
|||||||
yield $this->API->initAsynchronously();
|
yield $this->API->initAsynchronously();
|
||||||
$this->API->logger->logger('Finished init asynchronously');
|
$this->API->logger->logger('Finished init asynchronously');
|
||||||
}
|
}
|
||||||
|
|
||||||
$lower_name = \strtolower($name);
|
$lower_name = \strtolower($name);
|
||||||
if ($this->namespace !== '' || !isset($this->methods[$lower_name])) {
|
if ($this->namespace !== '' || !isset($this->methods[$lower_name])) {
|
||||||
$name = $this->namespace.$name;
|
$name = $this->namespace . $name;
|
||||||
$aargs = isset($arguments[1]) && \is_array($arguments[1]) ? $arguments[1] : [];
|
$aargs = isset($arguments[1]) && \is_array($arguments[1]) ? $arguments[1] : [];
|
||||||
$aargs['apifactory'] = true;
|
$aargs['apifactory'] = true;
|
||||||
$aargs['datacenter'] = $this->API->datacenter->curdc;
|
$aargs['datacenter'] = $this->API->datacenter->curdc;
|
||||||
$args = isset($arguments[0]) && \is_array($arguments[0]) ? $arguments[0] : [];
|
$args = isset($arguments[0]) && \is_array($arguments[0]) ? $arguments[0] : [];
|
||||||
|
|
||||||
return yield $this->API->methodCallAsyncRead($name, $args, $aargs);
|
return yield $this->API->methodCallAsyncRead($name, $args, $aargs);
|
||||||
}
|
}
|
||||||
return yield $this->methods[$lower_name](...$arguments);
|
return yield $this->methods[$lower_name](...$arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get attribute.
|
* Get attribute.
|
||||||
*
|
*
|
||||||
@ -189,16 +178,13 @@ abstract class AbstractAPIFactory extends AsyncConstruct
|
|||||||
}
|
}
|
||||||
if ($name === 'settings') {
|
if ($name === 'settings') {
|
||||||
$this->API->flushSettings = true;
|
$this->API->flushSettings = true;
|
||||||
|
|
||||||
return $this->API->settings;
|
return $this->API->settings;
|
||||||
}
|
}
|
||||||
if ($name === 'logger') {
|
if ($name === 'logger') {
|
||||||
return $this->API->logger;
|
return $this->API->logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->API->storage[$name];
|
return $this->API->storage[$name];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set an attribute.
|
* Set an attribute.
|
||||||
*
|
*
|
||||||
@ -218,13 +204,10 @@ abstract class AbstractAPIFactory extends AsyncConstruct
|
|||||||
if ($this->API->asyncInitPromise) {
|
if ($this->API->asyncInitPromise) {
|
||||||
$this->API->init();
|
$this->API->init();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->API->__construct(\array_replace_recursive($this->API->settings, $value));
|
return $this->API->__construct(\array_replace_recursive($this->API->settings, $value));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->API->storage[$name] = $value;
|
return $this->API->storage[$name] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether an attribute exists.
|
* Whether an attribute exists.
|
||||||
*
|
*
|
||||||
@ -237,10 +220,8 @@ abstract class AbstractAPIFactory extends AsyncConstruct
|
|||||||
if ($this->asyncAPIPromise) {
|
if ($this->asyncAPIPromise) {
|
||||||
Tools::wait($this->asyncAPIPromise);
|
Tools::wait($this->asyncAPIPromise);
|
||||||
}
|
}
|
||||||
|
|
||||||
return isset($this->API->storage[$name]);
|
return isset($this->API->storage[$name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unset attribute.
|
* Unset attribute.
|
||||||
*
|
*
|
||||||
|
@ -27,7 +27,6 @@ use phpDocumentor\Reflection\DocBlockFactory;
|
|||||||
class AnnotationsBuilder
|
class AnnotationsBuilder
|
||||||
{
|
{
|
||||||
use Tools;
|
use Tools;
|
||||||
|
|
||||||
public function __construct(Logger $logger, array $settings, string $output, array $reflectionClasses, string $namespace)
|
public function __construct(Logger $logger, array $settings, string $output, array $reflectionClasses, string $namespace)
|
||||||
{
|
{
|
||||||
$this->reflectionClasses = $reflectionClasses;
|
$this->reflectionClasses = $reflectionClasses;
|
||||||
@ -43,14 +42,12 @@ class AnnotationsBuilder
|
|||||||
$this->settings = $settings;
|
$this->settings = $settings;
|
||||||
$this->output = $output;
|
$this->output = $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function mkAnnotations()
|
public function mkAnnotations()
|
||||||
{
|
{
|
||||||
\danog\MadelineProto\Logger::log('Generating annotations...', \danog\MadelineProto\Logger::NOTICE);
|
\danog\MadelineProto\Logger::log('Generating annotations...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
$this->setProperties();
|
$this->setProperties();
|
||||||
$this->createInternalClasses();
|
$this->createInternalClasses();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open file of class APIFactory
|
* Open file of class APIFactory
|
||||||
* Insert properties
|
* Insert properties
|
||||||
@ -68,16 +65,15 @@ class AnnotationsBuilder
|
|||||||
if ($raw_docblock = $property->getDocComment()) {
|
if ($raw_docblock = $property->getDocComment()) {
|
||||||
$docblock = $fixture->create($raw_docblock);
|
$docblock = $fixture->create($raw_docblock);
|
||||||
if ($docblock->hasTag('internal')) {
|
if ($docblock->hasTag('internal')) {
|
||||||
$content = \str_replace("\n ".$raw_docblock."\n public \$".$property->getName().';', '', $content);
|
$content = \str_replace("\n " . $raw_docblock . "\n public \$" . $property->getName() . ';', '', $content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach ($this->TL->getMethodNamespaces() as $namespace) {
|
foreach ($this->TL->getMethodNamespaces() as $namespace) {
|
||||||
$content = \preg_replace('/(class( \\w+[,]?){0,}\\n{\\n)/', '${1}'." /**\n"." * @internal this is a internal property generated by build_docs.php, don't change manually\n"." *\n"." * @var {$namespace}\n"." */\n"." public \${$namespace};\n", $content);
|
$content = \preg_replace('/(class( \\w+[,]?){0,}\\n{\\n)/', '${1}' . " /**\n" . " * @internal this is a internal property generated by build_docs.php, don't change manually\n" . " *\n" . " * @var {$namespace}\n" . " */\n" . " public \${$namespace};\n", $content);
|
||||||
}
|
}
|
||||||
\file_put_contents($filename, $content);
|
\file_put_contents($filename, $content);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create internalDoc.
|
* Create internalDoc.
|
||||||
*
|
*
|
||||||
@ -88,23 +84,19 @@ class AnnotationsBuilder
|
|||||||
\danog\MadelineProto\Logger::log('Creating internal classes...', \danog\MadelineProto\Logger::NOTICE);
|
\danog\MadelineProto\Logger::log('Creating internal classes...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
$handle = \fopen($this->output, 'w');
|
$handle = \fopen($this->output, 'w');
|
||||||
\fwrite($handle, "<?php namespace {$this->namespace}; class InternalDoc extends APIFactory {}");
|
\fwrite($handle, "<?php namespace {$this->namespace}; class InternalDoc extends APIFactory {}");
|
||||||
|
|
||||||
$class = new \ReflectionClass($this->reflectionClasses['API']);
|
$class = new \ReflectionClass($this->reflectionClasses['API']);
|
||||||
$methods = $class->getMethods(\ReflectionMethod::IS_STATIC | \ReflectionMethod::IS_PUBLIC);
|
$methods = $class->getMethods(\ReflectionMethod::IS_STATIC | \ReflectionMethod::IS_PUBLIC);
|
||||||
$ignoreMethods = ['fetchserializableobject'];
|
$ignoreMethods = ['fetchserializableobject'];
|
||||||
foreach ($methods as $method) {
|
foreach ($methods as $method) {
|
||||||
$ignoreMethods[$method->getName()] = $method->getName();
|
$ignoreMethods[$method->getName()] = $method->getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
$class = new \ReflectionClass(TLCallback::class);
|
$class = new \ReflectionClass(TLCallback::class);
|
||||||
$methods = $class->getMethods(\ReflectionMethod::IS_STATIC | \ReflectionMethod::IS_PUBLIC);
|
$methods = $class->getMethods(\ReflectionMethod::IS_STATIC | \ReflectionMethod::IS_PUBLIC);
|
||||||
foreach ($methods as $method) {
|
foreach ($methods as $method) {
|
||||||
$ignoreMethods[$method->getName()] = $method->getName();
|
$ignoreMethods[$method->getName()] = $method->getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
\fclose($handle);
|
\fclose($handle);
|
||||||
$handle = \fopen($this->output, 'w');
|
$handle = \fopen($this->output, 'w');
|
||||||
|
|
||||||
$internalDoc = [];
|
$internalDoc = [];
|
||||||
foreach ($this->TL->getMethods()->by_id as $id => $data) {
|
foreach ($this->TL->getMethods()->by_id as $id => $data) {
|
||||||
if (!\strpos($data['method'], '.')) {
|
if (!\strpos($data['method'], '.')) {
|
||||||
@ -115,7 +107,6 @@ class AnnotationsBuilder
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$internalDoc[$namespace][$method]['title'] = \str_replace(['](../', '.md'], ['](https://docs.madelineproto.xyz/API_docs/', '.html'], Lang::$current_lang["method_{$data['method']}"] ?? '');
|
$internalDoc[$namespace][$method]['title'] = \str_replace(['](../', '.md'], ['](https://docs.madelineproto.xyz/API_docs/', '.html'], Lang::$current_lang["method_{$data['method']}"] ?? '');
|
||||||
|
|
||||||
$type = \str_ireplace(['vector<', '>'], [' of ', '[]'], $data['type']);
|
$type = \str_ireplace(['vector<', '>'], [' of ', '[]'], $data['type']);
|
||||||
foreach ($data['params'] as $param) {
|
foreach ($data['params'] as $param) {
|
||||||
if (\in_array($param['name'], ['flags', 'random_id', 'random_bytes'])) {
|
if (\in_array($param['name'], ['flags', 'random_id', 'random_bytes'])) {
|
||||||
@ -133,31 +124,25 @@ class AnnotationsBuilder
|
|||||||
$param['type'] = 'Vector t';
|
$param['type'] = 'Vector t';
|
||||||
$param['subtype'] = 'int';
|
$param['subtype'] = 'int';
|
||||||
}
|
}
|
||||||
|
|
||||||
$stype = 'type';
|
$stype = 'type';
|
||||||
if (isset($param['subtype'])) {
|
if (isset($param['subtype'])) {
|
||||||
$stype = 'subtype';
|
$stype = 'subtype';
|
||||||
}
|
}
|
||||||
|
|
||||||
$ptype = $param[$stype];
|
$ptype = $param[$stype];
|
||||||
switch ($ptype) {
|
switch ($ptype) {
|
||||||
case 'true':
|
case 'true':
|
||||||
case 'false':
|
case 'false':
|
||||||
$ptype = 'boolean';
|
$ptype = 'boolean';
|
||||||
}
|
}
|
||||||
$ptype = $stype === 'type' ? $ptype : "[$ptype]";
|
$ptype = $stype === 'type' ? $ptype : "[{$ptype}]";
|
||||||
$opt = ($param['pow'] ?? false) ? 'Optional: ' : '';
|
$opt = $param['pow'] ?? false ? 'Optional: ' : '';
|
||||||
$internalDoc[$namespace][$method]['attr'][$param['name']] = [
|
$internalDoc[$namespace][$method]['attr'][$param['name']] = ['type' => $ptype, 'description' => \str_replace(['](../', '.md'], ['](https://docs.madelineproto.xyz/API_docs/', '.html'], $opt . (Lang::$current_lang["method_{$data['method']}_param_{$param['name']}_type_{$param['type']}"] ?? ''))];
|
||||||
'type' => $ptype,
|
|
||||||
'description' => \str_replace(['](../', '.md'], ['](https://docs.madelineproto.xyz/API_docs/', '.html'], $opt.(Lang::$current_lang["method_{$data['method']}_param_{$param['name']}_type_{$param['type']}"] ?? ''))
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
if ($type === 'Bool') {
|
if ($type === 'Bool') {
|
||||||
$type = \strtolower($type);
|
$type = \strtolower($type);
|
||||||
}
|
}
|
||||||
$internalDoc[$namespace][$method]['return'] = $type;
|
$internalDoc[$namespace][$method]['return'] = $type;
|
||||||
}
|
}
|
||||||
|
|
||||||
$class = new \ReflectionClass($this->reflectionClasses['MTProto']);
|
$class = new \ReflectionClass($this->reflectionClasses['MTProto']);
|
||||||
$methods = $class->getMethods(\ReflectionMethod::IS_STATIC | \ReflectionMethod::IS_PUBLIC);
|
$methods = $class->getMethods(\ReflectionMethod::IS_STATIC | \ReflectionMethod::IS_PUBLIC);
|
||||||
foreach ($methods as $key => $method) {
|
foreach ($methods as $key => $method) {
|
||||||
@ -183,15 +168,13 @@ class AnnotationsBuilder
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$static = $method->isStatic();
|
$static = $method->isStatic();
|
||||||
|
|
||||||
if (!$static) {
|
if (!$static) {
|
||||||
$code = \file_get_contents($method->getFileName());
|
$code = \file_get_contents($method->getFileName());
|
||||||
$code = \implode("\n", \array_slice(\explode("\n", $code), $method->getStartLine(), $method->getEndLine() - $method->getStartLine()));
|
$code = \implode("\n", \array_slice(\explode("\n", $code), $method->getStartLine(), $method->getEndLine() - $method->getStartLine()));
|
||||||
if (\strpos($code, '$this') === false) {
|
if (\strpos($code, '$this') === false) {
|
||||||
Logger::log("$name should be STATIC!", Logger::FATAL_ERROR);
|
Logger::log("{$name} should be STATIC!", Logger::FATAL_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($name == 'methodCallAsyncRead') {
|
if ($name == 'methodCallAsyncRead') {
|
||||||
$name = 'methodCall';
|
$name = 'methodCall';
|
||||||
} elseif (\stripos($name, 'async') !== false) {
|
} elseif (\stripos($name, 'async') !== false) {
|
||||||
@ -203,10 +186,8 @@ class AnnotationsBuilder
|
|||||||
}
|
}
|
||||||
$name = Tools::fromSnakeCase($name);
|
$name = Tools::fromSnakeCase($name);
|
||||||
$name = \str_ireplace(['mtproto', 'api'], ['MTProto', 'API'], $name);
|
$name = \str_ireplace(['mtproto', 'api'], ['MTProto', 'API'], $name);
|
||||||
|
|
||||||
$doc = 'public function ';
|
$doc = 'public function ';
|
||||||
$doc .= $name;
|
$doc .= $name;
|
||||||
|
|
||||||
$doc .= '(';
|
$doc .= '(';
|
||||||
$paramList = '';
|
$paramList = '';
|
||||||
$hasVariadic = false;
|
$hasVariadic = false;
|
||||||
@ -224,7 +205,7 @@ class AnnotationsBuilder
|
|||||||
$doc .= $type->getName();
|
$doc .= $type->getName();
|
||||||
$doc .= ' ';
|
$doc .= ' ';
|
||||||
} else {
|
} else {
|
||||||
Logger::log($name.'.'.$param->getName()." has no type!", Logger::WARNING);
|
Logger::log($name . '.' . $param->getName() . " has no type!", Logger::WARNING);
|
||||||
}
|
}
|
||||||
if ($param->isVariadic()) {
|
if ($param->isVariadic()) {
|
||||||
$doc .= '...';
|
$doc .= '...';
|
||||||
@ -237,19 +218,17 @@ class AnnotationsBuilder
|
|||||||
if ($param->isOptional() && !$param->isVariadic()) {
|
if ($param->isOptional() && !$param->isVariadic()) {
|
||||||
$doc .= ' = ';
|
$doc .= ' = ';
|
||||||
if ($param->isDefaultValueConstant()) {
|
if ($param->isDefaultValueConstant()) {
|
||||||
$doc .= '\\'.\str_replace(['NULL', 'self'], ['null', 'danog\\MadelineProto\\MTProto'], $param->getDefaultValueConstantName());
|
$doc .= '\\' . \str_replace(['NULL', 'self'], ['null', 'danog\\MadelineProto\\MTProto'], $param->getDefaultValueConstantName());
|
||||||
} else {
|
} else {
|
||||||
$doc .= \str_replace('NULL', 'null', \var_export($param->getDefaultValue(), true));
|
$doc .= \str_replace('NULL', 'null', \var_export($param->getDefaultValue(), true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$doc .= ', ';
|
$doc .= ', ';
|
||||||
|
|
||||||
|
|
||||||
if ($param->isVariadic()) {
|
if ($param->isVariadic()) {
|
||||||
$hasVariadic = true;
|
$hasVariadic = true;
|
||||||
$paramList .= '...';
|
$paramList .= '...';
|
||||||
}
|
}
|
||||||
$paramList .= '$'.$param->getName().', ';
|
$paramList .= '$' . $param->getName() . ', ';
|
||||||
}
|
}
|
||||||
$hasReturnValue = ($type = $method->getReturnType()) && !\in_array($type->getName(), [\Generator::class, Promise::class]);
|
$hasReturnValue = ($type = $method->getReturnType()) && !\in_array($type->getName(), [\Generator::class, Promise::class]);
|
||||||
if (!$hasVariadic && !$static && !$hasReturnValue) {
|
if (!$hasVariadic && !$static && !$hasReturnValue) {
|
||||||
@ -271,35 +250,29 @@ class AnnotationsBuilder
|
|||||||
$doc .= $type->getName() === 'self' ? $this->reflectionClasses['API'] : $type->getName();
|
$doc .= $type->getName() === 'self' ? $this->reflectionClasses['API'] : $type->getName();
|
||||||
$async = false;
|
$async = false;
|
||||||
}
|
}
|
||||||
$finalParamList = $hasVariadic ? "Tools::arr($paramList)" : "[$paramList]";
|
$finalParamList = $hasVariadic ? "Tools::arr({$paramList})" : "[{$paramList}]";
|
||||||
|
|
||||||
$ret = $type && \in_array($type->getName(), ['self', 'void']) ? '' : 'return';
|
$ret = $type && \in_array($type->getName(), ['self', 'void']) ? '' : 'return';
|
||||||
|
|
||||||
$doc .= "\n{\n";
|
$doc .= "\n{\n";
|
||||||
if ($async) {
|
if ($async) {
|
||||||
$doc .= " $ret \$this->__call(__FUNCTION__, $finalParamList);\n";
|
$doc .= " {$ret} \$this->__call(__FUNCTION__, {$finalParamList});\n";
|
||||||
} elseif (!$static) {
|
} elseif (!$static) {
|
||||||
$doc .= " $ret \$this->API->$name($paramList);\n";
|
$doc .= " {$ret} \$this->API->{$name}({$paramList});\n";
|
||||||
} else {
|
} else {
|
||||||
$doc .= " $ret \\".$method->getDeclaringClass()->getName()."::".$name."($paramList);\n";
|
$doc .= " {$ret} \\" . $method->getDeclaringClass()->getName() . "::" . $name . "({$paramList});\n";
|
||||||
}
|
}
|
||||||
if (!$ret && $type->getName() === 'self') {
|
if (!$ret && $type->getName() === 'self') {
|
||||||
$doc .= " return \$this;\n";
|
$doc .= " return \$this;\n";
|
||||||
}
|
}
|
||||||
$doc .= "}\n";
|
$doc .= "}\n";
|
||||||
|
|
||||||
|
|
||||||
if (!$method->getDocComment()) {
|
if (!$method->getDocComment()) {
|
||||||
Logger::log("$name has no PHPDOC!", Logger::FATAL_ERROR);
|
Logger::log("{$name} has no PHPDOC!", Logger::FATAL_ERROR);
|
||||||
}
|
}
|
||||||
if (!$type) {
|
if (!$type) {
|
||||||
Logger::log("$name has no return type!", Logger::FATAL_ERROR);
|
Logger::log("{$name} has no return type!", Logger::FATAL_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
$internalDoc['InternalDoc'][$name]['method'] = $method->getDocComment() ?? '';
|
$internalDoc['InternalDoc'][$name]['method'] = $method->getDocComment() ?? '';
|
||||||
$internalDoc['InternalDoc'][$name]['method'] .= "\n ".\implode("\n ", \explode("\n", $doc));
|
$internalDoc['InternalDoc'][$name]['method'] .= "\n " . \implode("\n ", \explode("\n", $doc));
|
||||||
}
|
}
|
||||||
|
|
||||||
\fwrite($handle, "<?php\n");
|
\fwrite($handle, "<?php\n");
|
||||||
\fwrite($handle, "/**\n");
|
\fwrite($handle, "/**\n");
|
||||||
\fwrite($handle, " * This file is automatic generated by build_docs.php file\n");
|
\fwrite($handle, " * This file is automatic generated by build_docs.php file\n");
|
||||||
@ -331,8 +304,8 @@ class AnnotationsBuilder
|
|||||||
$longest[2] = \max($longest[2], \strlen($param['description']));
|
$longest[2] = \max($longest[2], \strlen($param['description']));
|
||||||
}
|
}
|
||||||
foreach ($properties['attr'] as $name => $param) {
|
foreach ($properties['attr'] as $name => $param) {
|
||||||
$param['type'] = \str_pad('`'.$param['type'].'`', $longest[0]+2);
|
$param['type'] = \str_pad('`' . $param['type'] . '`', $longest[0] + 2);
|
||||||
$name = \str_pad('**'.$name.'**', $longest[1]+4);
|
$name = \str_pad('**' . $name . '**', $longest[1] + 4);
|
||||||
$param['description'] = \str_pad($param['description'], $longest[2]);
|
$param['description'] = \str_pad($param['description'], $longest[2]);
|
||||||
\fwrite($handle, " * * {$param['type']} {$name} - {$param['description']}\n");
|
\fwrite($handle, " * * {$param['type']} {$name} - {$param['description']}\n");
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Async constructor abstract class.
|
* Async constructor abstract class.
|
||||||
*
|
*
|
||||||
@ -35,7 +36,6 @@ class AsyncConstruct
|
|||||||
* @var Promise
|
* @var Promise
|
||||||
*/
|
*/
|
||||||
public $asyncInitPromise;
|
public $asyncInitPromise;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blockingly init.
|
* Blockingly init.
|
||||||
*
|
*
|
||||||
@ -47,7 +47,6 @@ class AsyncConstruct
|
|||||||
Tools::wait($this->asyncInitPromise);
|
Tools::wait($this->asyncInitPromise);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asynchronously init.
|
* Asynchronously init.
|
||||||
*
|
*
|
||||||
@ -59,7 +58,6 @@ class AsyncConstruct
|
|||||||
yield $this->asyncInitPromise;
|
yield $this->asyncInitPromise;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set init promise.
|
* Set init promise.
|
||||||
*
|
*
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Async parameters class.
|
* Async parameters class.
|
||||||
*
|
*
|
||||||
@ -33,7 +34,6 @@ class AsyncParameters
|
|||||||
* @var callable
|
* @var callable
|
||||||
*/
|
*/
|
||||||
private $callable;
|
private $callable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create async parameters.
|
* Create async parameters.
|
||||||
*
|
*
|
||||||
@ -43,8 +43,6 @@ class AsyncParameters
|
|||||||
{
|
{
|
||||||
$this->callable = $callable;
|
$this->callable = $callable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create async parameters.
|
* Create async parameters.
|
||||||
*
|
*
|
||||||
@ -54,7 +52,6 @@ class AsyncParameters
|
|||||||
{
|
{
|
||||||
$this->callable = $callable;
|
$this->callable = $callable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get parameters asynchronously.
|
* Get parameters asynchronously.
|
||||||
*
|
*
|
||||||
@ -63,7 +60,6 @@ class AsyncParameters
|
|||||||
public function getParameters()
|
public function getParameters()
|
||||||
{
|
{
|
||||||
$callable = $this->callable;
|
$callable = $this->callable;
|
||||||
|
|
||||||
return $callable();
|
return $callable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,19 +33,15 @@ class CombinedAPI
|
|||||||
public $serialization_interval = 30;
|
public $serialization_interval = 30;
|
||||||
public $serialized = 0;
|
public $serialized = 0;
|
||||||
protected $async;
|
protected $async;
|
||||||
|
|
||||||
public function __magic_construct($session, $paths = [])
|
public function __magic_construct($session, $paths = [])
|
||||||
{
|
{
|
||||||
\set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
|
\set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
|
||||||
\danog\MadelineProto\Magic::classExists();
|
\danog\MadelineProto\Magic::classExists();
|
||||||
|
|
||||||
$realpaths = Serialization::realpaths($session);
|
$realpaths = Serialization::realpaths($session);
|
||||||
$this->session = $realpaths['file'];
|
$this->session = $realpaths['file'];
|
||||||
|
|
||||||
foreach ($paths as $path => $settings) {
|
foreach ($paths as $path => $settings) {
|
||||||
$this->addInstance($path, $settings);
|
$this->addInstance($path, $settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (\file_exists($realpaths['file'])) {
|
if (\file_exists($realpaths['file'])) {
|
||||||
if (!\file_exists($realpaths['lockfile'])) {
|
if (!\file_exists($realpaths['lockfile'])) {
|
||||||
\touch($realpaths['lockfile']);
|
\touch($realpaths['lockfile']);
|
||||||
@ -55,7 +51,6 @@ class CombinedAPI
|
|||||||
\danog\MadelineProto\Logger::log('Waiting for shared lock of serialization lockfile...');
|
\danog\MadelineProto\Logger::log('Waiting for shared lock of serialization lockfile...');
|
||||||
\flock($realpaths['lockfile'], LOCK_SH);
|
\flock($realpaths['lockfile'], LOCK_SH);
|
||||||
\danog\MadelineProto\Logger::log('Shared lock acquired, deserializing...');
|
\danog\MadelineProto\Logger::log('Shared lock acquired, deserializing...');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$tounserialize = \file_get_contents($realpaths['file']);
|
$tounserialize = \file_get_contents($realpaths['file']);
|
||||||
} finally {
|
} finally {
|
||||||
@ -63,14 +58,11 @@ class CombinedAPI
|
|||||||
\fclose($realpaths['lockfile']);
|
\fclose($realpaths['lockfile']);
|
||||||
}
|
}
|
||||||
$deserialized = \unserialize($tounserialize);
|
$deserialized = \unserialize($tounserialize);
|
||||||
|
|
||||||
/*foreach ($deserialized['instance_paths'] as $path) {
|
/*foreach ($deserialized['instance_paths'] as $path) {
|
||||||
$this->addInstance($path, isset($paths[$path]) ? $paths[$path] : []);
|
$this->addInstance($path, isset($paths[$path]) ? $paths[$path] : []);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
$this->event_handler = $deserialized['event_handler'];
|
$this->event_handler = $deserialized['event_handler'];
|
||||||
$this->event_handler_instance = $deserialized['event_handler_instance'];
|
$this->event_handler_instance = $deserialized['event_handler_instance'];
|
||||||
|
|
||||||
if ($this->event_handler !== null) {
|
if ($this->event_handler !== null) {
|
||||||
$this->setEventHandler($this->event_handler);
|
$this->setEventHandler($this->event_handler);
|
||||||
}
|
}
|
||||||
@ -79,29 +71,23 @@ class CombinedAPI
|
|||||||
$this->addInstance($path, $settings);
|
$this->addInstance($path, $settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addInstance($path, $settings = [])
|
public function addInstance($path, $settings = [])
|
||||||
{
|
{
|
||||||
if (isset($this->instances[$path]) && isset($this->instance_paths[$path])) {
|
if (isset($this->instances[$path]) && isset($this->instance_paths[$path])) {
|
||||||
if (isset($this->event_handler_instance)) {
|
if (isset($this->event_handler_instance)) {
|
||||||
$this->event_handler_instance->referenceInstance($path);
|
$this->event_handler_instance->referenceInstance($path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
\danog\MadelineProto\Logger::constructor(3);
|
\danog\MadelineProto\Logger::constructor(3);
|
||||||
\danog\MadelineProto\Logger::log("INSTANTIATING $path...");
|
\danog\MadelineProto\Logger::log("INSTANTIATING {$path}...");
|
||||||
$instance = new \danog\MadelineProto\API($path, $settings);
|
$instance = new \danog\MadelineProto\API($path, $settings);
|
||||||
|
|
||||||
$this->instance_paths[$path] = $path;
|
$this->instance_paths[$path] = $path;
|
||||||
$this->instances[$path] = $instance;
|
$this->instances[$path] = $instance;
|
||||||
|
|
||||||
if (isset($this->event_handler_instance)) {
|
if (isset($this->event_handler_instance)) {
|
||||||
$this->event_handler_instance->referenceInstance($path);
|
$this->event_handler_instance->referenceInstance($path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function removeInstance($path)
|
public function removeInstance($path)
|
||||||
{
|
{
|
||||||
if (isset($this->instance_paths[$path])) {
|
if (isset($this->instance_paths[$path])) {
|
||||||
@ -110,27 +96,22 @@ class CombinedAPI
|
|||||||
if (isset($this->instances[$path])) {
|
if (isset($this->instances[$path])) {
|
||||||
unset($this->instances[$path]);
|
unset($this->instances[$path]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($this->event_handler_instance)) {
|
if (isset($this->event_handler_instance)) {
|
||||||
$this->event_handler_instance->removeInstance($path);
|
$this->event_handler_instance->removeInstance($path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __destruct()
|
public function __destruct()
|
||||||
{
|
{
|
||||||
if (\danog\MadelineProto\Magic::$has_thread && \is_object(\Thread::getCurrentThread()) || Magic::isFork()) {
|
if (\danog\MadelineProto\Magic::$has_thread && \is_object(\Thread::getCurrentThread()) || Magic::isFork()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->serialize();
|
$this->serialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function serialize($filename = '')
|
public function serialize($filename = '')
|
||||||
{
|
{
|
||||||
/*foreach ($this->instances as $instance) {
|
/*foreach ($this->instances as $instance) {
|
||||||
$instance->serialize();
|
$instance->serialize();
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
if (\is_null($this->session)) {
|
if (\is_null($this->session)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -147,7 +128,6 @@ class CombinedAPI
|
|||||||
\danog\MadelineProto\Logger::log('Waiting for exclusive lock of serialization lockfile...');
|
\danog\MadelineProto\Logger::log('Waiting for exclusive lock of serialization lockfile...');
|
||||||
\flock($realpaths['lockfile'], LOCK_EX);
|
\flock($realpaths['lockfile'], LOCK_EX);
|
||||||
\danog\MadelineProto\Logger::log('Lock acquired, serializing');
|
\danog\MadelineProto\Logger::log('Lock acquired, serializing');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$wrote = \file_put_contents($realpaths['tempfile'], \serialize(['event_handler' => $this->event_handler, 'event_handler_instance' => $this->event_handler_instance, 'instance_paths' => $this->instance_paths]));
|
$wrote = \file_put_contents($realpaths['tempfile'], \serialize(['event_handler' => $this->event_handler, 'event_handler_instance' => $this->event_handler_instance, 'instance_paths' => $this->instance_paths]));
|
||||||
\rename($realpaths['tempfile'], $realpaths['file']);
|
\rename($realpaths['tempfile'], $realpaths['file']);
|
||||||
@ -155,12 +135,9 @@ class CombinedAPI
|
|||||||
\flock($realpaths['lockfile'], LOCK_UN);
|
\flock($realpaths['lockfile'], LOCK_UN);
|
||||||
\fclose($realpaths['lockfile']);
|
\fclose($realpaths['lockfile']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->serialized = \time();
|
$this->serialized = \time();
|
||||||
|
|
||||||
return $wrote;
|
return $wrote;
|
||||||
}
|
}
|
||||||
|
|
||||||
public $event_handler;
|
public $event_handler;
|
||||||
private $event_handler_instance;
|
private $event_handler_instance;
|
||||||
private $event_handler_methods = [];
|
private $event_handler_methods = [];
|
||||||
@ -170,20 +147,17 @@ class CombinedAPI
|
|||||||
}
|
}
|
||||||
public function setEventHandler($event_handler)
|
public function setEventHandler($event_handler)
|
||||||
{
|
{
|
||||||
if (!\class_exists($event_handler) || !\is_subclass_of($event_handler, '\danog\MadelineProto\CombinedEventHandler')) {
|
if (!\class_exists($event_handler) || !\is_subclass_of($event_handler, '\\danog\\MadelineProto\\CombinedEventHandler')) {
|
||||||
throw new \danog\MadelineProto\Exception('Wrong event handler was defined');
|
throw new \danog\MadelineProto\Exception('Wrong event handler was defined');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->event_handler = $event_handler;
|
$this->event_handler = $event_handler;
|
||||||
|
if (!$this->event_handler_instance instanceof $this->event_handler) {
|
||||||
if (!($this->event_handler_instance instanceof $this->event_handler)) {
|
|
||||||
$class_name = $this->event_handler;
|
$class_name = $this->event_handler;
|
||||||
$this->event_handler_instance = new $class_name($this);
|
$this->event_handler_instance = new $class_name($this);
|
||||||
} else {
|
} else {
|
||||||
$this->event_handler_instance->__construct($this);
|
$this->event_handler_instance->__construct($this);
|
||||||
}
|
}
|
||||||
$this->event_handler_methods = [];
|
$this->event_handler_methods = [];
|
||||||
|
|
||||||
foreach (\get_class_methods($this->event_handler) as $method) {
|
foreach (\get_class_methods($this->event_handler) as $method) {
|
||||||
if ($method === 'onLoop') {
|
if ($method === 'onLoop') {
|
||||||
$this->loop_callback = [$this->event_handler_instance, 'onLoop'];
|
$this->loop_callback = [$this->event_handler_instance, 'onLoop'];
|
||||||
@ -199,16 +173,13 @@ class CombinedAPI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function eventUpdateHandler($update, $instance)
|
public function eventUpdateHandler($update, $instance)
|
||||||
{
|
{
|
||||||
if (isset($this->event_handler_methods[$update['_']])) {
|
if (isset($this->event_handler_methods[$update['_']])) {
|
||||||
return $this->event_handler_methods[$update['_']]($update, $instance);
|
return $this->event_handler_methods[$update['_']]($update, $instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private $loop_callback;
|
private $loop_callback;
|
||||||
|
|
||||||
public function async($async)
|
public function async($async)
|
||||||
{
|
{
|
||||||
$this->async = $async;
|
$this->async = $async;
|
||||||
@ -216,22 +187,18 @@ class CombinedAPI
|
|||||||
$instance->async($async);
|
$instance->async($async);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setLoopCallback($callback)
|
public function setLoopCallback($callback)
|
||||||
{
|
{
|
||||||
$this->loop_callback = $callback;
|
$this->loop_callback = $callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUpdates($params = [])
|
public function getUpdates($params = [])
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loop($max_forks = 0)
|
public function loop($max_forks = 0)
|
||||||
{
|
{
|
||||||
if (\is_callable($max_forks)) {
|
if (\is_callable($max_forks)) {
|
||||||
return \danog\MadelineProto\Tools::wait($max_forks());
|
return \danog\MadelineProto\Tools::wait($max_forks());
|
||||||
}
|
}
|
||||||
|
|
||||||
$loops = [];
|
$loops = [];
|
||||||
foreach ($this->instances as $path => $instance) {
|
foreach ($this->instances as $path => $instance) {
|
||||||
\danog\MadelineProto\Tools::wait($instance->initAsynchronously());
|
\danog\MadelineProto\Tools::wait($instance->initAsynchronously());
|
||||||
@ -250,12 +217,10 @@ class CombinedAPI
|
|||||||
}
|
}
|
||||||
$loops[] = \danog\MadelineProto\Tools::call($instance->loop(0, ['async' => true]));
|
$loops[] = \danog\MadelineProto\Tools::call($instance->loop(0, ['async' => true]));
|
||||||
}
|
}
|
||||||
|
|
||||||
Loop::repeat($this->serialization_interval * 1000, function () {
|
Loop::repeat($this->serialization_interval * 1000, function () {
|
||||||
\danog\MadelineProto\Logger::log('Serializing combined event handler');
|
\danog\MadelineProto\Logger::log('Serializing combined event handler');
|
||||||
$this->serialize();
|
$this->serialize();
|
||||||
});
|
});
|
||||||
|
|
||||||
\danog\MadelineProto\Logger::log('Started update loop', \danog\MadelineProto\Logger::NOTICE);
|
\danog\MadelineProto\Logger::log('Started update loop', \danog\MadelineProto\Logger::NOTICE);
|
||||||
\danog\MadelineProto\Tools::wait(all($loops));
|
\danog\MadelineProto\Tools::wait(all($loops));
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,6 @@ namespace danog\MadelineProto;
|
|||||||
abstract class CombinedEventHandler
|
abstract class CombinedEventHandler
|
||||||
{
|
{
|
||||||
private $CombinedAPI;
|
private $CombinedAPI;
|
||||||
|
|
||||||
public function __construct($CombinedAPI)
|
public function __construct($CombinedAPI)
|
||||||
{
|
{
|
||||||
$this->CombinedAPI = $CombinedAPI;
|
$this->CombinedAPI = $CombinedAPI;
|
||||||
@ -30,7 +29,6 @@ abstract class CombinedEventHandler
|
|||||||
$this->referenceInstance($path);
|
$this->referenceInstance($path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final public function __sleep()
|
final public function __sleep()
|
||||||
{
|
{
|
||||||
$keys = \method_exists($this, '__magic_sleep') ? $this->__magic_sleep() : \get_object_vars($this);
|
$keys = \method_exists($this, '__magic_sleep') ? $this->__magic_sleep() : \get_object_vars($this);
|
||||||
@ -46,15 +44,12 @@ abstract class CombinedEventHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return \array_keys($keys);
|
return \array_keys($keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
final public function referenceInstance($path)
|
final public function referenceInstance($path)
|
||||||
{
|
{
|
||||||
$this->{$path} = $this->CombinedAPI->instances[$path];
|
$this->{$path} = $this->CombinedAPI->instances[$path];
|
||||||
}
|
}
|
||||||
|
|
||||||
final public function removeInstance($path)
|
final public function removeInstance($path)
|
||||||
{
|
{
|
||||||
if (isset($this->{$path})) {
|
if (isset($this->{$path})) {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connection module.
|
* Connection module.
|
||||||
*
|
*
|
||||||
@ -44,7 +45,6 @@ class Connection extends Session
|
|||||||
{
|
{
|
||||||
use \danog\Serializable;
|
use \danog\Serializable;
|
||||||
use Tools;
|
use Tools;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writer loop.
|
* Writer loop.
|
||||||
*
|
*
|
||||||
@ -87,7 +87,6 @@ class Connection extends Session
|
|||||||
* @var ConnectionContext
|
* @var ConnectionContext
|
||||||
*/
|
*/
|
||||||
private $ctx;
|
private $ctx;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP request count.
|
* HTTP request count.
|
||||||
*
|
*
|
||||||
@ -100,14 +99,12 @@ class Connection extends Session
|
|||||||
* @var integer
|
* @var integer
|
||||||
*/
|
*/
|
||||||
private $httpResCount = 0;
|
private $httpResCount = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Date of last chunk received.
|
* Date of last chunk received.
|
||||||
*
|
*
|
||||||
* @var integer
|
* @var integer
|
||||||
*/
|
*/
|
||||||
private $lastChunk = 0;
|
private $lastChunk = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logger instance.
|
* Logger instance.
|
||||||
*
|
*
|
||||||
@ -126,28 +123,24 @@ class Connection extends Session
|
|||||||
* @var DataCenterConnection
|
* @var DataCenterConnection
|
||||||
*/
|
*/
|
||||||
protected $shared;
|
protected $shared;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DC ID.
|
* DC ID.
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $datacenter;
|
protected $datacenter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connection ID.
|
* Connection ID.
|
||||||
*
|
*
|
||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
private $id = 0;
|
private $id = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DC ID and connection ID concatenated.
|
* DC ID and connection ID concatenated.
|
||||||
*
|
*
|
||||||
* @var
|
* @var
|
||||||
*/
|
*/
|
||||||
private $datacenterId = '';
|
private $datacenterId = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this socket has to be reconnected.
|
* Whether this socket has to be reconnected.
|
||||||
*
|
*
|
||||||
@ -214,7 +207,6 @@ class Connection extends Session
|
|||||||
{
|
{
|
||||||
$this->shared->reading($reading, $this->id);
|
$this->shared->reading($reading, $this->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tell the class that we have read a chunk of data from the socket.
|
* Tell the class that we have read a chunk of data from the socket.
|
||||||
*
|
*
|
||||||
@ -233,7 +225,6 @@ class Connection extends Session
|
|||||||
{
|
{
|
||||||
return $this->lastChunk;
|
return $this->lastChunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicate a received HTTP response.
|
* Indicate a received HTTP response.
|
||||||
*
|
*
|
||||||
@ -270,7 +261,6 @@ class Connection extends Session
|
|||||||
{
|
{
|
||||||
return $this->httpReqCount;
|
return $this->httpReqCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get connection ID.
|
* Get connection ID.
|
||||||
*
|
*
|
||||||
@ -280,7 +270,6 @@ class Connection extends Session
|
|||||||
{
|
{
|
||||||
return $this->id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get datacenter concatenated with connection ID.
|
* Get datacenter concatenated with connection ID.
|
||||||
*
|
*
|
||||||
@ -290,7 +279,6 @@ class Connection extends Session
|
|||||||
{
|
{
|
||||||
return $this->datacenterId;
|
return $this->datacenterId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get connection context.
|
* Get connection context.
|
||||||
*
|
*
|
||||||
@ -300,7 +288,6 @@ class Connection extends Session
|
|||||||
{
|
{
|
||||||
return $this->ctx;
|
return $this->ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if is an HTTP connection.
|
* Check if is an HTTP connection.
|
||||||
*
|
*
|
||||||
@ -310,7 +297,6 @@ class Connection extends Session
|
|||||||
{
|
{
|
||||||
return \in_array($this->ctx->getStreamName(), [HttpStream::getName(), HttpsStream::getName()]);
|
return \in_array($this->ctx->getStreamName(), [HttpStream::getName(), HttpsStream::getName()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if is a media connection.
|
* Check if is a media connection.
|
||||||
*
|
*
|
||||||
@ -320,7 +306,6 @@ class Connection extends Session
|
|||||||
{
|
{
|
||||||
return $this->ctx->isMedia();
|
return $this->ctx->isMedia();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if is a CDN connection.
|
* Check if is a CDN connection.
|
||||||
*
|
*
|
||||||
@ -330,7 +315,6 @@ class Connection extends Session
|
|||||||
{
|
{
|
||||||
return $this->ctx->isCDN();
|
return $this->ctx->isCDN();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connects to a telegram DC using the specified protocol, proxy and connection parameters.
|
* Connects to a telegram DC using the specified protocol, proxy and connection parameters.
|
||||||
*
|
*
|
||||||
@ -342,18 +326,15 @@ 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->datacenterId = $this->datacenter . '.' . $this->id;
|
||||||
$this->API->logger->logger("Connecting to DC {$this->datacenterId}", \danog\MadelineProto\Logger::WARNING);
|
$this->API->logger->logger("Connecting to DC {$this->datacenterId}", \danog\MadelineProto\Logger::WARNING);
|
||||||
|
|
||||||
$ctx->setReadCallback([$this, 'haveRead']);
|
$ctx->setReadCallback([$this, 'haveRead']);
|
||||||
$this->stream = yield $ctx->getStream();
|
$this->stream = yield $ctx->getStream();
|
||||||
|
|
||||||
if ($this->needsReconnect) {
|
if ($this->needsReconnect) {
|
||||||
$this->needsReconnect = false;
|
$this->needsReconnect = false;
|
||||||
}
|
}
|
||||||
$this->httpReqCount = 0;
|
$this->httpReqCount = 0;
|
||||||
$this->httpResCount = 0;
|
$this->httpResCount = 0;
|
||||||
|
|
||||||
if (!isset($this->writer)) {
|
if (!isset($this->writer)) {
|
||||||
$this->writer = new WriteLoop($this);
|
$this->writer = new WriteLoop($this);
|
||||||
}
|
}
|
||||||
@ -378,7 +359,6 @@ class Connection extends Session
|
|||||||
unset($this->new_outgoing[$message_id], $this->outgoing_messages[$message_id]);
|
unset($this->new_outgoing[$message_id], $this->outgoing_messages[$message_id]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->writer->start();
|
$this->writer->start();
|
||||||
$this->reader->start();
|
$this->reader->start();
|
||||||
if (!$this->checker->start()) {
|
if (!$this->checker->start()) {
|
||||||
@ -389,7 +369,6 @@ class Connection extends Session
|
|||||||
$this->pinger->start();
|
$this->pinger->start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send an MTProto message.
|
* Send an MTProto message.
|
||||||
*
|
*
|
||||||
@ -427,17 +406,13 @@ class Connection extends Session
|
|||||||
public function sendMessage(array $message, bool $flush = true): \Generator
|
public function sendMessage(array $message, bool $flush = true): \Generator
|
||||||
{
|
{
|
||||||
$deferred = new Deferred();
|
$deferred = new Deferred();
|
||||||
|
|
||||||
if (!isset($message['serialized_body'])) {
|
if (!isset($message['serialized_body'])) {
|
||||||
$body = \is_object($message['body']) ? yield $message['body'] : $message['body'];
|
$body = \is_object($message['body']) ? yield $message['body'] : $message['body'];
|
||||||
|
|
||||||
$refreshNext = isset($message['refreshNext']) && $message['refreshNext'];
|
$refreshNext = isset($message['refreshNext']) && $message['refreshNext'];
|
||||||
//$refreshNext = true;
|
//$refreshNext = true;
|
||||||
|
|
||||||
if ($refreshNext) {
|
if ($refreshNext) {
|
||||||
$this->API->referenceDatabase->refreshNext(true);
|
$this->API->referenceDatabase->refreshNext(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($message['method']) {
|
if ($message['method']) {
|
||||||
$body = yield $this->API->getTL()->serializeMethod($message['_'], $body);
|
$body = yield $this->API->getTL()->serializeMethod($message['_'], $body);
|
||||||
} else {
|
} else {
|
||||||
@ -450,16 +425,13 @@ class Connection extends Session
|
|||||||
$message['serialized_body'] = $body;
|
$message['serialized_body'] = $body;
|
||||||
unset($body);
|
unset($body);
|
||||||
}
|
}
|
||||||
|
|
||||||
$message['send_promise'] = $deferred;
|
$message['send_promise'] = $deferred;
|
||||||
$this->pending_outgoing[$this->pending_outgoing_key++] = $message;
|
$this->pending_outgoing[$this->pending_outgoing_key++] = $message;
|
||||||
if ($flush && isset($this->writer)) {
|
if ($flush && isset($this->writer)) {
|
||||||
$this->writer->resume();
|
$this->writer->resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $deferred->promise();
|
return $deferred->promise();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flush pending packets.
|
* Flush pending packets.
|
||||||
*
|
*
|
||||||
@ -500,7 +472,6 @@ class Connection extends Session
|
|||||||
$this->API = $extra->getExtra();
|
$this->API = $extra->getExtra();
|
||||||
$this->logger = $this->API->logger;
|
$this->logger = $this->API->logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get main instance.
|
* Get main instance.
|
||||||
*
|
*
|
||||||
@ -510,7 +481,6 @@ class Connection extends Session
|
|||||||
{
|
{
|
||||||
return $this->API;
|
return $this->API;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get shared connection instance.
|
* Get shared connection instance.
|
||||||
*
|
*
|
||||||
@ -520,7 +490,6 @@ class Connection extends Session
|
|||||||
{
|
{
|
||||||
return $this->shared;
|
return $this->shared;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disconnect from DC.
|
* Disconnect from DC.
|
||||||
*
|
*
|
||||||
@ -549,7 +518,6 @@ class Connection extends Session
|
|||||||
}
|
}
|
||||||
$this->API->logger->logger("Disconnected from DC {$this->datacenterId}");
|
$this->API->logger->logger("Disconnected from DC {$this->datacenterId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reconnect to DC.
|
* Reconnect to DC.
|
||||||
*
|
*
|
||||||
@ -561,7 +529,6 @@ class Connection extends Session
|
|||||||
$this->disconnect(true);
|
$this->disconnect(true);
|
||||||
yield $this->API->datacenter->dcConnect($this->ctx->getDc(), $this->id);
|
yield $this->API->datacenter->dcConnect($this->ctx->getDc(), $this->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get name.
|
* Get name.
|
||||||
*
|
*
|
||||||
|
@ -37,16 +37,14 @@ class ContextConnector implements Connector
|
|||||||
$this->fromDns = $fromDns;
|
$this->fromDns = $fromDns;
|
||||||
$this->logger = $dataCenter->getAPI()->getLogger();
|
$this->logger = $dataCenter->getAPI()->getLogger();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function connect(string $uri, ?ConnectContext $ctx = null, ?CancellationToken $token = null): Promise
|
public function connect(string $uri, ?ConnectContext $ctx = null, ?CancellationToken $token = null): Promise
|
||||||
{
|
{
|
||||||
return Tools::call((function () use ($uri, $ctx, $token) {
|
return Tools::call((function () use ($uri, $ctx, $token): \Generator {
|
||||||
$ctx = $ctx ?? new ConnectContext;
|
$ctx = $ctx ?? new ConnectContext();
|
||||||
$token = $token ?? new NullCancellationToken;
|
$token = $token ?? new NullCancellationToken();
|
||||||
|
|
||||||
$ctxs = $this->dataCenter->generateContexts(0, $uri, $ctx);
|
$ctxs = $this->dataCenter->generateContexts(0, $uri, $ctx);
|
||||||
if (empty($ctxs)) {
|
if (empty($ctxs)) {
|
||||||
throw new Exception("No contexts for raw connection to URI $uri");
|
throw new Exception("No contexts for raw connection to URI {$uri}");
|
||||||
}
|
}
|
||||||
foreach ($ctxs as $ctx) {
|
foreach ($ctxs as $ctx) {
|
||||||
/* @var $ctx \danog\MadelineProto\Stream\ConnectionContext */
|
/* @var $ctx \danog\MadelineProto\Stream\ConnectionContext */
|
||||||
@ -55,22 +53,20 @@ class ContextConnector implements Connector
|
|||||||
$ctx->setCancellationToken($token);
|
$ctx->setCancellationToken($token);
|
||||||
$result = yield $ctx->getStream();
|
$result = yield $ctx->getStream();
|
||||||
$this->logger->logger('OK!', \danog\MadelineProto\Logger::WARNING);
|
$this->logger->logger('OK!', \danog\MadelineProto\Logger::WARNING);
|
||||||
|
|
||||||
return $result->getSocket();
|
return $result->getSocket();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
if (\MADELINEPROTO_TEST === 'pony') {
|
if (\MADELINEPROTO_TEST === 'pony') {
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
$this->logger->logger('Connection failed: '.$e, \danog\MadelineProto\Logger::ERROR);
|
$this->logger->logger('Connection failed: ' . $e, \danog\MadelineProto\Logger::ERROR);
|
||||||
if ($e instanceof MultiReasonException) {
|
if ($e instanceof MultiReasonException) {
|
||||||
foreach ($e->getReasons() as $reason) {
|
foreach ($e->getReasons() as $reason) {
|
||||||
$this->logger->logger('Multireason: '.$reason, \danog\MadelineProto\Logger::ERROR);
|
$this->logger->logger('Multireason: ' . $reason, \danog\MadelineProto\Logger::ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
throw new \danog\MadelineProto\Exception("Could not connect to URI {$uri}");
|
||||||
throw new \danog\MadelineProto\Exception("Could not connect to URI $uri");
|
|
||||||
})());
|
})());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Coroutine (modified version of AMP Coroutine).
|
* Coroutine (modified version of AMP Coroutine).
|
||||||
*
|
*
|
||||||
@ -57,24 +58,20 @@ final class Coroutine implements Promise, \ArrayAccess
|
|||||||
private $exception;
|
private $exception;
|
||||||
/** @var mixed Promise success value when executing next coroutine step, null at all other times. */
|
/** @var mixed Promise success value when executing next coroutine step, null at all other times. */
|
||||||
private $value;
|
private $value;
|
||||||
|
|
||||||
/** @var ?self Reference to coroutine that started this coroutine */
|
/** @var ?self Reference to coroutine that started this coroutine */
|
||||||
private $parentCoroutine;
|
private $parentCoroutine;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \Generator $generator
|
* @param \Generator $generator
|
||||||
*/
|
*/
|
||||||
public function __construct(\Generator $generator)
|
public function __construct(\Generator $generator)
|
||||||
{
|
{
|
||||||
$this->generator = $generator;
|
$this->generator = $generator;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$yielded = $this->generator->current();
|
$yielded = $this->generator->current();
|
||||||
while (!$yielded instanceof Promise) {
|
while (!$yielded instanceof Promise) {
|
||||||
if ($yielded instanceof \YieldReturnValue) {
|
if ($yielded instanceof \YieldReturnValue) {
|
||||||
$this->resolve($yielded->getReturn());
|
$this->resolve($yielded->getReturn());
|
||||||
$this->generator->next();
|
$this->generator->next();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!$this->generator->valid()) {
|
if (!$this->generator->valid()) {
|
||||||
@ -83,7 +80,6 @@ final class Coroutine implements Promise, \ArrayAccess
|
|||||||
} else {
|
} else {
|
||||||
$this->resolve(null);
|
$this->resolve(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($yielded instanceof \Generator) {
|
if ($yielded instanceof \Generator) {
|
||||||
@ -97,7 +93,6 @@ final class Coroutine implements Promise, \ArrayAccess
|
|||||||
}
|
}
|
||||||
} catch (\Throwable $exception) {
|
} catch (\Throwable $exception) {
|
||||||
$this->fail($exception);
|
$this->fail($exception);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -109,10 +104,8 @@ final class Coroutine implements Promise, \ArrayAccess
|
|||||||
$this->value = $value;
|
$this->value = $value;
|
||||||
if (!$this->immediate) {
|
if (!$this->immediate) {
|
||||||
$this->immediate = true;
|
$this->immediate = true;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
do {
|
do {
|
||||||
if ($this->exception) {
|
if ($this->exception) {
|
||||||
@ -127,10 +120,8 @@ final class Coroutine implements Promise, \ArrayAccess
|
|||||||
$this->resolve($yielded->getReturn());
|
$this->resolve($yielded->getReturn());
|
||||||
$this->onResolve = null;
|
$this->onResolve = null;
|
||||||
$this->generator->next();
|
$this->generator->next();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->generator->valid()) {
|
if (!$this->generator->valid()) {
|
||||||
if (PHP_MAJOR_VERSION >= 7) {
|
if (PHP_MAJOR_VERSION >= 7) {
|
||||||
$this->resolve($this->generator->getReturn());
|
$this->resolve($this->generator->getReturn());
|
||||||
@ -138,7 +129,6 @@ final class Coroutine implements Promise, \ArrayAccess
|
|||||||
$this->resolve(null);
|
$this->resolve(null);
|
||||||
}
|
}
|
||||||
$this->onResolve = null;
|
$this->onResolve = null;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($yielded instanceof \Generator) {
|
if ($yielded instanceof \Generator) {
|
||||||
@ -164,20 +154,19 @@ final class Coroutine implements Promise, \ArrayAccess
|
|||||||
};
|
};
|
||||||
$yielded->onResolve($this->onResolve);
|
$yielded->onResolve($this->onResolve);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Throw exception into the generator
|
* Throw exception into the generator.
|
||||||
*
|
*
|
||||||
* @param \Throwable $reason Exception
|
* @param \Throwable $reason Exception
|
||||||
*
|
*
|
||||||
* @internal
|
* @internal
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function throw(\Throwable $reason)
|
public function throw(\Throwable $reason)
|
||||||
{
|
{
|
||||||
if (!isset($reason->yieldedFrames)) {
|
if (!isset($reason->yieldedFrames)) {
|
||||||
if (method_exists($reason, 'updateTLTrace')) {
|
if (\method_exists($reason, 'updateTLTrace')) {
|
||||||
$reason->updateTLTrace($this->getTrace());
|
$reason->updateTLTrace($this->getTrace());
|
||||||
} else {
|
} else {
|
||||||
$reason->yieldedFrames = $this->getTrace();
|
$reason->yieldedFrames = $this->getTrace();
|
||||||
@ -185,7 +174,6 @@ final class Coroutine implements Promise, \ArrayAccess
|
|||||||
}
|
}
|
||||||
$this->generator->throw($reason);
|
$this->generator->throw($reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \Throwable $reason Failure reason.
|
* @param \Throwable $reason Failure reason.
|
||||||
*/
|
*/
|
||||||
@ -193,7 +181,6 @@ final class Coroutine implements Promise, \ArrayAccess
|
|||||||
{
|
{
|
||||||
$this->resolve(new Failure($reason));
|
$this->resolve(new Failure($reason));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function offsetExists($offset): bool
|
public function offsetExists($offset): bool
|
||||||
{
|
{
|
||||||
throw new Exception('Not supported!');
|
throw new Exception('Not supported!');
|
||||||
@ -207,14 +194,14 @@ final class Coroutine implements Promise, \ArrayAccess
|
|||||||
*/
|
*/
|
||||||
public function offsetGet($offset)
|
public function offsetGet($offset)
|
||||||
{
|
{
|
||||||
return Tools::call((function () use ($offset) {
|
return Tools::call((function () use ($offset): \Generator {
|
||||||
$result = yield $this;
|
$result = yield $this;
|
||||||
return $result[$offset];
|
return $result[$offset];
|
||||||
})());
|
})());
|
||||||
}
|
}
|
||||||
public function offsetSet($offset, $value)
|
public function offsetSet($offset, $value)
|
||||||
{
|
{
|
||||||
return Tools::call((function () use ($offset, $value) {
|
return Tools::call((function () use ($offset, $value): \Generator {
|
||||||
$result = yield $this;
|
$result = yield $this;
|
||||||
if ($offset === null) {
|
if ($offset === null) {
|
||||||
return $result[] = $value;
|
return $result[] = $value;
|
||||||
@ -224,12 +211,11 @@ final class Coroutine implements Promise, \ArrayAccess
|
|||||||
}
|
}
|
||||||
public function offsetUnset($offset)
|
public function offsetUnset($offset)
|
||||||
{
|
{
|
||||||
return Tools::call((function () use ($offset) {
|
return Tools::call((function () use ($offset): \Generator {
|
||||||
$result = yield $this;
|
$result = yield $this;
|
||||||
unset($result[$offset]);
|
unset($result[$offset]);
|
||||||
})());
|
})());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an attribute asynchronously.
|
* Get an attribute asynchronously.
|
||||||
*
|
*
|
||||||
@ -239,19 +225,18 @@ final class Coroutine implements Promise, \ArrayAccess
|
|||||||
*/
|
*/
|
||||||
public function __get(string $offset)
|
public function __get(string $offset)
|
||||||
{
|
{
|
||||||
return Tools::call((function () use ($offset) {
|
return Tools::call((function () use ($offset): \Generator {
|
||||||
$result = yield $this;
|
$result = yield $this;
|
||||||
return $result->{$offset};
|
return $result->{$offset};
|
||||||
})());
|
})());
|
||||||
}
|
}
|
||||||
public function __call(string $name, array $arguments)
|
public function __call(string $name, array $arguments)
|
||||||
{
|
{
|
||||||
return Tools::call((function () use ($name, $arguments) {
|
return Tools::call((function () use ($name, $arguments): \Generator {
|
||||||
$result = yield $this;
|
$result = yield $this;
|
||||||
return $result->{$name}($arguments);
|
return $result->{$name}($arguments);
|
||||||
})());
|
})());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get current stack trace for running coroutine.
|
* Get current stack trace for running coroutine.
|
||||||
*
|
*
|
||||||
@ -263,13 +248,7 @@ final class Coroutine implements Promise, \ArrayAccess
|
|||||||
try {
|
try {
|
||||||
$reflector = new ReflectionGenerator($this->generator);
|
$reflector = new ReflectionGenerator($this->generator);
|
||||||
$frames = $reflector->getTrace();
|
$frames = $reflector->getTrace();
|
||||||
$frames []= \array_merge(
|
$frames[] = \array_merge($this->parentCoroutine ? $this->parentCoroutine->getFrame() : [], ['function' => $reflector->getFunction()->getName(), 'args' => []]);
|
||||||
$this->parentCoroutine ? $this->parentCoroutine->getFrame() : [],
|
|
||||||
[
|
|
||||||
'function' => $reflector->getFunction()->getName(),
|
|
||||||
'args' => []
|
|
||||||
]
|
|
||||||
);
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
}
|
}
|
||||||
if ($this->parentCoroutine) {
|
if ($this->parentCoroutine) {
|
||||||
@ -277,9 +256,8 @@ final class Coroutine implements Promise, \ArrayAccess
|
|||||||
}
|
}
|
||||||
return $frames;
|
return $frames;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get current execution frame
|
* Get current execution frame.
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
@ -287,10 +265,7 @@ final class Coroutine implements Promise, \ArrayAccess
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$reflector = new ReflectionGenerator($this->generator);
|
$reflector = new ReflectionGenerator($this->generator);
|
||||||
return [
|
return ['file' => $reflector->getExecutingFile(), 'line' => $reflector->getExecutingLine()];
|
||||||
'file' => $reflector->getExecutingFile(),
|
|
||||||
'line' => $reflector->getExecutingLine(),
|
|
||||||
];
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
|
@ -114,12 +114,10 @@ class DataCenter
|
|||||||
* @var \Amp\Http\Client\Cookie\CookieJar
|
* @var \Amp\Http\Client\Cookie\CookieJar
|
||||||
*/
|
*/
|
||||||
private $CookieJar;
|
private $CookieJar;
|
||||||
|
|
||||||
public function __sleep()
|
public function __sleep()
|
||||||
{
|
{
|
||||||
return ['sockets', 'curdc', 'dclist', 'settings'];
|
return ['sockets', 'curdc', 'dclist', 'settings'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __wakeup()
|
public function __wakeup()
|
||||||
{
|
{
|
||||||
$array = [];
|
$array = [];
|
||||||
@ -136,7 +134,6 @@ class DataCenter
|
|||||||
}
|
}
|
||||||
$this->setDataCenterConnections($array);
|
$this->setDataCenterConnections($array);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set auth key information from saved auth array.
|
* Set auth key information from saved auth array.
|
||||||
*
|
*
|
||||||
@ -147,7 +144,7 @@ class DataCenter
|
|||||||
public function setDataCenterConnections(array $saved)
|
public function setDataCenterConnections(array $saved)
|
||||||
{
|
{
|
||||||
foreach ($saved as $id => $data) {
|
foreach ($saved as $id => $data) {
|
||||||
$connection = $this->sockets[$id] = new DataCenterConnection;
|
$connection = $this->sockets[$id] = new DataCenterConnection();
|
||||||
if (isset($data['permAuthKey'])) {
|
if (isset($data['permAuthKey'])) {
|
||||||
$connection->setPermAuthKey(new PermAuthKey($data['permAuthKey']));
|
$connection->setPermAuthKey(new PermAuthKey($data['permAuthKey']));
|
||||||
}
|
}
|
||||||
@ -187,12 +184,11 @@ class DataCenter
|
|||||||
public function __magic_construct($API, array $dclist, array $settings, bool $reconnectAll = true, CookieJar $jar = null)
|
public function __magic_construct($API, array $dclist, array $settings, bool $reconnectAll = true, CookieJar $jar = null)
|
||||||
{
|
{
|
||||||
$this->API = $API;
|
$this->API = $API;
|
||||||
|
|
||||||
$changed = [];
|
$changed = [];
|
||||||
$changedSettings = $this->settings !== $settings;
|
$changedSettings = $this->settings !== $settings;
|
||||||
if (!$reconnectAll) {
|
if (!$reconnectAll) {
|
||||||
$changed = [];
|
$changed = [];
|
||||||
$test = ($API->getCachedConfig()['test_mode'] ?? false) ? 'test' : 'main';
|
$test = $API->getCachedConfig()['test_mode'] ?? false ? 'test' : 'main';
|
||||||
foreach ($dclist[$test] as $ipv6 => $dcs) {
|
foreach ($dclist[$test] as $ipv6 => $dcs) {
|
||||||
foreach ($dcs as $id => $dc) {
|
foreach ($dcs as $id => $dc) {
|
||||||
if ($dc !== ($this->dclist[$test][$ipv6][$id] ?? [])) {
|
if ($dc !== ($this->dclist[$test][$ipv6][$id] ?? [])) {
|
||||||
@ -201,7 +197,6 @@ class DataCenter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->dclist = $dclist;
|
$this->dclist = $dclist;
|
||||||
$this->settings = $settings;
|
$this->settings = $settings;
|
||||||
foreach ($this->sockets as $key => $socket) {
|
foreach ($this->sockets as $key => $socket) {
|
||||||
@ -217,96 +212,57 @@ class DataCenter
|
|||||||
unset($this->sockets[$key]);
|
unset($this->sockets[$key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($reconnectAll || $changedSettings || !$this->CookieJar) {
|
if ($reconnectAll || $changedSettings || !$this->CookieJar) {
|
||||||
$this->CookieJar = $jar ?? new InMemoryCookieJar;
|
$this->CookieJar = $jar ?? new InMemoryCookieJar();
|
||||||
$this->HTTPClient = (new HttpClientBuilder)
|
$this->HTTPClient = (new HttpClientBuilder())->interceptNetwork(new CookieInterceptor($this->CookieJar))->usingPool(new UnlimitedConnectionPool(new DefaultConnectionFactory(new ContextConnector($this))))->build();
|
||||||
->interceptNetwork(new CookieInterceptor($this->CookieJar))
|
$DoHHTTPClient = (new HttpClientBuilder())->interceptNetwork(new CookieInterceptor($this->CookieJar))->usingPool(new UnlimitedConnectionPool(new DefaultConnectionFactory(new ContextConnector($this, true))))->build();
|
||||||
->usingPool(new UnlimitedConnectionPool(new DefaultConnectionFactory(new ContextConnector($this))))
|
$DoHConfig = new DoHConfig([new Nameserver('https://mozilla.cloudflare-dns.com/dns-query'), new Nameserver('https://dns.google/resolve')], $DoHHTTPClient);
|
||||||
->build();
|
$nonProxiedDoHConfig = new DoHConfig([new Nameserver('https://mozilla.cloudflare-dns.com/dns-query'), new Nameserver('https://dns.google/resolve')]);
|
||||||
|
$this->DoHClient = Magic::$altervista || Magic::$zerowebhost ? new Rfc1035StubResolver() : new Rfc8484StubResolver($DoHConfig);
|
||||||
$DoHHTTPClient = (new HttpClientBuilder)
|
$this->nonProxiedDoHClient = Magic::$altervista || Magic::$zerowebhost ? new Rfc1035StubResolver() : new Rfc8484StubResolver($nonProxiedDoHConfig);
|
||||||
->interceptNetwork(new CookieInterceptor($this->CookieJar))
|
|
||||||
->usingPool(new UnlimitedConnectionPool(new DefaultConnectionFactory(new ContextConnector($this, true))))
|
|
||||||
->build();
|
|
||||||
|
|
||||||
$DoHConfig = new DoHConfig(
|
|
||||||
[
|
|
||||||
new Nameserver('https://mozilla.cloudflare-dns.com/dns-query'),
|
|
||||||
new Nameserver('https://dns.google/resolve'),
|
|
||||||
],
|
|
||||||
$DoHHTTPClient
|
|
||||||
);
|
|
||||||
$nonProxiedDoHConfig = new DoHConfig(
|
|
||||||
[
|
|
||||||
new Nameserver('https://mozilla.cloudflare-dns.com/dns-query'),
|
|
||||||
new Nameserver('https://dns.google/resolve'),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
$this->DoHClient = Magic::$altervista || Magic::$zerowebhost ?
|
|
||||||
new Rfc1035StubResolver() :
|
|
||||||
new Rfc8484StubResolver($DoHConfig);
|
|
||||||
|
|
||||||
$this->nonProxiedDoHClient = Magic::$altervista || Magic::$zerowebhost ?
|
|
||||||
new Rfc1035StubResolver() :
|
|
||||||
new Rfc8484StubResolver($nonProxiedDoHConfig);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function dcConnect(string $dc_number, int $id = -1): \Generator
|
public function dcConnect(string $dc_number, int $id = -1): \Generator
|
||||||
{
|
{
|
||||||
$old = isset($this->sockets[$dc_number]) && (
|
$old = isset($this->sockets[$dc_number]) && ($this->sockets[$dc_number]->shouldReconnect() || $id !== -1 && $this->sockets[$dc_number]->hasConnection($id) && $this->sockets[$dc_number]->getConnection($id)->shouldReconnect());
|
||||||
$this->sockets[$dc_number]->shouldReconnect() ||
|
|
||||||
(
|
|
||||||
$id !== -1
|
|
||||||
&& $this->sockets[$dc_number]->hasConnection($id)
|
|
||||||
&& $this->sockets[$dc_number]->getConnection($id)->shouldReconnect()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
if (isset($this->sockets[$dc_number]) && !$old) {
|
if (isset($this->sockets[$dc_number]) && !$old) {
|
||||||
$this->API->logger("Not reconnecting to DC $dc_number ($id)");
|
$this->API->logger("Not reconnecting to DC {$dc_number} ({$id})");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$ctxs = $this->generateContexts($dc_number);
|
$ctxs = $this->generateContexts($dc_number);
|
||||||
|
|
||||||
if (empty($ctxs)) {
|
if (empty($ctxs)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
foreach ($ctxs as $ctx) {
|
foreach ($ctxs as $ctx) {
|
||||||
try {
|
try {
|
||||||
if ($old) {
|
if ($old) {
|
||||||
$this->API->logger->logger("Reconnecting to DC $dc_number ($id) from existing", \danog\MadelineProto\Logger::WARNING);
|
$this->API->logger->logger("Reconnecting to DC {$dc_number} ({$id}) from existing", \danog\MadelineProto\Logger::WARNING);
|
||||||
$this->sockets[$dc_number]->setExtra($this->API);
|
$this->sockets[$dc_number]->setExtra($this->API);
|
||||||
yield $this->sockets[$dc_number]->connect($ctx, $id);
|
yield $this->sockets[$dc_number]->connect($ctx, $id);
|
||||||
} else {
|
} else {
|
||||||
$this->API->logger->logger("Connecting to DC $dc_number from scratch", \danog\MadelineProto\Logger::WARNING);
|
$this->API->logger->logger("Connecting to DC {$dc_number} from scratch", \danog\MadelineProto\Logger::WARNING);
|
||||||
$this->sockets[$dc_number] = new DataCenterConnection();
|
$this->sockets[$dc_number] = new DataCenterConnection();
|
||||||
$this->sockets[$dc_number]->setExtra($this->API);
|
$this->sockets[$dc_number]->setExtra($this->API);
|
||||||
yield $this->sockets[$dc_number]->connect($ctx);
|
yield $this->sockets[$dc_number]->connect($ctx);
|
||||||
}
|
}
|
||||||
$this->API->logger->logger('OK!', \danog\MadelineProto\Logger::WARNING);
|
$this->API->logger->logger('OK!', \danog\MadelineProto\Logger::WARNING);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
if (\MADELINEPROTO_TEST === 'pony') {
|
if (\MADELINEPROTO_TEST === 'pony') {
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
$this->API->logger->logger('Connection failed: '.$e->getMessage(), \danog\MadelineProto\Logger::ERROR);
|
$this->API->logger->logger('Connection failed: ' . $e->getMessage(), \danog\MadelineProto\Logger::ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
throw new \danog\MadelineProto\Exception("Could not connect to DC {$dc_number}");
|
||||||
throw new \danog\MadelineProto\Exception("Could not connect to DC $dc_number");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateContexts($dc_number = 0, string $uri = '', ConnectContext $context = null)
|
public function generateContexts($dc_number = 0, string $uri = '', ConnectContext $context = null)
|
||||||
{
|
{
|
||||||
$ctxs = [];
|
$ctxs = [];
|
||||||
$combos = [];
|
$combos = [];
|
||||||
|
|
||||||
$dc_config_number = isset($this->settings[$dc_number]) ? $dc_number : 'all';
|
$dc_config_number = isset($this->settings[$dc_number]) ? $dc_number : 'all';
|
||||||
$test = $this->settings[$dc_config_number]['test_mode'] ? 'test' : 'main';
|
$test = $this->settings[$dc_config_number]['test_mode'] ? 'test' : 'main';
|
||||||
$ipv6 = $this->settings[$dc_config_number]['ipv6'] ? 'ipv6' : 'ipv4';
|
$ipv6 = $this->settings[$dc_config_number]['ipv6'] ? 'ipv6' : 'ipv4';
|
||||||
|
|
||||||
switch ($this->settings[$dc_config_number]['protocol']) {
|
switch ($this->settings[$dc_config_number]['protocol']) {
|
||||||
case 'abridged':
|
case 'abridged':
|
||||||
case 'tcp_abridged':
|
case 'tcp_abridged':
|
||||||
@ -319,7 +275,7 @@ class DataCenter
|
|||||||
case 'obfuscated2':
|
case 'obfuscated2':
|
||||||
$this->settings[$dc_config_number]['protocol'] = 'tcp_intermediate_padded';
|
$this->settings[$dc_config_number]['protocol'] = 'tcp_intermediate_padded';
|
||||||
$this->settings[$dc_config_number]['obfuscated'] = true;
|
$this->settings[$dc_config_number]['obfuscated'] = true;
|
||||||
// no break
|
// no break
|
||||||
case 'intermediate_padded':
|
case 'intermediate_padded':
|
||||||
case 'tcp_intermediate_padded':
|
case 'tcp_intermediate_padded':
|
||||||
$default = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []], [IntermediatePaddedStream::getName(), []]];
|
$default = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []], [IntermediatePaddedStream::getName(), []]];
|
||||||
@ -359,13 +315,11 @@ class DataCenter
|
|||||||
$default = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []]];
|
$default = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []]];
|
||||||
}
|
}
|
||||||
$combos[] = $default;
|
$combos[] = $default;
|
||||||
|
|
||||||
if (!isset($this->settings[$dc_config_number]['do_not_retry'])) {
|
if (!isset($this->settings[$dc_config_number]['do_not_retry'])) {
|
||||||
if ((isset($this->dclist[$test][$ipv6][$dc_number]['tcpo_only']) && $this->dclist[$test][$ipv6][$dc_number]['tcpo_only']) || isset($this->dclist[$test][$ipv6][$dc_number]['secret'])) {
|
if (isset($this->dclist[$test][$ipv6][$dc_number]['tcpo_only']) && $this->dclist[$test][$ipv6][$dc_number]['tcpo_only'] || isset($this->dclist[$test][$ipv6][$dc_number]['secret'])) {
|
||||||
$extra = isset($this->dclist[$test][$ipv6][$dc_number]['secret']) ? ['secret' => $this->dclist[$test][$ipv6][$dc_number]['secret']] : [];
|
$extra = isset($this->dclist[$test][$ipv6][$dc_number]['secret']) ? ['secret' => $this->dclist[$test][$ipv6][$dc_number]['secret']] : [];
|
||||||
$combos[] = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []], [ObfuscatedStream::getName(), $extra], [IntermediatePaddedStream::getName(), []]];
|
$combos[] = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []], [ObfuscatedStream::getName(), $extra], [IntermediatePaddedStream::getName(), []]];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (\is_iterable($this->settings[$dc_config_number]['proxy'])) {
|
if (\is_iterable($this->settings[$dc_config_number]['proxy'])) {
|
||||||
$proxies = $this->settings[$dc_config_number]['proxy'];
|
$proxies = $this->settings[$dc_config_number]['proxy'];
|
||||||
$proxy_extras = $this->settings[$dc_config_number]['proxy_extra'];
|
$proxy_extras = $this->settings[$dc_config_number]['proxy_extra'];
|
||||||
@ -423,12 +377,10 @@ class DataCenter
|
|||||||
$combo = \array_merge($first, $second);
|
$combo = \array_merge($first, $second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
\array_unshift($combos, $combo);
|
\array_unshift($combos, $combo);
|
||||||
//unset($combos[$k]);
|
//unset($combos[$k]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($dc_number) {
|
if ($dc_number) {
|
||||||
$combos[] = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []], [HttpsStream::getName(), []]];
|
$combos[] = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []], [HttpsStream::getName(), []]];
|
||||||
}
|
}
|
||||||
@ -436,19 +388,13 @@ class DataCenter
|
|||||||
}
|
}
|
||||||
/* @var $context \Amp\ConnectContext */
|
/* @var $context \Amp\ConnectContext */
|
||||||
$context = $context ?? (new ConnectContext())->withMaxAttempts(1)->withConnectTimeout(1000 * $this->settings[$dc_config_number]['timeout']);
|
$context = $context ?? (new ConnectContext())->withMaxAttempts(1)->withConnectTimeout(1000 * $this->settings[$dc_config_number]['timeout']);
|
||||||
|
|
||||||
foreach ($combos as $combo) {
|
foreach ($combos as $combo) {
|
||||||
$ipv6 = [$this->settings[$dc_config_number]['ipv6'] ? 'ipv6' : 'ipv4', $this->settings[$dc_config_number]['ipv6'] ? 'ipv4' : 'ipv6'];
|
$ipv6 = [$this->settings[$dc_config_number]['ipv6'] ? 'ipv6' : 'ipv4', $this->settings[$dc_config_number]['ipv6'] ? 'ipv4' : 'ipv6'];
|
||||||
|
|
||||||
foreach ($ipv6 as $ipv6) {
|
foreach ($ipv6 as $ipv6) {
|
||||||
// This is only for non-MTProto connections
|
// This is only for non-MTProto connections
|
||||||
if (!$dc_number) {
|
if (!$dc_number) {
|
||||||
/* @var $ctx \danog\MadelineProto\Stream\ConnectionContext */
|
/* @var $ctx \danog\MadelineProto\Stream\ConnectionContext */
|
||||||
$ctx = (new ConnectionContext())
|
$ctx = (new ConnectionContext())->setSocketContext($context)->setUri($uri)->setIpv6($ipv6 === 'ipv6');
|
||||||
->setSocketContext($context)
|
|
||||||
->setUri($uri)
|
|
||||||
->setIpv6($ipv6 === 'ipv6');
|
|
||||||
|
|
||||||
foreach ($combo as $stream) {
|
foreach ($combo as $stream) {
|
||||||
if ($stream[0] === DefaultStream::getName() && $stream[1] === []) {
|
if ($stream[0] === DefaultStream::getName() && $stream[1] === []) {
|
||||||
$stream[1] = new DoHConnector($this, $ctx);
|
$stream[1] = new DoHConnector($this, $ctx);
|
||||||
@ -458,59 +404,44 @@ class DataCenter
|
|||||||
$ctxs[] = $ctx;
|
$ctxs[] = $ctx;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is only for MTProto connections
|
// This is only for MTProto connections
|
||||||
if (!isset($this->dclist[$test][$ipv6][$dc_number]['ip_address'])) {
|
if (!isset($this->dclist[$test][$ipv6][$dc_number]['ip_address'])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$address = $this->dclist[$test][$ipv6][$dc_number]['ip_address'];
|
$address = $this->dclist[$test][$ipv6][$dc_number]['ip_address'];
|
||||||
$port = $this->dclist[$test][$ipv6][$dc_number]['port'];
|
$port = $this->dclist[$test][$ipv6][$dc_number]['port'];
|
||||||
|
|
||||||
foreach (\array_unique([$port, 443, 80, 88, 5222]) as $port) {
|
foreach (\array_unique([$port, 443, 80, 88, 5222]) as $port) {
|
||||||
$stream = \end($combo)[0];
|
$stream = \end($combo)[0];
|
||||||
|
|
||||||
if ($stream === HttpsStream::getName()) {
|
if ($stream === HttpsStream::getName()) {
|
||||||
$subdomain = $this->dclist['ssl_subdomains'][\preg_replace('/\D+/', '', $dc_number)];
|
$subdomain = $this->dclist['ssl_subdomains'][\preg_replace('/\\D+/', '', $dc_number)];
|
||||||
if (\strpos($dc_number, '_media') !== false) {
|
if (\strpos($dc_number, '_media') !== false) {
|
||||||
$subdomain .= '-1';
|
$subdomain .= '-1';
|
||||||
}
|
}
|
||||||
$path = $this->settings[$dc_config_number]['test_mode'] ? 'apiw_test1' : 'apiw1';
|
$path = $this->settings[$dc_config_number]['test_mode'] ? 'apiw_test1' : 'apiw1';
|
||||||
|
$uri = 'tcp://' . $subdomain . '.web.telegram.org:' . $port . '/' . $path;
|
||||||
$uri = 'tcp://'.$subdomain.'.web.telegram.org:'.$port.'/'.$path;
|
|
||||||
} elseif ($stream === HttpStream::getName()) {
|
} elseif ($stream === HttpStream::getName()) {
|
||||||
$uri = 'tcp://'.$address.':'.$port.'/api';
|
$uri = 'tcp://' . $address . ':' . $port . '/api';
|
||||||
} else {
|
} else {
|
||||||
$uri = 'tcp://'.$address.':'.$port;
|
$uri = 'tcp://' . $address . ':' . $port;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($combo[1][0] === WssStream::getName()) {
|
if ($combo[1][0] === WssStream::getName()) {
|
||||||
$subdomain = $this->dclist['ssl_subdomains'][\preg_replace('/\D+/', '', $dc_number)];
|
$subdomain = $this->dclist['ssl_subdomains'][\preg_replace('/\\D+/', '', $dc_number)];
|
||||||
if (\strpos($dc_number, '_media') !== false) {
|
if (\strpos($dc_number, '_media') !== false) {
|
||||||
$subdomain .= '-1';
|
$subdomain .= '-1';
|
||||||
}
|
}
|
||||||
$path = $this->settings[$dc_config_number]['test_mode'] ? 'apiws_test' : 'apiws';
|
$path = $this->settings[$dc_config_number]['test_mode'] ? 'apiws_test' : 'apiws';
|
||||||
|
$uri = 'tcp://' . $subdomain . '.web.telegram.org:' . $port . '/' . $path;
|
||||||
$uri = 'tcp://'.$subdomain.'.web.telegram.org:'.$port.'/'.$path;
|
|
||||||
} elseif ($combo[1][0] === WsStream::getName()) {
|
} elseif ($combo[1][0] === WsStream::getName()) {
|
||||||
$subdomain = $this->dclist['ssl_subdomains'][\preg_replace('/\D+/', '', $dc_number)];
|
$subdomain = $this->dclist['ssl_subdomains'][\preg_replace('/\\D+/', '', $dc_number)];
|
||||||
if (\strpos($dc_number, '_media') !== false) {
|
if (\strpos($dc_number, '_media') !== false) {
|
||||||
$subdomain .= '-1';
|
$subdomain .= '-1';
|
||||||
}
|
}
|
||||||
$path = $this->settings[$dc_config_number]['test_mode'] ? 'apiws_test' : 'apiws';
|
$path = $this->settings[$dc_config_number]['test_mode'] ? 'apiws_test' : 'apiws';
|
||||||
|
|
||||||
//$uri = 'tcp://' . $subdomain . '.web.telegram.org:' . $port . '/' . $path;
|
//$uri = 'tcp://' . $subdomain . '.web.telegram.org:' . $port . '/' . $path;
|
||||||
$uri = 'tcp://'.$address.':'.$port.'/'.$path;
|
$uri = 'tcp://' . $address . ':' . $port . '/' . $path;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @var $ctx \danog\MadelineProto\Stream\ConnectionContext */
|
/* @var $ctx \danog\MadelineProto\Stream\ConnectionContext */
|
||||||
$ctx = (new ConnectionContext())
|
$ctx = (new ConnectionContext())->setDc($dc_number)->setTest($this->settings[$dc_config_number]['test_mode'])->setSocketContext($context)->setUri($uri)->setIpv6($ipv6 === 'ipv6');
|
||||||
->setDc($dc_number)
|
|
||||||
->setTest($this->settings[$dc_config_number]['test_mode'])
|
|
||||||
->setSocketContext($context)
|
|
||||||
->setUri($uri)
|
|
||||||
->setIpv6($ipv6 === 'ipv6');
|
|
||||||
|
|
||||||
foreach ($combo as $stream) {
|
foreach ($combo as $stream) {
|
||||||
if ($stream[0] === DefaultStream::getName() && $stream[1] === []) {
|
if ($stream[0] === DefaultStream::getName() && $stream[1] === []) {
|
||||||
$stream[1] = new DoHConnector($this, $ctx);
|
$stream[1] = new DoHConnector($this, $ctx);
|
||||||
@ -524,22 +455,17 @@ class DataCenter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (isset($this->dclist[$test][$ipv6][$dc_number . '_bk']['ip_address'])) {
|
||||||
if (isset($this->dclist[$test][$ipv6][$dc_number.'_bk']['ip_address'])) {
|
$ctxs = \array_merge($ctxs, $this->generateContexts($dc_number . '_bk'));
|
||||||
$ctxs = \array_merge($ctxs, $this->generateContexts($dc_number.'_bk'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($ctxs)) {
|
if (empty($ctxs)) {
|
||||||
unset($this->sockets[$dc_number]);
|
unset($this->sockets[$dc_number]);
|
||||||
|
$this->API->logger->logger("No info for DC {$dc_number}", \danog\MadelineProto\Logger::ERROR);
|
||||||
$this->API->logger->logger("No info for DC $dc_number", \danog\MadelineProto\Logger::ERROR);
|
|
||||||
} elseif (\MADELINEPROTO_TEST === 'pony') {
|
} elseif (\MADELINEPROTO_TEST === 'pony') {
|
||||||
return [$ctxs[0]];
|
return [$ctxs[0]];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $ctxs;
|
return $ctxs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get main API.
|
* Get main API.
|
||||||
*
|
*
|
||||||
@ -549,7 +475,6 @@ class DataCenter
|
|||||||
{
|
{
|
||||||
return $this->API;
|
return $this->API;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get async HTTP client.
|
* Get async HTTP client.
|
||||||
*
|
*
|
||||||
@ -559,7 +484,6 @@ class DataCenter
|
|||||||
{
|
{
|
||||||
return $this->HTTPClient;
|
return $this->HTTPClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get async HTTP client cookies.
|
* Get async HTTP client cookies.
|
||||||
*
|
*
|
||||||
@ -587,7 +511,6 @@ class DataCenter
|
|||||||
{
|
{
|
||||||
return $this->nonProxiedDoHClient;
|
return $this->nonProxiedDoHClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get contents of file.
|
* Get contents of file.
|
||||||
*
|
*
|
||||||
@ -599,7 +522,6 @@ class DataCenter
|
|||||||
{
|
{
|
||||||
return yield (yield $this->getHTTPClient()->request(new Request($url)))->getBody()->buffer();
|
return yield (yield $this->getHTTPClient()->request(new Request($url)))->getBody()->buffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Connection instance for authorization.
|
* Get Connection instance for authorization.
|
||||||
*
|
*
|
||||||
@ -664,8 +586,6 @@ class DataCenter
|
|||||||
{
|
{
|
||||||
return isset($this->sockets[$dc]);
|
return isset($this->sockets[$dc]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if connected to datacenter using HTTP.
|
* Check if connected to datacenter using HTTP.
|
||||||
*
|
*
|
||||||
@ -677,7 +597,6 @@ class DataCenter
|
|||||||
{
|
{
|
||||||
return $this->sockets[$datacenter]->isHttp();
|
return $this->sockets[$datacenter]->isHttp();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if connected to datacenter directly using IP address.
|
* Check if connected to datacenter directly using IP address.
|
||||||
*
|
*
|
||||||
@ -689,7 +608,6 @@ class DataCenter
|
|||||||
{
|
{
|
||||||
return $this->sockets[$datacenter]->byIPAddress();
|
return $this->sockets[$datacenter]->byIPAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all DC IDs.
|
* Get all DC IDs.
|
||||||
*
|
*
|
||||||
@ -701,7 +619,6 @@ class DataCenter
|
|||||||
{
|
{
|
||||||
$test = $this->settings['all']['test_mode'] ? 'test' : 'main';
|
$test = $this->settings['all']['test_mode'] ? 'test' : 'main';
|
||||||
$ipv6 = $this->settings['all']['ipv6'] ? 'ipv6' : 'ipv4';
|
$ipv6 = $this->settings['all']['ipv6'] ? 'ipv6' : 'ipv4';
|
||||||
|
|
||||||
return $all ? \array_keys((array) $this->dclist[$test][$ipv6]) : \array_keys((array) $this->sockets);
|
return $all ? \array_keys((array) $this->dclist[$test][$ipv6]) : \array_keys((array) $this->sockets);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connection module handling all connections to a datacenter.
|
* Connection module handling all connections to a datacenter.
|
||||||
*
|
*
|
||||||
@ -36,7 +37,6 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
const READ_WEIGHT = 1;
|
const READ_WEIGHT = 1;
|
||||||
const READ_WEIGHT_MEDIA = 5;
|
const READ_WEIGHT_MEDIA = 5;
|
||||||
const WRITE_WEIGHT = 10;
|
const WRITE_WEIGHT = 10;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Promise for connection.
|
* Promise for connection.
|
||||||
*
|
*
|
||||||
@ -49,7 +49,6 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
* @var Deferred
|
* @var Deferred
|
||||||
*/
|
*/
|
||||||
private $connectionsDeferred;
|
private $connectionsDeferred;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Temporary auth key.
|
* Temporary auth key.
|
||||||
*
|
*
|
||||||
@ -62,7 +61,6 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
* @var PermAuthKey|null
|
* @var PermAuthKey|null
|
||||||
*/
|
*/
|
||||||
private $permAuthKey;
|
private $permAuthKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connections open to a certain DC.
|
* Connections open to a certain DC.
|
||||||
*
|
*
|
||||||
@ -75,42 +73,36 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
* @var array<string, int>
|
* @var array<string, int>
|
||||||
*/
|
*/
|
||||||
private $availableConnections = [];
|
private $availableConnections = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main API instance.
|
* Main API instance.
|
||||||
*
|
*
|
||||||
* @var \danog\MadelineProto\MTProto
|
* @var \danog\MadelineProto\MTProto
|
||||||
*/
|
*/
|
||||||
private $API;
|
private $API;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connection context.
|
* Connection context.
|
||||||
*
|
*
|
||||||
* @var ConnectionContext
|
* @var ConnectionContext
|
||||||
*/
|
*/
|
||||||
private $ctx;
|
private $ctx;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DC ID.
|
* DC ID.
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $datacenter;
|
private $datacenter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Linked DC ID.
|
* Linked DC ID.
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $linked;
|
private $linked;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loop to keep weights at sane value.
|
* Loop to keep weights at sane value.
|
||||||
*
|
*
|
||||||
* @var \danog\MadelineProto\Loop\Generic\PeriodicLoop
|
* @var \danog\MadelineProto\Loop\Generic\PeriodicLoop
|
||||||
*/
|
*/
|
||||||
private $robinLoop;
|
private $robinLoop;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrement roundrobin weight by this value if busy reading.
|
* Decrement roundrobin weight by this value if busy reading.
|
||||||
*
|
*
|
||||||
@ -123,14 +115,12 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
* @var integer
|
* @var integer
|
||||||
*/
|
*/
|
||||||
private $decWrite = 10;
|
private $decWrite = 10;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Backed up messages.
|
* Backed up messages.
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $backup = [];
|
private $backup = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this socket has to be reconnected.
|
* Whether this socket has to be reconnected.
|
||||||
*
|
*
|
||||||
@ -191,7 +181,6 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
{
|
{
|
||||||
$this->{$temp ? 'tempAuthKey' : 'permAuthKey'} = $key;
|
$this->{$temp ? 'tempAuthKey' : 'permAuthKey'} = $key;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get temporary authorization key.
|
* Get temporary authorization key.
|
||||||
*
|
*
|
||||||
@ -210,7 +199,6 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
{
|
{
|
||||||
return $this->getAuthKey(false);
|
return $this->getAuthKey(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if has temporary authorization key.
|
* Check if has temporary authorization key.
|
||||||
*
|
*
|
||||||
@ -220,7 +208,6 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
{
|
{
|
||||||
return $this->hasAuthKey(true);
|
return $this->hasAuthKey(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if has permanent authorization key.
|
* Check if has permanent authorization key.
|
||||||
*
|
*
|
||||||
@ -230,7 +217,6 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
{
|
{
|
||||||
return $this->hasAuthKey(false);
|
return $this->hasAuthKey(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set temporary authorization key.
|
* Set temporary authorization key.
|
||||||
*
|
*
|
||||||
@ -253,7 +239,6 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
{
|
{
|
||||||
return $this->setAuthKey($key, false);
|
return $this->setAuthKey($key, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind temporary and permanent auth keys.
|
* Bind temporary and permanent auth keys.
|
||||||
*
|
*
|
||||||
@ -286,7 +271,6 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
{
|
{
|
||||||
return $this->hasTempAuthKey() ? $this->getTempAuthKey()->isAuthorized() : false;
|
return $this->hasTempAuthKey() ? $this->getTempAuthKey()->isAuthorized() : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the authorized boolean.
|
* Set the authorized boolean.
|
||||||
*
|
*
|
||||||
@ -302,7 +286,6 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
$this->getTempAuthKey()->authorized($authorized);
|
$this->getTempAuthKey()->authorized($authorized);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Link permanent authorization info of main DC to media DC.
|
* Link permanent authorization info of main DC to media DC.
|
||||||
*
|
*
|
||||||
@ -313,9 +296,8 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
public function link(string $dc)
|
public function link(string $dc)
|
||||||
{
|
{
|
||||||
$this->linked = $dc;
|
$this->linked = $dc;
|
||||||
$this->permAuthKey = &$this->API->datacenter->getDataCenterConnection($dc)->permAuthKey;
|
$this->permAuthKey =& $this->API->datacenter->getDataCenterConnection($dc)->permAuthKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset MTProto sessions.
|
* Reset MTProto sessions.
|
||||||
*
|
*
|
||||||
@ -349,7 +331,6 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
$socket->flush();
|
$socket->flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get connection context.
|
* Get connection context.
|
||||||
*
|
*
|
||||||
@ -359,7 +340,6 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
{
|
{
|
||||||
return $this->ctx;
|
return $this->ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Has connection context?
|
* Has connection context?
|
||||||
*
|
*
|
||||||
@ -369,7 +349,6 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
{
|
{
|
||||||
return isset($this->ctx);
|
return isset($this->ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect function.
|
* Connect function.
|
||||||
*
|
*
|
||||||
@ -380,32 +359,26 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
*/
|
*/
|
||||||
public function connect(ConnectionContext $ctx, int $id = -1): \Generator
|
public function connect(ConnectionContext $ctx, int $id = -1): \Generator
|
||||||
{
|
{
|
||||||
$this->API->logger->logger("Trying shared connection via $ctx ($id)");
|
$this->API->logger->logger("Trying shared connection via {$ctx} ({$id})");
|
||||||
|
|
||||||
$this->ctx = $ctx->getCtx();
|
$this->ctx = $ctx->getCtx();
|
||||||
$this->datacenter = $ctx->getDc();
|
$this->datacenter = $ctx->getDc();
|
||||||
$media = $ctx->isMedia() || $ctx->isCDN();
|
$media = $ctx->isMedia() || $ctx->isCDN();
|
||||||
|
|
||||||
$count = $media ? $this->API->settings['connection_settings']['media_socket_count']['min'] : 1;
|
$count = $media ? $this->API->settings['connection_settings']['media_socket_count']['min'] : 1;
|
||||||
|
|
||||||
if ($count > 1) {
|
if ($count > 1) {
|
||||||
if (!$this->robinLoop) {
|
if (!$this->robinLoop) {
|
||||||
$this->robinLoop = new PeriodicLoop($this->API, [$this, 'even'], "robin loop DC {$this->datacenter}", $this->API->settings['connection_settings']['robin_period']);
|
$this->robinLoop = new PeriodicLoop($this->API, [$this, 'even'], "robin loop DC {$this->datacenter}", $this->API->settings['connection_settings']['robin_period']);
|
||||||
}
|
}
|
||||||
$this->robinLoop->start();
|
$this->robinLoop->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->decRead = $media ? self::READ_WEIGHT_MEDIA : self::READ_WEIGHT;
|
$this->decRead = $media ? self::READ_WEIGHT_MEDIA : self::READ_WEIGHT;
|
||||||
$this->decWrite = self::WRITE_WEIGHT;
|
$this->decWrite = self::WRITE_WEIGHT;
|
||||||
|
|
||||||
if ($id === -1 || !isset($this->connections[$id])) {
|
if ($id === -1 || !isset($this->connections[$id])) {
|
||||||
if ($this->connections) {
|
if ($this->connections) {
|
||||||
$this->API->logger("Already connected!", Logger::WARNING);
|
$this->API->logger("Already connected!", Logger::WARNING);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
yield $this->connectMore($count);
|
yield from $this->connectMore($count);
|
||||||
yield $this->restoreBackup();
|
yield $this->restoreBackup();
|
||||||
|
|
||||||
$this->connectionsPromise = new Success();
|
$this->connectionsPromise = new Success();
|
||||||
if ($this->connectionsDeferred) {
|
if ($this->connectionsDeferred) {
|
||||||
$connectionsDeferred = $this->connectionsDeferred;
|
$connectionsDeferred = $this->connectionsDeferred;
|
||||||
@ -414,10 +387,9 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$this->availableConnections[$id] = 0;
|
$this->availableConnections[$id] = 0;
|
||||||
yield $this->connections[$id]->connect($ctx);
|
yield from $this->connections[$id]->connect($ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to the DC using count more sockets.
|
* Connect to the DC using count more sockets.
|
||||||
*
|
*
|
||||||
@ -425,21 +397,19 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
private function connectMore(int $count)
|
private function connectMore(int $count): \Generator
|
||||||
{
|
{
|
||||||
$ctx = $this->ctx->getCtx();
|
$ctx = $this->ctx->getCtx();
|
||||||
$count += $previousCount = \count($this->connections);
|
$count += $previousCount = \count($this->connections);
|
||||||
for ($x = $previousCount; $x < $count; $x++) {
|
for ($x = $previousCount; $x < $count; $x++) {
|
||||||
$connection = new Connection();
|
$connection = new Connection();
|
||||||
$connection->setExtra($this, $x);
|
$connection->setExtra($this, $x);
|
||||||
yield $connection->connect($ctx);
|
yield from $connection->connect($ctx);
|
||||||
|
|
||||||
$this->connections[$x] = $connection;
|
$this->connections[$x] = $connection;
|
||||||
$this->availableConnections[$x] = 0;
|
$this->availableConnections[$x] = 0;
|
||||||
$ctx = $this->ctx->getCtx();
|
$ctx = $this->ctx->getCtx();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signal that a connection ID disconnected.
|
* Signal that a connection ID disconnected.
|
||||||
*
|
*
|
||||||
@ -459,12 +429,10 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
$list .= $message['_'] ?? '-';
|
$list .= $message['_'] ?? '-';
|
||||||
$list .= ', ';
|
$list .= ', ';
|
||||||
}
|
}
|
||||||
$this->API->logger->logger("Backed up $list from DC {$this->datacenter}.$id");
|
$this->API->logger->logger("Backed up {$list} from DC {$this->datacenter}.{$id}");
|
||||||
$this->backup = \array_merge($this->backup, $backup);
|
$this->backup = \array_merge($this->backup, $backup);
|
||||||
|
|
||||||
unset($this->connections[$id], $this->availableConnections[$id]);
|
unset($this->connections[$id], $this->availableConnections[$id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close all connections to DC.
|
* Close all connections to DC.
|
||||||
*
|
*
|
||||||
@ -472,9 +440,8 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
*/
|
*/
|
||||||
public function disconnect()
|
public function disconnect()
|
||||||
{
|
{
|
||||||
$this->connectionsDeferred = new Deferred;
|
$this->connectionsDeferred = new Deferred();
|
||||||
$this->connectionsPromise = $this->connectionsDeferred->promise();
|
$this->connectionsPromise = $this->connectionsDeferred->promise();
|
||||||
|
|
||||||
$this->API->logger->logger("Disconnecting from shared DC {$this->datacenter}");
|
$this->API->logger->logger("Disconnecting from shared DC {$this->datacenter}");
|
||||||
if ($this->robinLoop) {
|
if ($this->robinLoop) {
|
||||||
$this->robinLoop->signal(true);
|
$this->robinLoop->signal(true);
|
||||||
@ -485,12 +452,10 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
$connection->disconnect();
|
$connection->disconnect();
|
||||||
}
|
}
|
||||||
$count = \count($this->backup) - $before;
|
$count = \count($this->backup) - $before;
|
||||||
$this->API->logger->logger("Backed up $count, added to $before existing messages) from DC {$this->datacenter}");
|
$this->API->logger->logger("Backed up {$count}, added to {$before} existing messages) from DC {$this->datacenter}");
|
||||||
|
|
||||||
$this->connections = [];
|
$this->connections = [];
|
||||||
$this->availableConnections = [];
|
$this->availableConnections = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reconnect to DC.
|
* Reconnect to DC.
|
||||||
*
|
*
|
||||||
@ -500,9 +465,8 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
{
|
{
|
||||||
$this->API->logger->logger("Reconnecting shared DC {$this->datacenter}");
|
$this->API->logger->logger("Reconnecting shared DC {$this->datacenter}");
|
||||||
$this->disconnect();
|
$this->disconnect();
|
||||||
yield $this->connect($this->ctx);
|
yield from $this->connect($this->ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restore backed up messages.
|
* Restore backed up messages.
|
||||||
*
|
*
|
||||||
@ -513,7 +477,7 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
$backup = $this->backup;
|
$backup = $this->backup;
|
||||||
$this->backup = [];
|
$this->backup = [];
|
||||||
$count = \count($backup);
|
$count = \count($backup);
|
||||||
$this->API->logger->logger("Restoring $count messages to DC {$this->datacenter}");
|
$this->API->logger->logger("Restoring {$count} messages to DC {$this->datacenter}");
|
||||||
foreach ($backup as $message) {
|
foreach ($backup as $message) {
|
||||||
Tools::callFork($this->getConnection()->sendMessage($message, false));
|
Tools::callFork($this->getConnection()->sendMessage($message, false));
|
||||||
}
|
}
|
||||||
@ -528,7 +492,6 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
{
|
{
|
||||||
return $this->connections[0];
|
return $this->connections[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if any connection is available.
|
* Check if any connection is available.
|
||||||
*
|
*
|
||||||
@ -548,12 +511,10 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
public function waitGetConnection(): Promise
|
public function waitGetConnection(): Promise
|
||||||
{
|
{
|
||||||
if (empty($this->availableConnections)) {
|
if (empty($this->availableConnections)) {
|
||||||
$deferred = new Deferred;
|
$deferred = new Deferred();
|
||||||
$this->connectionsPromise->onResolve(
|
$this->connectionsPromise->onResolve(function ($e, $v) use ($deferred) {
|
||||||
function ($e, $v) use ($deferred) {
|
$deferred->resolve($this->getConnection());
|
||||||
$deferred->resolve($this->getConnection());
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
return $deferred->promise();
|
return $deferred->promise();
|
||||||
}
|
}
|
||||||
return new Success($this->getConnection());
|
return new Success($this->getConnection());
|
||||||
@ -575,12 +536,10 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
}
|
}
|
||||||
$max = \max($this->availableConnections);
|
$max = \max($this->availableConnections);
|
||||||
$key = \array_search($max, $this->availableConnections);
|
$key = \array_search($max, $this->availableConnections);
|
||||||
|
|
||||||
// Decrease to implement round robin
|
// Decrease to implement round robin
|
||||||
$this->availableConnections[$key]--;
|
$this->availableConnections[$key]--;
|
||||||
return $this->connections[$key];
|
return $this->connections[$key];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Even out round robin values.
|
* Even out round robin values.
|
||||||
*
|
*
|
||||||
@ -607,7 +566,6 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicate that one of the sockets is busy reading.
|
* Indicate that one of the sockets is busy reading.
|
||||||
*
|
*
|
||||||
@ -632,8 +590,6 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
{
|
{
|
||||||
$this->availableConnections[$x] += $writing ? -$this->decWrite : $this->decWrite;
|
$this->availableConnections[$x] += $writing ? -$this->decWrite : $this->decWrite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set main instance.
|
* Set main instance.
|
||||||
*
|
*
|
||||||
@ -645,7 +601,6 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
{
|
{
|
||||||
$this->API = $API;
|
$this->API = $API;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get main instance.
|
* Get main instance.
|
||||||
*
|
*
|
||||||
@ -655,7 +610,6 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
{
|
{
|
||||||
return $this->API;
|
return $this->API;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if is an HTTP connection.
|
* Check if is an HTTP connection.
|
||||||
*
|
*
|
||||||
@ -665,7 +619,6 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
{
|
{
|
||||||
return \in_array($this->ctx->getStreamName(), [HttpStream::getName(), HttpsStream::getName()]);
|
return \in_array($this->ctx->getStreamName(), [HttpStream::getName(), HttpsStream::getName()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if is connected directly by IP address.
|
* Check if is connected directly by IP address.
|
||||||
*
|
*
|
||||||
@ -675,7 +628,6 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
{
|
{
|
||||||
return !$this->ctx->hasStreamName(WssStream::getName()) && !$this->ctx->hasStreamName(HttpsStream::getName());
|
return !$this->ctx->hasStreamName(WssStream::getName()) && !$this->ctx->hasStreamName(HttpsStream::getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if is a media connection.
|
* Check if is a media connection.
|
||||||
*
|
*
|
||||||
@ -685,7 +637,6 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
{
|
{
|
||||||
return $this->ctx->isMedia();
|
return $this->ctx->isMedia();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if is a CDN connection.
|
* Check if is a CDN connection.
|
||||||
*
|
*
|
||||||
@ -695,7 +646,6 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
{
|
{
|
||||||
return $this->ctx->isCDN();
|
return $this->ctx->isCDN();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get DC-specific settings.
|
* Get DC-specific settings.
|
||||||
*
|
*
|
||||||
@ -706,7 +656,6 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
$dc_config_number = isset($this->API->settings['connection_settings'][$this->datacenter]) ? $this->datacenter : 'all';
|
$dc_config_number = isset($this->API->settings['connection_settings'][$this->datacenter]) ? $this->datacenter : 'all';
|
||||||
return $this->API->settings['connection_settings'][$dc_config_number];
|
return $this->API->settings['connection_settings'][$dc_config_number];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JSON serialize function.
|
* JSON serialize function.
|
||||||
*
|
*
|
||||||
@ -714,15 +663,7 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
*/
|
*/
|
||||||
public function jsonSerialize(): array
|
public function jsonSerialize(): array
|
||||||
{
|
{
|
||||||
return $this->linked ?
|
return $this->linked ? ['linked' => $this->linked, 'tempAuthKey' => $this->tempAuthKey] : ['permAuthKey' => $this->permAuthKey, 'tempAuthKey' => $this->tempAuthKey];
|
||||||
[
|
|
||||||
'linked' => $this->linked,
|
|
||||||
'tempAuthKey' => $this->tempAuthKey
|
|
||||||
] :
|
|
||||||
[
|
|
||||||
'permAuthKey' => $this->permAuthKey,
|
|
||||||
'tempAuthKey' => $this->tempAuthKey
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Sleep function.
|
* Sleep function.
|
||||||
|
@ -31,7 +31,6 @@ use Amp\Socket\ConnectException;
|
|||||||
use Amp\Socket\Connector;
|
use Amp\Socket\Connector;
|
||||||
use Amp\Socket\ResourceSocket;
|
use Amp\Socket\ResourceSocket;
|
||||||
use danog\MadelineProto\Stream\ConnectionContext;
|
use danog\MadelineProto\Stream\ConnectionContext;
|
||||||
|
|
||||||
use function Amp\Socket\Internal\parseUri;
|
use function Amp\Socket\Internal\parseUri;
|
||||||
|
|
||||||
class DoHConnector implements Connector
|
class DoHConnector implements Connector
|
||||||
@ -53,13 +52,11 @@ class DoHConnector implements Connector
|
|||||||
$this->dataCenter = $dataCenter;
|
$this->dataCenter = $dataCenter;
|
||||||
$this->ctx = $ctx;
|
$this->ctx = $ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function connect(string $uri, ?ConnectContext $socketContext = null, ?CancellationToken $token = null): Promise
|
public function connect(string $uri, ?ConnectContext $socketContext = null, ?CancellationToken $token = null): Promise
|
||||||
{
|
{
|
||||||
return Tools::call((function () use ($uri, $socketContext, $token) {
|
return Tools::call((function () use ($uri, $socketContext, $token): \Generator {
|
||||||
$socketContext = $socketContext ?? new ConnectContext;
|
$socketContext = $socketContext ?? new ConnectContext();
|
||||||
$token = $token ?? new NullCancellationToken;
|
$token = $token ?? new NullCancellationToken();
|
||||||
|
|
||||||
$attempt = 0;
|
$attempt = 0;
|
||||||
$uris = [];
|
$uris = [];
|
||||||
$failures = [];
|
$failures = [];
|
||||||
@ -105,7 +102,6 @@ class DoHConnector implements Connector
|
|||||||
if ($this->ctx->getIpv6()) {
|
if ($this->ctx->getIpv6()) {
|
||||||
$records = \array_reverse($records);
|
$records = \array_reverse($records);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($records as $record) {
|
foreach ($records as $record) {
|
||||||
/** @var Record $record */
|
/** @var Record $record */
|
||||||
if ($record->getType() === Record::AAAA) {
|
if ($record->getType() === Record::AAAA) {
|
||||||
@ -115,34 +111,23 @@ class DoHConnector implements Connector
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$flags = \STREAM_CLIENT_CONNECT | \STREAM_CLIENT_ASYNC_CONNECT;
|
$flags = \STREAM_CLIENT_CONNECT | \STREAM_CLIENT_ASYNC_CONNECT;
|
||||||
$timeout = $socketContext->getConnectTimeout();
|
$timeout = $socketContext->getConnectTimeout();
|
||||||
foreach ($uris as $builtUri) {
|
foreach ($uris as $builtUri) {
|
||||||
try {
|
try {
|
||||||
$streamContext = \stream_context_create($socketContext->withoutTlsContext()->toStreamContextArray());
|
$streamContext = \stream_context_create($socketContext->withoutTlsContext()->toStreamContextArray());
|
||||||
if (!$socket = @\stream_socket_client($builtUri, $errno, $errstr, null, $flags, $streamContext)) {
|
if (!($socket = @\stream_socket_client($builtUri, $errno, $errstr, null, $flags, $streamContext))) {
|
||||||
throw new ConnectException(\sprintf(
|
throw new ConnectException(\sprintf('Connection to %s failed: [Error #%d] %s%s', $uri, $errno, $errstr, $failures ? '; previous attempts: ' . \implode($failures) : ''), $errno);
|
||||||
'Connection to %s failed: [Error #%d] %s%s',
|
|
||||||
$uri,
|
|
||||||
$errno,
|
|
||||||
$errstr,
|
|
||||||
$failures ? '; previous attempts: ' . \implode($failures) : ''
|
|
||||||
), $errno);
|
|
||||||
}
|
}
|
||||||
\stream_set_blocking($socket, false);
|
\stream_set_blocking($socket, false);
|
||||||
$deferred = new Deferred;
|
$deferred = new Deferred();
|
||||||
$watcher = Loop::onWritable($socket, [$deferred, 'resolve']);
|
$watcher = Loop::onWritable($socket, [$deferred, 'resolve']);
|
||||||
$id = $token->subscribe([$deferred, 'fail']);
|
$id = $token->subscribe([$deferred, 'fail']);
|
||||||
try {
|
try {
|
||||||
yield Promise\timeout($deferred->promise(), $timeout);
|
yield Promise\timeout($deferred->promise(), $timeout);
|
||||||
} catch (TimeoutException $e) {
|
} catch (TimeoutException $e) {
|
||||||
throw new ConnectException(\sprintf(
|
throw new ConnectException(\sprintf('Connecting to %s failed: timeout exceeded (%d ms)%s', $uri, $timeout, $failures ? '; previous attempts: ' . \implode($failures) : ''), 110);
|
||||||
'Connecting to %s failed: timeout exceeded (%d ms)%s',
|
// See ETIMEDOUT in http://www.virtsync.com/c-error-codes-include-errno
|
||||||
$uri,
|
|
||||||
$timeout,
|
|
||||||
$failures ? '; previous attempts: ' . \implode($failures) : ''
|
|
||||||
), 110); // See ETIMEDOUT in http://www.virtsync.com/c-error-codes-include-errno
|
|
||||||
} finally {
|
} finally {
|
||||||
Loop::cancel($watcher);
|
Loop::cancel($watcher);
|
||||||
$token->unsubscribe($id);
|
$token->unsubscribe($id);
|
||||||
@ -150,26 +135,21 @@ class DoHConnector implements Connector
|
|||||||
// The following hack looks like the only way to detect connection refused errors with PHP's stream sockets.
|
// The following hack looks like the only way to detect connection refused errors with PHP's stream sockets.
|
||||||
if (\stream_socket_get_name($socket, true) === false) {
|
if (\stream_socket_get_name($socket, true) === false) {
|
||||||
\fclose($socket);
|
\fclose($socket);
|
||||||
throw new ConnectException(\sprintf(
|
throw new ConnectException(\sprintf('Connection to %s refused%s', $uri, $failures ? '; previous attempts: ' . \implode($failures) : ''), 111);
|
||||||
'Connection to %s refused%s',
|
// See ECONNREFUSED in http://www.virtsync.com/c-error-codes-include-errno
|
||||||
$uri,
|
|
||||||
$failures ? '; previous attempts: ' . \implode($failures) : ''
|
|
||||||
), 111); // See ECONNREFUSED in http://www.virtsync.com/c-error-codes-include-errno
|
|
||||||
}
|
}
|
||||||
} catch (ConnectException $e) {
|
} catch (ConnectException $e) {
|
||||||
// Includes only error codes used in this file, as error codes on other OS families might be different.
|
// Includes only error codes used in this file, as error codes on other OS families might be different.
|
||||||
// In fact, this might show a confusing error message on OS families that return 110 or 111 by itself.
|
// In fact, this might show a confusing error message on OS families that return 110 or 111 by itself.
|
||||||
$knownReasons = [
|
$knownReasons = [110 => 'connection timeout', 111 => 'connection refused'];
|
||||||
110 => 'connection timeout',
|
|
||||||
111 => 'connection refused',
|
|
||||||
];
|
|
||||||
$code = $e->getCode();
|
$code = $e->getCode();
|
||||||
$reason = $knownReasons[$code] ?? ('Error #' . $code);
|
$reason = $knownReasons[$code] ?? 'Error #' . $code;
|
||||||
if (++$attempt === $socketContext->getMaxAttempts()) {
|
if (++$attempt === $socketContext->getMaxAttempts()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$failures[] = "{$uri} ({$reason})";
|
$failures[] = "{$uri} ({$reason})";
|
||||||
continue; // Could not connect to host, try next host in the list.
|
continue;
|
||||||
|
// Could not connect to host, try next host in the list.
|
||||||
}
|
}
|
||||||
return ResourceSocket::fromClientSocket($socket, $socketContext->getTlsContext());
|
return ResourceSocket::fromClientSocket($socket, $socketContext->getTlsContext());
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,6 @@ class DocsBuilder
|
|||||||
use \danog\MadelineProto\DocsBuilder\Constructors;
|
use \danog\MadelineProto\DocsBuilder\Constructors;
|
||||||
use Tools;
|
use Tools;
|
||||||
public $td = false;
|
public $td = false;
|
||||||
|
|
||||||
public function __construct($logger, $settings)
|
public function __construct($logger, $settings)
|
||||||
{
|
{
|
||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
@ -50,19 +49,17 @@ class DocsBuilder
|
|||||||
\chdir($this->settings['output_dir']);
|
\chdir($this->settings['output_dir']);
|
||||||
$this->index = $settings['readme'] ? 'README.md' : 'index.md';
|
$this->index = $settings['readme'] ? 'README.md' : 'index.md';
|
||||||
}
|
}
|
||||||
|
|
||||||
public $types = [];
|
public $types = [];
|
||||||
public $any = '*';
|
public $any = '*';
|
||||||
|
|
||||||
public function mkDocs()
|
public function mkDocs()
|
||||||
{
|
{
|
||||||
\danog\MadelineProto\Logger::log('Generating documentation index...', \danog\MadelineProto\Logger::NOTICE);
|
\danog\MadelineProto\Logger::log('Generating documentation index...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
\file_put_contents($this->index, '---
|
\file_put_contents($this->index, '---
|
||||||
title: '.$this->settings['title'].'
|
title: ' . $this->settings['title'] . '
|
||||||
description: '.$this->settings['description'].'
|
description: ' . $this->settings['description'] . '
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
---
|
---
|
||||||
# '.$this->settings['description'].'
|
# ' . $this->settings['description'] . '
|
||||||
|
|
||||||
[Back to main documentation](..)
|
[Back to main documentation](..)
|
||||||
|
|
||||||
@ -90,14 +87,14 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
//$br = $new_namespace != $last_namespace ? '***<br><br>' : '';
|
//$br = $new_namespace != $last_namespace ? '***<br><br>' : '';
|
||||||
$type = \str_replace(['<', '>'], ['_of_', ''], $otype);
|
$type = \str_replace(['<', '>'], ['_of_', ''], $otype);
|
||||||
$type = \preg_replace('/.*_of_/', '', $type);
|
$type = \preg_replace('/.*_of_/', '', $type);
|
||||||
$index .= '['.\str_replace('_', '\\_', $type).']('.$type.'.md)<a name="'.$type.'"></a>
|
$index .= '[' . \str_replace('_', '\\_', $type) . '](' . $type . '.md)<a name="' . $type . '"></a>
|
||||||
|
|
||||||
';
|
';
|
||||||
$constructors = '';
|
$constructors = '';
|
||||||
foreach ($keys['constructors'] as $data) {
|
foreach ($keys['constructors'] as $data) {
|
||||||
$predicate = $data['predicate'].(isset($data['layer']) && $data['layer'] !== '' ? '_'.$data['layer'] : '');
|
$predicate = $data['predicate'] . (isset($data['layer']) && $data['layer'] !== '' ? '_' . $data['layer'] : '');
|
||||||
$md_predicate = \str_replace('_', '\\_', $predicate);
|
$md_predicate = \str_replace('_', '\\_', $predicate);
|
||||||
$constructors .= '['.$md_predicate.'](../constructors/'.$predicate.'.md)
|
$constructors .= '[' . $md_predicate . '](../constructors/' . $predicate . '.md)
|
||||||
|
|
||||||
';
|
';
|
||||||
}
|
}
|
||||||
@ -105,26 +102,25 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
foreach ($keys['methods'] as $data) {
|
foreach ($keys['methods'] as $data) {
|
||||||
$name = $data['method'];
|
$name = $data['method'];
|
||||||
$md_name = \str_replace(['.', '_'], ['->', '\\_'], $name);
|
$md_name = \str_replace(['.', '_'], ['->', '\\_'], $name);
|
||||||
$methods .= '[$MadelineProto->'.$md_name.'](../methods/'.$name.'.md)
|
$methods .= '[$MadelineProto->' . $md_name . '](../methods/' . $name . '.md)
|
||||||
|
|
||||||
';
|
';
|
||||||
}
|
}
|
||||||
$description = isset($this->td_descriptions['types'][$otype]) ? $this->td_descriptions['types'][$otype] : 'constructors and methods of type '.$type;
|
$description = isset($this->td_descriptions['types'][$otype]) ? $this->td_descriptions['types'][$otype] : 'constructors and methods of type ' . $type;
|
||||||
$symFile = \str_replace('.', '_', $type);
|
$symFile = \str_replace('.', '_', $type);
|
||||||
$redir = $symFile !== $type ? "\nredirect_from: /API_docs/types/$symFile.html" : '';
|
$redir = $symFile !== $type ? "\nredirect_from: /API_docs/types/{$symFile}.html" : '';
|
||||||
|
|
||||||
$header = '---
|
$header = '---
|
||||||
title: '.$type.'
|
title: ' . $type . '
|
||||||
description: constructors and methods of type '.$type.'
|
description: constructors and methods of type ' . $type . '
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png'.$redir.'
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png' . $redir . '
|
||||||
---
|
---
|
||||||
# Type: '.\str_replace('_', '\\_', $type).'
|
# Type: ' . \str_replace('_', '\\_', $type) . '
|
||||||
[Back to types index](index.md)
|
[Back to types index](index.md)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
';
|
';
|
||||||
$header .= isset($this->td_descriptions['types'][$otype]) ? $this->td_descriptions['types'][$otype].PHP_EOL.PHP_EOL : '';
|
$header .= isset($this->td_descriptions['types'][$otype]) ? $this->td_descriptions['types'][$otype] . PHP_EOL . PHP_EOL : '';
|
||||||
if (!isset($this->settings['td'])) {
|
if (!isset($this->settings['td'])) {
|
||||||
if (\in_array($type, ['User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputDialogPeer', 'DialogPeer', 'InputPeer', 'NotifyPeer', 'InputNotifyPeer'])) {
|
if (\in_array($type, ['User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputDialogPeer', 'DialogPeer', 'InputPeer', 'NotifyPeer', 'InputNotifyPeer'])) {
|
||||||
$header .= 'You can directly provide the [Update](Update.md) or [Message](Message.md) object here, MadelineProto will automatically extract the destination chat id.
|
$header .= 'You can directly provide the [Update](Update.md) or [Message](Message.md) object here, MadelineProto will automatically extract the destination chat id.
|
||||||
@ -132,23 +128,11 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png'.$redi
|
|||||||
The following syntaxes can also be used:
|
The following syntaxes can also be used:
|
||||||
|
|
||||||
```
|
```
|
||||||
$'.$type." = '@username'; // Username
|
$' . $type . " = '@username'; // Username\n\n\$" . $type . " = 'me'; // The currently logged-in user\n\n\$" . $type . ' = 44700; // bot API id (users)
|
||||||
|
$' . $type . ' = -492772765; // bot API id (chats)
|
||||||
|
$' . $type . ' = -10038575794; // bot API id (channels)
|
||||||
|
|
||||||
\$".$type." = 'me'; // The currently logged-in user
|
$' . $type . " = 'https://t.me/danogentili'; // t.me URLs\n\$" . $type . " = 'https://t.me/joinchat/asfln1-21fa_'; // t.me invite links\n\n\$" . $type . " = 'user#44700'; // tg-cli style id (users)\n\$" . $type . " = 'chat#492772765'; // tg-cli style id (chats)\n\$" . $type . " = 'channel#38575794'; // tg-cli style id (channels)\n```\n\nA [Chat](Chat.md), a [User](User.md), an [InputPeer](InputPeer.md), an [InputDialogPeer](InputDialogPeer.md), an [InputNotifyPeer](InputNotifyPeer.md), an [InputUser](InputUser.md), an [InputChannel](InputChannel.md), a [Peer](Peer.md), an [DialogPeer](DialogPeer.md), [NotifyPeer](NotifyPeer.md), or a [Chat](Chat.md) object can also be used.\n\n\n";
|
||||||
|
|
||||||
\$".$type.' = 44700; // bot API id (users)
|
|
||||||
$'.$type.' = -492772765; // bot API id (chats)
|
|
||||||
$'.$type.' = -10038575794; // bot API id (channels)
|
|
||||||
|
|
||||||
$'.$type." = 'https://t.me/danogentili'; // t.me URLs
|
|
||||||
\$".$type." = 'https://t.me/joinchat/asfln1-21fa_'; // t.me invite links
|
|
||||||
|
|
||||||
\$".$type." = 'user#44700'; // tg-cli style id (users)
|
|
||||||
\$".$type." = 'chat#492772765'; // tg-cli style id (chats)
|
|
||||||
\$".$type." = 'channel#38575794'; // tg-cli style id (channels)
|
|
||||||
```
|
|
||||||
|
|
||||||
A [Chat](Chat.md), a [User](User.md), an [InputPeer](InputPeer.md), an [InputDialogPeer](InputDialogPeer.md), an [InputNotifyPeer](InputNotifyPeer.md), an [InputUser](InputUser.md), an [InputChannel](InputChannel.md), a [Peer](Peer.md), an [DialogPeer](DialogPeer.md), [NotifyPeer](NotifyPeer.md), or a [Chat](Chat.md) object can also be used.\n\n\n";
|
|
||||||
}
|
}
|
||||||
if (\in_array($type, ['InputEncryptedChat'])) {
|
if (\in_array($type, ['InputEncryptedChat'])) {
|
||||||
$header .= 'You can directly provide the [Update](Update.md) or [EncryptedMessage](EncryptedMessage.md) object here, MadelineProto will automatically extract the destination chat id.
|
$header .= 'You can directly provide the [Update](Update.md) or [EncryptedMessage](EncryptedMessage.md) object here, MadelineProto will automatically extract the destination chat id.
|
||||||
@ -156,7 +140,7 @@ A [Chat](Chat.md), a [User](User.md), an [InputPeer](InputPeer.md), an [InputDia
|
|||||||
The following syntax can also be used:
|
The following syntax can also be used:
|
||||||
|
|
||||||
```
|
```
|
||||||
$'.$type.' = -147286699; // Numeric chat id returned by requestSecretChat, can be positive or negative
|
$' . $type . ' = -147286699; // Numeric chat id returned by requestSecretChat, can be positive or negative
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@ -166,7 +150,7 @@ $'.$type.' = -147286699; // Numeric chat id returned by requestSecretChat, can b
|
|||||||
$header .= 'The following syntax can also be used:
|
$header .= 'The following syntax can also be used:
|
||||||
|
|
||||||
```
|
```
|
||||||
$'.$type.' = \'filename.mp4\'; // The file path can also be used
|
$' . $type . ' = \'filename.mp4\'; // The file path can also be used
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@ -191,7 +175,7 @@ $'.$type.' = \'filename.mp4\'; // The file path can also be used
|
|||||||
$header .= 'The following syntax can also be used:
|
$header .= 'The following syntax can also be used:
|
||||||
|
|
||||||
```
|
```
|
||||||
$'.$type.' = 142; // Numeric message ID
|
$' . $type . ' = 142; // Numeric message ID
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@ -203,7 +187,7 @@ $'.$type.' = 142; // Numeric message ID
|
|||||||
To click these buttons simply run the `click` method:
|
To click these buttons simply run the `click` method:
|
||||||
|
|
||||||
```
|
```
|
||||||
$result = $'.$type.'->click();
|
$result = $' . $type . '->click();
|
||||||
```
|
```
|
||||||
|
|
||||||
`$result` can be one of the following:
|
`$result` can be one of the following:
|
||||||
@ -224,12 +208,12 @@ You can also access the properties of the constructor as a normal array, for exa
|
|||||||
}
|
}
|
||||||
$constructors = '### Possible values (constructors):
|
$constructors = '### Possible values (constructors):
|
||||||
|
|
||||||
'.$constructors.'
|
' . $constructors . '
|
||||||
|
|
||||||
';
|
';
|
||||||
$methods = '### Methods that return an object of this type (methods):
|
$methods = '### Methods that return an object of this type (methods):
|
||||||
|
|
||||||
'.$methods.'
|
' . $methods . '
|
||||||
|
|
||||||
';
|
';
|
||||||
if (!isset($this->settings['td'])) {
|
if (!isset($this->settings['td'])) {
|
||||||
@ -389,7 +373,7 @@ Easy as pie:
|
|||||||
|
|
||||||
```
|
```
|
||||||
$call->storage["pony"] = "fluttershy";
|
$call->storage["pony"] = "fluttershy";
|
||||||
\danog\MadelineProto\Logger::log($call->storage["pony"]); // fluttershy
|
\\danog\\MadelineProto\\Logger::log($call->storage["pony"]); // fluttershy
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: when modifying this property, *never* overwrite the previous values. Always either modify the values of the array separately like showed above, or use array_merge.
|
Note: when modifying this property, *never* overwrite the previous values. Always either modify the values of the array separately like showed above, or use array_merge.
|
||||||
@ -416,14 +400,14 @@ After modifying it, you must always parse the new configuration with a call to `
|
|||||||
';
|
';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (\file_exists('types/'.$type.'.md')) {
|
if (\file_exists('types/' . $type . '.md')) {
|
||||||
\danog\MadelineProto\Logger::log($type);
|
\danog\MadelineProto\Logger::log($type);
|
||||||
}
|
}
|
||||||
\file_put_contents('types/'.$type.'.md', $header.$constructors.$methods);
|
\file_put_contents('types/' . $type . '.md', $header . $constructors . $methods);
|
||||||
$last_namespace = $new_namespace;
|
$last_namespace = $new_namespace;
|
||||||
}
|
}
|
||||||
\danog\MadelineProto\Logger::log('Generating types index...', \danog\MadelineProto\Logger::NOTICE);
|
\danog\MadelineProto\Logger::log('Generating types index...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
\file_put_contents('types/'.$this->index, '---
|
\file_put_contents('types/' . $this->index, '---
|
||||||
title: Types
|
title: Types
|
||||||
description: List of types
|
description: List of types
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -432,7 +416,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
[Back to API documentation index](..)
|
[Back to API documentation index](..)
|
||||||
|
|
||||||
|
|
||||||
'.$index);
|
' . $index);
|
||||||
\danog\MadelineProto\Logger::log('Generating additional types...', \danog\MadelineProto\Logger::NOTICE);
|
\danog\MadelineProto\Logger::log('Generating additional types...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
\file_put_contents('types/string.md', '---
|
\file_put_contents('types/string.md', '---
|
||||||
title: string
|
title: string
|
||||||
@ -452,7 +436,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
## Type: bytes
|
## Type: bytes
|
||||||
[Back to constructor index](index.md)
|
[Back to constructor index](index.md)
|
||||||
|
|
||||||
An object of type `\danog\MadelineProto\TL\Types\Bytes`.
|
An object of type `\\danog\\MadelineProto\\TL\\Types\\Bytes`.
|
||||||
When casted to string, turns into a string of bytes of variable length, with length smaller than or equal to 16777215.
|
When casted to string, turns into a string of bytes of variable length, with length smaller than or equal to 16777215.
|
||||||
When JSON-serialized, turns into an array of the following format:
|
When JSON-serialized, turns into an array of the following format:
|
||||||
```
|
```
|
||||||
@ -604,7 +588,6 @@ Any json-encodable data.
|
|||||||
');
|
');
|
||||||
\danog\MadelineProto\Logger::log('Done!', \danog\MadelineProto\Logger::NOTICE);
|
\danog\MadelineProto\Logger::log('Done!', \danog\MadelineProto\Logger::NOTICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static $template = '<?php
|
public static $template = '<?php
|
||||||
/**
|
/**
|
||||||
* Lang module
|
* Lang module
|
||||||
@ -622,7 +605,7 @@ Any json-encodable data.
|
|||||||
* @link https://docs.madelineproto.xyz MadelineProto documentation
|
* @link https://docs.madelineproto.xyz MadelineProto documentation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace danog\MadelineProto;
|
namespace danog\\MadelineProto;
|
||||||
|
|
||||||
class Lang
|
class Lang
|
||||||
{
|
{
|
||||||
@ -631,12 +614,11 @@ class Lang
|
|||||||
// THIS WILL BE OVERWRITTEN BY $lang["en"]
|
// THIS WILL BE OVERWRITTEN BY $lang["en"]
|
||||||
public static $current_lang = %s;
|
public static $current_lang = %s;
|
||||||
}';
|
}';
|
||||||
|
|
||||||
public static function addToLang(string $key, string $value = '', bool $force = false)
|
public static function addToLang(string $key, string $value = '', bool $force = false)
|
||||||
{
|
{
|
||||||
if (!isset(\danog\MadelineProto\Lang::$lang['en'][$key]) || $force) {
|
if (!isset(\danog\MadelineProto\Lang::$lang['en'][$key]) || $force) {
|
||||||
\danog\MadelineProto\Lang::$lang['en'][$key] = $value;
|
\danog\MadelineProto\Lang::$lang['en'][$key] = $value;
|
||||||
\file_put_contents(__DIR__.'/Lang.php', \sprintf(self::$template, \var_export(\danog\MadelineProto\Lang::$lang, true), \var_export(\danog\MadelineProto\Lang::$lang['en'], true)));
|
\file_put_contents(__DIR__ . '/Lang.php', \sprintf(self::$template, \var_export(\danog\MadelineProto\Lang::$lang, true), \var_export(\danog\MadelineProto\Lang::$lang['en'], true)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ trait Constructors
|
|||||||
{
|
{
|
||||||
public function mkConstructors()
|
public function mkConstructors()
|
||||||
{
|
{
|
||||||
foreach (\glob('constructors/'.$this->any) as $unlink) {
|
foreach (\glob('constructors/' . $this->any) as $unlink) {
|
||||||
\unlink($unlink);
|
\unlink($unlink);
|
||||||
}
|
}
|
||||||
if (\file_exists('constructors')) {
|
if (\file_exists('constructors')) {
|
||||||
@ -42,10 +42,10 @@ trait Constructors
|
|||||||
}
|
}
|
||||||
$got[$id] = '';
|
$got[$id] = '';
|
||||||
/*
|
/*
|
||||||
if (preg_match('/%/', $type)) {
|
if (preg_match('/%/', $type)) {
|
||||||
$type = $this->TL->getConstructors($this->td)->findByType(str_replace('%', '', $type))['predicate'];
|
$type = $this->TL->getConstructors($this->td)->findByType(str_replace('%', '', $type))['predicate'];
|
||||||
}*/
|
}*/
|
||||||
$layer = isset($data['layer']) && $data['layer'] !== '' ? '_'.$data['layer'] : '';
|
$layer = isset($data['layer']) && $data['layer'] !== '' ? '_' . $data['layer'] : '';
|
||||||
$type = \str_replace(['<', '>'], ['_of_', ''], $data['type']);
|
$type = \str_replace(['<', '>'], ['_of_', ''], $data['type']);
|
||||||
$php_type = \preg_replace('/.*_of_/', '', $type);
|
$php_type = \preg_replace('/.*_of_/', '', $type);
|
||||||
$constructor = \str_replace(['<', '>'], ['_of_', ''], $data['predicate']);
|
$constructor = \str_replace(['<', '>'], ['_of_', ''], $data['predicate']);
|
||||||
@ -74,12 +74,12 @@ trait Constructors
|
|||||||
if (\substr($param[$type_or_subtype], -1) === '>') {
|
if (\substr($param[$type_or_subtype], -1) === '>') {
|
||||||
$param[$type_or_subtype] = \substr($param[$type_or_subtype], 0, -1);
|
$param[$type_or_subtype] = \substr($param[$type_or_subtype], 0, -1);
|
||||||
}
|
}
|
||||||
$params .= "'".$param['name']."' => ";
|
$params .= "'" . $param['name'] . "' => ";
|
||||||
$param[$type_or_subtype] = '['.Tools::markdownEscape($param[$type_or_subtype]).'](../'.$type_or_bare_type.'/'.$param[$type_or_subtype].'.md)';
|
$param[$type_or_subtype] = '[' . Tools::markdownEscape($param[$type_or_subtype]) . '](../' . $type_or_bare_type . '/' . $param[$type_or_subtype] . '.md)';
|
||||||
$params .= (isset($param['subtype']) ? '\\['.$param[$type_or_subtype].'\\]' : $param[$type_or_subtype]).', ';
|
$params .= (isset($param['subtype']) ? '\\[' . $param[$type_or_subtype] . '\\]' : $param[$type_or_subtype]) . ', ';
|
||||||
}
|
}
|
||||||
$md_constructor = \str_replace('_', '\\_', $constructor.$layer);
|
$md_constructor = \str_replace('_', '\\_', $constructor . $layer);
|
||||||
$this->docs_constructors[$constructor] = '[$'.$md_constructor.'](../constructors/'.$php_constructor.$layer.'.md) = \\['.$params.'\\];<a name="'.$constructor.$layer.'"></a>
|
$this->docs_constructors[$constructor] = '[$' . $md_constructor . '](../constructors/' . $php_constructor . $layer . '.md) = \\[' . $params . '\\];<a name="' . $constructor . $layer . '"></a>
|
||||||
|
|
||||||
';
|
';
|
||||||
$table = empty($data['params']) ? '' : '### Attributes:
|
$table = empty($data['params']) ? '' : '### Attributes:
|
||||||
@ -88,12 +88,11 @@ trait Constructors
|
|||||||
|----------|---------------|----------|
|
|----------|---------------|----------|
|
||||||
';
|
';
|
||||||
if (!isset($this->TL->getDescriptions()['constructors'][$data['predicate']])) {
|
if (!isset($this->TL->getDescriptions()['constructors'][$data['predicate']])) {
|
||||||
$this->addToLang('object_'.$data['predicate']);
|
$this->addToLang('object_' . $data['predicate']);
|
||||||
if (\danog\MadelineProto\Lang::$lang['en']['object_'.$data['predicate']] !== '') {
|
if (\danog\MadelineProto\Lang::$lang['en']['object_' . $data['predicate']] !== '') {
|
||||||
$this->TL->getDescriptions()['constructors'][$data['predicate']]['description'] = \danog\MadelineProto\Lang::$lang['en']['object_'.$data['predicate']];
|
$this->TL->getDescriptions()['constructors'][$data['predicate']]['description'] = \danog\MadelineProto\Lang::$lang['en']['object_' . $data['predicate']];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($this->TL->getDescriptions()['constructors'][$data['predicate']]) && !empty($data['params'])) {
|
if (isset($this->TL->getDescriptions()['constructors'][$data['predicate']]) && !empty($data['params'])) {
|
||||||
$table = '### Attributes:
|
$table = '### Attributes:
|
||||||
|
|
||||||
@ -115,7 +114,7 @@ trait Constructors
|
|||||||
$param['type'] = 'DecryptedMessage';
|
$param['type'] = 'DecryptedMessage';
|
||||||
}
|
}
|
||||||
if ($type === 'DecryptedMessageMedia' && \in_array($param['name'], ['key', 'iv'])) {
|
if ($type === 'DecryptedMessageMedia' && \in_array($param['name'], ['key', 'iv'])) {
|
||||||
unset(\danog\MadelineProto\Lang::$lang['en']['object_'.$data['predicate'].'_param_'.$param['name'].'_type_'.$param['type']]);
|
unset(\danog\MadelineProto\Lang::$lang['en']['object_' . $data['predicate'] . '_param_' . $param['name'] . '_type_' . $param['type']]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$ptype = $param[isset($param['subtype']) ? 'subtype' : 'type'];
|
$ptype = $param[isset($param['subtype']) ? 'subtype' : 'type'];
|
||||||
@ -139,59 +138,58 @@ trait Constructors
|
|||||||
}
|
}
|
||||||
$human_ptype = $ptype;
|
$human_ptype = $ptype;
|
||||||
if (\strpos($type, 'Input') === 0 && \in_array($ptype, ['User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputDialogPeer', 'DialogPeer', 'NotifyPeer', 'InputNotifyPeer', 'InputPeer']) && !isset($this->settings['td'])) {
|
if (\strpos($type, 'Input') === 0 && \in_array($ptype, ['User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputDialogPeer', 'DialogPeer', 'NotifyPeer', 'InputNotifyPeer', 'InputPeer']) && !isset($this->settings['td'])) {
|
||||||
$human_ptype = 'Username, chat ID, Update, Message or '.$ptype;
|
$human_ptype = 'Username, chat ID, Update, Message or ' . $ptype;
|
||||||
}
|
}
|
||||||
if (\strpos($type, 'Input') === 0 && \in_array($ptype, ['InputMedia', 'InputDocument', 'InputPhoto']) && !isset($this->settings['td'])) {
|
if (\strpos($type, 'Input') === 0 && \in_array($ptype, ['InputMedia', 'InputDocument', 'InputPhoto']) && !isset($this->settings['td'])) {
|
||||||
$human_ptype = 'MessageMedia, Message, Update or '.$ptype;
|
$human_ptype = 'MessageMedia, Message, Update or ' . $ptype;
|
||||||
}
|
}
|
||||||
if (\in_array($ptype, ['InputMessage']) && !isset($this->settings['td'])) {
|
if (\in_array($ptype, ['InputMessage']) && !isset($this->settings['td'])) {
|
||||||
$human_ptype = 'Message ID or '.$ptype;
|
$human_ptype = 'Message ID or ' . $ptype;
|
||||||
}
|
}
|
||||||
if (\in_array($ptype, ['InputEncryptedChat']) && !isset($this->settings['td'])) {
|
if (\in_array($ptype, ['InputEncryptedChat']) && !isset($this->settings['td'])) {
|
||||||
$human_ptype = 'Secret chat ID, Update, EncryptedMessage or '.$ptype;
|
$human_ptype = 'Secret chat ID, Update, EncryptedMessage or ' . $ptype;
|
||||||
}
|
}
|
||||||
if (\in_array($ptype, ['InputFile']) && !isset($this->settings['td'])) {
|
if (\in_array($ptype, ['InputFile']) && !isset($this->settings['td'])) {
|
||||||
$human_ptype = 'File path or '.$ptype;
|
$human_ptype = 'File path or ' . $ptype;
|
||||||
}
|
}
|
||||||
if (\in_array($ptype, ['InputEncryptedFile']) && !isset($this->settings['td'])) {
|
if (\in_array($ptype, ['InputEncryptedFile']) && !isset($this->settings['td'])) {
|
||||||
$human_ptype = 'File path or '.$ptype;
|
$human_ptype = 'File path or ' . $ptype;
|
||||||
}
|
}
|
||||||
$table .= '|'.\str_replace('_', '\\_', $param['name']).'|'.(isset($param['subtype']) ? 'Array of ' : '').'['.\str_replace('_', '\\_', $human_ptype).'](../'.$type_or_bare_type.'/'.$ptype.'.md) | '.(isset($param['pow']) || $this->TL->getConstructors($this->td)->findByPredicate(\lcfirst($param['type']).'Empty') || ($data['type'] === 'InputMedia' && $param['name'] === 'mime_type') || ($data['type'] === 'DocumentAttribute' && \in_array($param['name'], ['w', 'h', 'duration'])) ? 'Optional' : 'Yes').'|';
|
$table .= '|' . \str_replace('_', '\\_', $param['name']) . '|' . (isset($param['subtype']) ? 'Array of ' : '') . '[' . \str_replace('_', '\\_', $human_ptype) . '](../' . $type_or_bare_type . '/' . $ptype . '.md) | ' . (isset($param['pow']) || $this->TL->getConstructors($this->td)->findByPredicate(\lcfirst($param['type']) . 'Empty') || $data['type'] === 'InputMedia' && $param['name'] === 'mime_type' || $data['type'] === 'DocumentAttribute' && \in_array($param['name'], ['w', 'h', 'duration']) ? 'Optional' : 'Yes') . '|';
|
||||||
|
|
||||||
if (!isset($this->TL->getDescriptions()['constructors'][$data['predicate']]['params'][$param['name']])) {
|
if (!isset($this->TL->getDescriptions()['constructors'][$data['predicate']]['params'][$param['name']])) {
|
||||||
$this->addToLang('object_'.$data['predicate'].'_param_'.$param['name'].'_type_'.$param['type']);
|
$this->addToLang('object_' . $data['predicate'] . '_param_' . $param['name'] . '_type_' . $param['type']);
|
||||||
if (isset($this->TL->getDescriptions()['constructors'][$data['predicate']]['description'])) {
|
if (isset($this->TL->getDescriptions()['constructors'][$data['predicate']]['description'])) {
|
||||||
$this->TL->getDescriptions()['constructors'][$data['predicate']]['params'][$param['name']] = \danog\MadelineProto\Lang::$lang['en']['object_'.$data['predicate'].'_param_'.$param['name'].'_type_'.$param['type']];
|
$this->TL->getDescriptions()['constructors'][$data['predicate']]['params'][$param['name']] = \danog\MadelineProto\Lang::$lang['en']['object_' . $data['predicate'] . '_param_' . $param['name'] . '_type_' . $param['type']];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isset($this->TL->getDescriptions()['constructors'][$data['predicate']]['params'][$param['name']])) {
|
if (isset($this->TL->getDescriptions()['constructors'][$data['predicate']]['params'][$param['name']])) {
|
||||||
$table .= $this->TL->getDescriptions()['constructors'][$data['predicate']]['params'][$param['name']].'|';
|
$table .= $this->TL->getDescriptions()['constructors'][$data['predicate']]['params'][$param['name']] . '|';
|
||||||
}
|
}
|
||||||
$table .= PHP_EOL;
|
$table .= PHP_EOL;
|
||||||
$pptype = \in_array($ptype, ['string', 'bytes']) ? "'".$ptype."'" : $ptype;
|
$pptype = \in_array($ptype, ['string', 'bytes']) ? "'" . $ptype . "'" : $ptype;
|
||||||
$ppptype = \in_array($ptype, ['string']) ? '"'.$ptype.'"' : $ptype;
|
$ppptype = \in_array($ptype, ['string']) ? '"' . $ptype . '"' : $ptype;
|
||||||
$ppptype = \in_array($ptype, ['bytes']) ? '{"_": "bytes", "bytes":"base64 encoded '.$ptype.'"}' : $ppptype;
|
$ppptype = \in_array($ptype, ['bytes']) ? '{"_": "bytes", "bytes":"base64 encoded ' . $ptype . '"}' : $ppptype;
|
||||||
$params .= ", '".$param['name']."' => ";
|
$params .= ", '" . $param['name'] . "' => ";
|
||||||
$params .= isset($param['subtype']) ? '['.$pptype.', '.$pptype.']' : $pptype;
|
$params .= isset($param['subtype']) ? '[' . $pptype . ', ' . $pptype . ']' : $pptype;
|
||||||
$lua_params .= ', '.$param['name'].'=';
|
$lua_params .= ', ' . $param['name'] . '=';
|
||||||
$lua_params .= isset($param['subtype']) ? '{'.$pptype.'}' : $pptype;
|
$lua_params .= isset($param['subtype']) ? '{' . $pptype . '}' : $pptype;
|
||||||
$pwr_params .= ', "'.$param['name'].'": '.(isset($param['subtype']) ? '['.$ppptype.']' : $ppptype);
|
$pwr_params .= ', "' . $param['name'] . '": ' . (isset($param['subtype']) ? '[' . $ppptype . ']' : $ppptype);
|
||||||
if ($param['name'] === 'reply_markup') {
|
if ($param['name'] === 'reply_markup') {
|
||||||
$hasreplymarkup = true;
|
$hasreplymarkup = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$params = "['_' => '".$data['predicate']."'".$params.']';
|
$params = "['_' => '" . $data['predicate'] . "'" . $params . ']';
|
||||||
$lua_params = "{_='".$data['predicate']."'".$lua_params.'}';
|
$lua_params = "{_='" . $data['predicate'] . "'" . $lua_params . '}';
|
||||||
$pwr_params = '{"_": "'.$data['predicate'].'"'.$pwr_params.'}';
|
$pwr_params = '{"_": "' . $data['predicate'] . '"' . $pwr_params . '}';
|
||||||
$description = isset($this->TL->getDescriptions()['constructors'][$data['predicate']]) ? $this->TL->getDescriptions()['constructors'][$data['predicate']]['description'] : $constructor.' attributes, type and example';
|
$description = isset($this->TL->getDescriptions()['constructors'][$data['predicate']]) ? $this->TL->getDescriptions()['constructors'][$data['predicate']]['description'] : $constructor . ' attributes, type and example';
|
||||||
$symFile = \str_replace('.', '_', $constructor.$layer);
|
$symFile = \str_replace('.', '_', $constructor . $layer);
|
||||||
$redir = $symFile !== $constructor.$layer ? "\nredirect_from: /API_docs/constructors/$symFile.html" : '';
|
$redir = $symFile !== $constructor . $layer ? "\nredirect_from: /API_docs/constructors/{$symFile}.html" : '';
|
||||||
$header = '---
|
$header = '---
|
||||||
title: '.$data['predicate'].'
|
title: ' . $data['predicate'] . '
|
||||||
description: '.$description.'
|
description: ' . $description . '
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png'.$redir.'
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png' . $redir . '
|
||||||
---
|
---
|
||||||
# Constructor: '.\str_replace('_', '\\_', $data['predicate'].$layer).'
|
# Constructor: ' . \str_replace('_', '\\_', $data['predicate'] . $layer) . '
|
||||||
[Back to constructors index](index.md)
|
[Back to constructors index](index.md)
|
||||||
|
|
||||||
|
|
||||||
@ -202,9 +200,9 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png'.$redi
|
|||||||
|
|
||||||
';
|
';
|
||||||
if (isset($this->TL->getDescriptions()['constructors'][$data['predicate']])) {
|
if (isset($this->TL->getDescriptions()['constructors'][$data['predicate']])) {
|
||||||
$header .= $this->TL->getDescriptions()['constructors'][$data['predicate']]['description'].PHP_EOL.PHP_EOL;
|
$header .= $this->TL->getDescriptions()['constructors'][$data['predicate']]['description'] . PHP_EOL . PHP_EOL;
|
||||||
}
|
}
|
||||||
$type = '### Type: ['.\str_replace('_', '\\_', $php_type).'](../types/'.$php_type.'.md)
|
$type = '### Type: [' . \str_replace('_', '\\_', $php_type) . '](../types/' . $php_type . '.md)
|
||||||
|
|
||||||
|
|
||||||
';
|
';
|
||||||
@ -213,14 +211,14 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png'.$redi
|
|||||||
$example = '### Example:
|
$example = '### Example:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
$'.$constructor.$layer.' = '.$params.';
|
$' . $constructor . $layer . ' = ' . $params . ';
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
Or, if you\'re into Lua:
|
Or, if you\'re into Lua:
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
'.$constructor.$layer.'='.$lua_params.'
|
' . $constructor . $layer . '=' . $lua_params . '
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -270,7 +268,7 @@ MadelineProto supports all html entities supported by [html_entity_decode](http:
|
|||||||
';
|
';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
\file_put_contents('constructors/'.$constructor.$layer.'.md', $header.$table.$type.$example);
|
\file_put_contents('constructors/' . $constructor . $layer . '.md', $header . $table . $type . $example);
|
||||||
}
|
}
|
||||||
$this->logger->logger('Generating constructors index...', \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('Generating constructors index...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
\ksort($this->docs_constructors);
|
\ksort($this->docs_constructors);
|
||||||
@ -279,10 +277,10 @@ MadelineProto supports all html entities supported by [html_entity_decode](http:
|
|||||||
$new_namespace = \preg_replace('/_.*/', '', $constructor);
|
$new_namespace = \preg_replace('/_.*/', '', $constructor);
|
||||||
$br = $new_namespace != $last_namespace ? '***
|
$br = $new_namespace != $last_namespace ? '***
|
||||||
<br><br>' : '';
|
<br><br>' : '';
|
||||||
$value = $br.$value;
|
$value = $br . $value;
|
||||||
$last_namespace = $new_namespace;
|
$last_namespace = $new_namespace;
|
||||||
}
|
}
|
||||||
\file_put_contents('constructors/'.$this->index, '---
|
\file_put_contents('constructors/' . $this->index, '---
|
||||||
title: Constructors
|
title: Constructors
|
||||||
description: List of constructors
|
description: List of constructors
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -290,6 +288,6 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
# Constructors
|
# Constructors
|
||||||
[Back to API documentation index](..)
|
[Back to API documentation index](..)
|
||||||
|
|
||||||
'.\implode('', $this->docs_constructors));
|
' . \implode('', $this->docs_constructors));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ trait Methods
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (\glob('methods/'.$this->any) as $unlink) {
|
foreach (\glob('methods/' . $this->any) as $unlink) {
|
||||||
\unlink($unlink);
|
\unlink($unlink);
|
||||||
}
|
}
|
||||||
if (\file_exists('methods')) {
|
if (\file_exists('methods')) {
|
||||||
@ -80,31 +80,28 @@ trait Methods
|
|||||||
$type_or_subtype = isset($param['subtype']) ? 'subtype' : 'type';
|
$type_or_subtype = isset($param['subtype']) ? 'subtype' : 'type';
|
||||||
$type_or_bare_type = \ctype_upper(Tools::end(\explode('.', $param[$type_or_subtype]))[0]) || \in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int', 'long', 'int128', 'int256', 'int512', 'int53']) ? 'types' : 'constructors';
|
$type_or_bare_type = \ctype_upper(Tools::end(\explode('.', $param[$type_or_subtype]))[0]) || \in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int', 'long', 'int128', 'int256', 'int512', 'int53']) ? 'types' : 'constructors';
|
||||||
$param[$type_or_subtype] = \str_replace(['true', 'false'], ['Bool', 'Bool'], $param[$type_or_subtype]);
|
$param[$type_or_subtype] = \str_replace(['true', 'false'], ['Bool', 'Bool'], $param[$type_or_subtype]);
|
||||||
$param[$type_or_subtype] = '['.Tools::markdownEscape($param[$type_or_subtype]).'](../'.$type_or_bare_type.'/'.$param[$type_or_subtype].'.md)';
|
$param[$type_or_subtype] = '[' . Tools::markdownEscape($param[$type_or_subtype]) . '](../' . $type_or_bare_type . '/' . $param[$type_or_subtype] . '.md)';
|
||||||
$params .= "'".$param['name']."' => ".(isset($param['subtype']) ? '\\['.$param[$type_or_subtype].'\\]' : $param[$type_or_subtype]).', ';
|
$params .= "'" . $param['name'] . "' => " . (isset($param['subtype']) ? '\\[' . $param[$type_or_subtype] . '\\]' : $param[$type_or_subtype]) . ', ';
|
||||||
}
|
}
|
||||||
if (!isset($this->td_descriptions['methods'][$data['method']])) {
|
if (!isset($this->td_descriptions['methods'][$data['method']])) {
|
||||||
$this->addToLang('method_'.$data['method']);
|
$this->addToLang('method_' . $data['method']);
|
||||||
|
if (\danog\MadelineProto\Lang::$lang['en']['method_' . $data['method']] !== '') {
|
||||||
if (\danog\MadelineProto\Lang::$lang['en']['method_'.$data['method']] !== '') {
|
$this->td_descriptions['methods'][$data['method']]['description'] = \danog\MadelineProto\Lang::$lang['en']['method_' . $data['method']];
|
||||||
$this->td_descriptions['methods'][$data['method']]['description'] = \danog\MadelineProto\Lang::$lang['en']['method_'.$data['method']];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$md_method = '['.$php_method.']('.$method.'.md)';
|
$md_method = '[' . $php_method . '](' . $method . '.md)';
|
||||||
$this->docs_methods[$method] = '$MadelineProto->'.$md_method.'(\\['.$params.'\\]) === [$'.\str_replace('_', '\\_', $type).'](../types/'.$php_type.'.md)<a name="'.$method.'"></a>
|
$this->docs_methods[$method] = '$MadelineProto->' . $md_method . '(\\[' . $params . '\\]) === [$' . \str_replace('_', '\\_', $type) . '](../types/' . $php_type . '.md)<a name="' . $method . '"></a>
|
||||||
|
|
||||||
';
|
';
|
||||||
|
|
||||||
if (isset($this->td_descriptions['methods'][$data['method']])) {
|
if (isset($this->td_descriptions['methods'][$data['method']])) {
|
||||||
$desc = \Parsedown::instance()->line(\trim(\explode("\n", $this->td_descriptions['methods'][$data['method']]['description'])[0], '.'));
|
$desc = \Parsedown::instance()->line(\trim(\explode("\n", $this->td_descriptions['methods'][$data['method']]['description'])[0], '.'));
|
||||||
$dom = new \DOMDocument();
|
$dom = new \DOMDocument();
|
||||||
$dom->loadHTML(\mb_convert_encoding($desc, 'HTML-ENTITIES', 'UTF-8'));
|
$dom->loadHTML(\mb_convert_encoding($desc, 'HTML-ENTITIES', 'UTF-8'));
|
||||||
$desc = $dom->textContent;
|
$desc = $dom->textContent;
|
||||||
$this->human_docs_methods[$this->td_descriptions['methods'][$data['method']]['description'].': '.$data['method']] = '* <a href="'.$method.'.html" name="'.$method.'">'.$desc.': '.$data['method'].'</a>
|
$this->human_docs_methods[$this->td_descriptions['methods'][$data['method']]['description'] . ': ' . $data['method']] = '* <a href="' . $method . '.html" name="' . $method . '">' . $desc . ': ' . $data['method'] . '</a>
|
||||||
|
|
||||||
';
|
';
|
||||||
}
|
}
|
||||||
|
|
||||||
$params = '';
|
$params = '';
|
||||||
$lua_params = '';
|
$lua_params = '';
|
||||||
$pwr_params = '';
|
$pwr_params = '';
|
||||||
@ -148,47 +145,45 @@ trait Methods
|
|||||||
}
|
}
|
||||||
$human_ptype = $ptype;
|
$human_ptype = $ptype;
|
||||||
if (\in_array($ptype, ['InputDialogPeer', 'DialogPeer', 'NotifyPeer', 'InputNotifyPeer', 'User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputPeer']) && !isset($this->settings['td'])) {
|
if (\in_array($ptype, ['InputDialogPeer', 'DialogPeer', 'NotifyPeer', 'InputNotifyPeer', 'User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputPeer']) && !isset($this->settings['td'])) {
|
||||||
$human_ptype = 'Username, chat ID, Update, Message or '.$ptype;
|
$human_ptype = 'Username, chat ID, Update, Message or ' . $ptype;
|
||||||
}
|
}
|
||||||
if (\in_array($ptype, ['InputMedia', 'InputPhoto', 'InputDocument']) && !isset($this->settings['td'])) {
|
if (\in_array($ptype, ['InputMedia', 'InputPhoto', 'InputDocument']) && !isset($this->settings['td'])) {
|
||||||
$human_ptype = 'MessageMedia, Update, Message or '.$ptype;
|
$human_ptype = 'MessageMedia, Update, Message or ' . $ptype;
|
||||||
}
|
}
|
||||||
if (\in_array($ptype, ['InputMessage']) && !isset($this->settings['td'])) {
|
if (\in_array($ptype, ['InputMessage']) && !isset($this->settings['td'])) {
|
||||||
$human_ptype = 'Message ID or '.$ptype;
|
$human_ptype = 'Message ID or ' . $ptype;
|
||||||
}
|
}
|
||||||
if (\in_array($ptype, ['InputEncryptedChat']) && !isset($this->settings['td'])) {
|
if (\in_array($ptype, ['InputEncryptedChat']) && !isset($this->settings['td'])) {
|
||||||
$human_ptype = 'Secret chat ID, Update, EncryptedMessage or '.$ptype;
|
$human_ptype = 'Secret chat ID, Update, EncryptedMessage or ' . $ptype;
|
||||||
}
|
}
|
||||||
if (\in_array($ptype, ['InputFile']) && !isset($this->settings['td'])) {
|
if (\in_array($ptype, ['InputFile']) && !isset($this->settings['td'])) {
|
||||||
$human_ptype = 'File path or '.$ptype;
|
$human_ptype = 'File path or ' . $ptype;
|
||||||
}
|
}
|
||||||
if (\in_array($ptype, ['InputEncryptedFile']) && !isset($this->settings['td'])) {
|
if (\in_array($ptype, ['InputEncryptedFile']) && !isset($this->settings['td'])) {
|
||||||
$human_ptype = 'File path or '.$ptype;
|
$human_ptype = 'File path or ' . $ptype;
|
||||||
}
|
}
|
||||||
$type_or_bare_type = \ctype_upper(Tools::end(\explode('.', $param[$type_or_subtype]))[0]) || \in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int', 'long', 'int128', 'int256', 'int512', 'int53']) ? 'types' : 'constructors';
|
$type_or_bare_type = \ctype_upper(Tools::end(\explode('.', $param[$type_or_subtype]))[0]) || \in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int', 'long', 'int128', 'int256', 'int512', 'int53']) ? 'types' : 'constructors';
|
||||||
if (!isset($this->td_descriptions['methods'][$data['method']]['params'][$param['name']])) {
|
if (!isset($this->td_descriptions['methods'][$data['method']]['params'][$param['name']])) {
|
||||||
$this->addToLang('method_'.$data['method'].'_param_'.$param['name'].'_type_'.$param['type']);
|
$this->addToLang('method_' . $data['method'] . '_param_' . $param['name'] . '_type_' . $param['type']);
|
||||||
if (isset($this->td_descriptions['methods'][$data['method']]['description'])) {
|
if (isset($this->td_descriptions['methods'][$data['method']]['description'])) {
|
||||||
$this->td_descriptions['methods'][$data['method']]['params'][$param['name']] = \danog\MadelineProto\Lang::$lang['en']['method_'.$data['method'].'_param_'.$param['name'].'_type_'.$param['type']];
|
$this->td_descriptions['methods'][$data['method']]['params'][$param['name']] = \danog\MadelineProto\Lang::$lang['en']['method_' . $data['method'] . '_param_' . $param['name'] . '_type_' . $param['type']];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($this->td_descriptions['methods'][$data['method']])) {
|
if (isset($this->td_descriptions['methods'][$data['method']])) {
|
||||||
$table .= '|'.\str_replace('_', '\\_', $param['name']).'|'.(isset($param['subtype']) ? 'Array of ' : '').'['.\str_replace('_', '\\_', $human_ptype).'](../'.$type_or_bare_type.'/'.$ptype.'.md) | '.$this->td_descriptions['methods'][$data['method']]['params'][$param['name']].' | '.(isset($param['pow']) || (($id = $this->TL->getConstructors($this->td)->findByPredicate(\lcfirst($param['type']).'Empty')) && $id['type'] === $param['type']) || (($id = $this->TL->getConstructors($this->td)->findByPredicate('input'.$param['type'].'Empty')) && $id['type'] === $param['type']) ? 'Optional' : 'Yes').'|';
|
$table .= '|' . \str_replace('_', '\\_', $param['name']) . '|' . (isset($param['subtype']) ? 'Array of ' : '') . '[' . \str_replace('_', '\\_', $human_ptype) . '](../' . $type_or_bare_type . '/' . $ptype . '.md) | ' . $this->td_descriptions['methods'][$data['method']]['params'][$param['name']] . ' | ' . (isset($param['pow']) || ($id = $this->TL->getConstructors($this->td)->findByPredicate(\lcfirst($param['type']) . 'Empty')) && $id['type'] === $param['type'] || ($id = $this->TL->getConstructors($this->td)->findByPredicate('input' . $param['type'] . 'Empty')) && $id['type'] === $param['type'] ? 'Optional' : 'Yes') . '|';
|
||||||
} else {
|
} else {
|
||||||
$table .= '|'.\str_replace('_', '\\_', $param['name']).'|'.(isset($param['subtype']) ? 'Array of ' : '').'['.\str_replace('_', '\\_', $human_ptype).'](../'.$type_or_bare_type.'/'.$ptype.'.md) | '.(isset($param['pow']) || (($id = $this->TL->getConstructors($this->td)->findByPredicate(\lcfirst($param['type']).'Empty')) && $id['type'] === $param['type']) || (($id = $this->TL->getConstructors($this->td)->findByPredicate('input'.$param['type'].'Empty')) && $id['type'] === $param['type']) ? 'Optional' : 'Yes').'|';
|
$table .= '|' . \str_replace('_', '\\_', $param['name']) . '|' . (isset($param['subtype']) ? 'Array of ' : '') . '[' . \str_replace('_', '\\_', $human_ptype) . '](../' . $type_or_bare_type . '/' . $ptype . '.md) | ' . (isset($param['pow']) || ($id = $this->TL->getConstructors($this->td)->findByPredicate(\lcfirst($param['type']) . 'Empty')) && $id['type'] === $param['type'] || ($id = $this->TL->getConstructors($this->td)->findByPredicate('input' . $param['type'] . 'Empty')) && $id['type'] === $param['type'] ? 'Optional' : 'Yes') . '|';
|
||||||
}
|
}
|
||||||
$table .= PHP_EOL;
|
$table .= PHP_EOL;
|
||||||
$pptype = \in_array($ptype, ['string', 'bytes']) ? "'".$ptype."'" : $ptype;
|
$pptype = \in_array($ptype, ['string', 'bytes']) ? "'" . $ptype . "'" : $ptype;
|
||||||
$ppptype = \in_array($ptype, ['string']) ? '"'.$ptype.'"' : $ptype;
|
$ppptype = \in_array($ptype, ['string']) ? '"' . $ptype . '"' : $ptype;
|
||||||
$ppptype = \in_array($ptype, ['bytes']) ? '{"_": "bytes", "bytes":"base64 encoded '.$ptype.'"}' : $ppptype;
|
$ppptype = \in_array($ptype, ['bytes']) ? '{"_": "bytes", "bytes":"base64 encoded ' . $ptype . '"}' : $ppptype;
|
||||||
|
$params .= "'" . $param['name'] . "' => ";
|
||||||
$params .= "'".$param['name']."' => ";
|
$params .= (isset($param['subtype']) ? '[' . $pptype . ', ' . $pptype . ']' : $pptype) . ', ';
|
||||||
$params .= (isset($param['subtype']) ? '['.$pptype.', '.$pptype.']' : $pptype).', ';
|
$json_params .= '"' . $param['name'] . '": ' . (isset($param['subtype']) ? '[' . $ppptype . ']' : $ppptype) . ', ';
|
||||||
$json_params .= '"'.$param['name'].'": '.(isset($param['subtype']) ? '['.$ppptype.']' : $ppptype).', ';
|
$pwr_params .= $param['name'] . ' - Json encoded ' . (isset($param['subtype']) ? ' array of ' . $ptype : $ptype) . "\n\n";
|
||||||
$pwr_params .= $param['name'].' - Json encoded '.(isset($param['subtype']) ? ' array of '.$ptype : $ptype)."\n\n";
|
$lua_params .= $param['name'] . '=';
|
||||||
$lua_params .= $param['name'].'=';
|
$lua_params .= (isset($param['subtype']) ? '{' . $pptype . '}' : $pptype) . ', ';
|
||||||
$lua_params .= (isset($param['subtype']) ? '{'.$pptype.'}' : $pptype).', ';
|
|
||||||
if ($param['name'] === 'reply_markup') {
|
if ($param['name'] === 'reply_markup') {
|
||||||
$hasreplymarkup = true;
|
$hasreplymarkup = true;
|
||||||
}
|
}
|
||||||
@ -205,42 +200,42 @@ trait Methods
|
|||||||
$pwr_params = "parseMode - string\n";
|
$pwr_params = "parseMode - string\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$description = isset($this->td_descriptions['methods'][$data['method']]) ? $this->td_descriptions['methods'][$data['method']]['description'] : $data['method'].' parameters, return type and example';
|
$description = isset($this->td_descriptions['methods'][$data['method']]) ? $this->td_descriptions['methods'][$data['method']]['description'] : $data['method'] . ' parameters, return type and example';
|
||||||
$symFile = \str_replace('.', '_', $method);
|
$symFile = \str_replace('.', '_', $method);
|
||||||
$redir = $symFile !== $method ? "\nredirect_from: /API_docs/methods/$symFile.html" : '';
|
$redir = $symFile !== $method ? "\nredirect_from: /API_docs/methods/{$symFile}.html" : '';
|
||||||
$header = '---
|
$header = '---
|
||||||
title: '.$data['method'].'
|
title: ' . $data['method'] . '
|
||||||
description: '.$description.'
|
description: ' . $description . '
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png'.$redir.'
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png' . $redir . '
|
||||||
---
|
---
|
||||||
# Method: '.\str_replace('_', '\\_', $data['method']).'
|
# Method: ' . \str_replace('_', '\\_', $data['method']) . '
|
||||||
[Back to methods index](index.md)
|
[Back to methods index](index.md)
|
||||||
|
|
||||||
|
|
||||||
';
|
';
|
||||||
/*
|
/*
|
||||||
if (isset(\danog\MadelineProto\MTProto::DISALLOWED_METHODS[$data['method']])) {
|
if (isset(\danog\MadelineProto\MTProto::DISALLOWED_METHODS[$data['method']])) {
|
||||||
$header .= '**'.\danog\MadelineProto\MTProto::DISALLOWED_METHODS[$data['method']]."**\n\n\n\n\n";
|
$header .= '**'.\danog\MadelineProto\MTProto::DISALLOWED_METHODS[$data['method']]."**\n\n\n\n\n";
|
||||||
file_put_contents('methods/'.$method.'.md', $header);
|
file_put_contents('methods/'.$method.'.md', $header);
|
||||||
continue;
|
continue;
|
||||||
}*/
|
}*/
|
||||||
if ($this->td) {
|
if ($this->td) {
|
||||||
$header .= 'YOU CANNOT USE THIS METHOD IN MADELINEPROTO
|
$header .= 'YOU CANNOT USE THIS METHOD IN MADELINEPROTO
|
||||||
|
|
||||||
|
|
||||||
';
|
';
|
||||||
}
|
}
|
||||||
$header .= isset($this->td_descriptions['methods'][$data['method']]) ? $this->td_descriptions['methods'][$data['method']]['description'].PHP_EOL.PHP_EOL : '';
|
$header .= isset($this->td_descriptions['methods'][$data['method']]) ? $this->td_descriptions['methods'][$data['method']]['description'] . PHP_EOL . PHP_EOL : '';
|
||||||
$table .= '
|
$table .= '
|
||||||
|
|
||||||
';
|
';
|
||||||
$return = '### Return type: ['.\str_replace('_', '\\_', $type).'](../types/'.$php_type.'.md)
|
$return = '### Return type: [' . \str_replace('_', '\\_', $type) . '](../types/' . $php_type . '.md)
|
||||||
|
|
||||||
';
|
';
|
||||||
$bot = !\in_array($data['method'], $bots);
|
$bot = !\in_array($data['method'], $bots);
|
||||||
$example = '';
|
$example = '';
|
||||||
if (!isset($this->settings['td'])) {
|
if (!isset($this->settings['td'])) {
|
||||||
$example .= '### Can bots use this method: **'.($bot ? 'YES' : 'NO')."**\n\n\n";
|
$example .= '### Can bots use this method: **' . ($bot ? 'YES' : 'NO') . "**\n\n\n";
|
||||||
$example .= \str_replace('[]', '', '### MadelineProto Example ([now async for huge speed and parallelism!](https://docs.madelineproto.xyz/docs/ASYNC.html)):
|
$example .= \str_replace('[]', '', '### MadelineProto Example ([now async for huge speed and parallelism!](https://docs.madelineproto.xyz/docs/ASYNC.html)):
|
||||||
|
|
||||||
|
|
||||||
@ -250,16 +245,16 @@ if (!file_exists(\'madeline.php\')) {
|
|||||||
}
|
}
|
||||||
include \'madeline.php\';
|
include \'madeline.php\';
|
||||||
|
|
||||||
$MadelineProto = new \danog\MadelineProto\API(\'session.madeline\');
|
$MadelineProto = new \\danog\\MadelineProto\\API(\'session.madeline\');
|
||||||
$MadelineProto->start();
|
$MadelineProto->start();
|
||||||
|
|
||||||
$'.$type.' = $MadelineProto->'.$php_method.'(['.$params.']);
|
$' . $type . ' = $MadelineProto->' . $php_method . '([' . $params . ']);
|
||||||
```
|
```
|
||||||
|
|
||||||
Or, if you\'re into Lua:
|
Or, if you\'re into Lua:
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
'.$type.' = '.$data['method'].'({'.$lua_params.'})
|
' . $type . ' = ' . $data['method'] . '({' . $lua_params . '})
|
||||||
```
|
```
|
||||||
|
|
||||||
');
|
');
|
||||||
@ -276,7 +271,7 @@ You can provide bot API reply_markup objects here.
|
|||||||
$example .= '
|
$example .= '
|
||||||
## Return value
|
## Return value
|
||||||
|
|
||||||
If the length of the provided message is bigger than 4096, the message will be split in chunks and the method will be called multiple times, with the same parameters (except for the message), and an array of ['.\str_replace('_', '\\_', $type).'](../types/'.$php_type.'.md) will be returned instead.
|
If the length of the provided message is bigger than 4096, the message will be split in chunks and the method will be called multiple times, with the same parameters (except for the message), and an array of [' . \str_replace('_', '\\_', $type) . '](../types/' . $php_type . '.md) will be returned instead.
|
||||||
|
|
||||||
|
|
||||||
';
|
';
|
||||||
@ -328,12 +323,12 @@ MadelineProto supports all html entities supported by [html_entity_decode](http:
|
|||||||
';
|
';
|
||||||
foreach ($new['result'][$data['method']] as $error) {
|
foreach ($new['result'][$data['method']] as $error) {
|
||||||
[$error, $code] = $error;
|
[$error, $code] = $error;
|
||||||
$example .= "|$code|$error|".$errors['human_result'][$error][0].'|'."\n";
|
$example .= "|{$code}|{$error}|" . $errors['human_result'][$error][0] . '|' . "\n";
|
||||||
}
|
}
|
||||||
$example .= "\n\n";
|
$example .= "\n\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
\file_put_contents('methods/'.$method.'.md', $header.$table.$return.$example);
|
\file_put_contents('methods/' . $method . '.md', $header . $table . $return . $example);
|
||||||
}
|
}
|
||||||
$this->logger->logger('Generating methods index...', \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('Generating methods index...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
\ksort($this->docs_methods);
|
\ksort($this->docs_methods);
|
||||||
@ -344,10 +339,10 @@ MadelineProto supports all html entities supported by [html_entity_decode](http:
|
|||||||
$br = $new_namespace != $last_namespace ? '***
|
$br = $new_namespace != $last_namespace ? '***
|
||||||
<br><br>
|
<br><br>
|
||||||
' : '';
|
' : '';
|
||||||
$value = $br.$value;
|
$value = $br . $value;
|
||||||
$last_namespace = $new_namespace;
|
$last_namespace = $new_namespace;
|
||||||
}
|
}
|
||||||
\file_put_contents('methods/api_'.$this->index, '---
|
\file_put_contents('methods/api_' . $this->index, '---
|
||||||
title: Methods
|
title: Methods
|
||||||
description: List of methods
|
description: List of methods
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -355,7 +350,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
# Methods
|
# Methods
|
||||||
[Back to API documentation index](..)
|
[Back to API documentation index](..)
|
||||||
|
|
||||||
[Go to the new description-version method index]('.$this->index.')
|
[Go to the new description-version method index](' . $this->index . ')
|
||||||
|
|
||||||
$MadelineProto->[logout](https://docs.madelineproto.xyz/logout.html)();
|
$MadelineProto->[logout](https://docs.madelineproto.xyz/logout.html)();
|
||||||
|
|
||||||
@ -383,9 +378,8 @@ $MadelineProto->[requestCall](https://docs.madelineproto.xyz/requestCall.html)($
|
|||||||
|
|
||||||
$MadelineProto->[requestSecretChat](https://docs.madelineproto.xyz/requestSecretChat.html)($id);
|
$MadelineProto->[requestSecretChat](https://docs.madelineproto.xyz/requestSecretChat.html)($id);
|
||||||
|
|
||||||
'.\implode('', $this->docs_methods));
|
' . \implode('', $this->docs_methods));
|
||||||
|
\file_put_contents('methods/' . $this->index, '---
|
||||||
\file_put_contents('methods/'.$this->index, '---
|
|
||||||
title: Methods
|
title: Methods
|
||||||
description: What do you want to do?
|
description: What do you want to do?
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -393,7 +387,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
# What do you want to do?
|
# What do you want to do?
|
||||||
[Go back to API documentation index](..)
|
[Go back to API documentation index](..)
|
||||||
|
|
||||||
[Go to the old code-version method index](api_'.$this->index.')
|
[Go to the old code-version method index](api_' . $this->index . ')
|
||||||
|
|
||||||
* [Logout](https://docs.madelineproto.xyz/logout.html)
|
* [Logout](https://docs.madelineproto.xyz/logout.html)
|
||||||
|
|
||||||
@ -417,6 +411,6 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
|
|
||||||
* [Create a secret chat bot](https://docs.madelineproto.xyz/docs/SECRET_CHATS.html)
|
* [Create a secret chat bot](https://docs.madelineproto.xyz/docs/SECRET_CHATS.html)
|
||||||
|
|
||||||
'.\implode('', $this->human_docs_methods));
|
' . \implode('', $this->human_docs_methods));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,8 +35,8 @@ class EventHandler extends InternalDoc
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->API = $MadelineProto->API;
|
$this->API = $MadelineProto->API;
|
||||||
$this->async = &$MadelineProto->async;
|
$this->async =& $MadelineProto->async;
|
||||||
$this->methods = &$MadelineProto->methods;
|
$this->methods =& $MadelineProto->methods;
|
||||||
foreach ($this->API->getMethodNamespaces() as $namespace) {
|
foreach ($this->API->getMethodNamespaces() as $namespace) {
|
||||||
$this->{$namespace} = new APIFactory($namespace, $this->API, $this->async);
|
$this->{$namespace} = new APIFactory($namespace, $this->API, $this->async);
|
||||||
}
|
}
|
||||||
|
@ -23,12 +23,10 @@ class Exception extends \Exception
|
|||||||
{
|
{
|
||||||
use TL\PrettyException;
|
use TL\PrettyException;
|
||||||
public static $rollbar = true;
|
public static $rollbar = true;
|
||||||
|
|
||||||
public function __toString()
|
public function __toString()
|
||||||
{
|
{
|
||||||
return $this->file === 'MadelineProto' ? $this->message : '\\danog\\MadelineProto\\Exception'.($this->message !== '' ? ': ' : '').$this->message.' in '.$this->file.':'.$this->line.PHP_EOL.\danog\MadelineProto\Magic::$revision.PHP_EOL.'TL Trace:'.PHP_EOL.$this->getTLTrace();
|
return $this->file === 'MadelineProto' ? $this->message : '\\danog\\MadelineProto\\Exception' . ($this->message !== '' ? ': ' : '') . $this->message . ' in ' . $this->file . ':' . $this->line . PHP_EOL . \danog\MadelineProto\Magic::$revision . PHP_EOL . 'TL Trace:' . PHP_EOL . $this->getTLTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __construct($message = null, $code = 0, self $previous = null, $file = null, $line = null)
|
public function __construct($message = null, $code = 0, self $previous = null, $file = null, $line = null)
|
||||||
{
|
{
|
||||||
$this->prettifyTL();
|
$this->prettifyTL();
|
||||||
@ -40,9 +38,8 @@ class Exception extends \Exception
|
|||||||
}
|
}
|
||||||
parent::__construct($message, $code, $previous);
|
parent::__construct($message, $code, $previous);
|
||||||
if (\strpos($message, 'socket_accept') === false) {
|
if (\strpos($message, 'socket_accept') === false) {
|
||||||
\danog\MadelineProto\Logger::log($message.' in '.\basename($this->file).':'.$this->line, \danog\MadelineProto\Logger::FATAL_ERROR);
|
\danog\MadelineProto\Logger::log($message . ' in ' . \basename($this->file) . ':' . $this->line, \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (\in_array($message, ['The session is corrupted!', 'Re-executing query...', 'I had to recreate the temporary authorization key', 'This peer is not present in the internal peer database', "Couldn't get response", 'Chat forbidden', 'The php-libtgvoip extension is required to accept and manage calls. See daniil.it/MadelineProto for more info.', 'File does not exist', 'Please install this fork of phpseclib: https://github.com/danog/phpseclib'])) {
|
if (\in_array($message, ['The session is corrupted!', 'Re-executing query...', 'I had to recreate the temporary authorization key', 'This peer is not present in the internal peer database', "Couldn't get response", 'Chat forbidden', 'The php-libtgvoip extension is required to accept and manage calls. See daniil.it/MadelineProto for more info.', 'File does not exist', 'Please install this fork of phpseclib: https://github.com/danog/phpseclib'])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -53,18 +50,17 @@ class Exception extends \Exception
|
|||||||
\Rollbar\Rollbar::log(\Rollbar\Payload\Level::error(), $this, \debug_backtrace(0));
|
\Rollbar\Rollbar::log(\Rollbar\Payload\Level::error(), $this, \debug_backtrace(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function extension(string $extensionName)
|
public static function extension(string $extensionName)
|
||||||
{
|
{
|
||||||
$additional = 'Try running sudo apt-get install php'.PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION.'-'.$extensionName.'.';
|
$additional = 'Try running sudo apt-get install php' . PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '-' . $extensionName . '.';
|
||||||
if ($extensionName === 'libtgvoip') {
|
if ($extensionName === 'libtgvoip') {
|
||||||
$additional = 'Follow the instructions @ https://voip.madelineproto.xyz to install it.';
|
$additional = 'Follow the instructions @ https://voip.madelineproto.xyz to install it.';
|
||||||
} elseif ($extensionName === 'prime') {
|
} elseif ($extensionName === 'prime') {
|
||||||
$additional = 'Follow the instructions @ https://prime.madelineproto.xyz to install it.';
|
$additional = 'Follow the instructions @ https://prime.madelineproto.xyz to install it.';
|
||||||
}
|
}
|
||||||
$message = 'MadelineProto requires the '.$extensionName.' extension to run. '.$additional;
|
$message = 'MadelineProto requires the ' . $extensionName . ' extension to run. ' . $additional;
|
||||||
if (PHP_SAPI !== 'cli') {
|
if (PHP_SAPI !== 'cli') {
|
||||||
echo $message.'<br>';
|
echo $message . '<br>';
|
||||||
}
|
}
|
||||||
$file = 'MadelineProto';
|
$file = 'MadelineProto';
|
||||||
$line = 1;
|
$line = 1;
|
||||||
@ -78,17 +74,11 @@ class Exception extends \Exception
|
|||||||
public static function exceptionErrorHandler($errno = 0, $errstr = null, $errfile = null, $errline = null)
|
public static function exceptionErrorHandler($errno = 0, $errstr = null, $errfile = null, $errline = null)
|
||||||
{
|
{
|
||||||
// If error is suppressed with @, don't throw an exception
|
// If error is suppressed with @, don't throw an exception
|
||||||
if (\error_reporting() === 0
|
if (\error_reporting() === 0 || \strpos($errstr, 'headers already sent') || $errfile && (\strpos($errfile, 'vendor/amphp') !== false || \strpos($errfile, 'vendor/league') !== false)) {
|
||||||
|| \strpos($errstr, 'headers already sent')
|
|
||||||
|| ($errfile
|
|
||||||
&& (\strpos($errfile, 'vendor/amphp') !== false || \strpos($errfile, 'vendor/league') !== false))
|
|
||||||
) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new self($errstr, $errno, null, $errfile, $errline);
|
throw new self($errstr, $errno, null, $errfile, $errline);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ExceptionErrorHandler.
|
* ExceptionErrorHandler.
|
||||||
*
|
*
|
||||||
|
@ -36,7 +36,6 @@ class FileCallback implements FileCallbackInterface
|
|||||||
* @var callable
|
* @var callable
|
||||||
*/
|
*/
|
||||||
private $callback;
|
private $callback;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct file callback.
|
* Construct file callback.
|
||||||
*
|
*
|
||||||
@ -48,7 +47,6 @@ class FileCallback implements FileCallbackInterface
|
|||||||
$this->file = $file;
|
$this->file = $file;
|
||||||
$this->callback = $callback;
|
$this->callback = $callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get file.
|
* Get file.
|
||||||
*
|
*
|
||||||
@ -58,7 +56,6 @@ class FileCallback implements FileCallbackInterface
|
|||||||
{
|
{
|
||||||
return $this->file;
|
return $this->file;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoke callback.
|
* Invoke callback.
|
||||||
*
|
*
|
||||||
@ -71,7 +68,6 @@ class FileCallback implements FileCallbackInterface
|
|||||||
public function __invoke($percent, $speed, $time)
|
public function __invoke($percent, $speed, $time)
|
||||||
{
|
{
|
||||||
$callback = $this->callback;
|
$callback = $this->callback;
|
||||||
|
|
||||||
return $callback($percent, $speed, $time);
|
return $callback($percent, $speed, $time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@ interface FileCallbackInterface
|
|||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function getFile();
|
public function getFile();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoke callback.
|
* Invoke callback.
|
||||||
*
|
*
|
||||||
|
@ -5128,7 +5128,7 @@ class InternalDoc extends APIFactory
|
|||||||
* @param string $file File to lock
|
* @param string $file File to lock
|
||||||
* @param integer $operation Locking mode
|
* @param integer $operation Locking mode
|
||||||
* @param float $polling Polling interval
|
* @param float $polling Polling interval
|
||||||
*
|
*
|
||||||
* @return Promise
|
* @return Promise
|
||||||
*/
|
*/
|
||||||
public function flock(string $file, int $operation, float $polling = 0.1)
|
public function flock(string $file, int $operation, float $polling = 0.1)
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
* @author Daniil Gentili <daniil@daniil.it>
|
* @author Daniil Gentili <daniil@daniil.it>
|
||||||
* @copyright 2016-2019 Daniil Gentili <daniil@daniil.it>
|
* @copyright 2016-2019 Daniil Gentili <daniil@daniil.it>
|
||||||
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
|
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
|
||||||
* @link https://docs.madelineproto.xyz MadelineProto documentation
|
* @link https://docs.madelineproto.xyz MadelineProto documentation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace danog\MadelineProto;
|
namespace danog\MadelineProto;
|
||||||
|
@ -30,12 +30,10 @@ use function Amp\ByteStream\getStdout;
|
|||||||
class Logger
|
class Logger
|
||||||
{
|
{
|
||||||
use Tools;
|
use Tools;
|
||||||
|
|
||||||
const FOREGROUND = ['default' => 39, 'black' => 30, 'red' => 31, 'green' => 32, 'yellow' => 33, 'blue' => 34, 'magenta' => 35, 'cyan' => 36, 'light_gray' => 37, 'dark_gray' => 90, 'light_red' => 91, 'light_green' => 92, 'light_yellow' => 93, 'light_blue' => 94, 'light_magenta' => 95, 'light_cyan' => 96, 'white' => 97];
|
const FOREGROUND = ['default' => 39, 'black' => 30, 'red' => 31, 'green' => 32, 'yellow' => 33, 'blue' => 34, 'magenta' => 35, 'cyan' => 36, 'light_gray' => 37, 'dark_gray' => 90, 'light_red' => 91, 'light_green' => 92, 'light_yellow' => 93, 'light_blue' => 94, 'light_magenta' => 95, 'light_cyan' => 96, 'white' => 97];
|
||||||
const BACKGROUND = ['default' => 49, 'black' => 40, 'red' => 41, 'magenta' => 45, 'yellow' => 43, 'green' => 42, 'blue' => 44, 'cyan' => 46, 'light_gray' => 47, 'dark_gray' => 100, 'light_red' => 101, 'light_green' => 102, 'light_yellow' => 103, 'light_blue' => 104, 'light_magenta' => 105, 'light_cyan' => 106, 'white' => 107];
|
const BACKGROUND = ['default' => 49, 'black' => 40, 'red' => 41, 'magenta' => 45, 'yellow' => 43, 'green' => 42, 'blue' => 44, 'cyan' => 46, 'light_gray' => 47, 'dark_gray' => 100, 'light_red' => 101, 'light_green' => 102, 'light_yellow' => 103, 'light_blue' => 104, 'light_magenta' => 105, 'light_cyan' => 106, 'white' => 107];
|
||||||
const SET = ['bold' => 1, 'dim' => 2, 'underlined' => 3, 'blink' => 4, 'reverse' => 5, 'hidden' => 6];
|
const SET = ['bold' => 1, 'dim' => 2, 'underlined' => 3, 'blink' => 4, 'reverse' => 5, 'hidden' => 6];
|
||||||
const RESET = ['all' => 0, 'bold' => 21, 'dim' => 22, 'underlined' => 24, 'blink' => 25, 'reverse' => 26, 'hidden' => 28];
|
const RESET = ['all' => 0, 'bold' => 21, 'dim' => 22, 'underlined' => 24, 'blink' => 25, 'reverse' => 26, 'hidden' => 28];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logging mode.
|
* Logging mode.
|
||||||
*
|
*
|
||||||
@ -72,7 +70,6 @@ class Logger
|
|||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
public $newline = "\n";
|
public $newline = "\n";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default logger instance.
|
* Default logger instance.
|
||||||
*
|
*
|
||||||
@ -85,20 +82,17 @@ class Logger
|
|||||||
* @var boolean
|
* @var boolean
|
||||||
*/
|
*/
|
||||||
public static $printed = false;
|
public static $printed = false;
|
||||||
|
|
||||||
const ULTRA_VERBOSE = 5;
|
const ULTRA_VERBOSE = 5;
|
||||||
const VERBOSE = 4;
|
const VERBOSE = 4;
|
||||||
const NOTICE = 3;
|
const NOTICE = 3;
|
||||||
const WARNING = 2;
|
const WARNING = 2;
|
||||||
const ERROR = 1;
|
const ERROR = 1;
|
||||||
const FATAL_ERROR = 0;
|
const FATAL_ERROR = 0;
|
||||||
|
|
||||||
const NO_LOGGER = 0;
|
const NO_LOGGER = 0;
|
||||||
const DEFAULT_LOGGER = 1;
|
const DEFAULT_LOGGER = 1;
|
||||||
const FILE_LOGGER = 2;
|
const FILE_LOGGER = 2;
|
||||||
const ECHO_LOGGER = 3;
|
const ECHO_LOGGER = 3;
|
||||||
const CALLABLE_LOGGER = 4;
|
const CALLABLE_LOGGER = 4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct global static logger from MadelineProto settings.
|
* Construct global static logger from MadelineProto settings.
|
||||||
*
|
*
|
||||||
@ -133,28 +127,24 @@ class Logger
|
|||||||
$settings['logger']['logger_param'] = $settings['logger']['param'];
|
$settings['logger']['logger_param'] = $settings['logger']['param'];
|
||||||
}
|
}
|
||||||
if (PHP_SAPI !== 'cli' && isset($settings['logger']['logger_param']) && $settings['logger']['logger_param'] === 'MadelineProto.log') {
|
if (PHP_SAPI !== 'cli' && isset($settings['logger']['logger_param']) && $settings['logger']['logger_param'] === 'MadelineProto.log') {
|
||||||
$settings['logger']['logger_param'] = Magic::$script_cwd.'/MadelineProto.log';
|
$settings['logger']['logger_param'] = Magic::$script_cwd . '/MadelineProto.log';
|
||||||
}
|
}
|
||||||
|
|
||||||
$logger = new self($settings['logger']['logger'], $settings['logger']['logger_param'] ?? '', $prefix, $settings['logger']['logger_level'] ?? Logger::VERBOSE, $settings['logger']['max_size'] ?? 100 * 1024 * 1024);
|
$logger = new self($settings['logger']['logger'], $settings['logger']['logger_param'] ?? '', $prefix, $settings['logger']['logger_level'] ?? Logger::VERBOSE, $settings['logger']['max_size'] ?? 100 * 1024 * 1024);
|
||||||
if (!self::$default) {
|
if (!self::$default) {
|
||||||
self::$default = $logger;
|
self::$default = $logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PHP_SAPI !== 'cli') {
|
if (PHP_SAPI !== 'cli') {
|
||||||
try {
|
try {
|
||||||
\error_reporting(E_ALL);
|
\error_reporting(E_ALL);
|
||||||
\ini_set('log_errors', 1);
|
\ini_set('log_errors', 1);
|
||||||
\ini_set('error_log', $settings['logger']['logger'] === self::FILE_LOGGER ? $settings['logger']['logger_param'] : Magic::$script_cwd.'/MadelineProto.log');
|
\ini_set('error_log', $settings['logger']['logger'] === self::FILE_LOGGER ? $settings['logger']['logger_param'] : Magic::$script_cwd . '/MadelineProto.log');
|
||||||
\error_log('Enabled PHP logging');
|
\error_log('Enabled PHP logging');
|
||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
$logger->logger('Could not enable PHP logging');
|
$logger->logger('Could not enable PHP logging');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $logger;
|
return $logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct global logger.
|
* Construct global logger.
|
||||||
*
|
*
|
||||||
@ -170,7 +160,6 @@ class Logger
|
|||||||
{
|
{
|
||||||
self::$default = new self($mode, $optional, $prefix, $level, $max_size);
|
self::$default = new self($mode, $optional, $prefix, $level, $max_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct global logger.
|
* Construct global logger.
|
||||||
*
|
*
|
||||||
@ -189,21 +178,17 @@ class Logger
|
|||||||
}
|
}
|
||||||
$this->mode = $mode;
|
$this->mode = $mode;
|
||||||
$this->optional = $mode == 2 ? Absolute::absolute($optional) : $optional;
|
$this->optional = $mode == 2 ? Absolute::absolute($optional) : $optional;
|
||||||
$this->prefix = $prefix === '' ? '' : ', '.$prefix;
|
$this->prefix = $prefix === '' ? '' : ', ' . $prefix;
|
||||||
$this->level = $level;
|
$this->level = $level;
|
||||||
|
|
||||||
if ($this->mode === 2 && !\file_exists(\pathinfo($this->optional, PATHINFO_DIRNAME))) {
|
if ($this->mode === 2 && !\file_exists(\pathinfo($this->optional, PATHINFO_DIRNAME))) {
|
||||||
$this->optional = Magic::$script_cwd.'/MadelineProto.log';
|
$this->optional = Magic::$script_cwd . '/MadelineProto.log';
|
||||||
}
|
}
|
||||||
|
if ($this->mode === 2 && !\preg_match('/\\.log$/', $this->optional)) {
|
||||||
if ($this->mode === 2 && !\preg_match('/\.log$/', $this->optional)) {
|
|
||||||
$this->optional .= '.log';
|
$this->optional .= '.log';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($mode === 2 && $max_size !== -1 && \file_exists($this->optional) && \filesize($this->optional) > $max_size) {
|
if ($mode === 2 && $max_size !== -1 && \file_exists($this->optional) && \filesize($this->optional) > $max_size) {
|
||||||
\unlink($this->optional);
|
\unlink($this->optional);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->colors[self::ULTRA_VERBOSE] = \implode(';', [self::FOREGROUND['light_gray'], self::SET['dim']]);
|
$this->colors[self::ULTRA_VERBOSE] = \implode(';', [self::FOREGROUND['light_gray'], self::SET['dim']]);
|
||||||
$this->colors[self::VERBOSE] = \implode(';', [self::FOREGROUND['green'], self::SET['bold']]);
|
$this->colors[self::VERBOSE] = \implode(';', [self::FOREGROUND['green'], self::SET['bold']]);
|
||||||
$this->colors[self::NOTICE] = \implode(';', [self::FOREGROUND['yellow'], self::SET['bold']]);
|
$this->colors[self::NOTICE] = \implode(';', [self::FOREGROUND['yellow'], self::SET['bold']]);
|
||||||
@ -211,11 +196,10 @@ class Logger
|
|||||||
$this->colors[self::ERROR] = \implode(';', [self::FOREGROUND['white'], self::SET['bold'], self::BACKGROUND['red']]);
|
$this->colors[self::ERROR] = \implode(';', [self::FOREGROUND['white'], self::SET['bold'], self::BACKGROUND['red']]);
|
||||||
$this->colors[self::FATAL_ERROR] = \implode(';', [self::FOREGROUND['red'], self::SET['bold'], self::BACKGROUND['light_gray']]);
|
$this->colors[self::FATAL_ERROR] = \implode(';', [self::FOREGROUND['red'], self::SET['bold'], self::BACKGROUND['light_gray']]);
|
||||||
$this->newline = PHP_EOL;
|
$this->newline = PHP_EOL;
|
||||||
|
|
||||||
if ($this->mode === 3) {
|
if ($this->mode === 3) {
|
||||||
$this->stdout = getStdout();
|
$this->stdout = getStdout();
|
||||||
if (PHP_SAPI !== 'cli') {
|
if (PHP_SAPI !== 'cli') {
|
||||||
$this->newline = '<br>'.$this->newline;
|
$this->newline = '<br>' . $this->newline;
|
||||||
}
|
}
|
||||||
} elseif ($this->mode === 2) {
|
} elseif ($this->mode === 2) {
|
||||||
$this->stdout = new ResourceOutputStream(\fopen($this->optional, 'a+'));
|
$this->stdout = new ResourceOutputStream(\fopen($this->optional, 'a+'));
|
||||||
@ -230,7 +214,6 @@ class Logger
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log a message.
|
* Log a message.
|
||||||
*
|
*
|
||||||
@ -244,10 +227,9 @@ class Logger
|
|||||||
if (!\is_null(self::$default)) {
|
if (!\is_null(self::$default)) {
|
||||||
self::$default->logger($param, $level, \basename(\debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php'));
|
self::$default->logger($param, $level, \basename(\debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php'));
|
||||||
} else {
|
} else {
|
||||||
echo $param.PHP_EOL;
|
echo $param . PHP_EOL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log a message.
|
* Log a message.
|
||||||
*
|
*
|
||||||
@ -265,12 +247,10 @@ class Logger
|
|||||||
if (!self::$printed) {
|
if (!self::$printed) {
|
||||||
self::$printed = true;
|
self::$printed = true;
|
||||||
$this->colors[self::NOTICE] = \implode(';', [self::FOREGROUND['light_gray'], self::SET['bold'], self::BACKGROUND['blue']]);
|
$this->colors[self::NOTICE] = \implode(';', [self::FOREGROUND['light_gray'], self::SET['bold'], self::BACKGROUND['blue']]);
|
||||||
|
|
||||||
$this->logger('MadelineProto');
|
$this->logger('MadelineProto');
|
||||||
$this->logger('Copyright (C) 2016-2019 Daniil Gentili');
|
$this->logger('Copyright (C) 2016-2019 Daniil Gentili');
|
||||||
$this->logger('Licensed under AGPLv3');
|
$this->logger('Licensed under AGPLv3');
|
||||||
$this->logger('https://github.com/danog/MadelineProto');
|
$this->logger('https://github.com/danog/MadelineProto');
|
||||||
|
|
||||||
$this->colors[self::NOTICE] = \implode(';', [self::FOREGROUND['yellow'], self::SET['bold']]);
|
$this->colors[self::NOTICE] = \implode(';', [self::FOREGROUND['yellow'], self::SET['bold']]);
|
||||||
}
|
}
|
||||||
if ($this->mode === 4) {
|
if ($this->mode === 4) {
|
||||||
@ -289,22 +269,26 @@ class Logger
|
|||||||
if (empty($file)) {
|
if (empty($file)) {
|
||||||
$file = \basename(\debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php');
|
$file = \basename(\debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php');
|
||||||
}
|
}
|
||||||
$param = \str_pad($file.$prefix.': ', 16 + \strlen($prefix))."\t".$param;
|
$param = \str_pad($file . $prefix . ': ', 16 + \strlen($prefix)) . "\t" . $param;
|
||||||
switch ($this->mode) {
|
switch ($this->mode) {
|
||||||
case 1:
|
case 1:
|
||||||
if ($this->stdout->write($param.$this->newline) instanceof Failure) {
|
if ($this->stdout->write($param . $this->newline) instanceof Failure) {
|
||||||
\error_log($param);
|
\error_log($param);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$param = Magic::$isatty ? "\33[" . $this->colors[$level] . 'm' . $param . "\33[0m" . $this->newline : $param . $this->newline;
|
||||||
|
if ($this->stdout->write($param) instanceof Failure) {
|
||||||
|
switch ($this->mode) {
|
||||||
|
case 3:
|
||||||
|
echo $param;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
\file_put_contents($this->optional, $param, FILE_APPEND);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
default:
|
break;
|
||||||
$param = Magic::$isatty ? "\33[".$this->colors[$level].'m'.$param."\33[0m".$this->newline : $param.$this->newline;
|
}
|
||||||
if ($this->stdout->write($param) instanceof Failure) {
|
|
||||||
switch ($this->mode) {
|
|
||||||
case 3: echo $param; break;
|
|
||||||
case 2: \file_put_contents($this->optional, $param, FILE_APPEND); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RPC call status check loop.
|
* RPC call status check loop.
|
||||||
*
|
*
|
||||||
@ -43,7 +44,6 @@ class CheckLoop extends ResumableSignalLoop
|
|||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $datacenter;
|
protected $datacenter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DataCenterConnection instance.
|
* DataCenterConnection instance.
|
||||||
*
|
*
|
||||||
@ -57,106 +57,98 @@ class CheckLoop extends ResumableSignalLoop
|
|||||||
$this->datacenter = $connection->getDatacenterID();
|
$this->datacenter = $connection->getDatacenterID();
|
||||||
$this->datacenterConnection = $connection->getShared();
|
$this->datacenterConnection = $connection->getShared();
|
||||||
}
|
}
|
||||||
|
public function loop(): \Generator
|
||||||
public function loop()
|
|
||||||
{
|
{
|
||||||
$API = $this->API;
|
$API = $this->API;
|
||||||
$datacenter = $this->datacenter;
|
$datacenter = $this->datacenter;
|
||||||
$connection = $this->connection;
|
$connection = $this->connection;
|
||||||
$shared = $this->datacenterConnection;
|
$shared = $this->datacenterConnection;
|
||||||
|
|
||||||
$timeout = $shared->getSettings()['timeout'];
|
$timeout = $shared->getSettings()['timeout'];
|
||||||
$timeoutResend = $timeout * $timeout; // Typically 25 seconds, good enough
|
$timeoutResend = $timeout * $timeout;
|
||||||
|
// Typically 25 seconds, good enough
|
||||||
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())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($connection->hasPendingCalls()) {
|
if ($connection->hasPendingCalls()) {
|
||||||
$last_msgid = $connection->getMaxId(true);
|
$last_msgid = $connection->getMaxId(true);
|
||||||
$last_chunk = $connection->getLastChunk();
|
$last_chunk = $connection->getLastChunk();
|
||||||
|
|
||||||
if ($shared->hasTempAuthKey()) {
|
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();
|
||||||
$deferred->promise()->onResolve(
|
$deferred->promise()->onResolve(function ($e, $result) use ($message_ids, $API, $connection, $datacenter, $timeoutResend) {
|
||||||
function ($e, $result) use ($message_ids, $API, $connection, $datacenter, $timeoutResend) {
|
if ($e) {
|
||||||
if ($e) {
|
$API->logger("Got exception in check loop for DC {$datacenter}");
|
||||||
$API->logger("Got exception in check loop for DC $datacenter");
|
$API->logger((string) $e);
|
||||||
$API->logger((string) $e);
|
return;
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$reply = [];
|
|
||||||
foreach (\str_split($result['info']) as $key => $chr) {
|
|
||||||
$message_id = $message_ids[$key];
|
|
||||||
if (!isset($connection->outgoing_messages[$message_id])) {
|
|
||||||
$API->logger->logger('Already got response for and forgot about message ID '.($message_id));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!isset($connection->new_outgoing[$message_id])) {
|
|
||||||
$API->logger->logger('Already got response for '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.($message_id));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$chr = \ord($chr);
|
|
||||||
switch ($chr & 7) {
|
|
||||||
case 0:
|
|
||||||
$API->logger->logger('Wrong message status 0 for '.$connection->outgoing_messages[$message_id]['_'], \danog\MadelineProto\Logger::FATAL_ERROR);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
if ($connection->outgoing_messages[$message_id]['_'] === 'msgs_state_req') {
|
|
||||||
$connection->gotResponseForOutgoingMessageId($message_id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$API->logger->logger('Message '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.($message_id).' not received by server, resending...', \danog\MadelineProto\Logger::ERROR);
|
|
||||||
$connection->methodRecall('watcherId', ['message_id' => $message_id, 'postpone' => true]);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
if ($chr & 32) {
|
|
||||||
if ($connection->outgoing_messages[$message_id]['sent'] + $timeoutResend < \time()) {
|
|
||||||
$API->logger->logger('Message '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.($message_id).' received by server and is being processed for way too long, resending request...', \danog\MadelineProto\Logger::ERROR);
|
|
||||||
$connection->methodRecall('', ['message_id' => $message_id, 'postpone' => true]);
|
|
||||||
} else {
|
|
||||||
$API->logger->logger('Message '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.($message_id).' received by server and is being processed, waiting...', \danog\MadelineProto\Logger::ERROR);
|
|
||||||
}
|
|
||||||
} elseif ($chr & 64) {
|
|
||||||
$API->logger->logger('Message '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.($message_id).' received by server and was already processed, requesting reply...', \danog\MadelineProto\Logger::ERROR);
|
|
||||||
$reply[] = $message_id;
|
|
||||||
} elseif ($chr & 128) {
|
|
||||||
$API->logger->logger('Message '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.($message_id).' received by server and was already sent, requesting reply...', \danog\MadelineProto\Logger::ERROR);
|
|
||||||
$reply[] = $message_id;
|
|
||||||
} else {
|
|
||||||
$API->logger->logger('Message '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.($message_id).' received by server, requesting reply...', \danog\MadelineProto\Logger::ERROR);
|
|
||||||
$reply[] = $message_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($reply) {
|
|
||||||
\danog\MadelineProto\Tools::callFork($connection->objectCall('msg_resend_ans_req', ['msg_ids' => $reply], ['postpone' => true]));
|
|
||||||
}
|
|
||||||
$connection->flush();
|
|
||||||
}
|
}
|
||||||
);
|
$reply = [];
|
||||||
|
foreach (\str_split($result['info']) as $key => $chr) {
|
||||||
|
$message_id = $message_ids[$key];
|
||||||
|
if (!isset($connection->outgoing_messages[$message_id])) {
|
||||||
|
$API->logger->logger('Already got response for and forgot about message ID ' . $message_id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!isset($connection->new_outgoing[$message_id])) {
|
||||||
|
$API->logger->logger('Already got response for ' . $connection->outgoing_messages[$message_id]['_'] . ' with message ID ' . $message_id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$chr = \ord($chr);
|
||||||
|
switch ($chr & 7) {
|
||||||
|
case 0:
|
||||||
|
$API->logger->logger('Wrong message status 0 for ' . $connection->outgoing_messages[$message_id]['_'], \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
if ($connection->outgoing_messages[$message_id]['_'] === 'msgs_state_req') {
|
||||||
|
$connection->gotResponseForOutgoingMessageId($message_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$API->logger->logger('Message ' . $connection->outgoing_messages[$message_id]['_'] . ' with message ID ' . $message_id . ' not received by server, resending...', \danog\MadelineProto\Logger::ERROR);
|
||||||
|
$connection->methodRecall('watcherId', ['message_id' => $message_id, 'postpone' => true]);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
if ($chr & 32) {
|
||||||
|
if ($connection->outgoing_messages[$message_id]['sent'] + $timeoutResend < \time()) {
|
||||||
|
$API->logger->logger('Message ' . $connection->outgoing_messages[$message_id]['_'] . ' with message ID ' . $message_id . ' received by server and is being processed for way too long, resending request...', \danog\MadelineProto\Logger::ERROR);
|
||||||
|
$connection->methodRecall('', ['message_id' => $message_id, 'postpone' => true]);
|
||||||
|
} else {
|
||||||
|
$API->logger->logger('Message ' . $connection->outgoing_messages[$message_id]['_'] . ' with message ID ' . $message_id . ' received by server and is being processed, waiting...', \danog\MadelineProto\Logger::ERROR);
|
||||||
|
}
|
||||||
|
} elseif ($chr & 64) {
|
||||||
|
$API->logger->logger('Message ' . $connection->outgoing_messages[$message_id]['_'] . ' with message ID ' . $message_id . ' received by server and was already processed, requesting reply...', \danog\MadelineProto\Logger::ERROR);
|
||||||
|
$reply[] = $message_id;
|
||||||
|
} elseif ($chr & 128) {
|
||||||
|
$API->logger->logger('Message ' . $connection->outgoing_messages[$message_id]['_'] . ' with message ID ' . $message_id . ' received by server and was already sent, requesting reply...', \danog\MadelineProto\Logger::ERROR);
|
||||||
|
$reply[] = $message_id;
|
||||||
|
} else {
|
||||||
|
$API->logger->logger('Message ' . $connection->outgoing_messages[$message_id]['_'] . ' with message ID ' . $message_id . ' received by server, requesting reply...', \danog\MadelineProto\Logger::ERROR);
|
||||||
|
$reply[] = $message_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($reply) {
|
||||||
|
\danog\MadelineProto\Tools::callFork($connection->objectCall('msg_resend_ans_req', ['msg_ids' => $reply], ['postpone' => true]));
|
||||||
|
}
|
||||||
|
$connection->flush();
|
||||||
|
});
|
||||||
$list = '';
|
$list = '';
|
||||||
// Don't edit this here pls
|
// Don't edit this here pls
|
||||||
foreach ($message_ids as $message_id) {
|
foreach ($message_ids as $message_id) {
|
||||||
$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 $connection->objectCall('msgs_state_req', ['msg_ids' => $message_ids], ['promise' => $deferred]);
|
yield $connection->objectCall('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) {
|
||||||
if (isset($connection->outgoing_messages[$message_id]['sent'])
|
if (isset($connection->outgoing_messages[$message_id]['sent']) && $connection->outgoing_messages[$message_id]['sent'] + $timeout < \time() && $connection->outgoing_messages[$message_id]['unencrypted']) {
|
||||||
&& $connection->outgoing_messages[$message_id]['sent'] + $timeout < \time()
|
$API->logger->logger('Still missing ' . $connection->outgoing_messages[$message_id]['_'] . ' with message id ' . $message_id . " on DC {$datacenter}, resending", \danog\MadelineProto\Logger::ERROR);
|
||||||
&& $connection->outgoing_messages[$message_id]['unencrypted']
|
|
||||||
) {
|
|
||||||
$API->logger->logger('Still missing '.$connection->outgoing_messages[$message_id]['_'].' with message id '.($message_id)." on DC $datacenter, resending", \danog\MadelineProto\Logger::ERROR);
|
|
||||||
$connection->methodRecall('', ['message_id' => $message_id, 'postpone' => true]);
|
$connection->methodRecall('', ['message_id' => $message_id, 'postpone' => true]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -165,12 +157,10 @@ class CheckLoop extends ResumableSignalLoop
|
|||||||
if (yield $this->waitSignal($this->pause($timeout))) {
|
if (yield $this->waitSignal($this->pause($timeout))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($connection->getMaxId(true) === $last_msgid && $connection->getLastChunk() === $last_chunk) {
|
if ($connection->getMaxId(true) === $last_msgid && $connection->getLastChunk() === $last_chunk) {
|
||||||
$API->logger->logger("We did not receive a response for $timeout seconds: reconnecting and exiting check loop on DC $datacenter");
|
$API->logger->logger("We did not receive a response for {$timeout} seconds: reconnecting and exiting check loop on DC {$datacenter}");
|
||||||
//$this->exitedLoop();
|
//$this->exitedLoop();
|
||||||
Tools::callForkDefer($connection->reconnect());
|
Tools::callForkDefer($connection->reconnect());
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -180,7 +170,6 @@ class CheckLoop extends ResumableSignalLoop
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __toString(): string
|
public function __toString(): string
|
||||||
{
|
{
|
||||||
return "check loop in DC {$this->datacenter}";
|
return "check loop in DC {$this->datacenter}";
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HttpWait loop.
|
* HttpWait loop.
|
||||||
*
|
*
|
||||||
@ -40,14 +41,12 @@ class HttpWaitLoop extends ResumableSignalLoop
|
|||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $datacenter;
|
protected $datacenter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DataCenterConnection instance.
|
* DataCenterConnection instance.
|
||||||
*
|
*
|
||||||
* @var \danog\MadelineProto\DataCenterConnection
|
* @var \danog\MadelineProto\DataCenterConnection
|
||||||
*/
|
*/
|
||||||
protected $datacenterConnection;
|
protected $datacenterConnection;
|
||||||
|
|
||||||
public function __construct(Connection $connection)
|
public function __construct(Connection $connection)
|
||||||
{
|
{
|
||||||
$this->connection = $connection;
|
$this->connection = $connection;
|
||||||
@ -55,18 +54,15 @@ class HttpWaitLoop extends ResumableSignalLoop
|
|||||||
$this->datacenter = $connection->getDatacenterID();
|
$this->datacenter = $connection->getDatacenterID();
|
||||||
$this->datacenterConnection = $connection->getShared();
|
$this->datacenterConnection = $connection->getShared();
|
||||||
}
|
}
|
||||||
|
public function loop(): \Generator
|
||||||
public function loop()
|
|
||||||
{
|
{
|
||||||
$API = $this->API;
|
$API = $this->API;
|
||||||
$datacenter = $this->datacenter;
|
$datacenter = $this->datacenter;
|
||||||
$connection = $this->connection;
|
$connection = $this->connection;
|
||||||
$shared = $this->datacenterConnection;
|
$shared = $this->datacenterConnection;
|
||||||
|
|
||||||
if (!$shared->isHttp()) {
|
if (!$shared->isHttp()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (yield $this->waitSignal($this->pause())) {
|
if (yield $this->waitSignal($this->pause())) {
|
||||||
return;
|
return;
|
||||||
@ -79,14 +75,13 @@ class HttpWaitLoop extends ResumableSignalLoop
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$API->logger->logger("DC $datacenter: request {$connection->countHttpSent()}, response {$connection->countHttpReceived()}");
|
$API->logger->logger("DC {$datacenter}: request {$connection->countHttpSent()}, response {$connection->countHttpReceived()}");
|
||||||
if ($connection->countHttpSent() === $connection->countHttpReceived() && (!empty($connection->pending_outgoing) || (!empty($connection->new_outgoing) && !$connection->hasPendingCalls()))) {
|
if ($connection->countHttpSent() === $connection->countHttpReceived() && (!empty($connection->pending_outgoing) || !empty($connection->new_outgoing) && !$connection->hasPendingCalls())) {
|
||||||
yield $connection->sendMessage(['_' => 'http_wait', 'body' => ['max_wait' => 30000, 'wait_after' => 0, 'max_delay' => 0], 'contentRelated' => true, 'unencrypted' => false, 'method' => false]);
|
yield $connection->sendMessage(['_' => 'http_wait', 'body' => ['max_wait' => 30000, 'wait_after' => 0, 'max_delay' => 0], 'contentRelated' => true, 'unencrypted' => false, 'method' => false]);
|
||||||
}
|
}
|
||||||
$API->logger->logger("DC $datacenter: request {$connection->countHttpSent()}, response {$connection->countHttpReceived()}");
|
$API->logger->logger("DC {$datacenter}: request {$connection->countHttpSent()}, response {$connection->countHttpReceived()}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __toString(): string
|
public function __toString(): string
|
||||||
{
|
{
|
||||||
return "HTTP wait loop in DC {$this->datacenter}";
|
return "HTTP wait loop in DC {$this->datacenter}";
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ping loop.
|
* Ping loop.
|
||||||
*
|
*
|
||||||
@ -40,14 +41,12 @@ class PingLoop extends ResumableSignalLoop
|
|||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $datacenter;
|
protected $datacenter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DataCenterConnection instance.
|
* DataCenterConnection instance.
|
||||||
*
|
*
|
||||||
* @var \danog\MadelineProto\DataCenterConnection
|
* @var \danog\MadelineProto\DataCenterConnection
|
||||||
*/
|
*/
|
||||||
protected $datacenterConnection;
|
protected $datacenterConnection;
|
||||||
|
|
||||||
public function __construct(Connection $connection)
|
public function __construct(Connection $connection)
|
||||||
{
|
{
|
||||||
$this->connection = $connection;
|
$this->connection = $connection;
|
||||||
@ -55,14 +54,12 @@ class PingLoop extends ResumableSignalLoop
|
|||||||
$this->datacenter = $connection->getDatacenterID();
|
$this->datacenter = $connection->getDatacenterID();
|
||||||
$this->datacenterConnection = $connection->getShared();
|
$this->datacenterConnection = $connection->getShared();
|
||||||
}
|
}
|
||||||
|
public function loop(): \Generator
|
||||||
public function loop()
|
|
||||||
{
|
{
|
||||||
$API = $this->API;
|
$API = $this->API;
|
||||||
$datacenter = $this->datacenter;
|
$datacenter = $this->datacenter;
|
||||||
$connection = $this->connection;
|
$connection = $this->connection;
|
||||||
$shared = $this->datacenterConnection;
|
$shared = $this->datacenterConnection;
|
||||||
|
|
||||||
$timeout = $shared->getSettings()['timeout'];
|
$timeout = $shared->getSettings()['timeout'];
|
||||||
while (true) {
|
while (true) {
|
||||||
while (!$shared->hasTempAuthKey()) {
|
while (!$shared->hasTempAuthKey()) {
|
||||||
@ -74,17 +71,16 @@ class PingLoop extends ResumableSignalLoop
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (\time() - $connection->getLastChunk() >= $timeout) {
|
if (\time() - $connection->getLastChunk() >= $timeout) {
|
||||||
$API->logger->logger("Ping DC $datacenter");
|
$API->logger->logger("Ping DC {$datacenter}");
|
||||||
try {
|
try {
|
||||||
yield $connection->methodCallAsyncRead('ping', ['ping_id' => \random_bytes(8)]);
|
yield $connection->methodCallAsyncRead('ping', ['ping_id' => \random_bytes(8)]);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$API->logger->logger("Error while pinging DC $datacenter");
|
$API->logger->logger("Error while pinging DC {$datacenter}");
|
||||||
$API->logger->logger((string) $e);
|
$API->logger->logger((string) $e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __toString(): string
|
public function __toString(): string
|
||||||
{
|
{
|
||||||
return "Ping loop in DC {$this->datacenter}";
|
return "Ping loop in DC {$this->datacenter}";
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Socket read loop.
|
* Socket read loop.
|
||||||
*
|
*
|
||||||
@ -38,7 +39,6 @@ class ReadLoop extends SignalLoop
|
|||||||
{
|
{
|
||||||
use Tools;
|
use Tools;
|
||||||
use Crypt;
|
use Crypt;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connection instance.
|
* Connection instance.
|
||||||
*
|
*
|
||||||
@ -57,7 +57,6 @@ class ReadLoop extends SignalLoop
|
|||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $datacenter;
|
protected $datacenter;
|
||||||
|
|
||||||
public function __construct(Connection $connection)
|
public function __construct(Connection $connection)
|
||||||
{
|
{
|
||||||
$this->connection = $connection;
|
$this->connection = $connection;
|
||||||
@ -65,33 +64,29 @@ class ReadLoop extends SignalLoop
|
|||||||
$this->datacenter = $connection->getDatacenterID();
|
$this->datacenter = $connection->getDatacenterID();
|
||||||
$this->datacenterConnection = $connection->getShared();
|
$this->datacenterConnection = $connection->getShared();
|
||||||
}
|
}
|
||||||
|
public function loop(): \Generator
|
||||||
public function loop()
|
|
||||||
{
|
{
|
||||||
$API = $this->API;
|
$API = $this->API;
|
||||||
$datacenter = $this->datacenter;
|
$datacenter = $this->datacenter;
|
||||||
$connection = $this->connection;
|
$connection = $this->connection;
|
||||||
$shared = $this->datacenterConnection;
|
$shared = $this->datacenterConnection;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
$error = yield $this->waitSignal($this->readMessage());
|
$error = yield $this->waitSignal($this->readMessage());
|
||||||
} catch (NothingInTheSocketException | StreamException | PendingReadError | \Error $e) {
|
} catch (NothingInTheSocketException|StreamException|PendingReadError|\Error $e) {
|
||||||
if ($connection->shouldReconnect()) {
|
if ($connection->shouldReconnect()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Tools::callForkDefer((function () use ($API, $connection, $datacenter, $e) {
|
Tools::callForkDefer((function () use ($API, $connection, $datacenter, $e): \Generator {
|
||||||
$API->logger->logger($e);
|
$API->logger->logger($e);
|
||||||
$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();
|
||||||
})());
|
})());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (\is_int($error)) {
|
if (\is_int($error)) {
|
||||||
//$this->exitedLoop();
|
//$this->exitedLoop();
|
||||||
|
Tools::callForkDefer((function () use ($error, $shared, $connection, $datacenter, $API): \Generator {
|
||||||
Tools::callForkDefer((function () use ($error, $shared, $connection, $datacenter, $API) {
|
|
||||||
if ($error === -404) {
|
if ($error === -404) {
|
||||||
if ($shared->hasTempAuthKey()) {
|
if ($shared->hasTempAuthKey()) {
|
||||||
$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);
|
||||||
@ -117,70 +112,53 @@ class ReadLoop extends SignalLoop
|
|||||||
yield $connection->reconnect();
|
yield $connection->reconnect();
|
||||||
} else {
|
} else {
|
||||||
yield $connection->reconnect();
|
yield $connection->reconnect();
|
||||||
|
|
||||||
throw new \danog\MadelineProto\RPCErrorException($error, $error);
|
throw new \danog\MadelineProto\RPCErrorException($error, $error);
|
||||||
}
|
}
|
||||||
})());
|
})());
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$connection->httpReceived();
|
$connection->httpReceived();
|
||||||
|
|
||||||
Loop::defer([$connection, 'handleMessages']);
|
Loop::defer([$connection, 'handleMessages']);
|
||||||
|
|
||||||
if ($shared->isHttp()) {
|
if ($shared->isHttp()) {
|
||||||
Loop::defer([$connection, 'pingHttpWaiter']);
|
Loop::defer([$connection, 'pingHttpWaiter']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public function readMessage(): \Generator
|
||||||
public function readMessage()
|
|
||||||
{
|
{
|
||||||
$API = $this->API;
|
$API = $this->API;
|
||||||
$datacenter = $this->datacenter;
|
$datacenter = $this->datacenter;
|
||||||
$connection = $this->connection;
|
$connection = $this->connection;
|
||||||
$shared = $this->datacenterConnection;
|
$shared = $this->datacenterConnection;
|
||||||
|
|
||||||
if ($connection->shouldReconnect()) {
|
if ($connection->shouldReconnect()) {
|
||||||
$API->logger->logger('Not reading because connection is old');
|
$API->logger->logger('Not reading because connection is old');
|
||||||
|
|
||||||
throw new NothingInTheSocketException();
|
throw new NothingInTheSocketException();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$buffer = yield $connection->stream->getReadBuffer($payload_length);
|
$buffer = yield $connection->stream->getReadBuffer($payload_length);
|
||||||
} catch (ClosedException $e) {
|
} catch (ClosedException $e) {
|
||||||
$API->logger->logger($e->getReason());
|
$API->logger->logger($e->getReason());
|
||||||
if (\strpos($e->getReason(), ' ') === 0) {
|
if (\strpos($e->getReason(), ' ') === 0) {
|
||||||
$payload = -\substr($e->getReason(), 7);
|
$payload = -\substr($e->getReason(), 7);
|
||||||
$API->logger->logger("Received $payload from DC ".$datacenter, \danog\MadelineProto\Logger::ERROR);
|
$API->logger->logger("Received {$payload} from DC " . $datacenter, \danog\MadelineProto\Logger::ERROR);
|
||||||
|
|
||||||
return $payload;
|
return $payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($payload_length === 4) {
|
if ($payload_length === 4) {
|
||||||
$payload = \danog\MadelineProto\Tools::unpackSignedInt(yield $buffer->bufferRead(4));
|
$payload = \danog\MadelineProto\Tools::unpackSignedInt(yield $buffer->bufferRead(4));
|
||||||
$API->logger->logger("Received $payload from DC ".$datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$API->logger->logger("Received {$payload} from DC " . $datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
|
|
||||||
return $payload;
|
return $payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
$connection->reading(true);
|
$connection->reading(true);
|
||||||
try {
|
try {
|
||||||
$auth_key_id = yield $buffer->bufferRead(8);
|
$auth_key_id = yield $buffer->bufferRead(8);
|
||||||
|
|
||||||
if ($auth_key_id === "\0\0\0\0\0\0\0\0") {
|
if ($auth_key_id === "\0\0\0\0\0\0\0\0") {
|
||||||
$message_id = yield $buffer->bufferRead(8);
|
$message_id = yield $buffer->bufferRead(8);
|
||||||
if (!\in_array($message_id, [1, 0])) {
|
if (!\in_array($message_id, [1, 0])) {
|
||||||
$connection->checkMessageId($message_id, ['outgoing' => false, 'container' => false]);
|
$connection->checkMessageId($message_id, ['outgoing' => false, 'container' => false]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$message_length = \unpack('V', yield $buffer->bufferRead(4))[1];
|
$message_length = \unpack('V', yield $buffer->bufferRead(4))[1];
|
||||||
|
|
||||||
$message_data = yield $buffer->bufferRead($message_length);
|
$message_data = yield $buffer->bufferRead($message_length);
|
||||||
$left = $payload_length - $message_length - 4 - 8 - 8;
|
$left = $payload_length - $message_length - 4 - 8 - 8;
|
||||||
if ($left) {
|
if ($left) {
|
||||||
@ -195,18 +173,17 @@ class ReadLoop extends SignalLoop
|
|||||||
$message_key = yield $buffer->bufferRead(16);
|
$message_key = yield $buffer->bufferRead(16);
|
||||||
list($aes_key, $aes_iv) = $this->aesCalculate($message_key, $shared->getTempAuthKey()->getAuthKey(), false);
|
list($aes_key, $aes_iv) = $this->aesCalculate($message_key, $shared->getTempAuthKey()->getAuthKey(), false);
|
||||||
$encrypted_data = yield $buffer->bufferRead($payload_length - 24);
|
$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->igeDecrypt($encrypted_data, $aes_key, $aes_iv);
|
$decrypted_data = $this->igeDecrypt($encrypted_data, $aes_key, $aes_iv);
|
||||||
/*
|
/*
|
||||||
$server_salt = substr($decrypted_data, 0, 8);
|
$server_salt = substr($decrypted_data, 0, 8);
|
||||||
if ($server_salt != $shared->getTempAuthKey()->getServerSalt()) {
|
if ($server_salt != $shared->getTempAuthKey()->getServerSalt()) {
|
||||||
$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);
|
$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) {
|
||||||
$API->logger->logger("Session ID mismatch", Logger::FATAL_ERROR);
|
$API->logger->logger("Session ID mismatch", Logger::FATAL_ERROR);
|
||||||
@ -216,7 +193,6 @@ class ReadLoop extends SignalLoop
|
|||||||
$message_id = \substr($decrypted_data, 16, 8);
|
$message_id = \substr($decrypted_data, 16, 8);
|
||||||
$connection->checkMessageId($message_id, ['outgoing' => false, 'container' => false]);
|
$connection->checkMessageId($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');
|
||||||
@ -234,30 +210,26 @@ class ReadLoop extends SignalLoop
|
|||||||
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($shared->getTempAuthKey()->getAuthKey(), 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->getTL()->deserialize($message_data, ['type' => '', 'connection' => $connection]);
|
$deserialized = $API->getTL()->deserialize($message_data, ['type' => '', 'connection' => $connection]);
|
||||||
$API->referenceDatabase->reset();
|
$API->referenceDatabase->reset();
|
||||||
|
|
||||||
$connection->incoming_messages[$message_id]['content'] = $deserialized;
|
$connection->incoming_messages[$message_id]['content'] = $deserialized;
|
||||||
$connection->incoming_messages[$message_id]['response'] = -1;
|
$connection->incoming_messages[$message_id]['response'] = -1;
|
||||||
$connection->new_incoming[$message_id] = $message_id;
|
$connection->new_incoming[$message_id] = $message_id;
|
||||||
//$connection->last_http_wait = 0;
|
//$connection->last_http_wait = 0;
|
||||||
|
$API->logger->logger('Received payload from DC ' . $datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
$API->logger->logger('Received payload from DC '.$datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
|
||||||
} finally {
|
} finally {
|
||||||
$connection->reading(false);
|
$connection->reading(false);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __toString(): string
|
public function __toString(): string
|
||||||
{
|
{
|
||||||
return "read loop in DC {$this->datacenter}";
|
return "read loop in DC {$this->datacenter}";
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Socket write loop.
|
* Socket write loop.
|
||||||
*
|
*
|
||||||
@ -34,7 +35,6 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
{
|
{
|
||||||
use Crypt;
|
use Crypt;
|
||||||
use Tools;
|
use Tools;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connection instance.
|
* Connection instance.
|
||||||
*
|
*
|
||||||
@ -53,7 +53,6 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $datacenter;
|
protected $datacenter;
|
||||||
|
|
||||||
public function __construct(Connection $connection)
|
public function __construct(Connection $connection)
|
||||||
{
|
{
|
||||||
$this->connection = $connection;
|
$this->connection = $connection;
|
||||||
@ -62,14 +61,12 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
$ctx = $connection->getCtx();
|
$ctx = $connection->getCtx();
|
||||||
$this->datacenter = $connection->getDatacenterID();
|
$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;
|
$shared = $this->datacenterConnection;
|
||||||
$datacenter = $this->datacenter;
|
$datacenter = $this->datacenter;
|
||||||
|
|
||||||
$please_wait = false;
|
$please_wait = false;
|
||||||
while (true) {
|
while (true) {
|
||||||
while (empty($connection->pending_outgoing) || $please_wait) {
|
while (empty($connection->pending_outgoing) || $please_wait) {
|
||||||
@ -77,21 +74,18 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
$API->logger->logger('Not writing because connection is old');
|
$API->logger->logger('Not writing because connection is old');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$please_wait = false;
|
$please_wait = false;
|
||||||
$API->logger->logger("Waiting in $this", Logger::ULTRA_VERBOSE);
|
$API->logger->logger("Waiting in {$this}", Logger::ULTRA_VERBOSE);
|
||||||
if (yield $this->waitSignal($this->pause())) {
|
if (yield $this->waitSignal($this->pause())) {
|
||||||
$API->logger->logger("Exiting $this", Logger::ULTRA_VERBOSE);
|
$API->logger->logger("Exiting {$this}", Logger::ULTRA_VERBOSE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$API->logger->logger("Done waiting in $this", Logger::ULTRA_VERBOSE);
|
$API->logger->logger("Done waiting in {$this}", Logger::ULTRA_VERBOSE);
|
||||||
|
|
||||||
if ($connection->shouldReconnect()) {
|
if ($connection->shouldReconnect()) {
|
||||||
$API->logger->logger('Not writing because connection is old');
|
$API->logger->logger('Not writing because connection is old');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$connection->writing(true);
|
$connection->writing(true);
|
||||||
try {
|
try {
|
||||||
$please_wait = yield $this->{$shared->hasTempAuthKey() ? 'encryptedWriteLoop' : 'unencryptedWriteLoop'}();
|
$please_wait = yield $this->{$shared->hasTempAuthKey() ? 'encryptedWriteLoop' : 'unencryptedWriteLoop'}();
|
||||||
@ -99,7 +93,7 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
if ($connection->shouldReconnect()) {
|
if ($connection->shouldReconnect()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Tools::callForkDefer((function () use ($API, $connection, $datacenter, $e) {
|
Tools::callForkDefer((function () use ($API, $connection, $datacenter, $e): \Generator {
|
||||||
$API->logger->logger($e);
|
$API->logger->logger($e);
|
||||||
$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();
|
||||||
@ -108,18 +102,15 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
} finally {
|
} finally {
|
||||||
$connection->writing(false);
|
$connection->writing(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//$connection->waiter->resume();
|
//$connection->waiter->resume();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public function unencryptedWriteLoop(): \Generator
|
||||||
public function unencryptedWriteLoop()
|
|
||||||
{
|
{
|
||||||
$API = $this->API;
|
$API = $this->API;
|
||||||
$datacenter = $this->datacenter;
|
$datacenter = $this->datacenter;
|
||||||
$connection = $this->connection;
|
$connection = $this->connection;
|
||||||
$shared = $this->datacenterConnection;
|
$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) {
|
||||||
@ -130,20 +121,14 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$skipped_all = false;
|
$skipped_all = false;
|
||||||
|
|
||||||
$API->logger->logger("Sending {$message['_']} as unencrypted message to DC {$datacenter}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$API->logger->logger("Sending {$message['_']} as unencrypted message to DC {$datacenter}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
|
|
||||||
$message_id = isset($message['msg_id']) ? $message['msg_id'] : $connection->generateMessageId();
|
$message_id = isset($message['msg_id']) ? $message['msg_id'] : $connection->generateMessageId();
|
||||||
$length = \strlen($message['serialized_body']);
|
$length = \strlen($message['serialized_body']);
|
||||||
|
|
||||||
$pad_length = -$length & 15;
|
$pad_length = -$length & 15;
|
||||||
$pad_length += 16 * \danog\MadelineProto\Tools::randomInt($modulus = 16);
|
$pad_length += 16 * \danog\MadelineProto\Tools::randomInt($modulus = 16);
|
||||||
|
|
||||||
$pad = \danog\MadelineProto\Tools::random($pad_length);
|
$pad = \danog\MadelineProto\Tools::random($pad_length);
|
||||||
$buffer = yield $connection->stream->getWriteBuffer(8 + 8 + 4 + $pad_length + $length);
|
$buffer = yield $connection->stream->getWriteBuffer(8 + 8 + 4 + $pad_length + $length);
|
||||||
|
yield $buffer->bufferWrite("\0\0\0\0\0\0\0\0" . $message_id . \danog\MadelineProto\Tools::packUnsignedInt($length) . $message['serialized_body'] . $pad);
|
||||||
yield $buffer->bufferWrite("\0\0\0\0\0\0\0\0".$message_id.\danog\MadelineProto\Tools::packUnsignedInt($length).$message['serialized_body'].$pad);
|
|
||||||
|
|
||||||
//var_dump("plain ".bin2hex($message_id));
|
//var_dump("plain ".bin2hex($message_id));
|
||||||
$connection->httpSent();
|
$connection->httpSent();
|
||||||
$connection->outgoing_messages[$message_id] = $message;
|
$connection->outgoing_messages[$message_id] = $message;
|
||||||
@ -151,11 +136,8 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
$connection->outgoing_messages[$message_id]['tries'] = 0;
|
$connection->outgoing_messages[$message_id]['tries'] = 0;
|
||||||
$connection->outgoing_messages[$message_id]['unencrypted'] = true;
|
$connection->outgoing_messages[$message_id]['unencrypted'] = true;
|
||||||
$connection->new_outgoing[$message_id] = $message_id;
|
$connection->new_outgoing[$message_id] = $message_id;
|
||||||
|
|
||||||
unset($connection->pending_outgoing[$k]);
|
unset($connection->pending_outgoing[$k]);
|
||||||
|
|
||||||
$API->logger->logger("Sent {$message['_']} as unencrypted message to DC {$datacenter}!", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$API->logger->logger("Sent {$message['_']} as unencrypted message to DC {$datacenter}!", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
|
|
||||||
$message['send_promise']->resolve(isset($message['promise']) ? $message['promise'] : true);
|
$message['send_promise']->resolve(isset($message['promise']) ? $message['promise'] : true);
|
||||||
unset($message['send_promise']);
|
unset($message['send_promise']);
|
||||||
}
|
}
|
||||||
@ -164,14 +146,12 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function encryptedWriteLoop(): \Generator
|
public function encryptedWriteLoop(): \Generator
|
||||||
{
|
{
|
||||||
$API = $this->API;
|
$API = $this->API;
|
||||||
$datacenter = $this->datacenter;
|
$datacenter = $this->datacenter;
|
||||||
$connection = $this->connection;
|
$connection = $this->connection;
|
||||||
$shared = $this->datacenterConnection;
|
$shared = $this->datacenterConnection;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (!$shared->hasTempAuthKey()) {
|
if (!$shared->hasTempAuthKey()) {
|
||||||
return;
|
return;
|
||||||
@ -182,13 +162,12 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
$temporary_keys = [];
|
$temporary_keys = [];
|
||||||
if (\count($to_ack = $connection->ack_queue)) {
|
if (\count($to_ack = $connection->ack_queue)) {
|
||||||
foreach (\array_chunk($connection->ack_queue, 8192) as $acks) {
|
foreach (\array_chunk($connection->ack_queue, 8192) as $acks) {
|
||||||
$connection->pending_outgoing[$connection->pending_outgoing_key] = ['_' => 'msgs_ack', 'serialized_body' => yield $this->API->getTL()->serializeObject(['type' => ''], ['_' => 'msgs_ack','msg_ids' => $acks], 'msgs_ack'), 'contentRelated' => false, 'unencrypted' => false, 'method' => false];
|
$connection->pending_outgoing[$connection->pending_outgoing_key] = ['_' => 'msgs_ack', 'serialized_body' => yield $this->API->getTL()->serializeObject(['type' => ''], ['_' => 'msgs_ack', 'msg_ids' => $acks], 'msgs_ack'), 'contentRelated' => false, 'unencrypted' => false, 'method' => false];
|
||||||
$temporary_keys[$connection->pending_outgoing_key] = true;
|
$temporary_keys[$connection->pending_outgoing_key] = true;
|
||||||
$API->logger->logger("Adding msgs_ack {$connection->pending_outgoing_key}", Logger::ULTRA_VERBOSE);
|
$API->logger->logger("Adding msgs_ack {$connection->pending_outgoing_key}", Logger::ULTRA_VERBOSE);
|
||||||
$connection->pending_outgoing_key++;
|
$connection->pending_outgoing_key++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$has_http_wait = false;
|
$has_http_wait = false;
|
||||||
$messages = [];
|
$messages = [];
|
||||||
$keys = [];
|
$keys = [];
|
||||||
@ -206,7 +185,6 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
$connection->pending_outgoing_key++;
|
$connection->pending_outgoing_key++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$total_length = 0;
|
$total_length = 0;
|
||||||
$count = 0;
|
$count = 0;
|
||||||
\ksort($connection->pending_outgoing);
|
\ksort($connection->pending_outgoing);
|
||||||
@ -231,45 +209,20 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
$API->logger->logger('Length overflow, postponing part of payload', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$API->logger->logger('Length overflow, postponing part of payload', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$message_id = isset($message['msg_id']) ? $message['msg_id'] : $connection->generateMessageId();
|
$message_id = isset($message['msg_id']) ? $message['msg_id'] : $connection->generateMessageId();
|
||||||
|
|
||||||
$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->generateOutSeqNo($message['contentRelated'])];
|
$MTmessage = ['_' => 'MTmessage', 'msg_id' => $message_id, 'body' => $message['serialized_body'], 'seqno' => $connection->generateOutSeqNo($message['contentRelated'])];
|
||||||
|
|
||||||
if (isset($message['method']) && $message['method'] && $message['_'] !== 'http_wait') {
|
if (isset($message['method']) && $message['method'] && $message['_'] !== 'http_wait') {
|
||||||
if (!$shared->getTempAuthKey()->isInited() && $message['_'] !== 'auth.bindTempAuthKey' && !$inited) {
|
if (!$shared->getTempAuthKey()->isInited() && $message['_'] !== 'auth.bindTempAuthKey' && !$inited) {
|
||||||
$inited = true;
|
$inited = true;
|
||||||
$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->getTL()->serializeMethod(
|
$MTmessage['body'] = yield $API->getTL()->serializeMethod('invokeWithLayer', ['layer' => $API->settings['tl_schema']['layer'], 'query' => yield $API->getTL()->serializeMethod('initConnection', ['api_id' => $API->settings['app_info']['api_id'], 'api_hash' => $API->settings['app_info']['api_hash'], 'device_model' => !$connection->isCDN() ? $API->settings['app_info']['device_model'] : 'n/a', 'system_version' => !$connection->isCDN() ? $API->settings['app_info']['system_version'] : 'n/a', 'app_version' => $API->settings['app_info']['app_version'], 'system_lang_code' => $API->settings['app_info']['lang_code'], 'lang_code' => $API->settings['app_info']['lang_code'], 'lang_pack' => $API->settings['app_info']['lang_pack'], 'proxy' => $connection->getCtx()->getInputClientProxy(), 'query' => $MTmessage['body']])]);
|
||||||
'invokeWithLayer',
|
|
||||||
[
|
|
||||||
'layer' => $API->settings['tl_schema']['layer'],
|
|
||||||
'query' => yield $API->getTL()->serializeMethod(
|
|
||||||
'initConnection',
|
|
||||||
[
|
|
||||||
'api_id' => $API->settings['app_info']['api_id'],
|
|
||||||
'api_hash' => $API->settings['app_info']['api_hash'],
|
|
||||||
'device_model' => !$connection->isCDN() ? $API->settings['app_info']['device_model'] : 'n/a',
|
|
||||||
'system_version' => !$connection->isCDN() ? $API->settings['app_info']['system_version'] : 'n/a',
|
|
||||||
'app_version' => $API->settings['app_info']['app_version'],
|
|
||||||
'system_lang_code' => $API->settings['app_info']['lang_code'],
|
|
||||||
'lang_code' => $API->settings['app_info']['lang_code'],
|
|
||||||
'lang_pack' => $API->settings['app_info']['lang_pack'],
|
|
||||||
'proxy' => $connection->getCtx()->getInputClientProxy(),
|
|
||||||
'query' => $MTmessage['body'],
|
|
||||||
]
|
|
||||||
),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
if (isset($message['queue'])) {
|
if (isset($message['queue'])) {
|
||||||
if (!isset($connection->call_queue[$message['queue']])) {
|
if (!isset($connection->call_queue[$message['queue']])) {
|
||||||
$connection->call_queue[$message['queue']] = [];
|
$connection->call_queue[$message['queue']] = [];
|
||||||
}
|
}
|
||||||
$MTmessage['body'] = yield $API->getTL()->serializeMethod('invokeAfterMsgs', ['msg_ids' => $connection->call_queue[$message['queue']], 'query' => $MTmessage['body']]);
|
$MTmessage['body'] = yield $API->getTL()->serializeMethod('invokeAfterMsgs', ['msg_ids' => $connection->call_queue[$message['queue']], 'query' => $MTmessage['body']]);
|
||||||
|
|
||||||
$connection->call_queue[$message['queue']][$message_id] = $message_id;
|
$connection->call_queue[$message['queue']][$message_id] = $message_id;
|
||||||
if (\count($connection->call_queue[$message['queue']]) > $API->settings['msg_array_limit']['call_queue']) {
|
if (\count($connection->call_queue[$message['queue']]) > $API->settings['msg_array_limit']['call_queue']) {
|
||||||
\reset($connection->call_queue[$message['queue']]);
|
\reset($connection->call_queue[$message['queue']]);
|
||||||
@ -279,12 +232,12 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
}
|
}
|
||||||
// TODO
|
// TODO
|
||||||
/* if ($API->settings['requests']['gzip_encode_if_gt'] !== -1 && ($l = strlen($MTmessage['body'])) > $API->settings['requests']['gzip_encode_if_gt']) {
|
/* if ($API->settings['requests']['gzip_encode_if_gt'] !== -1 && ($l = strlen($MTmessage['body'])) > $API->settings['requests']['gzip_encode_if_gt']) {
|
||||||
if (($g = strlen($gzipped = gzencode($MTmessage['body']))) < $l) {
|
if (($g = strlen($gzipped = gzencode($MTmessage['body']))) < $l) {
|
||||||
$MTmessage['body'] = yield $API->getTL()->serializeObject(['type' => ''], ['_' => 'gzip_packed', 'packed_data' => $gzipped], 'gzipped data');
|
$MTmessage['body'] = yield $API->getTL()->serializeObject(['type' => ''], ['_' => 'gzip_packed', 'packed_data' => $gzipped], 'gzipped data');
|
||||||
$API->logger->logger('Using GZIP compression for ' . $message['_'] . ', saved ' . ($l - $g) . ' bytes of data, reduced call size by ' . $g * 100 / $l . '%', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$API->logger->logger('Using GZIP compression for ' . $message['_'] . ', saved ' . ($l - $g) . ' bytes of data, reduced call size by ' . $g * 100 / $l . '%', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
}
|
}
|
||||||
unset($gzipped);
|
unset($gzipped);
|
||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$body_length = \strlen($MTmessage['body']);
|
$body_length = \strlen($MTmessage['body']);
|
||||||
@ -295,32 +248,25 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
}
|
}
|
||||||
$count++;
|
$count++;
|
||||||
$total_length += $actual_length;
|
$total_length += $actual_length;
|
||||||
|
|
||||||
$MTmessage['bytes'] = $body_length;
|
$MTmessage['bytes'] = $body_length;
|
||||||
$messages[] = $MTmessage;
|
$messages[] = $MTmessage;
|
||||||
$keys[$k] = $message_id;
|
$keys[$k] = $message_id;
|
||||||
}
|
}
|
||||||
if ($shared->isHttp() && $skipped && $count === \count($temporary_keys)) {
|
if ($shared->isHttp() && $skipped && $count === \count($temporary_keys)) {
|
||||||
foreach ($temporary_keys as $key => $true) {
|
foreach ($temporary_keys as $key => $true) {
|
||||||
$API->logger->logger("Removing temporary {$connection->pending_outgoing[$key]['_']} by $key", Logger::ULTRA_VERBOSE);
|
$API->logger->logger("Removing temporary {$connection->pending_outgoing[$key]['_']} by {$key}", Logger::ULTRA_VERBOSE);
|
||||||
unset($connection->pending_outgoing[$key]);
|
unset($connection->pending_outgoing[$key]);
|
||||||
$count--;
|
$count--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$MTmessage = null;
|
$MTmessage = null;
|
||||||
|
|
||||||
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->generateMessageId();
|
$message_id = $connection->generateMessageId();
|
||||||
$connection->pending_outgoing[$connection->pending_outgoing_key] = ['_' => 'msg_container', 'container' => \array_values($keys), 'contentRelated' => false, 'method' => false, 'unencrypted' => false];
|
$connection->pending_outgoing[$connection->pending_outgoing_key] = ['_' => 'msg_container', 'container' => \array_values($keys), 'contentRelated' => false, 'method' => false, 'unencrypted' => false];
|
||||||
|
|
||||||
//var_dumP("container ".bin2hex($message_id));
|
//var_dumP("container ".bin2hex($message_id));
|
||||||
$keys[$connection->pending_outgoing_key++] = $message_id;
|
$keys[$connection->pending_outgoing_key++] = $message_id;
|
||||||
|
|
||||||
$message_data = yield $API->getTL()->serializeObject(['type' => ''], ['_' => 'msg_container', 'messages' => $messages], 'container');
|
$message_data = yield $API->getTL()->serializeObject(['type' => ''], ['_' => 'msg_container', 'messages' => $messages], 'container');
|
||||||
|
|
||||||
$message_data_length = \strlen($message_data);
|
$message_data_length = \strlen($message_data);
|
||||||
$seq_no = $connection->generateOutSeqNo(false);
|
$seq_no = $connection->generateOutSeqNo(false);
|
||||||
} elseif ($count) {
|
} elseif ($count) {
|
||||||
@ -330,44 +276,30 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
$message_id = $message['msg_id'];
|
$message_id = $message['msg_id'];
|
||||||
$seq_no = $message['seqno'];
|
$seq_no = $message['seqno'];
|
||||||
} else {
|
} else {
|
||||||
$API->logger->logger("NO MESSAGE SENT in DC $datacenter", \danog\MadelineProto\Logger::WARNING);
|
$API->logger->logger("NO MESSAGE SENT in DC {$datacenter}", \danog\MadelineProto\Logger::WARNING);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
unset($messages);
|
unset($messages);
|
||||||
|
$plaintext = $shared->getTempAuthKey()->getServerSalt() . $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 = \danog\MadelineProto\Tools::posmod(-\strlen($plaintext), 16);
|
$padding = \danog\MadelineProto\Tools::posmod(-\strlen($plaintext), 16);
|
||||||
if ($padding < 12) {
|
if ($padding < 12) {
|
||||||
$padding += 16;
|
$padding += 16;
|
||||||
}
|
}
|
||||||
$padding = \danog\MadelineProto\Tools::random($padding);
|
$padding = \danog\MadelineProto\Tools::random($padding);
|
||||||
|
$message_key = \substr(\hash('sha256', \substr($shared->getTempAuthKey()->getAuthKey(), 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->aesCalculate($message_key, $shared->getTempAuthKey()->getAuthKey());
|
list($aes_key, $aes_iv) = $this->aesCalculate($message_key, $shared->getTempAuthKey()->getAuthKey());
|
||||||
|
$message = $shared->getTempAuthKey()->getID() . $message_key . $this->igeEncrypt($plaintext . $padding, $aes_key, $aes_iv);
|
||||||
$message = $shared->getTempAuthKey()->getID().$message_key.$this->igeEncrypt($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();
|
||||||
|
|
||||||
$API->logger->logger("Sent encrypted payload to DC {$datacenter}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$API->logger->logger("Sent encrypted payload to DC {$datacenter}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
|
|
||||||
$sent = \time();
|
$sent = \time();
|
||||||
|
|
||||||
if ($to_ack) {
|
if ($to_ack) {
|
||||||
$connection->ack_queue = [];
|
$connection->ack_queue = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($keys as $key => $message_id) {
|
foreach ($keys as $key => $message_id) {
|
||||||
$connection->outgoing_messages[$message_id] = &$connection->pending_outgoing[$key];
|
$connection->outgoing_messages[$message_id] =& $connection->pending_outgoing[$key];
|
||||||
|
|
||||||
if (isset($connection->outgoing_messages[$message_id]['promise'])) {
|
if (isset($connection->outgoing_messages[$message_id]['promise'])) {
|
||||||
$connection->new_outgoing[$message_id] = $message_id;
|
$connection->new_outgoing[$message_id] = $message_id;
|
||||||
$connection->outgoing_messages[$message_id]['sent'] = $sent;
|
$connection->outgoing_messages[$message_id]['sent'] = $sent;
|
||||||
@ -380,17 +312,13 @@ class WriteLoop extends ResumableSignalLoop
|
|||||||
//var_dumP("encrypted ".bin2hex($message_id)." ".$connection->outgoing_messages[$message_id]['_']);
|
//var_dumP("encrypted ".bin2hex($message_id)." ".$connection->outgoing_messages[$message_id]['_']);
|
||||||
unset($connection->pending_outgoing[$key]);
|
unset($connection->pending_outgoing[$key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (!empty($connection->pending_outgoing)) $connection->select();
|
//if (!empty($connection->pending_outgoing)) $connection->select();
|
||||||
} while (!empty($connection->pending_outgoing) && !$skipped);
|
} while (!empty($connection->pending_outgoing) && !$skipped);
|
||||||
|
|
||||||
if (empty($connection->pending_outgoing)) {
|
if (empty($connection->pending_outgoing)) {
|
||||||
$connection->pending_outgoing_key = 'a';
|
$connection->pending_outgoing_key = 'a';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $skipped;
|
return $skipped;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __toString(): string
|
public function __toString(): string
|
||||||
{
|
{
|
||||||
return "write loop in DC {$this->datacenter}";
|
return "write loop in DC {$this->datacenter}";
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic loop.
|
* Generic loop.
|
||||||
*
|
*
|
||||||
@ -30,10 +31,8 @@ class GenericLoop extends ResumableSignalLoop
|
|||||||
const STOP = -1;
|
const STOP = -1;
|
||||||
const PAUSE = null;
|
const PAUSE = null;
|
||||||
const CONTINUE = 0;
|
const CONTINUE = 0;
|
||||||
|
|
||||||
protected $callback;
|
protected $callback;
|
||||||
protected $name;
|
protected $name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
@ -54,24 +53,21 @@ class GenericLoop extends ResumableSignalLoop
|
|||||||
$this->callback = $callback->bindTo($this);
|
$this->callback = $callback->bindTo($this);
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
}
|
}
|
||||||
|
public function loop(): \Generator
|
||||||
public function loop()
|
|
||||||
{
|
{
|
||||||
$callback = $this->callback;
|
$callback = $this->callback;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
$timeout = yield $callback();
|
$timeout = yield $callback();
|
||||||
if ($timeout === self::PAUSE) {
|
if ($timeout === self::PAUSE) {
|
||||||
$this->API->logger->logger("Pausing $this", \danog\MadelineProto\Logger::VERBOSE);
|
$this->API->logger->logger("Pausing {$this}", \danog\MadelineProto\Logger::VERBOSE);
|
||||||
} elseif ($timeout > 0) {
|
} elseif ($timeout > 0) {
|
||||||
$this->API->logger->logger("Pausing $this for $timeout", \danog\MadelineProto\Logger::VERBOSE);
|
$this->API->logger->logger("Pausing {$this} for {$timeout}", \danog\MadelineProto\Logger::VERBOSE);
|
||||||
}
|
}
|
||||||
if ($timeout === self::STOP || yield $this->waitSignal($this->pause($timeout))) {
|
if ($timeout === self::STOP || yield $this->waitSignal($this->pause($timeout))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __toString(): string
|
public function __toString(): string
|
||||||
{
|
{
|
||||||
return $this->name;
|
return $this->name;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Periodic loop.
|
* Periodic loop.
|
||||||
*
|
*
|
||||||
@ -31,7 +32,6 @@ class PeriodicLoop extends ResumableSignalLoop
|
|||||||
private $callback;
|
private $callback;
|
||||||
private $name;
|
private $name;
|
||||||
private $timeout;
|
private $timeout;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
@ -47,22 +47,19 @@ class PeriodicLoop extends ResumableSignalLoop
|
|||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
$this->timeout = $timeout;
|
$this->timeout = $timeout;
|
||||||
}
|
}
|
||||||
|
public function loop(): \Generator
|
||||||
public function loop()
|
|
||||||
{
|
{
|
||||||
$callback = $this->callback;
|
$callback = $this->callback;
|
||||||
$logger = $this->API->logger;
|
$logger = $this->API->logger;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
$result = yield $this->waitSignal($this->pause($this->timeout));
|
$result = yield $this->waitSignal($this->pause($this->timeout));
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$logger->logger("Got signal in $this, exiting");
|
$logger->logger("Got signal in {$this}, exiting");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
yield $callback();
|
yield $callback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __toString(): string
|
public function __toString(): string
|
||||||
{
|
{
|
||||||
return $this->name;
|
return $this->name;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loop helper trait.
|
* Loop helper trait.
|
||||||
*
|
*
|
||||||
@ -32,59 +33,49 @@ use danog\MadelineProto\Loop\LoopInterface;
|
|||||||
abstract class Loop implements LoopInterface
|
abstract class Loop implements LoopInterface
|
||||||
{
|
{
|
||||||
use \danog\MadelineProto\Tools;
|
use \danog\MadelineProto\Tools;
|
||||||
|
|
||||||
private $count = 0;
|
private $count = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MTProto instance.
|
* MTProto instance.
|
||||||
*
|
*
|
||||||
* @var \danog\MadelineProto\MTProto
|
* @var \danog\MadelineProto\MTProto
|
||||||
*/
|
*/
|
||||||
public $API;
|
public $API;
|
||||||
|
|
||||||
public function __construct($API)
|
public function __construct($API)
|
||||||
{
|
{
|
||||||
$this->API = $API;
|
$this->API = $API;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function start()
|
public function start()
|
||||||
{
|
{
|
||||||
if ($this->count) {
|
if ($this->count) {
|
||||||
//$this->API->logger->logger("NOT entering $this with running count {$this->count}", Logger::ERROR);
|
//$this->API->logger->logger("NOT entering $this with running count {$this->count}", Logger::ERROR);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return \danog\MadelineProto\Tools::callFork($this->loopImpl());
|
return \danog\MadelineProto\Tools::callFork($this->loopImpl());
|
||||||
}
|
}
|
||||||
|
private function loopImpl(): \Generator
|
||||||
private function loopImpl()
|
|
||||||
{
|
{
|
||||||
//yield ['my_trace' => debug_backtrace(0, 1)[0], (string) $this];
|
//yield ['my_trace' => debug_backtrace(0, 1)[0], (string) $this];
|
||||||
$this->startedLoop();
|
$this->startedLoop();
|
||||||
$this->API->logger->logger("Entered $this", Logger::ULTRA_VERBOSE);
|
$this->API->logger->logger("Entered {$this}", Logger::ULTRA_VERBOSE);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
yield $this->loop();
|
yield $this->loop();
|
||||||
} finally {
|
} finally {
|
||||||
$this->exitedLoop();
|
$this->exitedLoop();
|
||||||
$this->API->logger->logger("Physically exited $this", Logger::ULTRA_VERBOSE);
|
$this->API->logger->logger("Physically exited {$this}", Logger::ULTRA_VERBOSE);
|
||||||
//return null;
|
//return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function exitedLoop()
|
public function exitedLoop()
|
||||||
{
|
{
|
||||||
if ($this->count) {
|
if ($this->count) {
|
||||||
$this->API->logger->logger("Exited $this", Logger::ULTRA_VERBOSE);
|
$this->API->logger->logger("Exited {$this}", Logger::ULTRA_VERBOSE);
|
||||||
$this->count--;
|
$this->count--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function startedLoop()
|
public function startedLoop()
|
||||||
{
|
{
|
||||||
$this->count++;
|
$this->count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isRunning()
|
public function isRunning()
|
||||||
{
|
{
|
||||||
return $this->count;
|
return $this->count;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loop helper trait.
|
* Loop helper trait.
|
||||||
*
|
*
|
||||||
@ -36,7 +37,6 @@ abstract class ResumableSignalLoop extends SignalLoop implements ResumableLoopIn
|
|||||||
private $resume;
|
private $resume;
|
||||||
private $pause;
|
private $pause;
|
||||||
private $resumeWatcher;
|
private $resumeWatcher;
|
||||||
|
|
||||||
public function pause($time = null): Promise
|
public function pause($time = null): Promise
|
||||||
{
|
{
|
||||||
if (!\is_null($time)) {
|
if (!\is_null($time)) {
|
||||||
@ -51,16 +51,13 @@ abstract class ResumableSignalLoop extends SignalLoop implements ResumableLoopIn
|
|||||||
$this->resumeWatcher = Loop::delay((int) ($time * 1000), [$this, 'resume'], $resume);
|
$this->resumeWatcher = Loop::delay((int) ($time * 1000), [$this, 'resume'], $resume);
|
||||||
}
|
}
|
||||||
$this->resume = new Deferred();
|
$this->resume = new Deferred();
|
||||||
|
|
||||||
$pause = $this->pause;
|
$pause = $this->pause;
|
||||||
$this->pause = new Deferred();
|
$this->pause = new Deferred();
|
||||||
if ($pause) {
|
if ($pause) {
|
||||||
Loop::defer([$pause, 'resolve']);
|
Loop::defer([$pause, 'resolve']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->resume->promise();
|
return $this->resume->promise();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function resume($watcherId = null, $expected = 0)
|
public function resume($watcherId = null, $expected = 0)
|
||||||
{
|
{
|
||||||
if ($this->resumeWatcher) {
|
if ($this->resumeWatcher) {
|
||||||
@ -75,15 +72,12 @@ abstract class ResumableSignalLoop extends SignalLoop implements ResumableLoopIn
|
|||||||
$resume = $this->resume;
|
$resume = $this->resume;
|
||||||
$this->resume = null;
|
$this->resume = null;
|
||||||
$resume->resolve();
|
$resume->resolve();
|
||||||
|
|
||||||
return $this->pause ? $this->pause->promise() : null;
|
return $this->pause ? $this->pause->promise() : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function resumeDefer()
|
public function resumeDefer()
|
||||||
{
|
{
|
||||||
Loop::defer([$this, 'resume']);
|
Loop::defer([$this, 'resume']);
|
||||||
|
|
||||||
return $this->pause ? $this->pause->promise() : null;
|
return $this->pause ? $this->pause->promise() : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loop helper trait.
|
* Loop helper trait.
|
||||||
*
|
*
|
||||||
@ -31,7 +32,6 @@ use danog\MadelineProto\Loop\SignalLoopInterface;
|
|||||||
abstract class SignalLoop extends Loop implements SignalLoopInterface
|
abstract class SignalLoop extends Loop implements SignalLoopInterface
|
||||||
{
|
{
|
||||||
private $signalDeferred;
|
private $signalDeferred;
|
||||||
|
|
||||||
public function signal($what)
|
public function signal($what)
|
||||||
{
|
{
|
||||||
if ($this->signalDeferred) {
|
if ($this->signalDeferred) {
|
||||||
@ -44,7 +44,6 @@ abstract class SignalLoop extends Loop implements SignalLoopInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function waitSignal($promise): Promise
|
public function waitSignal($promise): Promise
|
||||||
{
|
{
|
||||||
if ($promise instanceof \Generator) {
|
if ($promise instanceof \Generator) {
|
||||||
@ -52,7 +51,6 @@ abstract class SignalLoop extends Loop implements SignalLoopInterface
|
|||||||
}
|
}
|
||||||
$this->signalDeferred = new Deferred();
|
$this->signalDeferred = new Deferred();
|
||||||
$dpromise = $this->signalDeferred->promise();
|
$dpromise = $this->signalDeferred->promise();
|
||||||
|
|
||||||
$promise->onResolve(function () use ($promise) {
|
$promise->onResolve(function () use ($promise) {
|
||||||
if ($this->signalDeferred !== null) {
|
if ($this->signalDeferred !== null) {
|
||||||
$deferred = $this->signalDeferred;
|
$deferred = $this->signalDeferred;
|
||||||
@ -60,7 +58,6 @@ abstract class SignalLoop extends Loop implements SignalLoopInterface
|
|||||||
$deferred->resolve($promise);
|
$deferred->resolve($promise);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return $dpromise;
|
return $dpromise;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loop interface.
|
* Loop interface.
|
||||||
*
|
*
|
||||||
@ -31,14 +32,12 @@ interface LoopInterface
|
|||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function start();
|
public function start();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The actual loop.
|
* The actual loop.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function loop();
|
public function loop();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get name of the loop.
|
* Get name of the loop.
|
||||||
*
|
*
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resumable loop interface.
|
* Resumable loop interface.
|
||||||
*
|
*
|
||||||
@ -35,7 +36,6 @@ interface ResumableLoopInterface extends LoopInterface
|
|||||||
* @return Promise
|
* @return Promise
|
||||||
*/
|
*/
|
||||||
public function pause($time = null): Promise;
|
public function pause($time = null): Promise;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resume the loop.
|
* Resume the loop.
|
||||||
*
|
*
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signal loop interface.
|
* Signal loop interface.
|
||||||
*
|
*
|
||||||
@ -35,7 +36,6 @@ interface SignalLoopInterface extends LoopInterface
|
|||||||
* @return Promise
|
* @return Promise
|
||||||
*/
|
*/
|
||||||
public function waitSignal($promise): Promise;
|
public function waitSignal($promise): Promise;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a signal to the the loop.
|
* Send a signal to the the loop.
|
||||||
*
|
*
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update feeder loop.
|
* Update feeder loop.
|
||||||
*
|
*
|
||||||
@ -38,29 +39,24 @@ class FeedLoop extends ResumableSignalLoop
|
|||||||
* @var UpdateLoop
|
* @var UpdateLoop
|
||||||
*/
|
*/
|
||||||
private $updater;
|
private $updater;
|
||||||
|
|
||||||
public function __construct($API, $channelId = false)
|
public function __construct($API, $channelId = false)
|
||||||
{
|
{
|
||||||
$this->API = $API;
|
$this->API = $API;
|
||||||
$this->channelId = $channelId;
|
$this->channelId = $channelId;
|
||||||
}
|
}
|
||||||
|
public function loop(): \Generator
|
||||||
public function loop()
|
|
||||||
{
|
{
|
||||||
$API = $this->API;
|
$API = $this->API;
|
||||||
$this->updater = $API->updaters[$this->channelId];
|
$this->updater = $API->updaters[$this->channelId];
|
||||||
|
|
||||||
if (!$this->API->settings['updates']['handle_updates']) {
|
if (!$this->API->settings['updates']['handle_updates']) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!$this->API->settings['updates']['handle_updates'] || !$API->hasAllAuth()) {
|
while (!$this->API->settings['updates']['handle_updates'] || !$API->hasAllAuth()) {
|
||||||
if (yield $this->waitSignal($this->pause())) {
|
if (yield $this->waitSignal($this->pause())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->state = $this->channelId === false ? (yield $API->loadUpdateState()) : $API->loadChannelState($this->channelId);
|
$this->state = $this->channelId === false ? yield $API->loadUpdateState() : $API->loadChannelState($this->channelId);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
while (!$this->API->settings['updates']['handle_updates'] || !$API->hasAllAuth()) {
|
while (!$this->API->settings['updates']['handle_updates'] || !$API->hasAllAuth()) {
|
||||||
if (yield $this->waitSignal($this->pause())) {
|
if (yield $this->waitSignal($this->pause())) {
|
||||||
@ -73,11 +69,11 @@ class FeedLoop extends ResumableSignalLoop
|
|||||||
if (!$this->API->settings['updates']['handle_updates']) {
|
if (!$this->API->settings['updates']['handle_updates']) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$API->logger->logger("Resumed $this");
|
$API->logger->logger("Resumed {$this}");
|
||||||
while ($this->incomingUpdates) {
|
while ($this->incomingUpdates) {
|
||||||
$updates = $this->incomingUpdates;
|
$updates = $this->incomingUpdates;
|
||||||
$this->incomingUpdates = [];
|
$this->incomingUpdates = [];
|
||||||
yield $this->parse($updates);
|
yield from $this->parse($updates);
|
||||||
$updates = null;
|
$updates = null;
|
||||||
}
|
}
|
||||||
while ($this->parsedUpdates) {
|
while ($this->parsedUpdates) {
|
||||||
@ -91,8 +87,7 @@ class FeedLoop extends ResumableSignalLoop
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public function parse($updates): \Generator
|
||||||
public function parse($updates)
|
|
||||||
{
|
{
|
||||||
\reset($updates);
|
\reset($updates);
|
||||||
while ($updates) {
|
while ($updates) {
|
||||||
@ -102,7 +97,6 @@ class FeedLoop extends ResumableSignalLoop
|
|||||||
if ($update['_'] === 'updateChannelTooLong') {
|
if ($update['_'] === 'updateChannelTooLong') {
|
||||||
$this->API->logger->logger('Got channel too long update, getting difference...', \danog\MadelineProto\Logger::VERBOSE);
|
$this->API->logger->logger('Got channel too long update, getting difference...', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
yield $this->updater->resume();
|
yield $this->updater->resume();
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (isset($update['pts'], $update['pts_count'])) {
|
if (isset($update['pts'], $update['pts_count'])) {
|
||||||
@ -111,12 +105,11 @@ class FeedLoop extends ResumableSignalLoop
|
|||||||
$mid = isset($update['message']['id']) ? $update['message']['id'] : '-';
|
$mid = isset($update['message']['id']) ? $update['message']['id'] : '-';
|
||||||
$mypts = $this->state->pts();
|
$mypts = $this->state->pts();
|
||||||
$computed = $mypts + $pts_count;
|
$computed = $mypts + $pts_count;
|
||||||
$this->API->logger->logger("$msg. My pts: {$mypts}, remote pts: {$update['pts']}, computed pts: $computed, msg id: {$mid}, channel id: {$this->channelId}", \danog\MadelineProto\Logger::ERROR);
|
$this->API->logger->logger("{$msg}. My pts: {$mypts}, remote pts: {$update['pts']}, computed pts: {$computed}, msg id: {$mid}, channel id: {$this->channelId}", \danog\MadelineProto\Logger::ERROR);
|
||||||
};
|
};
|
||||||
$result = $this->state->checkPts($update);
|
$result = $this->state->checkPts($update);
|
||||||
if ($result < 0) {
|
if ($result < 0) {
|
||||||
$logger('PTS duplicate');
|
$logger('PTS duplicate');
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($result > 0) {
|
if ($result > 0) {
|
||||||
@ -130,19 +123,16 @@ class FeedLoop extends ResumableSignalLoop
|
|||||||
if (isset($update['message']['id'], $update['message']['to_id']) && !\in_array($update['_'], ['updateEditMessage', 'updateEditChannelMessage', 'updateMessageID'])) {
|
if (isset($update['message']['id'], $update['message']['to_id']) && !\in_array($update['_'], ['updateEditMessage', 'updateEditChannelMessage', 'updateMessageID'])) {
|
||||||
if (!$this->API->checkMsgId($update['message'])) {
|
if (!$this->API->checkMsgId($update['message'])) {
|
||||||
$logger('MSGID duplicate');
|
$logger('MSGID duplicate');
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$logger('PTS OK');
|
$logger('PTS OK');
|
||||||
|
|
||||||
$this->state->pts($update['pts']);
|
$this->state->pts($update['pts']);
|
||||||
}
|
}
|
||||||
$this->save($update);
|
$this->save($update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public function feed($updates): \Generator
|
||||||
public function feed($updates)
|
|
||||||
{
|
{
|
||||||
$result = [];
|
$result = [];
|
||||||
foreach ($updates as $update) {
|
foreach ($updates as $update) {
|
||||||
@ -152,11 +142,9 @@ class FeedLoop extends ResumableSignalLoop
|
|||||||
}
|
}
|
||||||
$result[$res] = true;
|
$result[$res] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
public function feedSingle($update): \Generator
|
||||||
public function feedSingle($update)
|
|
||||||
{
|
{
|
||||||
$channelId = false;
|
$channelId = false;
|
||||||
switch ($update['_']) {
|
switch ($update['_']) {
|
||||||
@ -178,7 +166,6 @@ class FeedLoop extends ResumableSignalLoop
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($channelId && !$this->API->getChannelStates()->has($channelId)) {
|
if ($channelId && !$this->API->getChannelStates()->has($channelId)) {
|
||||||
$this->API->loadChannelState($channelId, $update);
|
$this->API->loadChannelState($channelId, $update);
|
||||||
if (!isset($this->API->feeders[$channelId])) {
|
if (!isset($this->API->feeders[$channelId])) {
|
||||||
@ -190,7 +177,6 @@ class FeedLoop extends ResumableSignalLoop
|
|||||||
$this->API->feeders[$channelId]->start();
|
$this->API->feeders[$channelId]->start();
|
||||||
$this->API->updaters[$channelId]->start();
|
$this->API->updaters[$channelId]->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ($update['_']) {
|
switch ($update['_']) {
|
||||||
case 'updateNewMessage':
|
case 'updateNewMessage':
|
||||||
case 'updateEditMessage':
|
case 'updateEditMessage':
|
||||||
@ -200,31 +186,21 @@ class FeedLoop extends ResumableSignalLoop
|
|||||||
$from = false;
|
$from = false;
|
||||||
$via_bot = false;
|
$via_bot = false;
|
||||||
$entities = false;
|
$entities = false;
|
||||||
if ($update['message']['_'] !== 'messageEmpty' && (
|
if ($update['message']['_'] !== 'messageEmpty' && (($from = isset($update['message']['from_id']) && !yield $this->API->peerIsset($update['message']['from_id'])) || ($to = !yield $this->API->peerIsset($update['message']['to_id'])) || ($via_bot = isset($update['message']['via_bot_id']) && !yield $this->API->peerIsset($update['message']['via_bot_id'])) || ($entities = isset($update['message']['entities']) && !yield $this->API->entitiesPeerIsset($update['message']['entities'])))) {
|
||||||
($from = isset($update['message']['from_id']) && !yield $this->API->peerIsset($update['message']['from_id'])) ||
|
|
||||||
($to = !yield $this->API->peerIsset($update['message']['to_id'])) ||
|
|
||||||
($via_bot = isset($update['message']['via_bot_id']) && !yield $this->API->peerIsset($update['message']['via_bot_id'])) ||
|
|
||||||
($entities = isset($update['message']['entities']) && !yield $this->API->entitiesPeerIsset($update['message']['entities'])) // ||
|
|
||||||
//isset($update['message']['fwd_from']) && !yield $this->fwdPeerIsset($update['message']['fwd_from'])
|
|
||||||
)) {
|
|
||||||
$log = '';
|
$log = '';
|
||||||
if ($from) {
|
if ($from) {
|
||||||
$log .= "from_id {$update['message']['from_id']}, ";
|
$log .= "from_id {$update['message']['from_id']}, ";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($to) {
|
if ($to) {
|
||||||
$log .= 'to_id '.\json_encode($update['message']['to_id']).', ';
|
$log .= 'to_id ' . \json_encode($update['message']['to_id']) . ', ';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($via_bot) {
|
if ($via_bot) {
|
||||||
$log .= "via_bot {$update['message']['via_bot_id']}, ";
|
$log .= "via_bot {$update['message']['via_bot_id']}, ";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($entities) {
|
if ($entities) {
|
||||||
$log .= 'entities '.\json_encode($update['message']['entities']).', ';
|
$log .= 'entities ' . \json_encode($update['message']['entities']) . ', ';
|
||||||
}
|
}
|
||||||
|
$this->API->logger->logger("Not enough data: for message update {$log}, getting difference...", \danog\MadelineProto\Logger::VERBOSE);
|
||||||
$this->API->logger->logger("Not enough data: for message update $log, getting difference...", \danog\MadelineProto\Logger::VERBOSE);
|
|
||||||
$update = ['_' => 'updateChannelTooLong'];
|
$update = ['_' => 'updateChannelTooLong'];
|
||||||
if ($channelId && $to) {
|
if ($channelId && $to) {
|
||||||
$channelId = false;
|
$channelId = false;
|
||||||
@ -233,47 +209,39 @@ class FeedLoop extends ResumableSignalLoop
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if ($channelId && !yield $this->API->peerIsset($this->API->toSupergroup($channelId))) {
|
if ($channelId && !yield $this->API->peerIsset($this->API->toSupergroup($channelId))) {
|
||||||
$this->API->logger->logger('Skipping update, I do not have the channel id '.$channelId, \danog\MadelineProto\Logger::ERROR);
|
$this->API->logger->logger('Skipping update, I do not have the channel id ' . $channelId, \danog\MadelineProto\Logger::ERROR);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ($channelId !== $this->channelId) {
|
if ($channelId !== $this->channelId) {
|
||||||
if (isset($this->API->feeders[$channelId])) {
|
if (isset($this->API->feeders[$channelId])) {
|
||||||
return yield $this->API->feeders[$channelId]->feedSingle($update);
|
return yield from $this->API->feeders[$channelId]->feedSingle($update);
|
||||||
} elseif ($this->channelId) {
|
} elseif ($this->channelId) {
|
||||||
return yield $this->API->feeders[false]->feedSingle($update);
|
return yield from $this->API->feeders[false]->feedSingle($update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$this->API->logger->logger('Was fed an update of type ' . $update['_'] . " in {$this}...", \danog\MadelineProto\Logger::VERBOSE);
|
||||||
$this->API->logger->logger('Was fed an update of type '.$update['_']." in $this...", \danog\MadelineProto\Logger::VERBOSE);
|
|
||||||
$this->incomingUpdates[] = $update;
|
$this->incomingUpdates[] = $update;
|
||||||
|
|
||||||
return $this->channelId;
|
return $this->channelId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function save($update)
|
public function save($update)
|
||||||
{
|
{
|
||||||
$this->parsedUpdates[] = $update;
|
$this->parsedUpdates[] = $update;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function saveMessages($messages)
|
public function saveMessages($messages)
|
||||||
{
|
{
|
||||||
foreach ($messages as $message) {
|
foreach ($messages as $message) {
|
||||||
if (!$this->API->checkMsgId($message)) {
|
if (!$this->API->checkMsgId($message)) {
|
||||||
$this->API->logger->logger("MSGID duplicate ({$message['id']}) in $this");
|
$this->API->logger->logger("MSGID duplicate ({$message['id']}) in {$this}");
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($message['_'] !== 'messageEmpty') {
|
if ($message['_'] !== 'messageEmpty') {
|
||||||
$this->API->logger->logger('Getdiff fed me message of type '.$message['_']." in $this...", \danog\MadelineProto\Logger::VERBOSE);
|
$this->API->logger->logger('Getdiff fed me message of type ' . $message['_'] . " in {$this}...", \danog\MadelineProto\Logger::VERBOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->parsedUpdates[] = ['_' => $this->channelId === false ? 'updateNewMessage' : 'updateNewChannelMessage', 'message' => $message, 'pts' => -1, 'pts_count' => -1];
|
$this->parsedUpdates[] = ['_' => $this->channelId === false ? 'updateNewMessage' : 'updateNewChannelMessage', 'message' => $message, 'pts' => -1, 'pts_count' => -1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __toString(): string
|
public function __toString(): string
|
||||||
{
|
{
|
||||||
return !$this->channelId ? 'update feed loop generic' : "update feed loop channel {$this->channelId}";
|
return !$this->channelId ? 'update feed loop generic' : "update feed loop channel {$this->channelId}";
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update feeder loop.
|
* Update feeder loop.
|
||||||
*
|
*
|
||||||
@ -31,28 +32,23 @@ class SeqLoop extends ResumableSignalLoop
|
|||||||
private $incomingUpdates = [];
|
private $incomingUpdates = [];
|
||||||
private $feeder;
|
private $feeder;
|
||||||
private $pendingWakeups = [];
|
private $pendingWakeups = [];
|
||||||
|
|
||||||
public function __construct($API)
|
public function __construct($API)
|
||||||
{
|
{
|
||||||
$this->API = $API;
|
$this->API = $API;
|
||||||
}
|
}
|
||||||
|
public function loop(): \Generator
|
||||||
public function loop()
|
|
||||||
{
|
{
|
||||||
$API = $this->API;
|
$API = $this->API;
|
||||||
$this->feeder = $API->feeders[false];
|
$this->feeder = $API->feeders[false];
|
||||||
|
|
||||||
if (!$this->API->settings['updates']['handle_updates']) {
|
if (!$this->API->settings['updates']['handle_updates']) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!$this->API->settings['updates']['handle_updates'] || !$API->hasAllAuth()) {
|
while (!$this->API->settings['updates']['handle_updates'] || !$API->hasAllAuth()) {
|
||||||
if (yield $this->waitSignal($this->pause())) {
|
if (yield $this->waitSignal($this->pause())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->state = yield $API->loadUpdateState();
|
$this->state = yield $API->loadUpdateState();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
while (!$this->API->settings['updates']['handle_updates'] || !$API->hasAllAuth()) {
|
while (!$this->API->settings['updates']['handle_updates'] || !$API->hasAllAuth()) {
|
||||||
if (yield $this->waitSignal($this->pause())) {
|
if (yield $this->waitSignal($this->pause())) {
|
||||||
@ -68,7 +64,7 @@ class SeqLoop extends ResumableSignalLoop
|
|||||||
while ($this->incomingUpdates) {
|
while ($this->incomingUpdates) {
|
||||||
$updates = $this->incomingUpdates;
|
$updates = $this->incomingUpdates;
|
||||||
$this->incomingUpdates = [];
|
$this->incomingUpdates = [];
|
||||||
yield $this->parse($updates);
|
yield from $this->parse($updates);
|
||||||
$updates = null;
|
$updates = null;
|
||||||
}
|
}
|
||||||
while ($this->pendingWakeups) {
|
while ($this->pendingWakeups) {
|
||||||
@ -79,8 +75,7 @@ class SeqLoop extends ResumableSignalLoop
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public function parse($updates): \Generator
|
||||||
public function parse($updates)
|
|
||||||
{
|
{
|
||||||
\reset($updates);
|
\reset($updates);
|
||||||
while ($updates) {
|
while ($updates) {
|
||||||
@ -88,53 +83,43 @@ class SeqLoop extends ResumableSignalLoop
|
|||||||
$key = \key($updates);
|
$key = \key($updates);
|
||||||
$update = $updates[$key];
|
$update = $updates[$key];
|
||||||
unset($updates[$key]);
|
unset($updates[$key]);
|
||||||
|
|
||||||
$options = $update['options'];
|
$options = $update['options'];
|
||||||
$seq_start = $options['seq_start'];
|
$seq_start = $options['seq_start'];
|
||||||
$seq_end = $options['seq_end'];
|
$seq_end = $options['seq_end'];
|
||||||
|
|
||||||
$result = $this->state->checkSeq($seq_start);
|
$result = $this->state->checkSeq($seq_start);
|
||||||
if ($result > 0) {
|
if ($result > 0) {
|
||||||
$this->API->logger->logger('Seq hole. seq_start: '.$seq_start.' != cur seq: '.($this->state->seq() + 1), \danog\MadelineProto\Logger::ERROR);
|
$this->API->logger->logger('Seq hole. seq_start: ' . $seq_start . ' != cur seq: ' . ($this->state->seq() + 1), \danog\MadelineProto\Logger::ERROR);
|
||||||
yield $this->pause(1.0);
|
yield $this->pause(1.0);
|
||||||
if (!$this->incomingUpdates) {
|
if (!$this->incomingUpdates) {
|
||||||
yield $this->API->updaters[false]->resume();
|
yield $this->API->updaters[false]->resume();
|
||||||
}
|
}
|
||||||
$this->incomingUpdates = \array_merge($this->incomingUpdates, [$update], $updates);
|
$this->incomingUpdates = \array_merge($this->incomingUpdates, [$update], $updates);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($result < 0) {
|
if ($result < 0) {
|
||||||
$this->API->logger->logger('Seq too old. seq_start: '.$seq_start.' != cur seq: '.($this->state->seq() + 1), \danog\MadelineProto\Logger::ERROR);
|
$this->API->logger->logger('Seq too old. seq_start: ' . $seq_start . ' != cur seq: ' . ($this->state->seq() + 1), \danog\MadelineProto\Logger::ERROR);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$this->state->seq($seq_end);
|
$this->state->seq($seq_end);
|
||||||
if (isset($options['date'])) {
|
if (isset($options['date'])) {
|
||||||
$this->state->date($options['date']);
|
$this->state->date($options['date']);
|
||||||
}
|
}
|
||||||
|
yield from $this->save($update);
|
||||||
yield $this->save($update);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function feed($updates)
|
public function feed($updates)
|
||||||
{
|
{
|
||||||
$this->API->logger->logger('Was fed updates of type '.$updates['_'].'...', \danog\MadelineProto\Logger::VERBOSE);
|
$this->API->logger->logger('Was fed updates of type ' . $updates['_'] . '...', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
|
|
||||||
$this->incomingUpdates[] = $updates;
|
$this->incomingUpdates[] = $updates;
|
||||||
}
|
}
|
||||||
|
public function save($updates): \Generator
|
||||||
public function save($updates)
|
|
||||||
{
|
{
|
||||||
$this->pendingWakeups += yield $this->feeder->feed($updates['updates']);
|
$this->pendingWakeups += yield $this->feeder->feed($updates['updates']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addPendingWakeups($wakeups)
|
public function addPendingWakeups($wakeups)
|
||||||
{
|
{
|
||||||
$this->pendingWakeups += $wakeups;
|
$this->pendingWakeups += $wakeups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function __toString(): string
|
public function __toString(): string
|
||||||
{
|
{
|
||||||
return 'update seq loop';
|
return 'update seq loop';
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update loop.
|
* Update loop.
|
||||||
*
|
*
|
||||||
@ -31,38 +32,31 @@ use danog\MadelineProto\RPCErrorException;
|
|||||||
class UpdateLoop extends ResumableSignalLoop
|
class UpdateLoop extends ResumableSignalLoop
|
||||||
{
|
{
|
||||||
use \danog\MadelineProto\Tools;
|
use \danog\MadelineProto\Tools;
|
||||||
|
|
||||||
private $toPts;
|
private $toPts;
|
||||||
private $channelId;
|
private $channelId;
|
||||||
private $feeder;
|
private $feeder;
|
||||||
|
|
||||||
public function __construct($API, $channelId)
|
public function __construct($API, $channelId)
|
||||||
{
|
{
|
||||||
$this->API = $API;
|
$this->API = $API;
|
||||||
$this->channelId = $channelId;
|
$this->channelId = $channelId;
|
||||||
}
|
}
|
||||||
|
public function loop(): \Generator
|
||||||
public function loop()
|
|
||||||
{
|
{
|
||||||
$API = $this->API;
|
$API = $this->API;
|
||||||
$feeder = $this->feeder = $API->feeders[$this->channelId];
|
$feeder = $this->feeder = $API->feeders[$this->channelId];
|
||||||
|
|
||||||
while (!$API->settings['updates']['handle_updates'] || !$API->hasAllAuth()) {
|
while (!$API->settings['updates']['handle_updates'] || !$API->hasAllAuth()) {
|
||||||
if (yield $this->waitSignal($this->pause())) {
|
if (yield $this->waitSignal($this->pause())) {
|
||||||
$API->logger->logger("Exiting $this due to signal");
|
$API->logger->logger("Exiting {$this} due to signal");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->state = $state = $this->channelId === false ? (yield $API->loadUpdateState()) : $API->loadChannelState($this->channelId);
|
$this->state = $state = $this->channelId === false ? yield $API->loadUpdateState() : $API->loadChannelState($this->channelId);
|
||||||
|
|
||||||
$timeout = $API->settings['updates']['getdifference_interval'];
|
$timeout = $API->settings['updates']['getdifference_interval'];
|
||||||
$first = true;
|
$first = true;
|
||||||
while (true) {
|
while (true) {
|
||||||
while (!$API->settings['updates']['handle_updates'] || !$API->hasAllAuth()) {
|
while (!$API->settings['updates']['handle_updates'] || !$API->hasAllAuth()) {
|
||||||
if (yield $this->waitSignal($this->pause())) {
|
if (yield $this->waitSignal($this->pause())) {
|
||||||
$API->logger->logger("Exiting $this due to signal");
|
$API->logger->logger("Exiting {$this} due to signal");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,7 +65,7 @@ class UpdateLoop extends ResumableSignalLoop
|
|||||||
$this->toPts = null;
|
$this->toPts = null;
|
||||||
while (true) {
|
while (true) {
|
||||||
if ($this->channelId) {
|
if ($this->channelId) {
|
||||||
$API->logger->logger('Resumed and fetching '.$this->channelId.' difference...', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$API->logger->logger('Resumed and fetching ' . $this->channelId . ' difference...', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
if ($state->pts() <= 1) {
|
if ($state->pts() <= 1) {
|
||||||
$limit = 10;
|
$limit = 10;
|
||||||
} elseif ($API->authorization['user']['bot']) {
|
} elseif ($API->authorization['user']['bot']) {
|
||||||
@ -80,17 +74,14 @@ class UpdateLoop extends ResumableSignalLoop
|
|||||||
$limit = 100;
|
$limit = 100;
|
||||||
}
|
}
|
||||||
$request_pts = $state->pts();
|
$request_pts = $state->pts();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$difference = yield $API->methodCallAsyncRead('updates.getChannelDifference', ['channel' => 'channel#'.$this->channelId, 'filter' => ['_' => 'channelMessagesFilterEmpty'], 'pts' => $request_pts, 'limit' => $limit, 'force' => true], ['datacenter' => $API->datacenter->curdc, 'postpone' => $first]);
|
$difference = yield $API->methodCallAsyncRead('updates.getChannelDifference', ['channel' => 'channel#' . $this->channelId, 'filter' => ['_' => 'channelMessagesFilterEmpty'], 'pts' => $request_pts, 'limit' => $limit, 'force' => true], ['datacenter' => $API->datacenter->curdc, 'postpone' => $first]);
|
||||||
} catch (RPCErrorException $e) {
|
} catch (RPCErrorException $e) {
|
||||||
if (\in_array($e->rpc, ['CHANNEL_PRIVATE', 'CHAT_FORBIDDEN', 'CHANNEL_INVALID'])) {
|
if (\in_array($e->rpc, ['CHANNEL_PRIVATE', 'CHAT_FORBIDDEN', 'CHANNEL_INVALID'])) {
|
||||||
$feeder->signal(true);
|
$feeder->signal(true);
|
||||||
unset($API->updaters[$this->channelId], $API->feeders[$this->channelId]);
|
unset($API->updaters[$this->channelId], $API->feeders[$this->channelId]);
|
||||||
|
|
||||||
$API->getChannelStates()->remove($this->channelId);
|
$API->getChannelStates()->remove($this->channelId);
|
||||||
$API->logger->logger("Channel private, exiting $this");
|
$API->logger->logger("Channel private, exiting {$this}");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
throw $e;
|
throw $e;
|
||||||
@ -99,9 +90,7 @@ class UpdateLoop extends ResumableSignalLoop
|
|||||||
$feeder->signal(true);
|
$feeder->signal(true);
|
||||||
$API->getChannelStates()->remove($this->channelId);
|
$API->getChannelStates()->remove($this->channelId);
|
||||||
unset($API->updaters[$this->channelId], $API->feeders[$this->channelId]);
|
unset($API->updaters[$this->channelId], $API->feeders[$this->channelId]);
|
||||||
|
$API->logger->logger("Channel private, exiting {$this}");
|
||||||
$API->logger->logger("Channel private, exiting $this");
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
throw $e;
|
throw $e;
|
||||||
@ -109,8 +98,7 @@ class UpdateLoop extends ResumableSignalLoop
|
|||||||
if (isset($difference['timeout'])) {
|
if (isset($difference['timeout'])) {
|
||||||
$timeout = $difference['timeout'];
|
$timeout = $difference['timeout'];
|
||||||
}
|
}
|
||||||
|
$API->logger->logger('Got ' . $difference['_'], \danog\MadelineProto\Logger::VERBOSE);
|
||||||
$API->logger->logger('Got '.$difference['_'], \danog\MadelineProto\Logger::VERBOSE);
|
|
||||||
switch ($difference['_']) {
|
switch ($difference['_']) {
|
||||||
case 'updates.channelDifferenceEmpty':
|
case 'updates.channelDifferenceEmpty':
|
||||||
$state->update($difference);
|
$state->update($difference);
|
||||||
@ -118,12 +106,11 @@ class UpdateLoop extends ResumableSignalLoop
|
|||||||
break 2;
|
break 2;
|
||||||
case 'updates.channelDifference':
|
case 'updates.channelDifference':
|
||||||
if ($request_pts >= $difference['pts'] && $request_pts > 1) {
|
if ($request_pts >= $difference['pts'] && $request_pts > 1) {
|
||||||
$API->logger->logger("The PTS ({$difference['pts']}) I got with getDifference is smaller than the PTS I requested ".$state->pts().', using '.($state->pts() + 1), \danog\MadelineProto\Logger::VERBOSE);
|
$API->logger->logger("The PTS ({$difference['pts']}) I got with getDifference is smaller than the PTS I requested " . $state->pts() . ', using ' . ($state->pts() + 1), \danog\MadelineProto\Logger::VERBOSE);
|
||||||
$difference['pts'] = $request_pts + 1;
|
$difference['pts'] = $request_pts + 1;
|
||||||
}
|
}
|
||||||
$result += yield $feeder->feed($difference['other_updates']);
|
$result += yield $feeder->feed($difference['other_updates']);
|
||||||
$state->update($difference);
|
$state->update($difference);
|
||||||
|
|
||||||
$feeder->saveMessages($difference['new_messages']);
|
$feeder->saveMessages($difference['new_messages']);
|
||||||
if (!$difference['final']) {
|
if (!$difference['final']) {
|
||||||
if ($difference['pts'] >= $toPts) {
|
if ($difference['pts'] >= $toPts) {
|
||||||
@ -144,13 +131,12 @@ class UpdateLoop extends ResumableSignalLoop
|
|||||||
unset($difference);
|
unset($difference);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new \danog\MadelineProto\Exception('Unrecognized update difference received: '.\var_export($difference, true));
|
throw new \danog\MadelineProto\Exception('Unrecognized update difference received: ' . \var_export($difference, true));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$API->logger->logger('Resumed and fetching normal difference...', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$API->logger->logger('Resumed and fetching normal difference...', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
|
|
||||||
$difference = yield $API->methodCallAsyncRead('updates.getDifference', ['pts' => $state->pts(), 'date' => $state->date(), 'qts' => $state->qts()], ['datacenter' => $API->settings['connection_settings']['default_dc']]);
|
$difference = yield $API->methodCallAsyncRead('updates.getDifference', ['pts' => $state->pts(), 'date' => $state->date(), 'qts' => $state->qts()], ['datacenter' => $API->settings['connection_settings']['default_dc']]);
|
||||||
$API->logger->logger('Got '.$difference['_'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$API->logger->logger('Got ' . $difference['_'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
switch ($difference['_']) {
|
switch ($difference['_']) {
|
||||||
case 'updates.differenceEmpty':
|
case 'updates.differenceEmpty':
|
||||||
$state->update($difference);
|
$state->update($difference);
|
||||||
@ -187,32 +173,28 @@ class UpdateLoop extends ResumableSignalLoop
|
|||||||
unset($difference);
|
unset($difference);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new \danog\MadelineProto\Exception('Unrecognized update difference received: '.\var_export($difference, true));
|
throw new \danog\MadelineProto\Exception('Unrecognized update difference received: ' . \var_export($difference, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$API->logger->logger("Finished parsing updates in $this, now resuming feeders");
|
$API->logger->logger("Finished parsing updates in {$this}, now resuming feeders");
|
||||||
foreach ($result as $channelId => $boh) {
|
foreach ($result as $channelId => $boh) {
|
||||||
$API->feeders[$channelId]->resumeDefer();
|
$API->feeders[$channelId]->resumeDefer();
|
||||||
}
|
}
|
||||||
$API->logger->logger("Finished resuming feeders in $this, signaling updates");
|
$API->logger->logger("Finished resuming feeders in {$this}, signaling updates");
|
||||||
$API->signalUpdate();
|
$API->signalUpdate();
|
||||||
$API->logger->logger("Finished signaling updates in $this, pausing");
|
$API->logger->logger("Finished signaling updates in {$this}, pausing");
|
||||||
$first = false;
|
$first = false;
|
||||||
|
|
||||||
if (yield $this->waitSignal($this->pause($timeout))) {
|
if (yield $this->waitSignal($this->pause($timeout))) {
|
||||||
$API->logger->logger("Exiting $this due to signal");
|
$API->logger->logger("Exiting {$this} due to signal");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setLimit($toPts)
|
public function setLimit($toPts)
|
||||||
{
|
{
|
||||||
$this->toPts = $toPts;
|
$this->toPts = $toPts;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __toString(): string
|
public function __toString(): string
|
||||||
{
|
{
|
||||||
return !$this->channelId ? 'getUpdate loop generic' : "getUpdate loop channel {$this->channelId}";
|
return !$this->channelId ? 'getUpdate loop generic' : "getUpdate loop channel {$this->channelId}";
|
||||||
|
@ -25,7 +25,6 @@ class Lua
|
|||||||
public $MadelineProto;
|
public $MadelineProto;
|
||||||
protected $Lua;
|
protected $Lua;
|
||||||
protected $script;
|
protected $script;
|
||||||
|
|
||||||
public function __magic_construct($script, $MadelineProto)
|
public function __magic_construct($script, $MadelineProto)
|
||||||
{
|
{
|
||||||
if (!\file_exists($script)) {
|
if (!\file_exists($script)) {
|
||||||
@ -34,16 +33,13 @@ class Lua
|
|||||||
$this->MadelineProto = $MadelineProto;
|
$this->MadelineProto = $MadelineProto;
|
||||||
$this->MadelineProto->settings['updates']['handle_updates'] = true;
|
$this->MadelineProto->settings['updates']['handle_updates'] = true;
|
||||||
$this->MadelineProto->API->datacenter->sockets[$this->MadelineProto->settings['connection_settings']['default_dc']]->startUpdateLoop();
|
$this->MadelineProto->API->datacenter->sockets[$this->MadelineProto->settings['connection_settings']['default_dc']]->startUpdateLoop();
|
||||||
|
|
||||||
$this->script = $script;
|
$this->script = $script;
|
||||||
$this->__wakeup();
|
$this->__wakeup();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __sleep()
|
public function __sleep()
|
||||||
{
|
{
|
||||||
return ['MadelineProto', 'script'];
|
return ['MadelineProto', 'script'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __wakeup()
|
public function __wakeup()
|
||||||
{
|
{
|
||||||
$this->Lua = new \Lua($this->script);
|
$this->Lua = new \Lua($this->script);
|
||||||
@ -77,7 +73,6 @@ class Lua
|
|||||||
$this->MadelineProto->{$namespace}->lua = true;
|
$this->MadelineProto->{$namespace}->lua = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function tdcliFunction($params, $cb = null, $cb_extra = null)
|
public function tdcliFunction($params, $cb = null, $cb_extra = null)
|
||||||
{
|
{
|
||||||
$params = $this->MadelineProto->td_to_mtproto($this->MadelineProto->tdcliToTd($params));
|
$params = $this->MadelineProto->td_to_mtproto($this->MadelineProto->tdcliToTd($params));
|
||||||
@ -88,10 +83,8 @@ class Lua
|
|||||||
if (\is_callable($cb)) {
|
if (\is_callable($cb)) {
|
||||||
$cb($this->MadelineProto->mtproto_to_td($result), $cb_extra);
|
$cb($this->MadelineProto->mtproto_to_td($result), $cb_extra);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function madelineFunction($params, $cb = null, $cb_extra = null)
|
public function madelineFunction($params, $cb = null, $cb_extra = null)
|
||||||
{
|
{
|
||||||
$result = $this->MadelineProto->API->methodCall($params['_'], $params, ['datacenter' => $this->MadelineProto->API->datacenter->curdc]);
|
$result = $this->MadelineProto->API->methodCall($params['_'], $params, ['datacenter' => $this->MadelineProto->API->datacenter->curdc]);
|
||||||
@ -99,15 +92,12 @@ class Lua
|
|||||||
$cb($result, $cb_extra);
|
$cb($result, $cb_extra);
|
||||||
}
|
}
|
||||||
self::convertObjects($result);
|
self::convertObjects($result);
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function tdcliUpdateCallback($update)
|
public function tdcliUpdateCallback($update)
|
||||||
{
|
{
|
||||||
$this->Lua->tdcliUpdateCallback($this->MadelineProto->mtproto_to_tdcli($update));
|
$this->Lua->tdcliUpdateCallback($this->MadelineProto->mtproto_to_tdcli($update));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function convertArray($array)
|
private function convertArray($array)
|
||||||
{
|
{
|
||||||
if (!\is_array($array)) {
|
if (!\is_array($array)) {
|
||||||
@ -119,29 +109,23 @@ class Lua
|
|||||||
}, \array_flip($array)));
|
}, \array_flip($array)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function isSequential(array $arr)
|
private function isSequential(array $arr)
|
||||||
{
|
{
|
||||||
if ([] === $arr) {
|
if ([] === $arr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return isset($arr[0]) && \array_keys($arr) === \range(0, \count($arr) - 1);
|
return isset($arr[0]) && \array_keys($arr) === \range(0, \count($arr) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __get($name)
|
public function __get($name)
|
||||||
{
|
{
|
||||||
if ($name === 'API') {
|
if ($name === 'API') {
|
||||||
return $this->MadelineProto->API;
|
return $this->MadelineProto->API;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->Lua->{$name};
|
return $this->Lua->{$name};
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __call($name, $params)
|
public function __call($name, $params)
|
||||||
{
|
{
|
||||||
self::convertObjects($params);
|
self::convertObjects($params);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return $this->Lua->{$name}(...$params);
|
return $this->Lua->{$name}(...$params);
|
||||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||||
@ -160,12 +144,10 @@ class Lua
|
|||||||
return ['error_code' => $e->getCode(), 'error' => $e->getMessage()];
|
return ['error_code' => $e->getCode(), 'error' => $e->getMessage()];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __set($name, $value)
|
public function __set($name, $value)
|
||||||
{
|
{
|
||||||
return $this->Lua->{$name} = $value;
|
return $this->Lua->{$name} = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function convertObjects(&$data)
|
public static function convertObjects(&$data)
|
||||||
{
|
{
|
||||||
\array_walk_recursive($data, function (&$value, $key) {
|
\array_walk_recursive($data, function (&$value, $key) {
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MTProto Auth key.
|
* MTProto Auth key.
|
||||||
*
|
*
|
||||||
@ -43,7 +44,6 @@ abstract class AuthKey implements JsonSerializable
|
|||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $serverSalt;
|
protected $serverSalt;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor function.
|
* Constructor function.
|
||||||
*
|
*
|
||||||
@ -52,7 +52,7 @@ abstract class AuthKey implements JsonSerializable
|
|||||||
public function __construct(array $old = [])
|
public function __construct(array $old = [])
|
||||||
{
|
{
|
||||||
if (isset($old['auth_key'])) {
|
if (isset($old['auth_key'])) {
|
||||||
if (\strlen($old['auth_key']) !== 2048/8 && \strpos($old['authkey'], 'pony') === 0) {
|
if (\strlen($old['auth_key']) !== 2048 / 8 && \strpos($old['authkey'], 'pony') === 0) {
|
||||||
$old['auth_key'] = \base64_decode(\substr($old['auth_key'], 4));
|
$old['auth_key'] = \base64_decode(\substr($old['auth_key'], 4));
|
||||||
}
|
}
|
||||||
$this->setAuthKey($old['auth_key']);
|
$this->setAuthKey($old['auth_key']);
|
||||||
@ -61,8 +61,6 @@ abstract class AuthKey implements JsonSerializable
|
|||||||
$this->setServerSalt($old['server_salt']);
|
$this->setServerSalt($old['server_salt']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set auth key.
|
* Set auth key.
|
||||||
*
|
*
|
||||||
@ -75,7 +73,6 @@ abstract class AuthKey implements JsonSerializable
|
|||||||
$this->authKey = $authKey;
|
$this->authKey = $authKey;
|
||||||
$this->id = \substr(\sha1($authKey, true), -8);
|
$this->id = \substr(\sha1($authKey, true), -8);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if auth key is present.
|
* Check if auth key is present.
|
||||||
*
|
*
|
||||||
@ -85,7 +82,6 @@ abstract class AuthKey implements JsonSerializable
|
|||||||
{
|
{
|
||||||
return $this->authKey !== null;
|
return $this->authKey !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get auth key.
|
* Get auth key.
|
||||||
*
|
*
|
||||||
@ -95,7 +91,6 @@ abstract class AuthKey implements JsonSerializable
|
|||||||
{
|
{
|
||||||
return $this->authKey;
|
return $this->authKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get auth key ID.
|
* Get auth key ID.
|
||||||
*
|
*
|
||||||
@ -105,7 +100,6 @@ abstract class AuthKey implements JsonSerializable
|
|||||||
{
|
{
|
||||||
return $this->id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set server salt.
|
* Set server salt.
|
||||||
*
|
*
|
||||||
@ -117,7 +111,6 @@ abstract class AuthKey implements JsonSerializable
|
|||||||
{
|
{
|
||||||
$this->serverSalt = $salt;
|
$this->serverSalt = $salt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get server salt.
|
* Get server salt.
|
||||||
*
|
*
|
||||||
@ -127,7 +120,6 @@ abstract class AuthKey implements JsonSerializable
|
|||||||
{
|
{
|
||||||
return $this->serverSalt;
|
return $this->serverSalt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if has server salt.
|
* Check if has server salt.
|
||||||
*
|
*
|
||||||
@ -137,14 +129,12 @@ abstract class AuthKey implements JsonSerializable
|
|||||||
{
|
{
|
||||||
return $this->serverSalt !== null;
|
return $this->serverSalt !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if we are logged in.
|
* Check if we are logged in.
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
abstract public function isAuthorized(): bool;
|
abstract public function isAuthorized(): bool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the authorized boolean.
|
* Set the authorized boolean.
|
||||||
*
|
*
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MTProto permanent auth key.
|
* MTProto permanent auth key.
|
||||||
*
|
*
|
||||||
@ -29,7 +30,6 @@ class PermAuthKey extends AuthKey
|
|||||||
* @var boolean
|
* @var boolean
|
||||||
*/
|
*/
|
||||||
private $authorized = false;
|
private $authorized = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor function.
|
* Constructor function.
|
||||||
*
|
*
|
||||||
@ -51,7 +51,6 @@ class PermAuthKey extends AuthKey
|
|||||||
{
|
{
|
||||||
return $this->authorized;
|
return $this->authorized;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the authorized boolean.
|
* Set the authorized boolean.
|
||||||
*
|
*
|
||||||
@ -63,8 +62,6 @@ class PermAuthKey extends AuthKey
|
|||||||
{
|
{
|
||||||
$this->authorized = $authorized;
|
$this->authorized = $authorized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JSON serialization function.
|
* JSON serialization function.
|
||||||
*
|
*
|
||||||
@ -72,11 +69,7 @@ class PermAuthKey extends AuthKey
|
|||||||
*/
|
*/
|
||||||
public function jsonSerialize(): array
|
public function jsonSerialize(): array
|
||||||
{
|
{
|
||||||
return [
|
return ['auth_key' => 'pony' . \base64_encode($this->authKey), 'server_salt' => $this->serverSalt, 'authorized' => $this->authorized];
|
||||||
'auth_key' => 'pony'.\base64_encode($this->authKey),
|
|
||||||
'server_salt' => $this->serverSalt,
|
|
||||||
'authorized' => $this->authorized
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Sleep function.
|
* Sleep function.
|
||||||
@ -85,11 +78,6 @@ class PermAuthKey extends AuthKey
|
|||||||
*/
|
*/
|
||||||
public function __sleep()
|
public function __sleep()
|
||||||
{
|
{
|
||||||
return [
|
return ['authKey', 'id', 'serverSalt', 'authorized'];
|
||||||
'authKey',
|
|
||||||
'id',
|
|
||||||
'serverSalt',
|
|
||||||
'authorized'
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MTProto temporary auth key.
|
* MTProto temporary auth key.
|
||||||
*
|
*
|
||||||
@ -31,21 +32,18 @@ class TempAuthKey extends AuthKey implements JsonSerializable
|
|||||||
* @var PermAuthKey|null
|
* @var PermAuthKey|null
|
||||||
*/
|
*/
|
||||||
private $bound;
|
private $bound;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expiration date.
|
* Expiration date.
|
||||||
*
|
*
|
||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
private $expires = 0;
|
private $expires = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the connection is inited for this auth key.
|
* Whether the connection is inited for this auth key.
|
||||||
*
|
*
|
||||||
* @var boolean
|
* @var boolean
|
||||||
*/
|
*/
|
||||||
protected $inited = false;
|
protected $inited = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor function.
|
* Constructor function.
|
||||||
*
|
*
|
||||||
@ -61,7 +59,6 @@ class TempAuthKey extends AuthKey implements JsonSerializable
|
|||||||
$this->init($old['connection_inited']);
|
$this->init($old['connection_inited']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Init or deinit connection for auth key.
|
* Init or deinit connection for auth key.
|
||||||
*
|
*
|
||||||
@ -82,7 +79,6 @@ class TempAuthKey extends AuthKey implements JsonSerializable
|
|||||||
{
|
{
|
||||||
return $this->inited;
|
return $this->inited;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind auth key.
|
* Bind auth key.
|
||||||
*
|
*
|
||||||
@ -96,11 +92,10 @@ class TempAuthKey extends AuthKey implements JsonSerializable
|
|||||||
$this->bound = $bound;
|
$this->bound = $bound;
|
||||||
if (!$pfs) {
|
if (!$pfs) {
|
||||||
foreach (['authKey', 'id', 'serverSalt'] as $key) {
|
foreach (['authKey', 'id', 'serverSalt'] as $key) {
|
||||||
$this->{$key} = &$bound->{$key};
|
$this->{$key} =& $bound->{$key};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if auth key is bound.
|
* Check if auth key is bound.
|
||||||
*
|
*
|
||||||
@ -110,7 +105,6 @@ class TempAuthKey extends AuthKey implements JsonSerializable
|
|||||||
{
|
{
|
||||||
return $this->bound !== null;
|
return $this->bound !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if we are logged in.
|
* Check if we are logged in.
|
||||||
*
|
*
|
||||||
@ -120,7 +114,6 @@ class TempAuthKey extends AuthKey implements JsonSerializable
|
|||||||
{
|
{
|
||||||
return $this->bound ? $this->bound->isAuthorized() : false;
|
return $this->bound ? $this->bound->isAuthorized() : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the authorized boolean.
|
* Set the authorized boolean.
|
||||||
*
|
*
|
||||||
@ -132,7 +125,6 @@ class TempAuthKey extends AuthKey implements JsonSerializable
|
|||||||
{
|
{
|
||||||
$this->bound->authorized($authorized);
|
$this->bound->authorized($authorized);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set expiration date of temporary auth key.
|
* Set expiration date of temporary auth key.
|
||||||
*
|
*
|
||||||
@ -144,7 +136,6 @@ class TempAuthKey extends AuthKey implements JsonSerializable
|
|||||||
{
|
{
|
||||||
$this->expires = $expires;
|
$this->expires = $expires;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if auth key has expired.
|
* Check if auth key has expired.
|
||||||
*
|
*
|
||||||
@ -154,7 +145,6 @@ class TempAuthKey extends AuthKey implements JsonSerializable
|
|||||||
{
|
{
|
||||||
return \time() > $this->expires;
|
return \time() > $this->expires;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JSON serialization function.
|
* JSON serialization function.
|
||||||
*
|
*
|
||||||
@ -162,15 +152,8 @@ class TempAuthKey extends AuthKey implements JsonSerializable
|
|||||||
*/
|
*/
|
||||||
public function jsonSerialize(): array
|
public function jsonSerialize(): array
|
||||||
{
|
{
|
||||||
return [
|
return ['auth_key' => 'pony' . \base64_encode($this->authKey), 'server_salt' => $this->serverSalt, 'bound' => $this->isBound(), 'expires' => $this->expires, 'connection_inited' => $this->inited];
|
||||||
'auth_key' => 'pony'.\base64_encode($this->authKey),
|
|
||||||
'server_salt' => $this->serverSalt,
|
|
||||||
'bound' => $this->isBound(),
|
|
||||||
'expires' => $this->expires,
|
|
||||||
'connection_inited' => $this->inited
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sleep function.
|
* Sleep function.
|
||||||
*
|
*
|
||||||
@ -178,14 +161,7 @@ class TempAuthKey extends AuthKey implements JsonSerializable
|
|||||||
*/
|
*/
|
||||||
public function __sleep()
|
public function __sleep()
|
||||||
{
|
{
|
||||||
return [
|
return ['authKey', 'id', 'serverSalt', 'bound', 'expires', 'inited'];
|
||||||
'authKey',
|
|
||||||
'id',
|
|
||||||
'serverSalt',
|
|
||||||
'bound',
|
|
||||||
'expires',
|
|
||||||
'inited'
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Wakeup function.
|
* Wakeup function.
|
||||||
|
@ -28,31 +28,27 @@ trait AckHandler
|
|||||||
{
|
{
|
||||||
// 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])) {
|
||||||
$this->logger->logger("WARNING: Couldn't find message id ".$message_id.' in the array of outgoing messages. Maybe try to increase its size?', \danog\MadelineProto\Logger::WARNING);
|
$this->logger->logger("WARNING: Couldn't find message id " . $message_id . ' in the array of outgoing messages. Maybe try to increase its size?', \danog\MadelineProto\Logger::WARNING);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
//$this->logger->logger("Ack-ed ".$this->outgoing_messages[$message_id]['_']." with message ID $message_id on DC $datacenter");
|
//$this->logger->logger("Ack-ed ".$this->outgoing_messages[$message_id]['_']." with message ID $message_id on DC $datacenter");
|
||||||
/*
|
/*
|
||||||
if (isset($this->outgoing_messages[$message_id]['body'])) {
|
if (isset($this->outgoing_messages[$message_id]['body'])) {
|
||||||
unset($this->outgoing_messages[$message_id]['body']);
|
unset($this->outgoing_messages[$message_id]['body']);
|
||||||
}
|
}
|
||||||
if (isset($this->new_outgoing[$message_id])) {
|
if (isset($this->new_outgoing[$message_id])) {
|
||||||
unset($this->new_outgoing[$message_id]);
|
unset($this->new_outgoing[$message_id]);
|
||||||
}*/
|
}*/
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function gotResponseForOutgoingMessageId($message_id): bool
|
public function gotResponseForOutgoingMessageId($message_id): bool
|
||||||
{
|
{
|
||||||
// The server acknowledges that it received my message
|
// The server acknowledges that it received my message
|
||||||
if (isset($this->new_outgoing[$message_id])) {
|
if (isset($this->new_outgoing[$message_id])) {
|
||||||
unset($this->new_outgoing[$message_id]);
|
unset($this->new_outgoing[$message_id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($this->outgoing_messages[$message_id])) {
|
if (!isset($this->outgoing_messages[$message_id])) {
|
||||||
$this->logger->logger("WARNING: Couldn't find message id ".$message_id.' in the array of outgoing messages. Maybe try to increase its size?', \danog\MadelineProto\Logger::WARNING);
|
$this->logger->logger("WARNING: Couldn't find message id " . $message_id . ' in the array of outgoing messages. Maybe try to increase its size?', \danog\MadelineProto\Logger::WARNING);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (isset($this->outgoing_messages[$message_id]['body'])) {
|
if (isset($this->outgoing_messages[$message_id]['body'])) {
|
||||||
@ -61,28 +57,21 @@ trait AckHandler
|
|||||||
if (isset($this->outgoing_messages[$message_id]['serialized_body'])) {
|
if (isset($this->outgoing_messages[$message_id]['serialized_body'])) {
|
||||||
unset($this->outgoing_messages[$message_id]['serialized_body']);
|
unset($this->outgoing_messages[$message_id]['serialized_body']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function ackIncomingMessageId($message_id): bool
|
public function ackIncomingMessageId($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])) {
|
||||||
$this->logger->logger("WARNING: Couldn't find message id ".$message_id.' in the array of incoming messages. Maybe try to increase its size?', \danog\MadelineProto\Logger::WARNING);
|
$this->logger->logger("WARNING: Couldn't find message id " . $message_id . ' in the array of incoming messages. Maybe try to increase its size?', \danog\MadelineProto\Logger::WARNING);
|
||||||
}
|
}
|
||||||
/*if ($this->temp_auth_key['id'] === null || $this->temp_auth_key['id'] === "\0\0\0\0\0\0\0\0") {
|
/*if ($this->temp_auth_key['id'] === null || $this->temp_auth_key['id'] === "\0\0\0\0\0\0\0\0") {
|
||||||
// || (isset($this->incoming_messages[$message_id]['ack']) && $this->incoming_messages[$message_id]['ack'])) {
|
// || (isset($this->incoming_messages[$message_id]['ack']) && $this->incoming_messages[$message_id]['ack'])) {
|
||||||
return;
|
return;
|
||||||
}*/
|
}*/
|
||||||
$this->ack_queue[$message_id] = $message_id;
|
$this->ack_queue[$message_id] = $message_id;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if there are some pending calls.
|
* Check if there are some pending calls.
|
||||||
*
|
*
|
||||||
@ -95,26 +84,17 @@ trait AckHandler
|
|||||||
$pfs = $settings['pfs'];
|
$pfs = $settings['pfs'];
|
||||||
$unencrypted = !$this->shared->hasTempAuthKey();
|
$unencrypted = !$this->shared->hasTempAuthKey();
|
||||||
$notBound = !$this->shared->isBound();
|
$notBound = !$this->shared->isBound();
|
||||||
|
|
||||||
$pfsNotBound = $pfs && $notBound;
|
$pfsNotBound = $pfs && $notBound;
|
||||||
|
|
||||||
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() && $unencrypted === $this->outgoing_messages[$message_id]['unencrypted'] && $this->outgoing_messages[$message_id]['_'] !== 'msgs_state_req') {
|
||||||
&& $this->outgoing_messages[$message_id]['sent'] + $timeout < \time()
|
|
||||||
&& $unencrypted === $this->outgoing_messages[$message_id]['unencrypted']
|
|
||||||
&& $this->outgoing_messages[$message_id]['_'] !== 'msgs_state_req'
|
|
||||||
) {
|
|
||||||
if ($pfsNotBound && $this->outgoing_messages[$message_id]['_'] !== 'auth.bindTempAuthKey') {
|
if ($pfsNotBound && $this->outgoing_messages[$message_id]['_'] !== 'auth.bindTempAuthKey') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all pending calls (also clear pending state requests).
|
* Get all pending calls (also clear pending state requests).
|
||||||
*
|
*
|
||||||
@ -127,28 +107,20 @@ trait AckHandler
|
|||||||
$pfs = $settings['pfs'];
|
$pfs = $settings['pfs'];
|
||||||
$unencrypted = !$this->shared->hasTempAuthKey();
|
$unencrypted = !$this->shared->hasTempAuthKey();
|
||||||
$notBound = !$this->shared->isBound();
|
$notBound = !$this->shared->isBound();
|
||||||
|
|
||||||
$pfsNotBound = $pfs && $notBound;
|
$pfsNotBound = $pfs && $notBound;
|
||||||
|
|
||||||
$result = [];
|
$result = [];
|
||||||
foreach ($this->new_outgoing as $k => $message_id) {
|
foreach ($this->new_outgoing as $k => $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() && $unencrypted === $this->outgoing_messages[$message_id]['unencrypted']) {
|
||||||
&& $this->outgoing_messages[$message_id]['sent'] + $timeout < \time()
|
|
||||||
&& $unencrypted === $this->outgoing_messages[$message_id]['unencrypted']
|
|
||||||
) {
|
|
||||||
if ($pfsNotBound && $this->outgoing_messages[$message_id]['_'] !== 'auth.bindTempAuthKey') {
|
if ($pfsNotBound && $this->outgoing_messages[$message_id]['_'] !== 'auth.bindTempAuthKey') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($this->outgoing_messages[$message_id]['_'] === 'msgs_state_req') {
|
if ($this->outgoing_messages[$message_id]['_'] === 'msgs_state_req') {
|
||||||
unset($this->new_outgoing[$k], $this->outgoing_messages[$message_id]);
|
unset($this->new_outgoing[$k], $this->outgoing_messages[$message_id]);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$result[] = $message_id;
|
$result[] = $message_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,6 @@ use Amp\Promise;
|
|||||||
use Amp\Success;
|
use Amp\Success;
|
||||||
use danog\MadelineProto\Async\AsyncParameters;
|
use danog\MadelineProto\Async\AsyncParameters;
|
||||||
use danog\MadelineProto\Tools;
|
use danog\MadelineProto\Tools;
|
||||||
|
|
||||||
use function Amp\Promise\all;
|
use function Amp\Promise\all;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -48,17 +47,13 @@ trait CallHandler
|
|||||||
if ($datacenter === $this->datacenter) {
|
if ($datacenter === $this->datacenter) {
|
||||||
$datacenter = false;
|
$datacenter = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$message_ids = $this->outgoing_messages[$message_id]['container'] ?? [$message_id];
|
$message_ids = $this->outgoing_messages[$message_id]['container'] ?? [$message_id];
|
||||||
|
|
||||||
foreach ($message_ids as $message_id) {
|
foreach ($message_ids as $message_id) {
|
||||||
if (isset($this->outgoing_messages[$message_id]['body'])) {
|
if (isset($this->outgoing_messages[$message_id]['body'])) {
|
||||||
if ($datacenter) {
|
if ($datacenter) {
|
||||||
$res = $this->API->datacenter->waitGetConnection($datacenter)->onResolve(
|
$res = $this->API->datacenter->waitGetConnection($datacenter)->onResolve(function ($e, $r) use ($message_id) {
|
||||||
function ($e, $r) use ($message_id) {
|
return $r->sendMessage($this->outgoing_messages[$message_id], false);
|
||||||
return $r->sendMessage($this->outgoing_messages[$message_id], false);
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
$res = $this->sendMessage($this->outgoing_messages[$message_id], false);
|
$res = $this->sendMessage($this->outgoing_messages[$message_id], false);
|
||||||
}
|
}
|
||||||
@ -66,7 +61,7 @@ trait CallHandler
|
|||||||
$this->ackOutgoingMessageId($message_id);
|
$this->ackOutgoingMessageId($message_id);
|
||||||
$this->gotResponseForOutgoingMessageId($message_id);
|
$this->gotResponseForOutgoingMessageId($message_id);
|
||||||
} else {
|
} else {
|
||||||
$this->logger->logger('Could not resend '.(isset($this->outgoing_messages[$message_id]['_']) ? $this->outgoing_messages[$message_id]['_'] : $message_id));
|
$this->logger->logger('Could not resend ' . (isset($this->outgoing_messages[$message_id]['_']) ? $this->outgoing_messages[$message_id]['_'] : $message_id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!$postpone) {
|
if (!$postpone) {
|
||||||
@ -77,7 +72,6 @@ trait CallHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call method and wait asynchronously for response.
|
* Call method and wait asynchronously for response.
|
||||||
*
|
*
|
||||||
@ -97,22 +91,17 @@ trait CallHandler
|
|||||||
$deferred->fail($e);
|
$deferred->fail($e);
|
||||||
} else {
|
} else {
|
||||||
if (\is_array($read_deferred)) {
|
if (\is_array($read_deferred)) {
|
||||||
$read_deferred = \array_map(
|
$read_deferred = \array_map(function ($value) {
|
||||||
function ($value) {
|
return $value->promise();
|
||||||
return $value->promise();
|
}, $read_deferred);
|
||||||
},
|
|
||||||
$read_deferred
|
|
||||||
);
|
|
||||||
$deferred->resolve(all($read_deferred));
|
$deferred->resolve(all($read_deferred));
|
||||||
} else {
|
} else {
|
||||||
$deferred->resolve($read_deferred->promise());
|
$deferred->resolve($read_deferred->promise());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return $aargs['noResponse'] ?? false ? new Success() : $deferred->promise();
|
||||||
return ($aargs['noResponse'] ?? false) ? new Success() : $deferred->promise();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call method and make sure it is asynchronously sent.
|
* Call method and make sure it is asynchronously sent.
|
||||||
*
|
*
|
||||||
@ -126,7 +115,6 @@ trait CallHandler
|
|||||||
{
|
{
|
||||||
return \danog\MadelineProto\Tools::call($this->methodCallAsyncWriteGenerator($method, $args, $aargs));
|
return \danog\MadelineProto\Tools::call($this->methodCallAsyncWriteGenerator($method, $args, $aargs));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call method and make sure it is asynchronously sent (generator).
|
* Call method and make sure it is asynchronously sent (generator).
|
||||||
*
|
*
|
||||||
@ -138,24 +126,18 @@ trait CallHandler
|
|||||||
*/
|
*/
|
||||||
public function methodCallAsyncWriteGenerator(string $method, $args = [], array $aargs = ['msg_id' => null]): \Generator
|
public function methodCallAsyncWriteGenerator(string $method, $args = [], array $aargs = ['msg_id' => null]): \Generator
|
||||||
{
|
{
|
||||||
if (\is_array($args)
|
if (\is_array($args) && isset($args['id']['_']) && isset($args['id']['dc_id']) && $args['id']['_'] === 'inputBotInlineMessageID' && $this->datacenter !== $args['id']['dc_id']) {
|
||||||
&& isset($args['id']['_'])
|
|
||||||
&& isset($args['id']['dc_id'])
|
|
||||||
&& $args['id']['_'] === 'inputBotInlineMessageID'
|
|
||||||
&& $this->datacenter !== $args['id']['dc_id']
|
|
||||||
) {
|
|
||||||
$aargs['datacenter'] = $args['id']['dc_id'];
|
$aargs['datacenter'] = $args['id']['dc_id'];
|
||||||
return $this->API->methodCallAsyncWriteGenerator($method, $args, $aargs);
|
return $this->API->methodCallAsyncWriteGenerator($method, $args, $aargs);
|
||||||
}
|
}
|
||||||
if (($aargs['file'] ?? false) && !$this->isMedia() && $this->API->datacenter->has($this->datacenter.'_media')) {
|
if (($aargs['file'] ?? false) && !$this->isMedia() && $this->API->datacenter->has($this->datacenter . '_media')) {
|
||||||
$this->logger->logger('Using media DC');
|
$this->logger->logger('Using media DC');
|
||||||
$aargs['datacenter'] = $this->datacenter.'_media';
|
$aargs['datacenter'] = $this->datacenter . '_media';
|
||||||
return $this->API->methodCallAsyncWriteGenerator($method, $args, $aargs);
|
return $this->API->methodCallAsyncWriteGenerator($method, $args, $aargs);
|
||||||
}
|
}
|
||||||
if (\in_array($method, ['messages.setEncryptedTyping', 'messages.readEncryptedHistory', 'messages.sendEncrypted', 'messages.sendEncryptedFile', 'messages.sendEncryptedService', 'messages.receivedQueue'])) {
|
if (\in_array($method, ['messages.setEncryptedTyping', 'messages.readEncryptedHistory', 'messages.sendEncrypted', 'messages.sendEncryptedFile', 'messages.sendEncryptedService', 'messages.receivedQueue'])) {
|
||||||
$aargs['queue'] = 'secret';
|
$aargs['queue'] = 'secret';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (\is_array($args)) {
|
if (\is_array($args)) {
|
||||||
if (isset($args['multiple'])) {
|
if (isset($args['multiple'])) {
|
||||||
$aargs['multiple'] = true;
|
$aargs['multiple'] = true;
|
||||||
@ -170,18 +152,15 @@ trait CallHandler
|
|||||||
$new_aargs = $aargs;
|
$new_aargs = $aargs;
|
||||||
$new_aargs['postpone'] = true;
|
$new_aargs['postpone'] = true;
|
||||||
unset($new_aargs['multiple']);
|
unset($new_aargs['multiple']);
|
||||||
|
|
||||||
if (isset($args['multiple'])) {
|
if (isset($args['multiple'])) {
|
||||||
unset($args['multiple']);
|
unset($args['multiple']);
|
||||||
}
|
}
|
||||||
foreach ($args as $single_args) {
|
foreach ($args as $single_args) {
|
||||||
$promises[] = $this->methodCallAsyncWrite($method, $single_args, $new_aargs);
|
$promises[] = $this->methodCallAsyncWrite($method, $single_args, $new_aargs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($aargs['postpone'])) {
|
if (!isset($aargs['postpone'])) {
|
||||||
$this->writer->resume();
|
$this->writer->resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
return yield all($promises);
|
return yield all($promises);
|
||||||
}
|
}
|
||||||
$args = yield $this->API->botAPIToMTProto($args);
|
$args = yield $this->API->botAPIToMTProto($args);
|
||||||
@ -189,37 +168,21 @@ trait CallHandler
|
|||||||
$args['ping_id'] = Tools::packSignedLong($args['ping_id']);
|
$args['ping_id'] = Tools::packSignedLong($args['ping_id']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$deferred = new Deferred();
|
$deferred = new Deferred();
|
||||||
$message = \array_merge(
|
$message = \array_merge($aargs, ['_' => $method, 'type' => $this->API->getTL()->getMethods()->findByMethod($method)['type'], 'contentRelated' => $this->contentRelated($method), 'promise' => $deferred, 'method' => true, 'unencrypted' => !$this->shared->hasTempAuthKey() && \strpos($method, '.') === false]);
|
||||||
$aargs,
|
|
||||||
[
|
|
||||||
'_' => $method,
|
|
||||||
'type' => $this->API->getTL()->getMethods()->findByMethod($method)['type'],
|
|
||||||
'contentRelated' => $this->contentRelated($method),
|
|
||||||
'promise' => $deferred,
|
|
||||||
'method' => true,
|
|
||||||
'unencrypted' => !$this->shared->hasTempAuthKey() && \strpos($method, '.') === false
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
if (\is_object($args) && $args instanceof AsyncParameters) {
|
if (\is_object($args) && $args instanceof AsyncParameters) {
|
||||||
$message['body'] = yield $args->fetchParameters();
|
$message['body'] = yield $args->fetchParameters();
|
||||||
} else {
|
} else {
|
||||||
$message['body'] = $args;
|
$message['body'] = $args;
|
||||||
}
|
}
|
||||||
|
if ($method === 'users.getUsers' && $args === ['id' => [['_' => 'inputUserSelf']]] || $method === 'auth.exportAuthorization' || $method === 'updates.getDifference') {
|
||||||
if (($method === 'users.getUsers' && $args === ['id' => [['_' => 'inputUserSelf']]]) || $method === 'auth.exportAuthorization' || $method === 'updates.getDifference') {
|
|
||||||
$message['user_related'] = true;
|
$message['user_related'] = true;
|
||||||
}
|
}
|
||||||
$aargs['postpone'] = $aargs['postpone'] ?? false;
|
$aargs['postpone'] = $aargs['postpone'] ?? false;
|
||||||
$deferred = yield $this->sendMessage($message, !$aargs['postpone']);
|
$deferred = yield $this->sendMessage($message, !$aargs['postpone']);
|
||||||
|
|
||||||
$this->checker->resume();
|
$this->checker->resume();
|
||||||
|
|
||||||
return $deferred;
|
return $deferred;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send object and make sure it is asynchronously sent (generator).
|
* Send object and make sure it is asynchronously sent (generator).
|
||||||
*
|
*
|
||||||
@ -235,7 +198,6 @@ trait CallHandler
|
|||||||
if (isset($aargs['promise'])) {
|
if (isset($aargs['promise'])) {
|
||||||
$message['promise'] = $aargs['promise'];
|
$message['promise'] = $aargs['promise'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$aargs['postpone'] = $aargs['postpone'] ?? false;
|
$aargs['postpone'] = $aargs['postpone'] ?? false;
|
||||||
return $this->sendMessage($message, !$aargs['postpone']);
|
return $this->sendMessage($message, !$aargs['postpone']);
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,6 @@ trait MsgIdHandler
|
|||||||
{
|
{
|
||||||
public $max_incoming_id;
|
public $max_incoming_id;
|
||||||
public $max_outgoing_id;
|
public $max_outgoing_id;
|
||||||
|
|
||||||
public function checkMessageId($new_message_id, $aargs)
|
public function checkMessageId($new_message_id, $aargs)
|
||||||
{
|
{
|
||||||
if (!\is_object($new_message_id)) {
|
if (!\is_object($new_message_id)) {
|
||||||
@ -34,18 +33,18 @@ trait MsgIdHandler
|
|||||||
}
|
}
|
||||||
$min_message_id = (new \tgseclib\Math\BigInteger(\time() + $this->time_delta - 300))->bitwise_leftShift(32);
|
$min_message_id = (new \tgseclib\Math\BigInteger(\time() + $this->time_delta - 300))->bitwise_leftShift(32);
|
||||||
if ($min_message_id->compare($new_message_id) > 0) {
|
if ($min_message_id->compare($new_message_id) > 0) {
|
||||||
$this->API->logger->logger('Given message id ('.$new_message_id.') is too old compared to the min value ('.$min_message_id.').', \danog\MadelineProto\Logger::WARNING);
|
$this->API->logger->logger('Given message id (' . $new_message_id . ') is too old compared to the min value (' . $min_message_id . ').', \danog\MadelineProto\Logger::WARNING);
|
||||||
}
|
}
|
||||||
$max_message_id = (new \tgseclib\Math\BigInteger(\time() + $this->time_delta + 30))->bitwise_leftShift(32);
|
$max_message_id = (new \tgseclib\Math\BigInteger(\time() + $this->time_delta + 30))->bitwise_leftShift(32);
|
||||||
if ($max_message_id->compare($new_message_id) < 0) {
|
if ($max_message_id->compare($new_message_id) < 0) {
|
||||||
throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is too new compared to the max value ('.$max_message_id.'). Consider syncing your date.');
|
throw new \danog\MadelineProto\Exception('Given message id (' . $new_message_id . ') is too new compared to the max value (' . $max_message_id . '). Consider syncing your date.');
|
||||||
}
|
}
|
||||||
if ($aargs['outgoing']) {
|
if ($aargs['outgoing']) {
|
||||||
if (!$new_message_id->divide(\danog\MadelineProto\Magic::$four)[1]->equals(\danog\MadelineProto\Magic::$zero)) {
|
if (!$new_message_id->divide(\danog\MadelineProto\Magic::$four)[1]->equals(\danog\MadelineProto\Magic::$zero)) {
|
||||||
throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is not divisible by 4. Consider syncing your date.');
|
throw new \danog\MadelineProto\Exception('Given message id (' . $new_message_id . ') is not divisible by 4. Consider syncing your date.');
|
||||||
}
|
}
|
||||||
if (!\danog\MadelineProto\Magic::$has_thread && $new_message_id->compare($key = $this->getMaxId($incoming = false)) <= 0) {
|
if (!\danog\MadelineProto\Magic::$has_thread && $new_message_id->compare($key = $this->getMaxId($incoming = false)) <= 0) {
|
||||||
throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is lower than or equal to the current limit ('.$key.'). Consider syncing your date.', 1);
|
throw new \danog\MadelineProto\Exception('Given message id (' . $new_message_id . ') is lower than or equal to the current limit (' . $key . '). Consider syncing your date.', 1);
|
||||||
}
|
}
|
||||||
if (\count($this->outgoing_messages) > $this->API->settings['msg_array_limit']['outgoing']) {
|
if (\count($this->outgoing_messages) > $this->API->settings['msg_array_limit']['outgoing']) {
|
||||||
\reset($this->outgoing_messages);
|
\reset($this->outgoing_messages);
|
||||||
@ -63,11 +62,11 @@ trait MsgIdHandler
|
|||||||
$key = $this->getMaxId($incoming = true);
|
$key = $this->getMaxId($incoming = true);
|
||||||
if ($aargs['container']) {
|
if ($aargs['container']) {
|
||||||
if ($new_message_id->compare($key = $this->getMaxId($incoming = true)) >= 0) {
|
if ($new_message_id->compare($key = $this->getMaxId($incoming = true)) >= 0) {
|
||||||
$this->API->logger->logger('WARNING: Given message id ('.$new_message_id.') is bigger than or equal to the current limit ('.$key.'). Consider syncing your date.', \danog\MadelineProto\Logger::WARNING);
|
$this->API->logger->logger('WARNING: Given message id (' . $new_message_id . ') is bigger than or equal to the current limit (' . $key . '). Consider syncing your date.', \danog\MadelineProto\Logger::WARNING);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ($new_message_id->compare($key = $this->getMaxId($incoming = true)) <= 0) {
|
if ($new_message_id->compare($key = $this->getMaxId($incoming = true)) <= 0) {
|
||||||
$this->API->logger->logger('WARNING: Given message id ('.$new_message_id.') is lower than or equal to the current limit ('.$key.'). Consider syncing your date.', \danog\MadelineProto\Logger::WARNING);
|
$this->API->logger->logger('WARNING: Given message id (' . $new_message_id . ') is lower than or equal to the current limit (' . $key . '). Consider syncing your date.', \danog\MadelineProto\Logger::WARNING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (\count($this->incoming_messages) > $this->API->settings['msg_array_limit']['incoming']) {
|
if (\count($this->incoming_messages) > $this->API->settings['msg_array_limit']['incoming']) {
|
||||||
@ -81,7 +80,6 @@ trait MsgIdHandler
|
|||||||
$this->incoming_messages[\strrev($new_message_id->toBytes())] = [];
|
$this->incoming_messages[\strrev($new_message_id->toBytes())] = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateMessageId()
|
public function generateMessageId()
|
||||||
{
|
{
|
||||||
$message_id = (new \tgseclib\Math\BigInteger(\time() + $this->time_delta))->bitwise_leftShift(32);
|
$message_id = (new \tgseclib\Math\BigInteger(\time() + $this->time_delta))->bitwise_leftShift(32);
|
||||||
@ -89,17 +87,14 @@ trait MsgIdHandler
|
|||||||
$message_id = $key->add(\danog\MadelineProto\Magic::$four);
|
$message_id = $key->add(\danog\MadelineProto\Magic::$four);
|
||||||
}
|
}
|
||||||
$this->checkMessageId($message_id, ['outgoing' => true, 'container' => false]);
|
$this->checkMessageId($message_id, ['outgoing' => true, 'container' => false]);
|
||||||
|
|
||||||
return \strrev($message_id->toBytes());
|
return \strrev($message_id->toBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMaxId($incoming)
|
public function getMaxId($incoming)
|
||||||
{
|
{
|
||||||
$incoming = $incoming ? 'incoming' : 'outgoing';
|
$incoming = $incoming ? 'incoming' : 'outgoing';
|
||||||
if (isset($this->{'max_'.$incoming.'_id'}) && \is_object($this->{'max_'.$incoming.'_id'})) {
|
if (isset($this->{'max_' . $incoming . '_id'}) && \is_object($this->{'max_' . $incoming . '_id'})) {
|
||||||
return $this->{'max_'.$incoming.'_id'};
|
return $this->{'max_' . $incoming . '_id'};
|
||||||
}
|
}
|
||||||
|
|
||||||
return \danog\MadelineProto\Magic::$zero;
|
return \danog\MadelineProto\Magic::$zero;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,35 +28,33 @@ use danog\MadelineProto\MTProto;
|
|||||||
*/
|
*/
|
||||||
trait ResponseHandler
|
trait ResponseHandler
|
||||||
{
|
{
|
||||||
public function sendMsgsStateInfo($req_msg_id, $msg_ids)
|
public function sendMsgsStateInfo($req_msg_id, $msg_ids): \Generator
|
||||||
{
|
{
|
||||||
$this->logger->logger('Sending state info for '.\count($msg_ids).' message IDs');
|
$this->logger->logger('Sending state info for ' . \count($msg_ids) . ' message IDs');
|
||||||
$info = '';
|
$info = '';
|
||||||
foreach ($msg_ids as $msg_id) {
|
foreach ($msg_ids as $msg_id) {
|
||||||
$cur_info = 0;
|
$cur_info = 0;
|
||||||
if (!isset($this->incoming_messages[$msg_id])) {
|
if (!isset($this->incoming_messages[$msg_id])) {
|
||||||
$msg_id = new \tgseclib\Math\BigInteger(\strrev($msg_id), 256);
|
$msg_id = new \tgseclib\Math\BigInteger(\strrev($msg_id), 256);
|
||||||
if ((new \tgseclib\Math\BigInteger(\time() + $this->time_delta + 30))->bitwise_leftShift(32)->compare($msg_id) < 0) {
|
if ((new \tgseclib\Math\BigInteger(\time() + $this->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");
|
$this->logger->logger("Do not know anything about {$msg_id} and it is too small");
|
||||||
$cur_info |= 3;
|
$cur_info |= 3;
|
||||||
} elseif ((new \tgseclib\Math\BigInteger(\time() + $this->time_delta - 300))->bitwise_leftShift(32)->compare($msg_id) > 0) {
|
} elseif ((new \tgseclib\Math\BigInteger(\time() + $this->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");
|
$this->logger->logger("Do not know anything about {$msg_id} and it is too big");
|
||||||
$cur_info |= 1;
|
$cur_info |= 1;
|
||||||
} else {
|
} else {
|
||||||
$this->logger->logger("Do not know anything about $msg_id");
|
$this->logger->logger("Do not know anything about {$msg_id}");
|
||||||
$cur_info |= 2;
|
$cur_info |= 2;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$this->logger->logger("Know about $msg_id");
|
$this->logger->logger("Know about {$msg_id}");
|
||||||
$cur_info |= 4;
|
$cur_info |= 4;
|
||||||
}
|
}
|
||||||
$info .= \chr($cur_info);
|
$info .= \chr($cur_info);
|
||||||
}
|
}
|
||||||
$this->outgoing_messages[yield $this->objectCall('msgs_state_info', ['req_msg_id' => $req_msg_id, 'info' => $info], ['postpone' => true])]['response'] = $req_msg_id;
|
$this->outgoing_messages[yield $this->objectCall('msgs_state_info', ['req_msg_id' => $req_msg_id, 'info' => $info], ['postpone' => true])]['response'] = $req_msg_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public $n = 0;
|
public $n = 0;
|
||||||
|
|
||||||
public function handleMessages()
|
public function handleMessages()
|
||||||
{
|
{
|
||||||
$only_updates = true;
|
$only_updates = true;
|
||||||
@ -67,8 +65,7 @@ trait ResponseHandler
|
|||||||
unset($this->new_incoming[$current_msg_id]);
|
unset($this->new_incoming[$current_msg_id]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$this->logger->logger((isset($this->incoming_messages[$current_msg_id]['from_container']) ? 'Inside of container, received ' : 'Received ').$this->incoming_messages[$current_msg_id]['content']['_'].' from DC '.$this->datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->logger->logger((isset($this->incoming_messages[$current_msg_id]['from_container']) ? 'Inside of container, received ' : 'Received ') . $this->incoming_messages[$current_msg_id]['content']['_'] . ' from DC ' . $this->datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
|
|
||||||
switch ($this->incoming_messages[$current_msg_id]['content']['_']) {
|
switch ($this->incoming_messages[$current_msg_id]['content']['_']) {
|
||||||
case 'msgs_ack':
|
case 'msgs_ack':
|
||||||
unset($this->new_incoming[$current_msg_id]);
|
unset($this->new_incoming[$current_msg_id]);
|
||||||
@ -78,7 +75,6 @@ trait ResponseHandler
|
|||||||
$this->ackOutgoingMessageId($msg_id);
|
$this->ackOutgoingMessageId($msg_id);
|
||||||
// Acknowledge that the server received my message
|
// Acknowledge that the server received my message
|
||||||
}
|
}
|
||||||
|
|
||||||
unset($this->incoming_messages[$current_msg_id]['content']);
|
unset($this->incoming_messages[$current_msg_id]['content']);
|
||||||
break;
|
break;
|
||||||
case 'rpc_result':
|
case 'rpc_result':
|
||||||
@ -89,47 +85,39 @@ trait ResponseHandler
|
|||||||
$req_msg_id = $this->incoming_messages[$current_msg_id]['content']['req_msg_id'];
|
$req_msg_id = $this->incoming_messages[$current_msg_id]['content']['req_msg_id'];
|
||||||
$this->incoming_messages[$current_msg_id]['content'] = $this->incoming_messages[$current_msg_id]['content']['result'];
|
$this->incoming_messages[$current_msg_id]['content'] = $this->incoming_messages[$current_msg_id]['content']['result'];
|
||||||
$this->checkInSeqNo($current_msg_id);
|
$this->checkInSeqNo($current_msg_id);
|
||||||
|
|
||||||
$this->handleResponse($req_msg_id, $current_msg_id);
|
$this->handleResponse($req_msg_id, $current_msg_id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'future_salts':
|
case 'future_salts':
|
||||||
case 'msgs_state_info':
|
case 'msgs_state_info':
|
||||||
$msg_id_type = 'req_msg_id';
|
$msg_id_type = 'req_msg_id';
|
||||||
// no break
|
// no break
|
||||||
case 'bad_server_salt':
|
case 'bad_server_salt':
|
||||||
case 'bad_msg_notification':
|
case 'bad_msg_notification':
|
||||||
$msg_id_type = isset($msg_id_type) ? $msg_id_type : 'bad_msg_id';
|
$msg_id_type = isset($msg_id_type) ? $msg_id_type : 'bad_msg_id';
|
||||||
// no break
|
// no break
|
||||||
case 'pong':
|
case 'pong':
|
||||||
$msg_id_type = isset($msg_id_type) ? $msg_id_type : 'msg_id';
|
$msg_id_type = isset($msg_id_type) ? $msg_id_type : 'msg_id';
|
||||||
unset($this->new_incoming[$current_msg_id]);
|
unset($this->new_incoming[$current_msg_id]);
|
||||||
$this->checkInSeqNo($current_msg_id);
|
$this->checkInSeqNo($current_msg_id);
|
||||||
$only_updates = false;
|
$only_updates = false;
|
||||||
|
|
||||||
$this->handleResponse($this->incoming_messages[$current_msg_id]['content'][$msg_id_type], $current_msg_id);
|
$this->handleResponse($this->incoming_messages[$current_msg_id]['content'][$msg_id_type], $current_msg_id);
|
||||||
unset($msg_id_type);
|
unset($msg_id_type);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'new_session_created':
|
case 'new_session_created':
|
||||||
unset($this->new_incoming[$current_msg_id]);
|
unset($this->new_incoming[$current_msg_id]);
|
||||||
$this->checkInSeqNo($current_msg_id);
|
$this->checkInSeqNo($current_msg_id);
|
||||||
$only_updates = false;
|
$only_updates = false;
|
||||||
|
|
||||||
$this->shared->getTempAuthKey()->setServerSalt($this->incoming_messages[$current_msg_id]['content']['server_salt']);
|
$this->shared->getTempAuthKey()->setServerSalt($this->incoming_messages[$current_msg_id]['content']['server_salt']);
|
||||||
$this->ackIncomingMessageId($current_msg_id);
|
$this->ackIncomingMessageId($current_msg_id);
|
||||||
|
|
||||||
// Acknowledge that I received the server's response
|
// Acknowledge that I received the server's response
|
||||||
if ($this->API->authorized === MTProto::LOGGED_IN && !$this->API->isInitingAuthorization() && $this->API->datacenter->getDataCenterConnection($this->API->datacenter->curdc)->hasTempAuthKey() && isset($this->API->updaters[false])) {
|
if ($this->API->authorized === MTProto::LOGGED_IN && !$this->API->isInitingAuthorization() && $this->API->datacenter->getDataCenterConnection($this->API->datacenter->curdc)->hasTempAuthKey() && isset($this->API->updaters[false])) {
|
||||||
$this->API->updaters[false]->resumeDefer();
|
$this->API->updaters[false]->resumeDefer();
|
||||||
}
|
}
|
||||||
|
|
||||||
unset($this->incoming_messages[$current_msg_id]['content']);
|
unset($this->incoming_messages[$current_msg_id]['content']);
|
||||||
break;
|
break;
|
||||||
case 'msg_container':
|
case 'msg_container':
|
||||||
unset($this->new_incoming[$current_msg_id]);
|
unset($this->new_incoming[$current_msg_id]);
|
||||||
$only_updates = false;
|
$only_updates = false;
|
||||||
|
|
||||||
foreach ($this->incoming_messages[$current_msg_id]['content']['messages'] as $message) {
|
foreach ($this->incoming_messages[$current_msg_id]['content']['messages'] as $message) {
|
||||||
$this->checkMessageId($message['msg_id'], ['outgoing' => false, 'container' => true]);
|
$this->checkMessageId($message['msg_id'], ['outgoing' => false, 'container' => true]);
|
||||||
$this->incoming_messages[$message['msg_id']] = ['seq_no' => $message['seqno'], 'content' => $message['body'], 'from_container' => true];
|
$this->incoming_messages[$message['msg_id']] = ['seq_no' => $message['seqno'], 'content' => $message['body'], 'from_container' => true];
|
||||||
@ -138,14 +126,12 @@ trait ResponseHandler
|
|||||||
\ksort($this->new_incoming);
|
\ksort($this->new_incoming);
|
||||||
//$this->handleMessages();
|
//$this->handleMessages();
|
||||||
//$this->checkInSeqNo($current_msg_id);
|
//$this->checkInSeqNo($current_msg_id);
|
||||||
|
|
||||||
unset($this->incoming_messages[$current_msg_id]['content']);
|
unset($this->incoming_messages[$current_msg_id]['content']);
|
||||||
break;
|
break;
|
||||||
case 'msg_copy':
|
case 'msg_copy':
|
||||||
unset($this->new_incoming[$current_msg_id]);
|
unset($this->new_incoming[$current_msg_id]);
|
||||||
$this->checkInSeqNo($current_msg_id);
|
$this->checkInSeqNo($current_msg_id);
|
||||||
$only_updates = false;
|
$only_updates = false;
|
||||||
|
|
||||||
$this->ackIncomingMessageId($current_msg_id);
|
$this->ackIncomingMessageId($current_msg_id);
|
||||||
// Acknowledge that I received the server's response
|
// Acknowledge that I received the server's response
|
||||||
if (isset($this->incoming_messages[$this->incoming_messages[$current_msg_id]['content']['orig_message']['msg_id']])) {
|
if (isset($this->incoming_messages[$this->incoming_messages[$current_msg_id]['content']['orig_message']['msg_id']])) {
|
||||||
@ -157,25 +143,19 @@ trait ResponseHandler
|
|||||||
$this->incoming_messages[$message['orig_message']['msg_id']] = ['content' => $this->incoming_messages[$current_msg_id]['content']['orig_message']];
|
$this->incoming_messages[$message['orig_message']['msg_id']] = ['content' => $this->incoming_messages[$current_msg_id]['content']['orig_message']];
|
||||||
$this->new_incoming[$message['orig_message']['msg_id']] = $message['orig_message']['msg_id'];
|
$this->new_incoming[$message['orig_message']['msg_id']] = $message['orig_message']['msg_id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
unset($this->incoming_messages[$current_msg_id]['content']);
|
unset($this->incoming_messages[$current_msg_id]['content']);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'http_wait':
|
case 'http_wait':
|
||||||
unset($this->new_incoming[$current_msg_id]);
|
unset($this->new_incoming[$current_msg_id]);
|
||||||
$this->checkInSeqNo($current_msg_id);
|
$this->checkInSeqNo($current_msg_id);
|
||||||
$only_updates = false;
|
$only_updates = false;
|
||||||
|
|
||||||
$this->logger->logger($this->incoming_messages[$current_msg_id]['content'], \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger($this->incoming_messages[$current_msg_id]['content'], \danog\MadelineProto\Logger::NOTICE);
|
||||||
|
|
||||||
unset($this->incoming_messages[$current_msg_id]['content']);
|
unset($this->incoming_messages[$current_msg_id]['content']);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'msgs_state_req':
|
case 'msgs_state_req':
|
||||||
$this->checkInSeqNo($current_msg_id);
|
$this->checkInSeqNo($current_msg_id);
|
||||||
$only_updates = false;
|
$only_updates = false;
|
||||||
unset($this->new_incoming[$current_msg_id]);
|
unset($this->new_incoming[$current_msg_id]);
|
||||||
|
|
||||||
\danog\MadelineProto\Tools::callFork($this->sendMsgsStateInfo($current_msg_id, $this->incoming_messages[$current_msg_id]['content']['msg_ids']));
|
\danog\MadelineProto\Tools::callFork($this->sendMsgsStateInfo($current_msg_id, $this->incoming_messages[$current_msg_id]['content']['msg_ids']));
|
||||||
unset($this->incoming_messages[$current_msg_id]['content']);
|
unset($this->incoming_messages[$current_msg_id]['content']);
|
||||||
break;
|
break;
|
||||||
@ -183,11 +163,10 @@ trait ResponseHandler
|
|||||||
$this->checkInSeqNo($current_msg_id);
|
$this->checkInSeqNo($current_msg_id);
|
||||||
$only_updates = false;
|
$only_updates = false;
|
||||||
unset($this->new_incoming[$current_msg_id]);
|
unset($this->new_incoming[$current_msg_id]);
|
||||||
|
|
||||||
foreach ($this->incoming_messages[$current_msg_id]['content']['msg_ids'] as $key => $msg_id) {
|
foreach ($this->incoming_messages[$current_msg_id]['content']['msg_ids'] as $key => $msg_id) {
|
||||||
$info = \ord($this->incoming_messages[$current_msg_id]['content']['info'][$key]);
|
$info = \ord($this->incoming_messages[$current_msg_id]['content']['info'][$key]);
|
||||||
$msg_id = new \tgseclib\Math\BigInteger(\strrev($msg_id), 256);
|
$msg_id = new \tgseclib\Math\BigInteger(\strrev($msg_id), 256);
|
||||||
$status = 'Status for message id '.$msg_id.': ';
|
$status = 'Status for message id ' . $msg_id . ': ';
|
||||||
/*if ($info & 4) {
|
/*if ($info & 4) {
|
||||||
*$this->gotResponseForOutgoingMessageId($msg_id);
|
*$this->gotResponseForOutgoingMessageId($msg_id);
|
||||||
*}
|
*}
|
||||||
@ -203,7 +182,6 @@ trait ResponseHandler
|
|||||||
case 'msg_detailed_info':
|
case 'msg_detailed_info':
|
||||||
$this->checkInSeqNo($current_msg_id);
|
$this->checkInSeqNo($current_msg_id);
|
||||||
unset($this->new_incoming[$current_msg_id]);
|
unset($this->new_incoming[$current_msg_id]);
|
||||||
|
|
||||||
$only_updates = false;
|
$only_updates = false;
|
||||||
if (isset($this->outgoing_messages[$this->incoming_messages[$current_msg_id]['content']['msg_id']])) {
|
if (isset($this->outgoing_messages[$this->incoming_messages[$current_msg_id]['content']['msg_id']])) {
|
||||||
if (isset($this->incoming_messages[$this->incoming_messages[$current_msg_id]['content']['answer_msg_id']])) {
|
if (isset($this->incoming_messages[$this->incoming_messages[$current_msg_id]['content']['answer_msg_id']])) {
|
||||||
@ -217,7 +195,6 @@ trait ResponseHandler
|
|||||||
$this->checkInSeqNo($current_msg_id);
|
$this->checkInSeqNo($current_msg_id);
|
||||||
$only_updates = false;
|
$only_updates = false;
|
||||||
unset($this->new_incoming[$current_msg_id]);
|
unset($this->new_incoming[$current_msg_id]);
|
||||||
|
|
||||||
if (isset($this->incoming_messages[$this->incoming_messages[$current_msg_id]['content']['answer_msg_id']])) {
|
if (isset($this->incoming_messages[$this->incoming_messages[$current_msg_id]['content']['answer_msg_id']])) {
|
||||||
$this->ackIncomingMessageId($this->incoming_messages[$current_msg_id]['content']['answer_msg_id']);
|
$this->ackIncomingMessageId($this->incoming_messages[$current_msg_id]['content']['answer_msg_id']);
|
||||||
} else {
|
} else {
|
||||||
@ -228,7 +205,6 @@ trait ResponseHandler
|
|||||||
$this->checkInSeqNo($current_msg_id);
|
$this->checkInSeqNo($current_msg_id);
|
||||||
$only_updates = false;
|
$only_updates = false;
|
||||||
unset($this->new_incoming[$current_msg_id]);
|
unset($this->new_incoming[$current_msg_id]);
|
||||||
|
|
||||||
$ok = true;
|
$ok = true;
|
||||||
foreach ($this->incoming_messages[$current_msg_id]['content']['msg_ids'] as $msg_id) {
|
foreach ($this->incoming_messages[$current_msg_id]['content']['msg_ids'] as $msg_id) {
|
||||||
if (!isset($this->outgoing_messages[$msg_id]) || isset($this->incoming_messages[$msg_id])) {
|
if (!isset($this->outgoing_messages[$msg_id]) || isset($this->incoming_messages[$msg_id])) {
|
||||||
@ -247,7 +223,6 @@ trait ResponseHandler
|
|||||||
$this->checkInSeqNo($current_msg_id);
|
$this->checkInSeqNo($current_msg_id);
|
||||||
$only_updates = false;
|
$only_updates = false;
|
||||||
unset($this->new_incoming[$current_msg_id]);
|
unset($this->new_incoming[$current_msg_id]);
|
||||||
|
|
||||||
\danog\MadelineProto\Tools::callFork($this->sendMsgsStateInfo($current_msg_id, $this->incoming_messages[$current_msg_id]['content']['msg_ids']));
|
\danog\MadelineProto\Tools::callFork($this->sendMsgsStateInfo($current_msg_id, $this->incoming_messages[$current_msg_id]['content']['msg_ids']));
|
||||||
foreach ($this->incoming_messages[$current_msg_id]['content']['msg_ids'] as $msg_id) {
|
foreach ($this->incoming_messages[$current_msg_id]['content']['msg_ids'] as $msg_id) {
|
||||||
if (isset($this->incoming_messages[$msg_id]['response']) && isset($this->outgoing_messages[$this->incoming_messages[$msg_id]['response']])) {
|
if (isset($this->incoming_messages[$msg_id]['response']) && isset($this->outgoing_messages[$this->incoming_messages[$msg_id]['response']])) {
|
||||||
@ -260,29 +235,24 @@ trait ResponseHandler
|
|||||||
$this->ackIncomingMessageId($current_msg_id);
|
$this->ackIncomingMessageId($current_msg_id);
|
||||||
// Acknowledge that I received the server's response
|
// Acknowledge that I received the server's response
|
||||||
$response_type = $this->API->getTL()->getConstructors()->findByPredicate($this->incoming_messages[$current_msg_id]['content']['_'])['type'];
|
$response_type = $this->API->getTL()->getConstructors()->findByPredicate($this->incoming_messages[$current_msg_id]['content']['_'])['type'];
|
||||||
|
|
||||||
switch ($response_type) {
|
switch ($response_type) {
|
||||||
case 'Updates':
|
case 'Updates':
|
||||||
unset($this->new_incoming[$current_msg_id]);
|
unset($this->new_incoming[$current_msg_id]);
|
||||||
|
|
||||||
if (!$this->isCdn()) {
|
if (!$this->isCdn()) {
|
||||||
\danog\MadelineProto\Tools::callForkDefer($this->API->handleUpdates($this->incoming_messages[$current_msg_id]['content']));
|
\danog\MadelineProto\Tools::callForkDefer($this->API->handleUpdates($this->incoming_messages[$current_msg_id]['content']));
|
||||||
}
|
}
|
||||||
|
|
||||||
unset($this->incoming_messages[$current_msg_id]['content']);
|
unset($this->incoming_messages[$current_msg_id]['content']);
|
||||||
|
|
||||||
$only_updates = true && $only_updates;
|
$only_updates = true && $only_updates;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$only_updates = false;
|
$only_updates = false;
|
||||||
$this->logger->logger('Trying to assign a response of type '.$response_type.' to its request...', \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('Trying to assign a response of type ' . $response_type . ' to its request...', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
foreach ($this->new_outgoing as $key => $expecting_msg_id) {
|
foreach ($this->new_outgoing as $key => $expecting_msg_id) {
|
||||||
$expecting = $this->outgoing_messages[$expecting_msg_id];
|
$expecting = $this->outgoing_messages[$expecting_msg_id];
|
||||||
if (!isset($expecting['type'])) {
|
if (!isset($expecting['type'])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
$this->logger->logger('Does the request of return type ' . $expecting['type'] . ' 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']) {
|
if ($response_type === $expecting['type']) {
|
||||||
$this->logger->logger('Yes', \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('Yes', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
unset($this->new_incoming[$current_msg_id]);
|
unset($this->new_incoming[$current_msg_id]);
|
||||||
@ -291,8 +261,7 @@ trait ResponseHandler
|
|||||||
}
|
}
|
||||||
$this->logger->logger('No', \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('No', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
}
|
}
|
||||||
|
$this->logger->logger('Dunno how to handle ' . PHP_EOL . \var_export($this->incoming_messages[$current_msg_id]['content'], true), \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||||
$this->logger->logger('Dunno how to handle '.PHP_EOL.\var_export($this->incoming_messages[$current_msg_id]['content'], true), \danog\MadelineProto\Logger::FATAL_ERROR);
|
|
||||||
unset($this->new_incoming[$current_msg_id]);
|
unset($this->new_incoming[$current_msg_id]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -302,12 +271,9 @@ trait ResponseHandler
|
|||||||
if ($this->pending_outgoing) {
|
if ($this->pending_outgoing) {
|
||||||
$this->writer->resume();
|
$this->writer->resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
//$this->n--;
|
//$this->n--;
|
||||||
|
|
||||||
return $only_updates;
|
return $only_updates;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reject request with exception.
|
* Reject request with exception.
|
||||||
*
|
*
|
||||||
@ -321,9 +287,8 @@ trait ResponseHandler
|
|||||||
if (isset($request['promise']) && \is_object($request['promise'])) {
|
if (isset($request['promise']) && \is_object($request['promise'])) {
|
||||||
Loop::defer(function () use (&$request, $data) {
|
Loop::defer(function () use (&$request, $data) {
|
||||||
if (isset($request['promise'])) {
|
if (isset($request['promise'])) {
|
||||||
$this->logger->logger('Rejecting: '.(isset($request['_']) ? $request['_'] : '-'));
|
$this->logger->logger('Rejecting: ' . (isset($request['_']) ? $request['_'] : '-'));
|
||||||
$this->logger->logger("Rejecting: $data");
|
$this->logger->logger("Rejecting: {$data}");
|
||||||
|
|
||||||
$promise = $request['promise'];
|
$promise = $request['promise'];
|
||||||
unset($request['promise']);
|
unset($request['promise']);
|
||||||
try {
|
try {
|
||||||
@ -335,8 +300,8 @@ trait ResponseHandler
|
|||||||
$this->logger->logger("Got promise already resolved error", \danog\MadelineProto\Logger::FATAL_ERROR);
|
$this->logger->logger("Got promise already resolved error", \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$this->logger->logger('Rejecting: already got response for '.(isset($request['_']) ? $request['_'] : '-'));
|
$this->logger->logger('Rejecting: already got response for ' . (isset($request['_']) ? $request['_'] : '-'));
|
||||||
$this->logger->logger("Rejecting: $data");
|
$this->logger->logger("Rejecting: {$data}");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} elseif (isset($request['container'])) {
|
} elseif (isset($request['container'])) {
|
||||||
@ -344,28 +309,24 @@ trait ResponseHandler
|
|||||||
$this->handleReject($this->outgoing_messages[$message_id], $data);
|
$this->handleReject($this->outgoing_messages[$message_id], $data);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$this->logger->logger('Rejecting: already got response for '.(isset($request['_']) ? $request['_'] : '-'));
|
$this->logger->logger('Rejecting: already got response for ' . (isset($request['_']) ? $request['_'] : '-'));
|
||||||
$this->logger->logger("Rejecting: $data");
|
$this->logger->logger("Rejecting: {$data}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleResponse($request_id, $response_id)
|
public function handleResponse($request_id, $response_id)
|
||||||
{
|
{
|
||||||
$response = &$this->incoming_messages[$response_id]['content'];
|
$response =& $this->incoming_messages[$response_id]['content'];
|
||||||
unset($this->incoming_messages[$response_id]['content']);
|
unset($this->incoming_messages[$response_id]['content']);
|
||||||
$request = &$this->outgoing_messages[$request_id];
|
$request =& $this->outgoing_messages[$request_id];
|
||||||
|
|
||||||
if (isset($response['_'])) {
|
if (isset($response['_'])) {
|
||||||
switch ($response['_']) {
|
switch ($response['_']) {
|
||||||
case 'rpc_error':
|
case 'rpc_error':
|
||||||
if (($request['method'] ?? false) && $request['_'] !== 'auth.bindTempAuthKey' && $this->shared->hasTempAuthKey() && !$this->shared->getTempAuthKey()->isInited()) {
|
if (($request['method'] ?? false) && $request['_'] !== 'auth.bindTempAuthKey' && $this->shared->hasTempAuthKey() && !$this->shared->getTempAuthKey()->isInited()) {
|
||||||
$this->shared->getTempAuthKey()->init(true);
|
$this->shared->getTempAuthKey()->init(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (\in_array($response['error_message'], ['PERSISTENT_TIMESTAMP_EMPTY', 'PERSISTENT_TIMESTAMP_INVALID'])) {
|
if (\in_array($response['error_message'], ['PERSISTENT_TIMESTAMP_EMPTY', 'PERSISTENT_TIMESTAMP_INVALID'])) {
|
||||||
$this->gotResponseForOutgoingMessageId($request_id);
|
$this->gotResponseForOutgoingMessageId($request_id);
|
||||||
$this->handleReject($request, new \danog\MadelineProto\PTSException($response['error_message']));
|
$this->handleReject($request, new \danog\MadelineProto\PTSException($response['error_message']));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($response['error_message'] === 'PERSISTENT_TIMESTAMP_OUTDATED') {
|
if ($response['error_message'] === 'PERSISTENT_TIMESTAMP_OUTDATED') {
|
||||||
@ -373,14 +334,11 @@ trait ResponseHandler
|
|||||||
}
|
}
|
||||||
if (\strpos($response['error_message'], 'FILE_REFERENCE_') === 0) {
|
if (\strpos($response['error_message'], 'FILE_REFERENCE_') === 0) {
|
||||||
$this->logger->logger("Got {$response['error_message']}, refreshing file reference and repeating method call...");
|
$this->logger->logger("Got {$response['error_message']}, refreshing file reference and repeating method call...");
|
||||||
|
|
||||||
$request['refreshReferences'] = true;
|
$request['refreshReferences'] = true;
|
||||||
if (isset($request['serialized_body'])) {
|
if (isset($request['serialized_body'])) {
|
||||||
unset($request['serialized_body']);
|
unset($request['serialized_body']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->methodRecall('', ['message_id' => $request_id, 'postpone' => true]);
|
$this->methodRecall('', ['message_id' => $request_id, 'postpone' => true]);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch ($response['error_code']) {
|
switch ($response['error_code']) {
|
||||||
@ -389,32 +347,26 @@ trait ResponseHandler
|
|||||||
if ($response['error_message'] === 'MSG_WAIT_FAILED') {
|
if ($response['error_message'] === 'MSG_WAIT_FAILED') {
|
||||||
$this->call_queue[$request['queue']] = [];
|
$this->call_queue[$request['queue']] = [];
|
||||||
$this->methodRecall('', ['message_id' => $request_id, 'postpone' => true]);
|
$this->methodRecall('', ['message_id' => $request_id, 'postpone' => true]);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (\in_array($response['error_message'], ['MSGID_DECREASE_RETRY', 'HISTORY_GET_FAILED', 'RPC_CALL_FAIL', 'PERSISTENT_TIMESTAMP_OUTDATED', 'RPC_MCGET_FAIL', 'no workers running', 'No workers running'])) {
|
if (\in_array($response['error_message'], ['MSGID_DECREASE_RETRY', 'HISTORY_GET_FAILED', 'RPC_CALL_FAIL', 'PERSISTENT_TIMESTAMP_OUTDATED', 'RPC_MCGET_FAIL', 'no workers running', 'No workers running'])) {
|
||||||
Loop::delay(1 * 1000, [$this, 'methodRecall'], ['message_id' => $request_id, ]);
|
Loop::delay(1 * 1000, [$this, 'methodRecall'], ['message_id' => $request_id]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->gotResponseForOutgoingMessageId($request_id);
|
$this->gotResponseForOutgoingMessageId($request_id);
|
||||||
|
|
||||||
$this->handleReject($request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code'], $request['_'] ?? ''));
|
$this->handleReject($request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code'], $request['_'] ?? ''));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
case 303:
|
case 303:
|
||||||
$this->API->datacenter->curdc = $datacenter = (int) \preg_replace('/[^0-9]+/', '', $response['error_message']);
|
$this->API->datacenter->curdc = $datacenter = (int) \preg_replace('/[^0-9]+/', '', $response['error_message']);
|
||||||
|
if (isset($request['file']) && $request['file'] && $this->API->datacenter->has($datacenter . '_media')) {
|
||||||
if (isset($request['file']) && $request['file'] && $this->API->datacenter->has($datacenter.'_media')) {
|
|
||||||
\danog\MadelineProto\Logger::log('Using media DC');
|
\danog\MadelineProto\Logger::log('Using media DC');
|
||||||
$datacenter .= '_media';
|
$datacenter .= '_media';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($request['user_related']) && $request['user_related']) {
|
if (isset($request['user_related']) && $request['user_related']) {
|
||||||
$this->API->settings['connection_settings']['default_dc'] = $this->API->authorized_dc = $this->API->datacenter->curdc;
|
$this->API->settings['connection_settings']['default_dc'] = $this->API->authorized_dc = $this->API->datacenter->curdc;
|
||||||
}
|
}
|
||||||
Loop::defer([$this, 'methodRecall'], ['message_id' => $request_id, 'datacenter' => $datacenter]);
|
Loop::defer([$this, 'methodRecall'], ['message_id' => $request_id, 'datacenter' => $datacenter]);
|
||||||
//$this->API->methodRecall('', ['message_id' => $request_id, 'datacenter' => $datacenter, 'postpone' => true]);
|
//$this->API->methodRecall('', ['message_id' => $request_id, 'datacenter' => $datacenter, 'postpone' => true]);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
case 401:
|
case 401:
|
||||||
switch ($response['error_message']) {
|
switch ($response['error_message']) {
|
||||||
@ -422,123 +374,95 @@ trait ResponseHandler
|
|||||||
case 'SESSION_REVOKED':
|
case 'SESSION_REVOKED':
|
||||||
case 'SESSION_EXPIRED':
|
case 'SESSION_EXPIRED':
|
||||||
$this->gotResponseForOutgoingMessageId($request_id);
|
$this->gotResponseForOutgoingMessageId($request_id);
|
||||||
|
|
||||||
$this->logger->logger($response['error_message'], \danog\MadelineProto\Logger::FATAL_ERROR);
|
$this->logger->logger($response['error_message'], \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||||
foreach ($this->API->datacenter->getDataCenterConnections() as $socket) {
|
foreach ($this->API->datacenter->getDataCenterConnections() as $socket) {
|
||||||
$socket->setTempAuthKey(null);
|
$socket->setTempAuthKey(null);
|
||||||
$socket->setPermAuthKey(null);
|
$socket->setPermAuthKey(null);
|
||||||
$socket->resetSession();
|
$socket->resetSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($response['error_message'] === 'USER_DEACTIVATED') {
|
if ($response['error_message'] === 'USER_DEACTIVATED') {
|
||||||
$this->logger->logger('!!!!!!! WARNING !!!!!!!', \danog\MadelineProto\Logger::FATAL_ERROR);
|
$this->logger->logger('!!!!!!! WARNING !!!!!!!', \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||||
$this->logger->logger("Telegram's flood prevention system suspended this account.", \danog\MadelineProto\Logger::ERROR);
|
$this->logger->logger("Telegram's flood prevention system suspended this account.", \danog\MadelineProto\Logger::ERROR);
|
||||||
$this->logger->logger('To continue, manual verification is required.', \danog\MadelineProto\Logger::FATAL_ERROR);
|
$this->logger->logger('To continue, manual verification is required.', \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||||
$phone = isset($this->authorization['user']['phone']) ? '+'.$this->authorization['user']['phone'] : 'you are currently using';
|
$phone = isset($this->authorization['user']['phone']) ? '+' . $this->authorization['user']['phone'] : 'you are currently using';
|
||||||
$this->logger->logger('Send an email to recover@telegram.org, asking to unban the phone number '.$phone.', and shortly describe what will you do with this phone number.', \danog\MadelineProto\Logger::FATAL_ERROR);
|
$this->logger->logger('Send an email to recover@telegram.org, asking to unban the phone number ' . $phone . ', and shortly describe what will you do with this phone number.', \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||||
$this->logger->logger('Then login again.', \danog\MadelineProto\Logger::FATAL_ERROR);
|
$this->logger->logger('Then login again.', \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||||
$this->logger->logger('If you intentionally deleted this account, ignore this message.', \danog\MadelineProto\Logger::FATAL_ERROR);
|
$this->logger->logger('If you intentionally deleted this account, ignore this message.', \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->API->resetSession();
|
$this->API->resetSession();
|
||||||
|
\danog\MadelineProto\Tools::callFork((function () use (&$request, &$response): \Generator {
|
||||||
\danog\MadelineProto\Tools::callFork((function () use (&$request, &$response) {
|
|
||||||
yield $this->API->initAuthorization();
|
yield $this->API->initAuthorization();
|
||||||
|
|
||||||
$this->handleReject($request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code'], $request['_'] ?? ''));
|
$this->handleReject($request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code'], $request['_'] ?? ''));
|
||||||
})());
|
})());
|
||||||
|
|
||||||
return;
|
return;
|
||||||
case 'AUTH_KEY_UNREGISTERED':
|
case 'AUTH_KEY_UNREGISTERED':
|
||||||
case 'AUTH_KEY_INVALID':
|
case 'AUTH_KEY_INVALID':
|
||||||
if ($this->API->authorized !== MTProto::LOGGED_IN) {
|
if ($this->API->authorized !== MTProto::LOGGED_IN) {
|
||||||
$this->gotResponseForOutgoingMessageId($request_id);
|
$this->gotResponseForOutgoingMessageId($request_id);
|
||||||
|
\danog\MadelineProto\Tools::callFork((function () use (&$request, &$response): \Generator {
|
||||||
\danog\MadelineProto\Tools::callFork((function () use (&$request, &$response) {
|
|
||||||
yield $this->API->initAuthorization();
|
yield $this->API->initAuthorization();
|
||||||
|
|
||||||
$this->handleReject($request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code'], $request['_'] ?? ''));
|
$this->handleReject($request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code'], $request['_'] ?? ''));
|
||||||
})());
|
})());
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->session_id = null;
|
$this->session_id = null;
|
||||||
$this->shared->setTempAuthKey(null);
|
$this->shared->setTempAuthKey(null);
|
||||||
$this->shared->setPermAuthKey(null);
|
$this->shared->setPermAuthKey(null);
|
||||||
|
|
||||||
$this->logger->logger('Auth key not registered, resetting temporary and permanent auth keys...', \danog\MadelineProto\Logger::ERROR);
|
$this->logger->logger('Auth key not registered, resetting temporary and permanent auth keys...', \danog\MadelineProto\Logger::ERROR);
|
||||||
|
|
||||||
if ($this->API->authorized_dc === $this->datacenter && $this->API->authorized === MTProto::LOGGED_IN) {
|
if ($this->API->authorized_dc === $this->datacenter && $this->API->authorized === MTProto::LOGGED_IN) {
|
||||||
$this->gotResponseForOutgoingMessageId($request_id);
|
$this->gotResponseForOutgoingMessageId($request_id);
|
||||||
|
|
||||||
$this->logger->logger('Permanent auth key was main authorized key, logging out...', \danog\MadelineProto\Logger::FATAL_ERROR);
|
$this->logger->logger('Permanent auth key was main authorized key, logging out...', \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||||
foreach ($this->API->datacenter->getDataCenterConnections() as $socket) {
|
foreach ($this->API->datacenter->getDataCenterConnections() as $socket) {
|
||||||
$socket->setTempAuthKey(null);
|
$socket->setTempAuthKey(null);
|
||||||
$socket->setPermAuthKey(null);
|
$socket->setPermAuthKey(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger->logger('!!!!!!! WARNING !!!!!!!', \danog\MadelineProto\Logger::FATAL_ERROR);
|
$this->logger->logger('!!!!!!! WARNING !!!!!!!', \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||||
$this->logger->logger("Telegram's flood prevention system suspended this account.", \danog\MadelineProto\Logger::ERROR);
|
$this->logger->logger("Telegram's flood prevention system suspended this account.", \danog\MadelineProto\Logger::ERROR);
|
||||||
$this->logger->logger('To continue, manual verification is required.', \danog\MadelineProto\Logger::FATAL_ERROR);
|
$this->logger->logger('To continue, manual verification is required.', \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||||
$phone = isset($this->authorization['user']['phone']) ? '+'.$this->authorization['user']['phone'] : 'you are currently using';
|
$phone = isset($this->authorization['user']['phone']) ? '+' . $this->authorization['user']['phone'] : 'you are currently using';
|
||||||
$this->logger->logger('Send an email to recover@telegram.org, asking to unban the phone number '.$phone.', and quickly describe what will you do with this phone number.', \danog\MadelineProto\Logger::FATAL_ERROR);
|
$this->logger->logger('Send an email to recover@telegram.org, asking to unban the phone number ' . $phone . ', and quickly describe what will you do with this phone number.', \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||||
$this->logger->logger('Then login again.', \danog\MadelineProto\Logger::FATAL_ERROR);
|
$this->logger->logger('Then login again.', \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||||
$this->logger->logger('If you intentionally deleted this account, ignore this message.', \danog\MadelineProto\Logger::FATAL_ERROR);
|
$this->logger->logger('If you intentionally deleted this account, ignore this message.', \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||||
|
|
||||||
$this->API->resetSession();
|
$this->API->resetSession();
|
||||||
|
\danog\MadelineProto\Tools::callFork((function () use (&$request, &$response): \Generator {
|
||||||
\danog\MadelineProto\Tools::callFork((function () use (&$request, &$response) {
|
|
||||||
yield $this->API->initAuthorization();
|
yield $this->API->initAuthorization();
|
||||||
|
|
||||||
$this->handleReject($request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code'], $request['_'] ?? ''));
|
$this->handleReject($request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code'], $request['_'] ?? ''));
|
||||||
})());
|
})());
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
\danog\MadelineProto\Tools::callFork((function () use ($request_id) {
|
\danog\MadelineProto\Tools::callFork((function () use ($request_id): \Generator {
|
||||||
yield $this->API->initAuthorization();
|
yield $this->API->initAuthorization();
|
||||||
|
$this->methodRecall('', ['message_id' => $request_id]);
|
||||||
$this->methodRecall('', ['message_id' => $request_id, ]);
|
|
||||||
})());
|
})());
|
||||||
|
|
||||||
return;
|
return;
|
||||||
case 'AUTH_KEY_PERM_EMPTY':
|
case 'AUTH_KEY_PERM_EMPTY':
|
||||||
$this->logger->logger('Temporary auth key not bound, resetting temporary auth key...', \danog\MadelineProto\Logger::ERROR);
|
$this->logger->logger('Temporary auth key not bound, resetting temporary auth key...', \danog\MadelineProto\Logger::ERROR);
|
||||||
|
|
||||||
$this->shared->setTempAuthKey(null);
|
$this->shared->setTempAuthKey(null);
|
||||||
\danog\MadelineProto\Tools::callFork((function () use ($request_id) {
|
\danog\MadelineProto\Tools::callFork((function () use ($request_id): \Generator {
|
||||||
yield $this->API->initAuthorization();
|
yield $this->API->initAuthorization();
|
||||||
$this->methodRecall('', ['message_id' => $request_id, ]);
|
$this->methodRecall('', ['message_id' => $request_id]);
|
||||||
})());
|
})());
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->gotResponseForOutgoingMessageId($request_id);
|
$this->gotResponseForOutgoingMessageId($request_id);
|
||||||
|
|
||||||
$this->handleReject($request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code'], $request['_'] ?? ''));
|
$this->handleReject($request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code'], $request['_'] ?? ''));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
case 420:
|
case 420:
|
||||||
$seconds = \preg_replace('/[^0-9]+/', '', $response['error_message']);
|
$seconds = \preg_replace('/[^0-9]+/', '', $response['error_message']);
|
||||||
$limit = $request['FloodWaitLimit'] ?? $this->API->settings['flood_timeout']['wait_if_lt'];
|
$limit = $request['FloodWaitLimit'] ?? $this->API->settings['flood_timeout']['wait_if_lt'];
|
||||||
if (\is_numeric($seconds) && $seconds < $limit) {
|
if (\is_numeric($seconds) && $seconds < $limit) {
|
||||||
//$this->gotResponseForOutgoingMessageId($request_id);
|
//$this->gotResponseForOutgoingMessageId($request_id);
|
||||||
|
$this->logger->logger('Flood, waiting ' . $seconds . ' seconds before repeating async call of ' . ($request['_'] ?? '') . '...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
$this->logger->logger('Flood, waiting '.$seconds.' seconds before repeating async call of '.($request['_'] ?? '').'...', \danog\MadelineProto\Logger::NOTICE);
|
|
||||||
$request['sent'] = ($request['sent'] ?? \time()) + $seconds;
|
$request['sent'] = ($request['sent'] ?? \time()) + $seconds;
|
||||||
Loop::delay($seconds * 1000, [$this, 'methodRecall'], ['message_id' => $request_id, ]);
|
Loop::delay($seconds * 1000, [$this, 'methodRecall'], ['message_id' => $request_id]);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// no break
|
// no break
|
||||||
default:
|
default:
|
||||||
$this->gotResponseForOutgoingMessageId($request_id);
|
$this->gotResponseForOutgoingMessageId($request_id);
|
||||||
|
|
||||||
$this->handleReject($request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code'], $request['_'] ?? ''));
|
$this->handleReject($request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code'], $request['_'] ?? ''));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
case 'boolTrue':
|
case 'boolTrue':
|
||||||
case 'boolFalse':
|
case 'boolFalse':
|
||||||
@ -546,41 +470,35 @@ trait ResponseHandler
|
|||||||
break;
|
break;
|
||||||
case 'bad_server_salt':
|
case 'bad_server_salt':
|
||||||
case 'bad_msg_notification':
|
case 'bad_msg_notification':
|
||||||
$this->logger->logger('Received bad_msg_notification: '.MTProto::BAD_MSG_ERROR_CODES[$response['error_code']], \danog\MadelineProto\Logger::WARNING);
|
$this->logger->logger('Received bad_msg_notification: ' . MTProto::BAD_MSG_ERROR_CODES[$response['error_code']], \danog\MadelineProto\Logger::WARNING);
|
||||||
switch ($response['error_code']) {
|
switch ($response['error_code']) {
|
||||||
case 48:
|
case 48:
|
||||||
$this->shared->getTempAuthKey()->setServerSalt($response['new_server_salt']);
|
$this->shared->getTempAuthKey()->setServerSalt($response['new_server_salt']);
|
||||||
$this->methodRecall('', ['message_id' => $request_id, 'postpone' => true]);
|
$this->methodRecall('', ['message_id' => $request_id, 'postpone' => true]);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
case 16:
|
case 16:
|
||||||
case 17:
|
case 17:
|
||||||
$this->time_delta = (int) (new \tgseclib\Math\BigInteger(\strrev($response_id), 256))->bitwise_rightShift(32)->subtract(new \tgseclib\Math\BigInteger(\time()))->toString();
|
$this->time_delta = (int) (new \tgseclib\Math\BigInteger(\strrev($response_id), 256))->bitwise_rightShift(32)->subtract(new \tgseclib\Math\BigInteger(\time()))->toString();
|
||||||
$this->logger->logger('Set time delta to '.$this->time_delta, \danog\MadelineProto\Logger::WARNING);
|
$this->logger->logger('Set time delta to ' . $this->time_delta, \danog\MadelineProto\Logger::WARNING);
|
||||||
$this->API->resetMTProtoSession();
|
$this->API->resetMTProtoSession();
|
||||||
$this->shared->setTempAuthKey(null);
|
$this->shared->setTempAuthKey(null);
|
||||||
\danog\MadelineProto\Tools::callFork((function () use ($request_id) {
|
\danog\MadelineProto\Tools::callFork((function () use ($request_id): \Generator {
|
||||||
yield $this->API->initAuthorization();
|
yield $this->API->initAuthorization();
|
||||||
$this->methodRecall('', ['message_id' => $request_id, ]);
|
$this->methodRecall('', ['message_id' => $request_id]);
|
||||||
})());
|
})());
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->gotResponseForOutgoingMessageId($request_id);
|
$this->gotResponseForOutgoingMessageId($request_id);
|
||||||
$this->handleReject($request, new \danog\MadelineProto\RPCErrorException('Received bad_msg_notification: '.MTProto::BAD_MSG_ERROR_CODES[$response['error_code']], $response['error_code'], $request['_'] ?? ''));
|
$this->handleReject($request, new \danog\MadelineProto\RPCErrorException('Received bad_msg_notification: ' . MTProto::BAD_MSG_ERROR_CODES[$response['error_code']], $response['error_code'], $request['_'] ?? ''));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($request['method'] ?? false) && $request['_'] !== 'auth.bindTempAuthKey' && $this->shared->hasTempAuthKey() && !$this->shared->getTempAuthKey()->isInited()) {
|
if (($request['method'] ?? false) && $request['_'] !== 'auth.bindTempAuthKey' && $this->shared->hasTempAuthKey() && !$this->shared->getTempAuthKey()->isInited()) {
|
||||||
$this->shared->getTempAuthKey()->init(true);
|
$this->shared->getTempAuthKey()->init(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($request['promise'])) {
|
if (!isset($request['promise'])) {
|
||||||
$this->gotResponseForOutgoingMessageId($request_id);
|
$this->gotResponseForOutgoingMessageId($request_id);
|
||||||
$this->logger->logger('Response: already got response for '.(isset($request['_']) ? $request['_'] : '-').' with message ID '.$request_id);
|
$this->logger->logger('Response: already got response for ' . (isset($request['_']) ? $request['_'] : '-') . ' with message ID ' . $request_id);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$botAPI = isset($request['botAPI']) && $request['botAPI'];
|
$botAPI = isset($request['botAPI']) && $request['botAPI'];
|
||||||
@ -591,27 +509,26 @@ trait ResponseHandler
|
|||||||
unset($request);
|
unset($request);
|
||||||
$this->gotResponseForOutgoingMessageId($request_id);
|
$this->gotResponseForOutgoingMessageId($request_id);
|
||||||
$r = isset($response['_']) ? $response['_'] : \json_encode($response);
|
$r = isset($response['_']) ? $response['_'] : \json_encode($response);
|
||||||
$this->logger->logger("Defer sending $r to deferred", Logger::ULTRA_VERBOSE);
|
$this->logger->logger("Defer sending {$r} to deferred", Logger::ULTRA_VERBOSE);
|
||||||
\danog\MadelineProto\Tools::callFork((
|
\danog\MadelineProto\Tools::callFork((function () use ($request_id, $response, $botAPI): \Generator {
|
||||||
function () use ($request_id, $response, $botAPI) {
|
$r = isset($response['_']) ? $response['_'] : \json_encode($response);
|
||||||
$r = isset($response['_']) ? $response['_'] : \json_encode($response);
|
$this->logger->logger("Deferred: sent {$r} to deferred", Logger::ULTRA_VERBOSE);
|
||||||
$this->logger->logger("Deferred: sent $r to deferred", Logger::ULTRA_VERBOSE);
|
if ($botAPI) {
|
||||||
if ($botAPI) {
|
$response = yield $this->MTProtoToBotAPI($response);
|
||||||
$response = yield $this->MTProtoToBotAPI($response);
|
}
|
||||||
}
|
if (isset($this->outgoing_messages[$request_id]['promise'])) {
|
||||||
if (isset($this->outgoing_messages[$request_id]['promise'])) { // This should not happen but happens, should debug
|
// This should not happen but happens, should debug
|
||||||
$promise = $this->outgoing_messages[$request_id]['promise'];
|
$promise = $this->outgoing_messages[$request_id]['promise'];
|
||||||
unset($this->outgoing_messages[$request_id]['promise']);
|
unset($this->outgoing_messages[$request_id]['promise']);
|
||||||
try {
|
try {
|
||||||
$promise->resolve($response);
|
$promise->resolve($response);
|
||||||
} catch (\Error $e) {
|
} catch (\Error $e) {
|
||||||
if (\strpos($e->getMessage(), "Promise has already been resolved") !== 0) {
|
if (\strpos($e->getMessage(), "Promise has already been resolved") !== 0) {
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
|
||||||
$this->logger->logger("Got promise already resolved error", \danog\MadelineProto\Logger::FATAL_ERROR);
|
|
||||||
}
|
}
|
||||||
|
$this->logger->logger("Got promise already resolved error", \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)());
|
})());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,9 +28,7 @@ trait SeqNoHandler
|
|||||||
{
|
{
|
||||||
public $session_out_seq_no = 0;
|
public $session_out_seq_no = 0;
|
||||||
public $session_in_seq_no = 0;
|
public $session_in_seq_no = 0;
|
||||||
|
|
||||||
public $session_id;
|
public $session_id;
|
||||||
|
|
||||||
public function generateOutSeqNo($contentRelated)
|
public function generateOutSeqNo($contentRelated)
|
||||||
{
|
{
|
||||||
$in = $contentRelated ? 1 : 0;
|
$in = $contentRelated ? 1 : 0;
|
||||||
@ -39,17 +37,15 @@ trait SeqNoHandler
|
|||||||
//$this->API->logger->logger("OUT: $value + $in = ".$this->session_out_seq_no);
|
//$this->API->logger->logger("OUT: $value + $in = ".$this->session_out_seq_no);
|
||||||
return $value * 2 + $in;
|
return $value * 2 + $in;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkInSeqNo($current_msg_id)
|
public function checkInSeqNo($current_msg_id)
|
||||||
{
|
{
|
||||||
$type = isset($this->incoming_messages[$current_msg_id]['content']['_']) ? $this->incoming_messages[$current_msg_id]['content']['_'] : '-';
|
$type = isset($this->incoming_messages[$current_msg_id]['content']['_']) ? $this->incoming_messages[$current_msg_id]['content']['_'] : '-';
|
||||||
if (isset($this->incoming_messages[$current_msg_id]['seq_no']) && ($seq_no = $this->generateInSeqNo($this->contentRelated($this->incoming_messages[$current_msg_id]['content']))) !== $this->incoming_messages[$current_msg_id]['seq_no']) {
|
if (isset($this->incoming_messages[$current_msg_id]['seq_no']) && ($seq_no = $this->generateInSeqNo($this->contentRelated($this->incoming_messages[$current_msg_id]['content']))) !== $this->incoming_messages[$current_msg_id]['seq_no']) {
|
||||||
$this->API->logger->logger('SECURITY WARNING: Seqno mismatch (should be '.$seq_no.', is '.$this->incoming_messages[$current_msg_id]['seq_no'].', '.$type.')', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->API->logger->logger('SECURITY WARNING: Seqno mismatch (should be ' . $seq_no . ', is ' . $this->incoming_messages[$current_msg_id]['seq_no'] . ', ' . $type . ')', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
} elseif (isset($seq_no)) {
|
} elseif (isset($seq_no)) {
|
||||||
$this->API->logger->logger('Seqno OK (should be '.$seq_no.', is '.$this->incoming_messages[$current_msg_id]['seq_no'].', '.$type.')', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->API->logger->logger('Seqno OK (should be ' . $seq_no . ', is ' . $this->incoming_messages[$current_msg_id]['seq_no'] . ', ' . $type . ')', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateInSeqNo($contentRelated)
|
public function generateInSeqNo($contentRelated)
|
||||||
{
|
{
|
||||||
$in = $contentRelated ? 1 : 0;
|
$in = $contentRelated ? 1 : 0;
|
||||||
@ -58,11 +54,9 @@ trait SeqNoHandler
|
|||||||
//$this->API->logger->logger("IN: $value + $in = ".$this->session_in_seq_no);
|
//$this->API->logger->logger("IN: $value + $in = ".$this->session_in_seq_no);
|
||||||
return $value * 2 + $in;
|
return $value * 2 + $in;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function contentRelated($method)
|
public function contentRelated($method)
|
||||||
{
|
{
|
||||||
$method = \is_array($method) && isset($method['_']) ? $method['_'] : $method;
|
$method = \is_array($method) && isset($method['_']) ? $method['_'] : $method;
|
||||||
|
|
||||||
return \is_string($method) ? !\in_array($method, MTProto::NOT_CONTENT_RELATED) : true;
|
return \is_string($method) ? !\in_array($method, MTProto::NOT_CONTENT_RELATED) : true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Session module.
|
* Session module.
|
||||||
*
|
*
|
||||||
@ -28,20 +29,15 @@ abstract class Session
|
|||||||
use ResponseHandler;
|
use ResponseHandler;
|
||||||
use SeqNoHandler;
|
use SeqNoHandler;
|
||||||
use CallHandler;
|
use CallHandler;
|
||||||
|
|
||||||
public $incoming_messages = [];
|
public $incoming_messages = [];
|
||||||
public $outgoing_messages = [];
|
public $outgoing_messages = [];
|
||||||
public $new_incoming = [];
|
public $new_incoming = [];
|
||||||
public $new_outgoing = [];
|
public $new_outgoing = [];
|
||||||
|
|
||||||
public $pending_outgoing = [];
|
public $pending_outgoing = [];
|
||||||
public $pending_outgoing_key = 'a';
|
public $pending_outgoing_key = 'a';
|
||||||
|
|
||||||
public $time_delta = 0;
|
public $time_delta = 0;
|
||||||
|
|
||||||
public $call_queue = [];
|
public $call_queue = [];
|
||||||
public $ack_queue = [];
|
public $ack_queue = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset MTProto session.
|
* Reset MTProto session.
|
||||||
*
|
*
|
||||||
@ -68,7 +64,6 @@ abstract class Session
|
|||||||
$this->session_out_seq_no = 0;
|
$this->session_out_seq_no = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Backup eventual unsent messages before session deletion.
|
* Backup eventual unsent messages before session deletion.
|
||||||
*
|
*
|
||||||
|
@ -46,7 +46,6 @@ trait AuthKeyHandler
|
|||||||
* @var boolean
|
* @var boolean
|
||||||
*/
|
*/
|
||||||
private $pending_auth = false;
|
private $pending_auth = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create authorization key.
|
* Create authorization key.
|
||||||
*
|
*
|
||||||
@ -62,7 +61,6 @@ trait AuthKeyHandler
|
|||||||
$connection = $this->datacenter->getAuthConnection($datacenter);
|
$connection = $this->datacenter->getAuthConnection($datacenter);
|
||||||
$cdn = $connection->isCDN();
|
$cdn = $connection->isCDN();
|
||||||
$req_pq = $cdn ? 'req_pq' : 'req_pq_multi';
|
$req_pq = $cdn ? 'req_pq' : 'req_pq_multi';
|
||||||
|
|
||||||
for ($retry_id_total = 1; $retry_id_total <= $this->settings['max_tries']['authorization']; $retry_id_total++) {
|
for ($retry_id_total = 1; $retry_id_total <= $this->settings['max_tries']['authorization']; $retry_id_total++) {
|
||||||
try {
|
try {
|
||||||
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['req_pq'], \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['req_pq'], \danog\MadelineProto\Logger::VERBOSE);
|
||||||
@ -128,7 +126,6 @@ trait AuthKeyHandler
|
|||||||
list($p, $q) = [$q, $p];
|
list($p, $q) = [$q, $p];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$pq->equals($p->multiply($q))) {
|
if (!$pq->equals($p->multiply($q))) {
|
||||||
$this->logger->logger('Automatic factorization failed, trying alt py module', \danog\MadelineProto\Logger::ERROR);
|
$this->logger->logger('Automatic factorization failed, trying alt py module', \danog\MadelineProto\Logger::ERROR);
|
||||||
$p = new \tgseclib\Math\BigInteger(\danog\PrimeModule::python_single_alt($pq->__toString()));
|
$p = new \tgseclib\Math\BigInteger(\danog\PrimeModule::python_single_alt($pq->__toString()));
|
||||||
@ -138,7 +135,6 @@ trait AuthKeyHandler
|
|||||||
list($p, $q) = [$q, $p];
|
list($p, $q) = [$q, $p];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$pq->equals($p->multiply($q))) {
|
if (!$pq->equals($p->multiply($q))) {
|
||||||
$this->logger->logger('Automatic factorization failed, trying py module', \danog\MadelineProto\Logger::ERROR);
|
$this->logger->logger('Automatic factorization failed, trying py module', \danog\MadelineProto\Logger::ERROR);
|
||||||
$p = new \tgseclib\Math\BigInteger(\danog\PrimeModule::python_single($pq->__toString()));
|
$p = new \tgseclib\Math\BigInteger(\danog\PrimeModule::python_single($pq->__toString()));
|
||||||
@ -148,7 +144,6 @@ trait AuthKeyHandler
|
|||||||
list($p, $q) = [$q, $p];
|
list($p, $q) = [$q, $p];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$pq->equals($p->multiply($q))) {
|
if (!$pq->equals($p->multiply($q))) {
|
||||||
$this->logger->logger('Automatic factorization failed, trying native module', \danog\MadelineProto\Logger::ERROR);
|
$this->logger->logger('Automatic factorization failed, trying native module', \danog\MadelineProto\Logger::ERROR);
|
||||||
$p = new \tgseclib\Math\BigInteger(\danog\PrimeModule::native_single($pq->__toString()));
|
$p = new \tgseclib\Math\BigInteger(\danog\PrimeModule::native_single($pq->__toString()));
|
||||||
@ -158,37 +153,32 @@ trait AuthKeyHandler
|
|||||||
list($p, $q) = [$q, $p];
|
list($p, $q) = [$q, $p];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$pq->equals($p->multiply($q))) {
|
if (!$pq->equals($p->multiply($q))) {
|
||||||
$this->logger->logger('Automatic factorization failed, trying wolfram module', \danog\MadelineProto\Logger::ERROR);
|
$this->logger->logger('Automatic factorization failed, trying wolfram module', \danog\MadelineProto\Logger::ERROR);
|
||||||
|
$p = new \tgseclib\Math\BigInteger(yield from $this->wolframSingle($pq->__toString()));
|
||||||
$p = new \tgseclib\Math\BigInteger(yield $this->wolframSingle($pq->__toString()));
|
|
||||||
if (!$p->equals(\danog\MadelineProto\Magic::$zero)) {
|
if (!$p->equals(\danog\MadelineProto\Magic::$zero)) {
|
||||||
$q = $pq->divide($p)[0];
|
$q = $pq->divide($p)[0];
|
||||||
if ($p->compare($q) > 0) {
|
if ($p->compare($q) > 0) {
|
||||||
list($p, $q) = [$q, $p];
|
list($p, $q) = [$q, $p];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$pq->equals($p->multiply($q))) {
|
if (!$pq->equals($p->multiply($q))) {
|
||||||
throw new \danog\MadelineProto\SecurityException("Couldn't compute p and q, install prime.madelineproto.xyz to fix. Original pq: {$pq}, computed p: {$p}, computed q: {$q}, computed pq: ".$p->multiply($q));
|
throw new \danog\MadelineProto\SecurityException("Couldn't compute p and q, install prime.madelineproto.xyz to fix. Original pq: {$pq}, computed p: {$p}, computed q: {$q}, computed pq: " . $p->multiply($q));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$this->logger->logger('Factorization ' . $pq . ' = ' . $p . ' * ' . $q, \danog\MadelineProto\Logger::VERBOSE);
|
||||||
$this->logger->logger('Factorization '.$pq.' = '.$p.' * '.$q, \danog\MadelineProto\Logger::VERBOSE);
|
|
||||||
/*
|
/*
|
||||||
* ***********************************************************************
|
* ***********************************************************************
|
||||||
* Serialize object for req_DH_params
|
* Serialize object for req_DH_params
|
||||||
*/
|
*/
|
||||||
$p_bytes = $p->toBytes();
|
$p_bytes = $p->toBytes();
|
||||||
$q_bytes = $q->toBytes();
|
$q_bytes = $q->toBytes();
|
||||||
|
|
||||||
$new_nonce = \danog\MadelineProto\Tools::random(32);
|
$new_nonce = \danog\MadelineProto\Tools::random(32);
|
||||||
$data_unserialized = ['_' => 'p_q_inner_data'.($expires_in < 0 ? '' : '_temp'), 'pq' => $pq_bytes, 'p' => $p_bytes, 'q' => $q_bytes, 'nonce' => $nonce, 'server_nonce' => $server_nonce, 'new_nonce' => $new_nonce, 'expires_in' => $expires_in, 'dc' => \preg_replace('|_.*|', '', $datacenter)];
|
$data_unserialized = ['_' => 'p_q_inner_data' . ($expires_in < 0 ? '' : '_temp'), 'pq' => $pq_bytes, 'p' => $p_bytes, 'q' => $q_bytes, 'nonce' => $nonce, 'server_nonce' => $server_nonce, 'new_nonce' => $new_nonce, 'expires_in' => $expires_in, 'dc' => \preg_replace('|_.*|', '', $datacenter)];
|
||||||
$p_q_inner_data = yield $this->TL->serializeObject(['type' => ''], $data_unserialized, 'p_q_inner_data');
|
$p_q_inner_data = yield $this->TL->serializeObject(['type' => ''], $data_unserialized, 'p_q_inner_data');
|
||||||
/*
|
/*
|
||||||
* ***********************************************************************
|
* ***********************************************************************
|
||||||
@ -196,8 +186,7 @@ trait AuthKeyHandler
|
|||||||
*/
|
*/
|
||||||
$sha_digest = \sha1($p_q_inner_data, true);
|
$sha_digest = \sha1($p_q_inner_data, true);
|
||||||
$random_bytes = \danog\MadelineProto\Tools::random(255 - \strlen($p_q_inner_data) - \strlen($sha_digest));
|
$random_bytes = \danog\MadelineProto\Tools::random(255 - \strlen($p_q_inner_data) - \strlen($sha_digest));
|
||||||
$to_encrypt = $sha_digest.$p_q_inner_data.$random_bytes;
|
$to_encrypt = $sha_digest . $p_q_inner_data . $random_bytes;
|
||||||
|
|
||||||
$encrypted_data = $key->encrypt($to_encrypt);
|
$encrypted_data = $key->encrypt($to_encrypt);
|
||||||
$this->logger->logger('Starting Diffie Hellman key exchange', \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('Starting Diffie Hellman key exchange', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
/*
|
/*
|
||||||
@ -248,10 +237,8 @@ trait AuthKeyHandler
|
|||||||
* Get key, iv and decrypt answer
|
* Get key, iv and decrypt answer
|
||||||
*/
|
*/
|
||||||
$encrypted_answer = $server_dh_params['encrypted_answer'];
|
$encrypted_answer = $server_dh_params['encrypted_answer'];
|
||||||
|
$tmp_aes_key = \sha1($new_nonce . $server_nonce, true) . \substr(\sha1($server_nonce . $new_nonce, true), 0, 12);
|
||||||
$tmp_aes_key = \sha1($new_nonce.$server_nonce, true).\substr(\sha1($server_nonce.$new_nonce, true), 0, 12);
|
$tmp_aes_iv = \substr(\sha1($server_nonce . $new_nonce, true), 12, 8) . \sha1($new_nonce . $new_nonce, true) . \substr($new_nonce, 0, 4);
|
||||||
$tmp_aes_iv = \substr(\sha1($server_nonce.$new_nonce, true), 12, 8).\sha1($new_nonce.$new_nonce, true).\substr($new_nonce, 0, 4);
|
|
||||||
|
|
||||||
$answer_with_hash = $this->igeDecrypt($encrypted_answer, $tmp_aes_key, $tmp_aes_iv);
|
$answer_with_hash = $this->igeDecrypt($encrypted_answer, $tmp_aes_key, $tmp_aes_iv);
|
||||||
/*
|
/*
|
||||||
* ***********************************************************************
|
* ***********************************************************************
|
||||||
@ -331,8 +318,8 @@ trait AuthKeyHandler
|
|||||||
* ***********************************************************************
|
* ***********************************************************************
|
||||||
* encrypt client_DH_inner_data
|
* encrypt client_DH_inner_data
|
||||||
*/
|
*/
|
||||||
$data_with_sha = \sha1($data, true).$data;
|
$data_with_sha = \sha1($data, true) . $data;
|
||||||
$data_with_sha_padded = $data_with_sha.\danog\MadelineProto\Tools::random(\danog\MadelineProto\Tools::posmod(-\strlen($data_with_sha), 16));
|
$data_with_sha_padded = $data_with_sha . \danog\MadelineProto\Tools::random(\danog\MadelineProto\Tools::posmod(-\strlen($data_with_sha), 16));
|
||||||
$encrypted_data = $this->igeEncrypt($data_with_sha_padded, $tmp_aes_key, $tmp_aes_iv);
|
$encrypted_data = $this->igeEncrypt($data_with_sha_padded, $tmp_aes_key, $tmp_aes_iv);
|
||||||
$this->logger->logger('Executing set_client_DH_params...', \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('Executing set_client_DH_params...', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
/*
|
/*
|
||||||
@ -362,9 +349,9 @@ trait AuthKeyHandler
|
|||||||
$auth_key_str = $auth_key->toBytes();
|
$auth_key_str = $auth_key->toBytes();
|
||||||
$auth_key_sha = \sha1($auth_key_str, true);
|
$auth_key_sha = \sha1($auth_key_str, true);
|
||||||
$auth_key_aux_hash = \substr($auth_key_sha, 0, 8);
|
$auth_key_aux_hash = \substr($auth_key_sha, 0, 8);
|
||||||
$new_nonce_hash1 = \substr(\sha1($new_nonce.\chr(1).$auth_key_aux_hash, true), -16);
|
$new_nonce_hash1 = \substr(\sha1($new_nonce . \chr(1) . $auth_key_aux_hash, true), -16);
|
||||||
$new_nonce_hash2 = \substr(\sha1($new_nonce.\chr(2).$auth_key_aux_hash, true), -16);
|
$new_nonce_hash2 = \substr(\sha1($new_nonce . \chr(2) . $auth_key_aux_hash, true), -16);
|
||||||
$new_nonce_hash3 = \substr(\sha1($new_nonce.\chr(3).$auth_key_aux_hash, true), -16);
|
$new_nonce_hash3 = \substr(\sha1($new_nonce . \chr(3) . $auth_key_aux_hash, true), -16);
|
||||||
/*
|
/*
|
||||||
* ***********************************************************************
|
* ***********************************************************************
|
||||||
* Check if the client's nonce and the server's nonce are the same
|
* Check if the client's nonce and the server's nonce are the same
|
||||||
@ -389,16 +376,13 @@ trait AuthKeyHandler
|
|||||||
throw new \danog\MadelineProto\SecurityException('wrong new_nonce_hash1');
|
throw new \danog\MadelineProto\SecurityException('wrong new_nonce_hash1');
|
||||||
}
|
}
|
||||||
$this->logger->logger('Diffie Hellman key exchange processed successfully!', \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('Diffie Hellman key exchange processed successfully!', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
|
|
||||||
$key = $expires_in < 0 ? new PermAuthKey() : new TempAuthKey();
|
$key = $expires_in < 0 ? new PermAuthKey() : new TempAuthKey();
|
||||||
if ($expires_in >= 0) {
|
if ($expires_in >= 0) {
|
||||||
$key->expires(\time() + $expires_in);
|
$key->expires(\time() + $expires_in);
|
||||||
}
|
}
|
||||||
$key->setServerSalt(\substr($new_nonce, 0, 8) ^ \substr($server_nonce, 0, 8));
|
$key->setServerSalt(\substr($new_nonce, 0, 8) ^ \substr($server_nonce, 0, 8));
|
||||||
$key->setAuthKey($auth_key_str);
|
$key->setAuthKey($auth_key_str);
|
||||||
|
|
||||||
$this->logger->logger('Auth key generated', \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('Auth key generated', \danog\MadelineProto\Logger::NOTICE);
|
||||||
|
|
||||||
return $key;
|
return $key;
|
||||||
case 'dh_gen_retry':
|
case 'dh_gen_retry':
|
||||||
if ($Set_client_DH_params_answer['new_nonce_hash2'] != $new_nonce_hash2) {
|
if ($Set_client_DH_params_answer['new_nonce_hash2'] != $new_nonce_hash2) {
|
||||||
@ -419,21 +403,20 @@ trait AuthKeyHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (\danog\MadelineProto\SecurityException $e) {
|
} catch (\danog\MadelineProto\SecurityException $e) {
|
||||||
$this->logger->logger('An exception occurred while generating the authorization key: '.$e->getMessage().' in '.\basename($e->getFile(), '.php').' on line '.$e->getLine().'. Retrying...', \danog\MadelineProto\Logger::WARNING);
|
$this->logger->logger('An exception occurred while generating the authorization key: ' . $e->getMessage() . ' in ' . \basename($e->getFile(), '.php') . ' on line ' . $e->getLine() . '. Retrying...', \danog\MadelineProto\Logger::WARNING);
|
||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
$this->logger->logger('An exception occurred while generating the authorization key: '.$e->getMessage().' in '.\basename($e->getFile(), '.php').' on line '.$e->getLine().'. Retrying...', \danog\MadelineProto\Logger::WARNING);
|
$this->logger->logger('An exception occurred while generating the authorization key: ' . $e->getMessage() . ' in ' . \basename($e->getFile(), '.php') . ' on line ' . $e->getLine() . '. Retrying...', \danog\MadelineProto\Logger::WARNING);
|
||||||
$req_pq = $req_pq === 'req_pq_multi' ? 'req_pq' : 'req_pq_multi';
|
$req_pq = $req_pq === 'req_pq_multi' ? 'req_pq' : 'req_pq_multi';
|
||||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||||
$this->logger->logger('An RPCErrorException occurred while generating the authorization key: '.$e->getMessage().' Retrying (try number '.$retry_id_total.')...', \danog\MadelineProto\Logger::WARNING);
|
$this->logger->logger('An RPCErrorException occurred while generating the authorization key: ' . $e->getMessage() . ' Retrying (try number ' . $retry_id_total . ')...', \danog\MadelineProto\Logger::WARNING);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->logger->logger('An exception occurred while generating the authorization key: '.$e.PHP_EOL.' Retrying (try number '.$retry_id_total.')...', \danog\MadelineProto\Logger::WARNING);
|
$this->logger->logger('An exception occurred while generating the authorization key: ' . $e . PHP_EOL . ' Retrying (try number ' . $retry_id_total . ')...', \danog\MadelineProto\Logger::WARNING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!$cdn) {
|
if (!$cdn) {
|
||||||
throw new \danog\MadelineProto\SecurityException('Auth Failed');
|
throw new \danog\MadelineProto\SecurityException('Auth Failed');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check validity of g_a parameters.
|
* Check validity of g_a parameters.
|
||||||
*
|
*
|
||||||
@ -459,10 +442,8 @@ trait AuthKeyHandler
|
|||||||
if ($g_a->compare(\danog\MadelineProto\Magic::$twoe1984) < 0 || $g_a->compare($p->subtract(\danog\MadelineProto\Magic::$twoe1984)) >= 0) {
|
if ($g_a->compare(\danog\MadelineProto\Magic::$twoe1984) < 0 || $g_a->compare($p->subtract(\danog\MadelineProto\Magic::$twoe1984)) >= 0) {
|
||||||
throw new \danog\MadelineProto\SecurityException('g_a is invalid (2^1984 < g_a < p - 2^1984 is false).');
|
throw new \danog\MadelineProto\SecurityException('g_a is invalid (2^1984 < g_a < p - 2^1984 is false).');
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check validity of p and g parameters.
|
* Check validity of p and g parameters.
|
||||||
*
|
*
|
||||||
@ -492,11 +473,11 @@ trait AuthKeyHandler
|
|||||||
* Almost always fails
|
* Almost always fails
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
$this->logger->logger('Executing p/g checks (2/3)...', \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('Executing p/g checks (2/3)...', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
if (!$p->subtract(\danog\MadelineProto\Magic::$one)->divide(\danog\MadelineProto\Magic::$two)[0]->isPrime()) {
|
if (!$p->subtract(\danog\MadelineProto\Magic::$one)->divide(\danog\MadelineProto\Magic::$two)[0]->isPrime()) {
|
||||||
throw new \danog\MadelineProto\SecurityException("p isn't a safe 2048-bit prime ((p - 1) / 2 isn't a prime).");
|
throw new \danog\MadelineProto\SecurityException("p isn't a safe 2048-bit prime ((p - 1) / 2 isn't a prime).");
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* ***********************************************************************
|
* ***********************************************************************
|
||||||
* Check validity of p
|
* Check validity of p
|
||||||
@ -515,10 +496,8 @@ trait AuthKeyHandler
|
|||||||
if ($g->compare(\danog\MadelineProto\Magic::$one) <= 0 || $g->compare($p->subtract(\danog\MadelineProto\Magic::$one)) >= 0) {
|
if ($g->compare(\danog\MadelineProto\Magic::$one) <= 0 || $g->compare($p->subtract(\danog\MadelineProto\Magic::$one)) >= 0) {
|
||||||
throw new \danog\MadelineProto\SecurityException('g is invalid (1 < g < p - 1 is false).');
|
throw new \danog\MadelineProto\SecurityException('g is invalid (1 < g < p - 1 is false).');
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get diffie-hellman configuration.
|
* Get diffie-hellman configuration.
|
||||||
*
|
*
|
||||||
@ -531,16 +510,13 @@ trait AuthKeyHandler
|
|||||||
$dh_config = yield $this->methodCallAsyncRead('messages.getDhConfig', ['version' => $this->dh_config['version'], 'random_length' => 0], ['datacenter' => $this->datacenter->curdc]);
|
$dh_config = yield $this->methodCallAsyncRead('messages.getDhConfig', ['version' => $this->dh_config['version'], 'random_length' => 0], ['datacenter' => $this->datacenter->curdc]);
|
||||||
if ($dh_config['_'] === 'messages.dhConfigNotModified') {
|
if ($dh_config['_'] === 'messages.dhConfigNotModified') {
|
||||||
$this->logger->logger('DH configuration not modified', \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('DH configuration not modified', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
|
|
||||||
return $this->dh_config;
|
return $this->dh_config;
|
||||||
}
|
}
|
||||||
$dh_config['p'] = new \tgseclib\Math\BigInteger((string) $dh_config['p'], 256);
|
$dh_config['p'] = new \tgseclib\Math\BigInteger((string) $dh_config['p'], 256);
|
||||||
$dh_config['g'] = new \tgseclib\Math\BigInteger($dh_config['g']);
|
$dh_config['g'] = new \tgseclib\Math\BigInteger($dh_config['g']);
|
||||||
$this->checkPG($dh_config['p'], $dh_config['g']);
|
$this->checkPG($dh_config['p'], $dh_config['g']);
|
||||||
|
|
||||||
return $this->dh_config = $dh_config;
|
return $this->dh_config = $dh_config;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind temporary and permanent auth keys.
|
* Bind temporary and permanent auth keys.
|
||||||
*
|
*
|
||||||
@ -555,7 +531,6 @@ trait AuthKeyHandler
|
|||||||
{
|
{
|
||||||
$datacenterConnection = $this->datacenter->getDataCenterConnection($datacenter);
|
$datacenterConnection = $this->datacenter->getDataCenterConnection($datacenter);
|
||||||
$connection = $datacenterConnection->getAuthConnection();
|
$connection = $datacenterConnection->getAuthConnection();
|
||||||
|
|
||||||
for ($retry_id_total = 1; $retry_id_total <= $this->settings['max_tries']['authorization']; $retry_id_total++) {
|
for ($retry_id_total = 1; $retry_id_total <= $this->settings['max_tries']['authorization']; $retry_id_total++) {
|
||||||
try {
|
try {
|
||||||
$this->logger->logger('Binding authorization keys...', \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('Binding authorization keys...', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
@ -564,34 +539,31 @@ trait AuthKeyHandler
|
|||||||
$temp_auth_key_id = $datacenterConnection->getTempAuthKey()->getID();
|
$temp_auth_key_id = $datacenterConnection->getTempAuthKey()->getID();
|
||||||
$perm_auth_key_id = $datacenterConnection->getPermAuthKey()->getID();
|
$perm_auth_key_id = $datacenterConnection->getPermAuthKey()->getID();
|
||||||
$temp_session_id = $connection->session_id;
|
$temp_session_id = $connection->session_id;
|
||||||
$message_data = yield $this->TL->serializeObject(['type' => ''], ['_' => 'bind_auth_key_inner','nonce' => $nonce, 'temp_auth_key_id' => $temp_auth_key_id, 'perm_auth_key_id' => $perm_auth_key_id, 'temp_session_id' => $temp_session_id, 'expires_at' => $expires_at], 'bindTempAuthKey_inner');
|
$message_data = yield $this->TL->serializeObject(['type' => ''], ['_' => 'bind_auth_key_inner', 'nonce' => $nonce, 'temp_auth_key_id' => $temp_auth_key_id, 'perm_auth_key_id' => $perm_auth_key_id, 'temp_session_id' => $temp_session_id, 'expires_at' => $expires_at], 'bindTempAuthKey_inner');
|
||||||
$message_id = $connection->generateMessageId();
|
$message_id = $connection->generateMessageId();
|
||||||
$seq_no = 0;
|
$seq_no = 0;
|
||||||
$encrypted_data = \danog\MadelineProto\Tools::random(16).$message_id.\pack('VV', $seq_no, \strlen($message_data)).$message_data;
|
$encrypted_data = \danog\MadelineProto\Tools::random(16) . $message_id . \pack('VV', $seq_no, \strlen($message_data)) . $message_data;
|
||||||
$message_key = \substr(\sha1($encrypted_data, true), -16);
|
$message_key = \substr(\sha1($encrypted_data, true), -16);
|
||||||
$padding = \danog\MadelineProto\Tools::random(\danog\MadelineProto\Tools::posmod(-\strlen($encrypted_data), 16));
|
$padding = \danog\MadelineProto\Tools::random(\danog\MadelineProto\Tools::posmod(-\strlen($encrypted_data), 16));
|
||||||
list($aes_key, $aes_iv) = $this->oldAesCalculate($message_key, $datacenterConnection->getPermAuthKey()->getAuthKey());
|
list($aes_key, $aes_iv) = $this->oldAesCalculate($message_key, $datacenterConnection->getPermAuthKey()->getAuthKey());
|
||||||
$encrypted_message = $datacenterConnection->getPermAuthKey()->getID().$message_key.$this->igeEncrypt($encrypted_data.$padding, $aes_key, $aes_iv);
|
$encrypted_message = $datacenterConnection->getPermAuthKey()->getID() . $message_key . $this->igeEncrypt($encrypted_data . $padding, $aes_key, $aes_iv);
|
||||||
$res = yield $connection->methodCallAsyncRead('auth.bindTempAuthKey', ['perm_auth_key_id' => $perm_auth_key_id, 'nonce' => $nonce, 'expires_at' => $expires_at, 'encrypted_message' => $encrypted_message], ['msg_id' => $message_id]);
|
$res = yield $connection->methodCallAsyncRead('auth.bindTempAuthKey', ['perm_auth_key_id' => $perm_auth_key_id, 'nonce' => $nonce, 'expires_at' => $expires_at, 'encrypted_message' => $encrypted_message], ['msg_id' => $message_id]);
|
||||||
if ($res === true) {
|
if ($res === true) {
|
||||||
$this->logger->logger('Bound temporary and permanent authorization keys, DC '.$datacenter, \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('Bound temporary and permanent authorization keys, DC ' . $datacenter, \danog\MadelineProto\Logger::NOTICE);
|
||||||
$datacenterConnection->bind();
|
$datacenterConnection->bind();
|
||||||
$datacenterConnection->flush();
|
$datacenterConnection->flush();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (\danog\MadelineProto\SecurityException $e) {
|
} catch (\danog\MadelineProto\SecurityException $e) {
|
||||||
$this->logger->logger('An exception occurred while generating the authorization key: '.$e->getMessage().' Retrying (try number '.$retry_id_total.')...', \danog\MadelineProto\Logger::WARNING);
|
$this->logger->logger('An exception occurred while generating the authorization key: ' . $e->getMessage() . ' Retrying (try number ' . $retry_id_total . ')...', \danog\MadelineProto\Logger::WARNING);
|
||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
$this->logger->logger('An exception occurred while generating the authorization key: '.$e->getMessage().' Retrying (try number '.$retry_id_total.')...', \danog\MadelineProto\Logger::WARNING);
|
$this->logger->logger('An exception occurred while generating the authorization key: ' . $e->getMessage() . ' Retrying (try number ' . $retry_id_total . ')...', \danog\MadelineProto\Logger::WARNING);
|
||||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||||
$this->logger->logger('An RPCErrorException occurred while generating the authorization key: '.$e->getMessage().' Retrying (try number '.$retry_id_total.')...', \danog\MadelineProto\Logger::WARNING);
|
$this->logger->logger('An RPCErrorException occurred while generating the authorization key: ' . $e->getMessage() . ' Retrying (try number ' . $retry_id_total . ')...', \danog\MadelineProto\Logger::WARNING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new \danog\MadelineProto\SecurityException('An error occurred while binding temporary and permanent authorization keys.');
|
throw new \danog\MadelineProto\SecurityException('An error occurred while binding temporary and permanent authorization keys.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factorize number asynchronously using the wolfram API.
|
* Factorize number asynchronously using the wolfram API.
|
||||||
*
|
*
|
||||||
@ -602,22 +574,11 @@ trait AuthKeyHandler
|
|||||||
private function wolframSingle($what): \Generator
|
private function wolframSingle($what): \Generator
|
||||||
{
|
{
|
||||||
$code = yield $this->datacenter->fileGetContents('http://www.wolframalpha.com/api/v1/code');
|
$code = yield $this->datacenter->fileGetContents('http://www.wolframalpha.com/api/v1/code');
|
||||||
$query = 'Do prime factorization of '.$what;
|
$query = 'Do prime factorization of ' . $what;
|
||||||
$params = [
|
$params = ['async' => true, 'banners' => 'raw', 'debuggingdata' => false, 'format' => 'moutput', 'formattimeout' => 8, 'input' => $query, 'output' => 'JSON', 'proxycode' => \json_decode($code, true)['code']];
|
||||||
'async' => true,
|
$url = 'https://www.wolframalpha.com/input/json.jsp?' . \http_build_query($params);
|
||||||
'banners' => 'raw',
|
|
||||||
'debuggingdata' => false,
|
|
||||||
'format' => 'moutput',
|
|
||||||
'formattimeout' => 8,
|
|
||||||
'input' => $query,
|
|
||||||
'output' => 'JSON',
|
|
||||||
'proxycode' => \json_decode($code, true)['code'],
|
|
||||||
];
|
|
||||||
$url = 'https://www.wolframalpha.com/input/json.jsp?'.\http_build_query($params);
|
|
||||||
|
|
||||||
$request = new Request($url);
|
$request = new Request($url);
|
||||||
$request->setHeader('referer', 'https://www.wolframalpha.com/input/?i='.\urlencode($query));
|
$request->setHeader('referer', 'https://www.wolframalpha.com/input/?i=' . \urlencode($query));
|
||||||
|
|
||||||
$res = \json_decode(yield (yield $this->datacenter->getHTTPClient()->request($request))->getBody()->buffer(), true);
|
$res = \json_decode(yield (yield $this->datacenter->getHTTPClient()->request($request))->getBody()->buffer(), true);
|
||||||
if (!isset($res['queryresult']['pods'])) {
|
if (!isset($res['queryresult']['pods'])) {
|
||||||
return false;
|
return false;
|
||||||
@ -625,24 +586,20 @@ trait AuthKeyHandler
|
|||||||
$fres = false;
|
$fres = false;
|
||||||
foreach ($res['queryresult']['pods'] as $cur) {
|
foreach ($res['queryresult']['pods'] as $cur) {
|
||||||
if ($cur['id'] === 'Divisors') {
|
if ($cur['id'] === 'Divisors') {
|
||||||
$fres = \explode(', ', \preg_replace(["/{\d+, /", "/, \d+}$/"], '', $cur['subpods'][0]['moutput']));
|
$fres = \explode(', ', \preg_replace(["/{\\d+, /", "/, \\d+}\$/"], '', $cur['subpods'][0]['moutput']));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (\is_array($fres)) {
|
if (\is_array($fres)) {
|
||||||
$fres = $fres[0];
|
$fres = $fres[0];
|
||||||
|
|
||||||
$newval = \intval($fres);
|
$newval = \intval($fres);
|
||||||
if (\is_int($newval)) {
|
if (\is_int($newval)) {
|
||||||
$fres = $newval;
|
$fres = $newval;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $fres;
|
return $fres;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asynchronously create, bind and check auth keys for all DCs.
|
* Asynchronously create, bind and check auth keys for all DCs.
|
||||||
*
|
*
|
||||||
@ -658,9 +615,7 @@ trait AuthKeyHandler
|
|||||||
}
|
}
|
||||||
$this->logger("Initing authorization...");
|
$this->logger("Initing authorization...");
|
||||||
$initing = $this->initing_authorization;
|
$initing = $this->initing_authorization;
|
||||||
|
|
||||||
$this->initing_authorization = true;
|
$this->initing_authorization = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$dcs = [];
|
$dcs = [];
|
||||||
$postpone = [];
|
$postpone = [];
|
||||||
@ -688,26 +643,22 @@ trait AuthKeyHandler
|
|||||||
$first = \array_shift($dcs)();
|
$first = \array_shift($dcs)();
|
||||||
yield $first;
|
yield $first;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($dcs as $id => &$dc) {
|
foreach ($dcs as $id => &$dc) {
|
||||||
$dc = $dc();
|
$dc = $dc();
|
||||||
}
|
}
|
||||||
yield \danog\MadelineProto\Tools::all($dcs);
|
yield \danog\MadelineProto\Tools::all($dcs);
|
||||||
|
|
||||||
foreach ($postpone as $id => $socket) {
|
foreach ($postpone as $id => $socket) {
|
||||||
yield $this->initAuthorizationSocket($id, $socket);
|
yield from $this->initAuthorizationSocket($id, $socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->pending_auth && empty($this->init_auth_dcs)) {
|
if ($this->pending_auth && empty($this->init_auth_dcs)) {
|
||||||
$this->pending_auth = false;
|
$this->pending_auth = false;
|
||||||
yield $this->initAuthorization();
|
yield from $this->initAuthorization();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
$this->pending_auth = false;
|
$this->pending_auth = false;
|
||||||
$this->initing_authorization = $initing;
|
$this->initing_authorization = $initing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Init auth keys for single DC.
|
* Init auth keys for single DC.
|
||||||
*
|
*
|
||||||
@ -720,20 +671,17 @@ trait AuthKeyHandler
|
|||||||
*/
|
*/
|
||||||
public function initAuthorizationSocket(string $id, DataCenterConnection $socket): \Generator
|
public function initAuthorizationSocket(string $id, DataCenterConnection $socket): \Generator
|
||||||
{
|
{
|
||||||
$this->logger("Initing authorization DC $id...");
|
$this->logger("Initing authorization DC {$id}...");
|
||||||
$this->init_auth_dcs[$id] = true;
|
$this->init_auth_dcs[$id] = true;
|
||||||
$connection = $socket->getAuthConnection();
|
$connection = $socket->getAuthConnection();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$socket->createSession();
|
$socket->createSession();
|
||||||
|
|
||||||
$cdn = $socket->isCDN();
|
$cdn = $socket->isCDN();
|
||||||
$media = $socket->isMedia();
|
$media = $socket->isMedia();
|
||||||
|
|
||||||
if (!$socket->hasTempAuthKey() || !$socket->hasPermAuthKey() || !$socket->isBound()) {
|
if (!$socket->hasTempAuthKey() || !$socket->hasPermAuthKey() || !$socket->isBound()) {
|
||||||
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->createAuthKey(-1, $id));
|
$socket->setPermAuthKey(yield from $this->createAuthKey(-1, $id));
|
||||||
//$socket->authorized(false);
|
//$socket->authorized(false);
|
||||||
}
|
}
|
||||||
if ($media) {
|
if ($media) {
|
||||||
@ -745,40 +693,35 @@ trait AuthKeyHandler
|
|||||||
if ($this->datacenter->getDataCenterConnection($id)->getSettings()['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);
|
||||||
|
|
||||||
//$authorized = $socket->authorized;
|
//$authorized = $socket->authorized;
|
||||||
//$socket->authorized = false;
|
//$socket->authorized = false;
|
||||||
|
|
||||||
$socket->setTempAuthKey(null);
|
$socket->setTempAuthKey(null);
|
||||||
$socket->setTempAuthKey(yield $this->createAuthKey($this->settings['authorization']['default_temp_auth_key_expires_in'], $id));
|
$socket->setTempAuthKey(yield from $this->createAuthKey($this->settings['authorization']['default_temp_auth_key_expires_in'], $id));
|
||||||
yield $this->bindTempAuthKey($this->settings['authorization']['default_temp_auth_key_expires_in'], $id);
|
yield from $this->bindTempAuthKey($this->settings['authorization']['default_temp_auth_key_expires_in'], $id);
|
||||||
|
|
||||||
$this->config = yield $connection->methodCallAsyncRead('help.getConfig', []);
|
$this->config = yield $connection->methodCallAsyncRead('help.getConfig', []);
|
||||||
|
yield from $this->syncAuthorization($id);
|
||||||
yield $this->syncAuthorization($id);
|
|
||||||
} elseif (!$socket->hasTempAuthKey()) {
|
} elseif (!$socket->hasTempAuthKey()) {
|
||||||
$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);
|
||||||
$socket->setTempAuthKey(yield $this->createAuthKey($this->settings['authorization']['default_temp_auth_key_expires_in'], $id));
|
$socket->setTempAuthKey(yield from $this->createAuthKey($this->settings['authorization']['default_temp_auth_key_expires_in'], $id));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!$cdn) {
|
if (!$cdn) {
|
||||||
$socket->bind(false);
|
$socket->bind(false);
|
||||||
$this->config = yield $connection->methodCallAsyncRead('help.getConfig', []);
|
$this->config = yield $connection->methodCallAsyncRead('help.getConfig', []);
|
||||||
yield $this->syncAuthorization($id);
|
yield from $this->syncAuthorization($id);
|
||||||
} elseif (!$socket->hasTempAuthKey()) {
|
} elseif (!$socket->hasTempAuthKey()) {
|
||||||
$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);
|
||||||
$socket->setTempAuthKey(yield $this->createAuthKey($this->settings['authorization']['default_temp_auth_key_expires_in'], $id));
|
$socket->setTempAuthKey(yield from $this->createAuthKey($this->settings['authorization']['default_temp_auth_key_expires_in'], $id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elseif (!$cdn) {
|
} elseif (!$cdn) {
|
||||||
yield $this->syncAuthorization($id);
|
yield from $this->syncAuthorization($id);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
$this->logger("Done initing authorization DC $id");
|
$this->logger("Done initing authorization DC {$id}");
|
||||||
unset($this->init_auth_dcs[$id]);
|
unset($this->init_auth_dcs[$id]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sync authorization data between DCs.
|
* Sync authorization data between DCs.
|
||||||
*
|
*
|
||||||
@ -801,15 +744,15 @@ trait AuthKeyHandler
|
|||||||
}
|
}
|
||||||
if ($authorized_socket->hasTempAuthKey() && $authorized_socket->hasPermAuthKey() && $authorized_socket->isAuthorized() && $this->authorized === self::LOGGED_IN && !$socket->isAuthorized() && !$authorized_socket->isCDN()) {
|
if ($authorized_socket->hasTempAuthKey() && $authorized_socket->hasPermAuthKey() && $authorized_socket->isAuthorized() && $this->authorized === self::LOGGED_IN && !$socket->isAuthorized() && !$authorized_socket->isCDN()) {
|
||||||
try {
|
try {
|
||||||
$this->logger->logger('Trying to copy authorization from dc '.$authorized_dc_id.' to dc '.$id);
|
$this->logger->logger('Trying to copy authorization from dc ' . $authorized_dc_id . ' to dc ' . $id);
|
||||||
$exported_authorization = yield $this->methodCallAsyncRead('auth.exportAuthorization', ['dc_id' => \preg_replace('|_.*|', '', $id)], ['datacenter' => $authorized_dc_id]);
|
$exported_authorization = yield $this->methodCallAsyncRead('auth.exportAuthorization', ['dc_id' => \preg_replace('|_.*|', '', $id)], ['datacenter' => $authorized_dc_id]);
|
||||||
$authorization = yield $this->methodCallAsyncRead('auth.importAuthorization', $exported_authorization, ['datacenter' => $id]);
|
$authorization = yield $this->methodCallAsyncRead('auth.importAuthorization', $exported_authorization, ['datacenter' => $id]);
|
||||||
$socket->authorized(true);
|
$socket->authorized(true);
|
||||||
break;
|
break;
|
||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
$this->logger->logger('Failure while syncing authorization from DC '.$authorized_dc_id.' to DC '.$id.': '.$e->getMessage(), \danog\MadelineProto\Logger::ERROR);
|
$this->logger->logger('Failure while syncing authorization from DC ' . $authorized_dc_id . ' to DC ' . $id . ': ' . $e->getMessage(), \danog\MadelineProto\Logger::ERROR);
|
||||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||||
$this->logger->logger('Failure while syncing authorization from DC '.$authorized_dc_id.' to DC '.$id.': '.$e->getMessage(), \danog\MadelineProto\Logger::ERROR);
|
$this->logger->logger('Failure while syncing authorization from DC ' . $authorized_dc_id . ' to DC ' . $id . ': ' . $e->getMessage(), \danog\MadelineProto\Logger::ERROR);
|
||||||
if ($e->rpc === 'DC_ID_INVALID') {
|
if ($e->rpc === 'DC_ID_INVALID') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,6 @@ trait CallHandler
|
|||||||
{
|
{
|
||||||
return \danog\MadelineProto\Tools::wait($this->methodCallAsyncRead($method, $args, $aargs));
|
return \danog\MadelineProto\Tools::wait($this->methodCallAsyncRead($method, $args, $aargs));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call method and wait asynchronously for response.
|
* Call method and wait asynchronously for response.
|
||||||
*
|
*
|
||||||
@ -54,16 +53,13 @@ trait CallHandler
|
|||||||
*/
|
*/
|
||||||
public function methodCallAsyncRead(string $method, $args = [], array $aargs = ['msg_id' => null]): Promise
|
public function methodCallAsyncRead(string $method, $args = [], array $aargs = ['msg_id' => null]): Promise
|
||||||
{
|
{
|
||||||
$deferred = new Deferred;
|
$deferred = new Deferred();
|
||||||
$this->datacenter->waitGetConnection($aargs['datacenter'] ?? $this->datacenter->curdc)->onResolve(
|
$this->datacenter->waitGetConnection($aargs['datacenter'] ?? $this->datacenter->curdc)->onResolve(static function ($e, $res) use (&$method, &$args, &$aargs, &$deferred) {
|
||||||
static function ($e, $res) use (&$method, &$args, &$aargs, &$deferred) {
|
if ($e) {
|
||||||
if ($e) {
|
throw $e;
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
$deferred->resolve($res->methodCallAsyncRead($method, $args, $aargs));
|
|
||||||
}
|
}
|
||||||
);
|
$deferred->resolve($res->methodCallAsyncRead($method, $args, $aargs));
|
||||||
|
});
|
||||||
return $deferred->promise();
|
return $deferred->promise();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -77,16 +73,13 @@ trait CallHandler
|
|||||||
*/
|
*/
|
||||||
public function methodCallAsyncWrite(string $method, $args = [], array $aargs = ['msg_id' => null]): Promise
|
public function methodCallAsyncWrite(string $method, $args = [], array $aargs = ['msg_id' => null]): Promise
|
||||||
{
|
{
|
||||||
$deferred = new Deferred;
|
$deferred = new Deferred();
|
||||||
$this->datacenter->waitGetConnection($aargs['datacenter'] ?? $this->datacenter->curdc)->onResolve(
|
$this->datacenter->waitGetConnection($aargs['datacenter'] ?? $this->datacenter->curdc)->onResolve(static function ($e, $res) use (&$method, &$args, &$aargs, &$deferred) {
|
||||||
static function ($e, $res) use (&$method, &$args, &$aargs, &$deferred) {
|
if ($e) {
|
||||||
if ($e) {
|
throw $e;
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
$deferred->resolve($res->methodCallAsyncWrite($method, $args, $aargs));
|
|
||||||
}
|
}
|
||||||
);
|
$deferred->resolve($res->methodCallAsyncWrite($method, $args, $aargs));
|
||||||
|
});
|
||||||
return $deferred->promise();
|
return $deferred->promise();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@ class CombinedUpdatesState
|
|||||||
* @var array<UpdatesState>
|
* @var array<UpdatesState>
|
||||||
*/
|
*/
|
||||||
private $states = [];
|
private $states = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor function.
|
* Constructor function.
|
||||||
*
|
*
|
||||||
@ -49,7 +48,6 @@ class CombinedUpdatesState
|
|||||||
$this->states[$channel] = $state;
|
$this->states[$channel] = $state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get or update multiple parameters.
|
* Get or update multiple parameters.
|
||||||
*
|
*
|
||||||
@ -66,10 +64,8 @@ class CombinedUpdatesState
|
|||||||
if (!isset($this->states[$channel])) {
|
if (!isset($this->states[$channel])) {
|
||||||
return $this->states[$channel] = new UpdatesState($init, $channel);
|
return $this->states[$channel] = new UpdatesState($init, $channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->states[$channel]->update($init);
|
return $this->states[$channel]->update($init);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove update state.
|
* Remove update state.
|
||||||
*
|
*
|
||||||
@ -83,7 +79,6 @@ class CombinedUpdatesState
|
|||||||
unset($this->states[$channel]);
|
unset($this->states[$channel]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if update state is present.
|
* Check if update state is present.
|
||||||
*
|
*
|
||||||
@ -95,7 +90,6 @@ class CombinedUpdatesState
|
|||||||
{
|
{
|
||||||
return isset($this->states[$channel]);
|
return isset($this->states[$channel]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Are we currently busy?
|
* Are we currently busy?
|
||||||
*
|
*
|
||||||
|
@ -35,14 +35,12 @@ trait Crypt
|
|||||||
public static function aesCalculate(string $msg_key, string $auth_key, bool $to_server = true): array
|
public static function aesCalculate(string $msg_key, string $auth_key, bool $to_server = true): array
|
||||||
{
|
{
|
||||||
$x = $to_server ? 0 : 8;
|
$x = $to_server ? 0 : 8;
|
||||||
$sha256_a = \hash('sha256', $msg_key.\substr($auth_key, $x, 36), true);
|
$sha256_a = \hash('sha256', $msg_key . \substr($auth_key, $x, 36), true);
|
||||||
$sha256_b = \hash('sha256', \substr($auth_key, 40 + $x, 36).$msg_key, true);
|
$sha256_b = \hash('sha256', \substr($auth_key, 40 + $x, 36) . $msg_key, true);
|
||||||
$aes_key = \substr($sha256_a, 0, 8).\substr($sha256_b, 8, 16).\substr($sha256_a, 24, 8);
|
$aes_key = \substr($sha256_a, 0, 8) . \substr($sha256_b, 8, 16) . \substr($sha256_a, 24, 8);
|
||||||
$aes_iv = \substr($sha256_b, 0, 8).\substr($sha256_a, 8, 16).\substr($sha256_b, 24, 8);
|
$aes_iv = \substr($sha256_b, 0, 8) . \substr($sha256_a, 8, 16) . \substr($sha256_b, 24, 8);
|
||||||
|
|
||||||
return [$aes_key, $aes_iv];
|
return [$aes_key, $aes_iv];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AES KDF function for MTProto v1.
|
* AES KDF function for MTProto v1.
|
||||||
*
|
*
|
||||||
@ -57,16 +55,14 @@ trait Crypt
|
|||||||
public static function oldAesCalculate(string $msg_key, string $auth_key, bool $to_server = true): array
|
public static function oldAesCalculate(string $msg_key, string $auth_key, bool $to_server = true): array
|
||||||
{
|
{
|
||||||
$x = $to_server ? 0 : 8;
|
$x = $to_server ? 0 : 8;
|
||||||
$sha1_a = \sha1($msg_key.\substr($auth_key, $x, 32), true);
|
$sha1_a = \sha1($msg_key . \substr($auth_key, $x, 32), true);
|
||||||
$sha1_b = \sha1(\substr($auth_key, 32 + $x, 16).$msg_key.\substr($auth_key, 48 + $x, 16), true);
|
$sha1_b = \sha1(\substr($auth_key, 32 + $x, 16) . $msg_key . \substr($auth_key, 48 + $x, 16), true);
|
||||||
$sha1_c = \sha1(\substr($auth_key, 64 + $x, 32).$msg_key, true);
|
$sha1_c = \sha1(\substr($auth_key, 64 + $x, 32) . $msg_key, true);
|
||||||
$sha1_d = \sha1($msg_key.\substr($auth_key, 96 + $x, 32), true);
|
$sha1_d = \sha1($msg_key . \substr($auth_key, 96 + $x, 32), true);
|
||||||
$aes_key = \substr($sha1_a, 0, 8).\substr($sha1_b, 8, 12).\substr($sha1_c, 4, 12);
|
$aes_key = \substr($sha1_a, 0, 8) . \substr($sha1_b, 8, 12) . \substr($sha1_c, 4, 12);
|
||||||
$aes_iv = \substr($sha1_a, 8, 12).\substr($sha1_b, 0, 8).\substr($sha1_c, 16, 4).\substr($sha1_d, 0, 8);
|
$aes_iv = \substr($sha1_a, 8, 12) . \substr($sha1_b, 0, 8) . \substr($sha1_c, 16, 4) . \substr($sha1_d, 0, 8);
|
||||||
|
|
||||||
return [$aes_key, $aes_iv];
|
return [$aes_key, $aes_iv];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CTR encrypt.
|
* CTR encrypt.
|
||||||
*
|
*
|
||||||
@ -83,10 +79,8 @@ trait Crypt
|
|||||||
$cipher = new \tgseclib\Crypt\AES('ctr');
|
$cipher = new \tgseclib\Crypt\AES('ctr');
|
||||||
$cipher->setKey($key);
|
$cipher->setKey($key);
|
||||||
$cipher->setIV($iv);
|
$cipher->setIV($iv);
|
||||||
|
|
||||||
return @$cipher->encrypt($message);
|
return @$cipher->encrypt($message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IGE encrypt.
|
* IGE encrypt.
|
||||||
*
|
*
|
||||||
@ -103,7 +97,6 @@ trait Crypt
|
|||||||
$cipher = new \tgseclib\Crypt\AES('ige');
|
$cipher = new \tgseclib\Crypt\AES('ige');
|
||||||
$cipher->setKey($key);
|
$cipher->setKey($key);
|
||||||
$cipher->setIV($iv);
|
$cipher->setIV($iv);
|
||||||
|
|
||||||
return @$cipher->encrypt($message);
|
return @$cipher->encrypt($message);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -122,7 +115,6 @@ trait Crypt
|
|||||||
$cipher = new \tgseclib\Crypt\AES('ige');
|
$cipher = new \tgseclib\Crypt\AES('ige');
|
||||||
$cipher->setKey($key);
|
$cipher->setKey($key);
|
||||||
$cipher->setIV($iv);
|
$cipher->setIV($iv);
|
||||||
|
|
||||||
return @$cipher->decrypt($message);
|
return @$cipher->decrypt($message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -29,26 +29,8 @@ use danog\MadelineProto\Tools;
|
|||||||
class MinDatabase implements TLCallback
|
class MinDatabase implements TLCallback
|
||||||
{
|
{
|
||||||
use Tools;
|
use Tools;
|
||||||
|
const SWITCH_CONSTRUCTORS = ['inputChannel', 'inputUser', 'inputPeerUser', 'inputPeerChannel'];
|
||||||
const SWITCH_CONSTRUCTORS = [
|
const CATCH_PEERS = ['message', 'messageService', 'peerUser', 'peerChannel', 'messageEntityMentionName', 'messageFwdHeader', 'messageActionChatCreate', 'messageActionChatAddUser', 'messageActionChatDeleteUser', 'messageActionChatJoinedByLink'];
|
||||||
'inputChannel',
|
|
||||||
'inputUser',
|
|
||||||
'inputPeerUser',
|
|
||||||
'inputPeerChannel',
|
|
||||||
];
|
|
||||||
const CATCH_PEERS = [
|
|
||||||
'message',
|
|
||||||
'messageService',
|
|
||||||
'peerUser',
|
|
||||||
'peerChannel',
|
|
||||||
'messageEntityMentionName',
|
|
||||||
|
|
||||||
'messageFwdHeader',
|
|
||||||
'messageActionChatCreate',
|
|
||||||
'messageActionChatAddUser',
|
|
||||||
'messageActionChatDeleteUser',
|
|
||||||
'messageActionChatJoinedByLink',
|
|
||||||
];
|
|
||||||
const ORIGINS = ['message', 'messageService'];
|
const ORIGINS = ['message', 'messageService'];
|
||||||
/**
|
/**
|
||||||
* References indexed by location.
|
* References indexed by location.
|
||||||
@ -68,23 +50,19 @@ class MinDatabase implements TLCallback
|
|||||||
* @var \danog\MadelineProto\MTProto
|
* @var \danog\MadelineProto\MTProto
|
||||||
*/
|
*/
|
||||||
private $API;
|
private $API;
|
||||||
|
|
||||||
public function __construct(MTProto $API)
|
public function __construct(MTProto $API)
|
||||||
{
|
{
|
||||||
$this->API = $API;
|
$this->API = $API;
|
||||||
$this->init();
|
$this->init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __wakeup()
|
public function __wakeup()
|
||||||
{
|
{
|
||||||
$this->init();
|
$this->init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __sleep()
|
public function __sleep()
|
||||||
{
|
{
|
||||||
return ['db', 'API'];
|
return ['db', 'API'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function init()
|
public function init()
|
||||||
{
|
{
|
||||||
foreach ($this->db as $id => $origin) {
|
foreach ($this->db as $id => $origin) {
|
||||||
@ -93,48 +71,37 @@ class MinDatabase implements TLCallback
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMethodCallbacks(): array
|
public function getMethodCallbacks(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMethodBeforeCallbacks(): array
|
public function getMethodBeforeCallbacks(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getConstructorCallbacks(): array
|
public function getConstructorCallbacks(): array
|
||||||
{
|
{
|
||||||
return \array_merge(
|
return \array_merge(\array_fill_keys(self::CATCH_PEERS, [[$this, 'addPeer']]), \array_fill_keys(self::ORIGINS, [[$this, 'addOrigin']]));
|
||||||
\array_fill_keys(self::CATCH_PEERS, [[$this, 'addPeer']]),
|
|
||||||
\array_fill_keys(self::ORIGINS, [[$this, 'addOrigin']])
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getConstructorBeforeCallbacks(): array
|
public function getConstructorBeforeCallbacks(): array
|
||||||
{
|
{
|
||||||
return \array_fill_keys(self::ORIGINS, [[$this, 'addOriginContext']]);
|
return \array_fill_keys(self::ORIGINS, [[$this, 'addOriginContext']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getConstructorSerializeCallbacks(): array
|
public function getConstructorSerializeCallbacks(): array
|
||||||
{
|
{
|
||||||
return \array_fill_keys(self::SWITCH_CONSTRUCTORS, [$this, 'populateFrom']);
|
return \array_fill_keys(self::SWITCH_CONSTRUCTORS, [$this, 'populateFrom']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTypeMismatchCallbacks(): array
|
public function getTypeMismatchCallbacks(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function reset()
|
public function reset()
|
||||||
{
|
{
|
||||||
if ($this->cache) {
|
if ($this->cache) {
|
||||||
$this->API->logger->logger('Found '.\count($this->cache).' pending contexts', \danog\MadelineProto\Logger::ERROR);
|
$this->API->logger->logger('Found ' . \count($this->cache) . ' pending contexts', \danog\MadelineProto\Logger::ERROR);
|
||||||
$this->cache = [];
|
$this->cache = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addPeer(array $location)
|
public function addPeer(array $location)
|
||||||
{
|
{
|
||||||
if (!$this->cache) {
|
if (!$this->cache) {
|
||||||
@ -148,18 +115,15 @@ class MinDatabase implements TLCallback
|
|||||||
if ($frame['args'][1]['subtype'] === $previous) {
|
if ($frame['args'][1]['subtype'] === $previous) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$frames[] = $frame['args'][1]['subtype'];
|
$frames[] = $frame['args'][1]['subtype'];
|
||||||
$previous = $frame['args'][1]['subtype'];
|
$previous = $frame['args'][1]['subtype'];
|
||||||
} elseif (isset($frame['args'][1]['type'])) {
|
} elseif (isset($frame['args'][1]['type'])) {
|
||||||
if ($frame['args'][1]['type'] === '') {
|
if ($frame['args'][1]['type'] === '') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($frame['args'][1]['type'] === $previous) {
|
if ($frame['args'][1]['type'] === $previous) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$frames[] = $frame['args'][1]['type'];
|
$frames[] = $frame['args'][1]['type'];
|
||||||
$previous = $frame['args'][1]['type'];
|
$previous = $frame['args'][1]['type'];
|
||||||
}
|
}
|
||||||
@ -168,10 +132,9 @@ class MinDatabase implements TLCallback
|
|||||||
$frames = \array_reverse($frames);
|
$frames = \array_reverse($frames);
|
||||||
$tl_trace = \array_shift($frames);
|
$tl_trace = \array_shift($frames);
|
||||||
foreach ($frames as $frame) {
|
foreach ($frames as $frame) {
|
||||||
$tl_trace .= "['".$frame."']";
|
$tl_trace .= "['" . $frame . "']";
|
||||||
}
|
}
|
||||||
$this->API->logger->logger($tl_trace, \danog\MadelineProto\Logger::ERROR);
|
$this->API->logger->logger($tl_trace, \danog\MadelineProto\Logger::ERROR);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$peers = [];
|
$peers = [];
|
||||||
@ -204,16 +167,13 @@ class MinDatabase implements TLCallback
|
|||||||
foreach ($peers as $id => $true) {
|
foreach ($peers as $id => $true) {
|
||||||
$this->cache[$key][$id] = $id;
|
$this->cache[$key][$id] = $id;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addOriginContext(string $type)
|
public function addOriginContext(string $type)
|
||||||
{
|
{
|
||||||
$this->API->logger->logger("Adding peer origin context for {$type}!", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->API->logger->logger("Adding peer origin context for {$type}!", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
$this->cache[] = [];
|
$this->cache[] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addOrigin(array $data = [])
|
public function addOrigin(array $data = [])
|
||||||
{
|
{
|
||||||
$cache = \array_pop($this->cache);
|
$cache = \array_pop($this->cache);
|
||||||
@ -236,10 +196,9 @@ class MinDatabase implements TLCallback
|
|||||||
}
|
}
|
||||||
$this->db[$id] = $origin;
|
$this->db[$id] = $origin;
|
||||||
}
|
}
|
||||||
$this->API->logger->logger("Added origin ({$data['_']}) to ".\count($cache).' peer locations', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->API->logger->logger("Added origin ({$data['_']}) to " . \count($cache) . ' peer locations', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
}
|
}
|
||||||
|
public function populateFrom(array $object): \Generator
|
||||||
public function populateFrom(array $object)
|
|
||||||
{
|
{
|
||||||
if (!($object['min'] ?? false)) {
|
if (!($object['min'] ?? false)) {
|
||||||
return $object;
|
return $object;
|
||||||
@ -250,17 +209,14 @@ class MinDatabase implements TLCallback
|
|||||||
$new['_'] .= 'FromMessage';
|
$new['_'] .= 'FromMessage';
|
||||||
$new['peer'] = (yield $this->API->getInfo($new['peer']))['InputPeer'];
|
$new['peer'] = (yield $this->API->getInfo($new['peer']))['InputPeer'];
|
||||||
if ($new['peer']['min']) {
|
if ($new['peer']['min']) {
|
||||||
$this->API->logger->logger("Don't have origin peer subinfo with min peer $id, this may fail");
|
$this->API->logger->logger("Don't have origin peer subinfo with min peer {$id}, this may fail");
|
||||||
return $object;
|
return $object;
|
||||||
}
|
}
|
||||||
return $new;
|
return $new;
|
||||||
}
|
}
|
||||||
$this->API->logger->logger("Don't have origin info with min peer $id, this may fail");
|
$this->API->logger->logger("Don't have origin info with min peer {$id}, this may fail");
|
||||||
|
|
||||||
|
|
||||||
return $object;
|
return $object;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if location info is available for peer.
|
* Check if location info is available for peer.
|
||||||
*
|
*
|
||||||
@ -274,6 +230,6 @@ class MinDatabase implements TLCallback
|
|||||||
}
|
}
|
||||||
public function __debugInfo()
|
public function __debugInfo()
|
||||||
{
|
{
|
||||||
return ['MinDatabase instance '.\spl_object_hash($this)];
|
return ['MinDatabase instance ' . \spl_object_hash($this)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Password calculator module.
|
* Password calculator module.
|
||||||
*
|
*
|
||||||
@ -34,7 +35,6 @@ class PasswordCalculator
|
|||||||
{
|
{
|
||||||
use AuthKeyHandler;
|
use AuthKeyHandler;
|
||||||
use Tools;
|
use Tools;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The algorithm to use for calculating the hash of new passwords (a PasswordKdfAlgo object).
|
* The algorithm to use for calculating the hash of new passwords (a PasswordKdfAlgo object).
|
||||||
*
|
*
|
||||||
@ -47,14 +47,12 @@ class PasswordCalculator
|
|||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $secure_random = '';
|
private $secure_random = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The algorithm to use for calculatuing the hash of the current password (a PasswordKdfAlgo object).
|
* The algorithm to use for calculatuing the hash of the current password (a PasswordKdfAlgo object).
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $current_algo;
|
private $current_algo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SRP b parameter.
|
* SRP b parameter.
|
||||||
*
|
*
|
||||||
@ -79,7 +77,6 @@ class PasswordCalculator
|
|||||||
* @var \danog\MadelineProto\Logger
|
* @var \danog\MadelineProto\Logger
|
||||||
*/
|
*/
|
||||||
public $logger;
|
public $logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize logger.
|
* Initialize logger.
|
||||||
*
|
*
|
||||||
@ -89,7 +86,6 @@ class PasswordCalculator
|
|||||||
{
|
{
|
||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Popupate 2FA configuration.
|
* Popupate 2FA configuration.
|
||||||
*
|
*
|
||||||
@ -115,7 +111,6 @@ class PasswordCalculator
|
|||||||
$this->checkPG($object['current_algo']['p'], $object['current_algo']['g']);
|
$this->checkPG($object['current_algo']['p'], $object['current_algo']['g']);
|
||||||
$object['current_algo']['gForHash'] = \str_pad($object['current_algo']['g']->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
|
$object['current_algo']['gForHash'] = \str_pad($object['current_algo']['g']->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
|
||||||
$object['current_algo']['pForHash'] = \str_pad($object['current_algo']['p']->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
|
$object['current_algo']['pForHash'] = \str_pad($object['current_algo']['p']->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Exception("Unknown KDF algo {$object['current_algo']['_']}");
|
throw new Exception("Unknown KDF algo {$object['current_algo']['_']}");
|
||||||
@ -146,7 +141,6 @@ class PasswordCalculator
|
|||||||
$this->checkPG($object['new_algo']['p'], $object['new_algo']['g']);
|
$this->checkPG($object['new_algo']['p'], $object['new_algo']['g']);
|
||||||
$object['new_algo']['gForHash'] = \str_pad($object['new_algo']['g']->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
|
$object['new_algo']['gForHash'] = \str_pad($object['new_algo']['g']->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
|
||||||
$object['new_algo']['pForHash'] = \str_pad($object['new_algo']['p']->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
|
$object['new_algo']['pForHash'] = \str_pad($object['new_algo']['p']->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Exception("Unknown KDF algo {$object['new_algo']['_']}");
|
throw new Exception("Unknown KDF algo {$object['new_algo']['_']}");
|
||||||
@ -154,7 +148,6 @@ class PasswordCalculator
|
|||||||
$this->new_algo = $object['new_algo'];
|
$this->new_algo = $object['new_algo'];
|
||||||
$this->secure_random = $object['secure_random'];
|
$this->secure_random = $object['secure_random'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a random string (eventually prefixed by the specified string).
|
* Create a random string (eventually prefixed by the specified string).
|
||||||
*
|
*
|
||||||
@ -163,9 +156,8 @@ class PasswordCalculator
|
|||||||
*/
|
*/
|
||||||
public function createSalt(string $prefix = ''): string
|
public function createSalt(string $prefix = ''): string
|
||||||
{
|
{
|
||||||
return $prefix.\danog\MadelineProto\Tools::random(32);
|
return $prefix . \danog\MadelineProto\Tools::random(32);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hash specified data using the salt with SHA256.
|
* Hash specified data using the salt with SHA256.
|
||||||
*
|
*
|
||||||
@ -177,9 +169,8 @@ class PasswordCalculator
|
|||||||
*/
|
*/
|
||||||
public function hashSha256(string $data, string $salt): string
|
public function hashSha256(string $data, string $salt): string
|
||||||
{
|
{
|
||||||
return \hash('sha256', $salt.$data.$salt, true);
|
return \hash('sha256', $salt . $data . $salt, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hashes the specified password.
|
* Hashes the specified password.
|
||||||
*
|
*
|
||||||
@ -193,10 +184,8 @@ class PasswordCalculator
|
|||||||
$buf = $this->hashSha256($password, $client_salt);
|
$buf = $this->hashSha256($password, $client_salt);
|
||||||
$buf = $this->hashSha256($buf, $server_salt);
|
$buf = $this->hashSha256($buf, $server_salt);
|
||||||
$hash = \hash_pbkdf2('sha512', $buf, $client_salt, 100000, 0, true);
|
$hash = \hash_pbkdf2('sha512', $buf, $client_salt, 100000, 0, true);
|
||||||
|
|
||||||
return $this->hashSha256($hash, $server_salt);
|
return $this->hashSha256($hash, $server_salt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the InputCheckPassword object for checking the validity of a password using account.checkPassword.
|
* Get the InputCheckPassword object for checking the validity of a password using account.checkPassword.
|
||||||
*
|
*
|
||||||
@ -214,42 +203,30 @@ class PasswordCalculator
|
|||||||
$gForHash = $this->current_algo['gForHash'];
|
$gForHash = $this->current_algo['gForHash'];
|
||||||
$p = $this->current_algo['p'];
|
$p = $this->current_algo['p'];
|
||||||
$pForHash = $this->current_algo['pForHash'];
|
$pForHash = $this->current_algo['pForHash'];
|
||||||
|
|
||||||
$B = $this->srp_B;
|
$B = $this->srp_B;
|
||||||
$BForHash = $this->srp_BForHash;
|
$BForHash = $this->srp_BForHash;
|
||||||
$id = $this->srp_id;
|
$id = $this->srp_id;
|
||||||
|
|
||||||
$x = new BigInteger($this->hashPassword($password, $client_salt, $server_salt), 256);
|
$x = new BigInteger($this->hashPassword($password, $client_salt, $server_salt), 256);
|
||||||
$g_x = $g->powMod($x, $p);
|
$g_x = $g->powMod($x, $p);
|
||||||
|
$k = new BigInteger(\hash('sha256', $pForHash . $gForHash, true), 256);
|
||||||
$k = new BigInteger(\hash('sha256', $pForHash.$gForHash, true), 256);
|
|
||||||
$kg_x = $k->multiply($g_x)->powMod(Magic::$one, $p);
|
$kg_x = $k->multiply($g_x)->powMod(Magic::$one, $p);
|
||||||
|
|
||||||
$a = new BigInteger(\danog\MadelineProto\Tools::random(2048 / 8), 256);
|
$a = new BigInteger(\danog\MadelineProto\Tools::random(2048 / 8), 256);
|
||||||
$A = $g->powMod($a, $p);
|
$A = $g->powMod($a, $p);
|
||||||
$this->checkG($A, $p);
|
$this->checkG($A, $p);
|
||||||
$AForHash = \str_pad($A->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
|
$AForHash = \str_pad($A->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
|
||||||
|
|
||||||
$b_kg_x = $B->powMod(Magic::$one, $p)->subtract($kg_x);
|
$b_kg_x = $B->powMod(Magic::$one, $p)->subtract($kg_x);
|
||||||
|
$u = new BigInteger(\hash('sha256', $AForHash . $BForHash, true), 256);
|
||||||
$u = new BigInteger(\hash('sha256', $AForHash.$BForHash, true), 256);
|
|
||||||
$ux = $u->multiply($x);
|
$ux = $u->multiply($x);
|
||||||
$a_ux = $a->add($ux);
|
$a_ux = $a->add($ux);
|
||||||
|
|
||||||
$S = $b_kg_x->powMod($a_ux, $p);
|
$S = $b_kg_x->powMod($a_ux, $p);
|
||||||
|
|
||||||
$SForHash = \str_pad($S->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
|
$SForHash = \str_pad($S->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
|
||||||
$K = \hash('sha256', $SForHash, true);
|
$K = \hash('sha256', $SForHash, true);
|
||||||
|
|
||||||
$h1 = \hash('sha256', $pForHash, true);
|
$h1 = \hash('sha256', $pForHash, true);
|
||||||
$h2 = \hash('sha256', $gForHash, true);
|
$h2 = \hash('sha256', $gForHash, true);
|
||||||
$h1 ^= $h2;
|
$h1 ^= $h2;
|
||||||
|
$M1 = \hash('sha256', $h1 . \hash('sha256', $client_salt, true) . \hash('sha256', $server_salt, true) . $AForHash . $BForHash . $K, true);
|
||||||
$M1 = \hash('sha256', $h1.\hash('sha256', $client_salt, true).\hash('sha256', $server_salt, true).$AForHash.$BForHash.$K, true);
|
|
||||||
|
|
||||||
return ['_' => 'inputCheckPasswordSRP', 'srp_id' => $id, 'A' => $AForHash, 'M1' => $M1];
|
return ['_' => 'inputCheckPasswordSRP', 'srp_id' => $id, 'A' => $AForHash, 'M1' => $M1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get parameters to be passed to the account.updatePasswordSettings to update/set a 2FA password.
|
* Get parameters to be passed to the account.updatePasswordSettings to update/set a 2FA password.
|
||||||
*
|
*
|
||||||
@ -261,36 +238,24 @@ class PasswordCalculator
|
|||||||
public function getPassword(array $params): array
|
public function getPassword(array $params): array
|
||||||
{
|
{
|
||||||
$oldPassword = $this->getCheckPassword($params['password'] ?? '');
|
$oldPassword = $this->getCheckPassword($params['password'] ?? '');
|
||||||
|
|
||||||
$return = ['password' => $oldPassword, 'new_settings' => ['_' => 'account.passwordInputSettings', 'new_algo' => ['_' => 'passwordKdfAlgoUnknown'], 'new_password_hash' => '', 'hint' => '']];
|
$return = ['password' => $oldPassword, 'new_settings' => ['_' => 'account.passwordInputSettings', 'new_algo' => ['_' => 'passwordKdfAlgoUnknown'], 'new_password_hash' => '', 'hint' => '']];
|
||||||
|
$new_settings =& $return['new_settings'];
|
||||||
$new_settings = &$return['new_settings'];
|
|
||||||
|
|
||||||
if (isset($params['new_password']) && $params['new_password'] !== '') {
|
if (isset($params['new_password']) && $params['new_password'] !== '') {
|
||||||
$client_salt = $this->createSalt($this->new_algo['salt1']);
|
$client_salt = $this->createSalt($this->new_algo['salt1']);
|
||||||
$server_salt = $this->new_algo['salt2'];
|
$server_salt = $this->new_algo['salt2'];
|
||||||
$g = $this->new_algo['g'];
|
$g = $this->new_algo['g'];
|
||||||
$p = $this->new_algo['p'];
|
$p = $this->new_algo['p'];
|
||||||
$pForHash = $this->new_algo['pForHash'];
|
$pForHash = $this->new_algo['pForHash'];
|
||||||
|
|
||||||
$x = new BigInteger($this->hashPassword($params['new_password'], $client_salt, $server_salt), 256);
|
$x = new BigInteger($this->hashPassword($params['new_password'], $client_salt, $server_salt), 256);
|
||||||
$v = $g->powMod($x, $p);
|
$v = $g->powMod($x, $p);
|
||||||
$vForHash = \str_pad($v->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
|
$vForHash = \str_pad($v->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
|
||||||
|
$new_settings['new_algo'] = ['_' => 'passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow', 'salt1' => $client_salt, 'salt2' => $server_salt, 'g' => (int) $g->toString(), 'p' => $pForHash];
|
||||||
$new_settings['new_algo'] = [
|
|
||||||
'_' => 'passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow',
|
|
||||||
'salt1' => $client_salt,
|
|
||||||
'salt2' => $server_salt,
|
|
||||||
'g' => (int) $g->toString(),
|
|
||||||
'p' => $pForHash,
|
|
||||||
];
|
|
||||||
$new_settings['new_password_hash'] = $vForHash;
|
$new_settings['new_password_hash'] = $vForHash;
|
||||||
$new_settings['hint'] = $params['hint'] ?? '';
|
$new_settings['hint'] = $params['hint'] ?? '';
|
||||||
if (isset($params['email'])) {
|
if (isset($params['email'])) {
|
||||||
$new_settings['email'] = $params['email'];
|
$new_settings['email'] = $params['email'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $return;
|
return $return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,9 +29,7 @@ trait PeerHandler
|
|||||||
public $caching_simple = [];
|
public $caching_simple = [];
|
||||||
public $caching_simple_username = [];
|
public $caching_simple_username = [];
|
||||||
public $caching_possible_username = [];
|
public $caching_possible_username = [];
|
||||||
|
|
||||||
public $caching_full_info = [];
|
public $caching_full_info = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert MTProto channel ID to bot API channel ID.
|
* Convert MTProto channel ID to bot API channel ID.
|
||||||
*
|
*
|
||||||
@ -43,7 +41,6 @@ trait PeerHandler
|
|||||||
{
|
{
|
||||||
return -($id + \pow(10, (int) \floor(\log($id, 10) + 3)));
|
return -($id + \pow(10, (int) \floor(\log($id, 10) + 3)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert bot API channel ID to MTProto channel ID.
|
* Convert bot API channel ID to MTProto channel ID.
|
||||||
*
|
*
|
||||||
@ -55,7 +52,6 @@ trait PeerHandler
|
|||||||
{
|
{
|
||||||
return -$id - \pow(10, (int) \floor(\log(-$id, 10)));
|
return -$id - \pow(10, (int) \floor(\log(-$id, 10)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether provided bot API ID is a channel.
|
* Check whether provided bot API ID is a channel.
|
||||||
*
|
*
|
||||||
@ -66,10 +62,8 @@ trait PeerHandler
|
|||||||
public static function isSupergroup($id): bool
|
public static function isSupergroup($id): bool
|
||||||
{
|
{
|
||||||
$log = \log(-$id, 10);
|
$log = \log(-$id, 10);
|
||||||
|
|
||||||
return ($log - \intval($log)) * 1000 < 10;
|
return ($log - \intval($log)) * 1000 < 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set support info.
|
* Set support info.
|
||||||
*
|
*
|
||||||
@ -83,7 +77,6 @@ trait PeerHandler
|
|||||||
{
|
{
|
||||||
$this->supportUser = $support['user']['id'];
|
$this->supportUser = $support['user']['id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add user info.
|
* Add user info.
|
||||||
*
|
*
|
||||||
@ -109,14 +102,12 @@ trait PeerHandler
|
|||||||
} else {
|
} else {
|
||||||
$this->logger->logger("No access hash with user {$user['id']}, tried and failed to fetch data...");
|
$this->logger->logger("No access hash with user {$user['id']}, tried and failed to fetch data...");
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch ($user['_']) {
|
switch ($user['_']) {
|
||||||
case 'user':
|
case 'user':
|
||||||
if (!isset($this->chats[$user['id']]) || $this->chats[$user['id']] !== $user) {
|
if (!isset($this->chats[$user['id']]) || $this->chats[$user['id']] !== $user) {
|
||||||
$this->logger->logger("Updated user {$user['id']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->logger->logger("Updated user {$user['id']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
|
|
||||||
if (($user['min'] ?? false) && isset($this->chats[$user['id']]) && !($this->chats[$user['id']]['min'] ?? false)) {
|
if (($user['min'] ?? false) && isset($this->chats[$user['id']]) && !($this->chats[$user['id']]['min'] ?? false)) {
|
||||||
$this->logger->logger("{$user['id']} is min, filling missing fields", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->logger->logger("{$user['id']} is min, filling missing fields", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
if (isset($this->chats[$user['id']]['access_hash'])) {
|
if (isset($this->chats[$user['id']]['access_hash'])) {
|
||||||
@ -124,7 +115,6 @@ trait PeerHandler
|
|||||||
$user['access_hash'] = $this->chats[$user['id']]['access_hash'];
|
$user['access_hash'] = $this->chats[$user['id']]['access_hash'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->chats[$user['id']] = $user;
|
$this->chats[$user['id']] = $user;
|
||||||
$this->cachePwrChat($user['id'], false, true);
|
$this->cachePwrChat($user['id'], false, true);
|
||||||
}
|
}
|
||||||
@ -135,7 +125,6 @@ trait PeerHandler
|
|||||||
throw new \danog\MadelineProto\Exception('Invalid user provided', $user);
|
throw new \danog\MadelineProto\Exception('Invalid user provided', $user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add chat to database.
|
* Add chat to database.
|
||||||
*
|
*
|
||||||
@ -168,7 +157,6 @@ trait PeerHandler
|
|||||||
if (isset($chat['username']) && !isset($this->caching_simple_username[$chat['username']])) {
|
if (isset($chat['username']) && !isset($this->caching_simple_username[$chat['username']])) {
|
||||||
$this->caching_possible_username[$bot_api_id] = $chat['username'];
|
$this->caching_possible_username[$bot_api_id] = $chat['username'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->cachePwrChat($bot_api_id, false, true);
|
$this->cachePwrChat($bot_api_id, false, true);
|
||||||
} elseif (isset($chat['username']) && !isset($this->chats[$bot_api_id]) && !isset($this->caching_simple_username[$chat['username']])) {
|
} elseif (isset($chat['username']) && !isset($this->chats[$bot_api_id]) && !isset($this->caching_simple_username[$chat['username']])) {
|
||||||
$this->logger->logger("No access hash with {$chat['_']} {$bot_api_id}, trying to fetch by username...");
|
$this->logger->logger("No access hash with {$chat['_']} {$bot_api_id}, trying to fetch by username...");
|
||||||
@ -176,14 +164,12 @@ trait PeerHandler
|
|||||||
} else {
|
} else {
|
||||||
$this->logger->logger("No access hash with {$chat['_']} {$bot_api_id}, tried and failed to fetch data...");
|
$this->logger->logger("No access hash with {$chat['_']} {$bot_api_id}, tried and failed to fetch data...");
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!isset($this->chats[$bot_api_id]) || $this->chats[$bot_api_id] !== $chat) {
|
if (!isset($this->chats[$bot_api_id]) || $this->chats[$bot_api_id] !== $chat) {
|
||||||
$this->logger->logger("Updated chat $bot_api_id", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->logger->logger("Updated chat {$bot_api_id}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
|
|
||||||
if (($chat['min'] ?? false) && isset($this->chats[$bot_api_id]) && !($this->chats[$bot_api_id]['min'] ?? false)) {
|
if (($chat['min'] ?? false) && isset($this->chats[$bot_api_id]) && !($this->chats[$bot_api_id]['min'] ?? false)) {
|
||||||
$this->logger->logger("$bot_api_id is min, filling missing fields", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->logger->logger("{$bot_api_id} is min, filling missing fields", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
$newchat = $this->chats[$bot_api_id];
|
$newchat = $this->chats[$bot_api_id];
|
||||||
foreach (['title', 'username', 'photo', 'banned_rights', 'megagroup', 'verified'] as $field) {
|
foreach (['title', 'username', 'photo', 'banned_rights', 'megagroup', 'verified'] as $field) {
|
||||||
if (isset($chat[$field])) {
|
if (isset($chat[$field])) {
|
||||||
@ -192,33 +178,29 @@ trait PeerHandler
|
|||||||
}
|
}
|
||||||
$chat = $newchat;
|
$chat = $newchat;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->chats[$bot_api_id] = $chat;
|
$this->chats[$bot_api_id] = $chat;
|
||||||
|
if ($this->settings['peer']['full_fetch'] && (!isset($this->full_chats[$bot_api_id]) || $this->full_chats[$bot_api_id]['full']['participants_count'] !== (yield from $this->getFullInfo($bot_api_id))['full']['participants_count'])) {
|
||||||
if ($this->settings['peer']['full_fetch'] && (!isset($this->full_chats[$bot_api_id]) || $this->full_chats[$bot_api_id]['full']['participants_count'] !== (yield $this->getFullInfo($bot_api_id))['full']['participants_count'])) {
|
|
||||||
$this->cachePwrChat($bot_api_id, $this->settings['peer']['full_fetch'], true);
|
$this->cachePwrChat($bot_api_id, $this->settings['peer']['full_fetch'], true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new \danog\MadelineProto\Exception('Invalid chat provided at key '.$key.': '.\var_export($chat, true));
|
throw new \danog\MadelineProto\Exception('Invalid chat provided at key ' . $key . ': ' . \var_export($chat, true));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function cachePwrChat($id, $full_fetch, $send)
|
private function cachePwrChat($id, $full_fetch, $send)
|
||||||
{
|
{
|
||||||
\danog\MadelineProto\Tools::callFork((function () use ($id, $full_fetch, $send) {
|
\danog\MadelineProto\Tools::callFork((function () use ($id, $full_fetch, $send): \Generator {
|
||||||
try {
|
try {
|
||||||
yield $this->getPwrChat($id, $full_fetch, $send);
|
yield from $this->getPwrChat($id, $full_fetch, $send);
|
||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
$this->logger->logger('While caching: '.$e->getMessage(), \danog\MadelineProto\Logger::WARNING);
|
$this->logger->logger('While caching: ' . $e->getMessage(), \danog\MadelineProto\Logger::WARNING);
|
||||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||||
$this->logger->logger('While caching: '.$e->getMessage(), \danog\MadelineProto\Logger::WARNING);
|
$this->logger->logger('While caching: ' . $e->getMessage(), \danog\MadelineProto\Logger::WARNING);
|
||||||
}
|
}
|
||||||
})());
|
})());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if peer is present in internal peer database.
|
* Check if peer is present in internal peer database.
|
||||||
*
|
*
|
||||||
@ -229,7 +211,7 @@ trait PeerHandler
|
|||||||
public function peerIsset($id): \Generator
|
public function peerIsset($id): \Generator
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return isset($this->chats[(yield $this->getInfo($id))['bot_api_id']]);
|
return isset($this->chats[(yield from $this->getInfo($id))['bot_api_id']]);
|
||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
return false;
|
return false;
|
||||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||||
@ -239,11 +221,9 @@ trait PeerHandler
|
|||||||
if ($e->rpc === 'CHANNEL_PRIVATE') {
|
if ($e->rpc === 'CHANNEL_PRIVATE') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if all peer entities are in db.
|
* Check if all peer entities are in db.
|
||||||
*
|
*
|
||||||
@ -258,7 +238,7 @@ trait PeerHandler
|
|||||||
try {
|
try {
|
||||||
foreach ($entities as $entity) {
|
foreach ($entities as $entity) {
|
||||||
if ($entity['_'] === 'messageEntityMentionName' || $entity['_'] === 'inputMessageEntityMentionName') {
|
if ($entity['_'] === 'messageEntityMentionName' || $entity['_'] === 'inputMessageEntityMentionName') {
|
||||||
if (!yield $this->peerIsset($entity['user_id'])) {
|
if (!(yield from $this->peerIsset($entity['user_id']))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -266,10 +246,8 @@ trait PeerHandler
|
|||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if fwd peer is set.
|
* Check if fwd peer is set.
|
||||||
*
|
*
|
||||||
@ -282,19 +260,17 @@ trait PeerHandler
|
|||||||
public function fwdPeerIsset(array $fwd): \Generator
|
public function fwdPeerIsset(array $fwd): \Generator
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (isset($fwd['user_id']) && !yield $this->peerIsset($fwd['user_id'])) {
|
if (isset($fwd['user_id']) && !(yield from $this->peerIsset($fwd['user_id']))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (isset($fwd['channel_id']) && !yield $this->peerIsset($this->toSupergroup($fwd['channel_id']))) {
|
if (isset($fwd['channel_id']) && !(yield from $this->peerIsset($this->toSupergroup($fwd['channel_id'])))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get folder ID from object.
|
* Get folder ID from object.
|
||||||
*
|
*
|
||||||
@ -327,7 +303,7 @@ trait PeerHandler
|
|||||||
case 'updateDialogUnreadMark':
|
case 'updateDialogUnreadMark':
|
||||||
case 'updateNotifySettings':
|
case 'updateNotifySettings':
|
||||||
$id = $id['peer'];
|
$id = $id['peer'];
|
||||||
// no break
|
// no break
|
||||||
case 'updateDraftMessage':
|
case 'updateDraftMessage':
|
||||||
case 'inputDialogPeer':
|
case 'inputDialogPeer':
|
||||||
case 'dialogPeer':
|
case 'dialogPeer':
|
||||||
@ -339,15 +315,12 @@ trait PeerHandler
|
|||||||
case 'folderPeer':
|
case 'folderPeer':
|
||||||
case 'inputFolderPeer':
|
case 'inputFolderPeer':
|
||||||
return $this->getId($id['peer']);
|
return $this->getId($id['peer']);
|
||||||
|
|
||||||
case 'inputUserFromMessage':
|
case 'inputUserFromMessage':
|
||||||
case 'inputPeerUserFromMessage':
|
case 'inputPeerUserFromMessage':
|
||||||
return $id['user_id'];
|
return $id['user_id'];
|
||||||
|
|
||||||
case 'inputChannelFromMessage':
|
case 'inputChannelFromMessage':
|
||||||
case 'inputPeerChannelFromMessage':
|
case 'inputPeerChannelFromMessage':
|
||||||
return $this->toSupergroup($id['channel_id']);
|
return $this->toSupergroup($id['channel_id']);
|
||||||
|
|
||||||
case 'inputUserSelf':
|
case 'inputUserSelf':
|
||||||
case 'inputPeerSelf':
|
case 'inputPeerSelf':
|
||||||
return $this->authorization['user']['id'];
|
return $this->authorization['user']['id'];
|
||||||
@ -383,9 +356,7 @@ trait PeerHandler
|
|||||||
if (!isset($id['from_id']) || $id['to_id']['_'] !== 'peerUser' || $id['to_id']['user_id'] !== $this->authorization['user']['id']) {
|
if (!isset($id['from_id']) || $id['to_id']['_'] !== 'peerUser' || $id['to_id']['user_id'] !== $this->authorization['user']['id']) {
|
||||||
return $this->getId($id['to_id']);
|
return $this->getId($id['to_id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $id['from_id'];
|
return $id['from_id'];
|
||||||
|
|
||||||
case 'updateChannelReadMessagesContents':
|
case 'updateChannelReadMessagesContents':
|
||||||
case 'updateChannelAvailableMessages':
|
case 'updateChannelAvailableMessages':
|
||||||
case 'updateChannel':
|
case 'updateChannel':
|
||||||
@ -399,7 +370,7 @@ trait PeerHandler
|
|||||||
return $this->toSupergroup($id['channel_id']);
|
return $this->toSupergroup($id['channel_id']);
|
||||||
case 'updateChatParticipants':
|
case 'updateChatParticipants':
|
||||||
$id = $id['participants'];
|
$id = $id['participants'];
|
||||||
// no break
|
// no break
|
||||||
case 'updateChatUserTyping':
|
case 'updateChatUserTyping':
|
||||||
case 'updateChatParticipantAdd':
|
case 'updateChatParticipantAdd':
|
||||||
case 'updateChatParticipantDelete':
|
case 'updateChatParticipantDelete':
|
||||||
@ -434,18 +405,18 @@ trait PeerHandler
|
|||||||
case 'updateEditChannelMessage':
|
case 'updateEditChannelMessage':
|
||||||
return $this->getId($id['message']);
|
return $this->getId($id['message']);
|
||||||
default:
|
default:
|
||||||
throw new \danog\MadelineProto\Exception('Invalid constructor given '.\var_export($id, true));
|
throw new \danog\MadelineProto\Exception('Invalid constructor given ' . \var_export($id, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (\is_string($id)) {
|
if (\is_string($id)) {
|
||||||
if (\strpos($id, '#') !== false) {
|
if (\strpos($id, '#') !== false) {
|
||||||
if (\preg_match('/^channel#(\d*)/', $id, $matches)) {
|
if (\preg_match('/^channel#(\\d*)/', $id, $matches)) {
|
||||||
return $this->toSupergroup($matches[1]);
|
return $this->toSupergroup($matches[1]);
|
||||||
}
|
}
|
||||||
if (\preg_match('/^chat#(\d*)/', $id, $matches)) {
|
if (\preg_match('/^chat#(\\d*)/', $id, $matches)) {
|
||||||
$id = '-'.$matches[1];
|
$id = '-' . $matches[1];
|
||||||
}
|
}
|
||||||
if (\preg_match('/^user#(\d*)/', $id, $matches)) {
|
if (\preg_match('/^user#(\\d*)/', $id, $matches)) {
|
||||||
return $matches[1];
|
return $matches[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -454,13 +425,10 @@ trait PeerHandler
|
|||||||
if (\is_string($id)) {
|
if (\is_string($id)) {
|
||||||
$id = \danog\MadelineProto\Magic::$bigint ? (float) $id : (int) $id;
|
$id = \danog\MadelineProto\Magic::$bigint ? (float) $id : (int) $id;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $id;
|
return $id;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get info about peer, returns an Info object.
|
* Get info about peer, returns an Info object.
|
||||||
*
|
*
|
||||||
@ -483,14 +451,13 @@ trait PeerHandler
|
|||||||
return $this->getSecretChat($id['chat_id']);
|
return $this->getSecretChat($id['chat_id']);
|
||||||
case 'updateNewEncryptedMessage':
|
case 'updateNewEncryptedMessage':
|
||||||
$id = $id['message'];
|
$id = $id['message'];
|
||||||
// no break
|
// no break
|
||||||
case 'encryptedMessage':
|
case 'encryptedMessage':
|
||||||
case 'encryptedMessageService':
|
case 'encryptedMessageService':
|
||||||
$id = $id['chat_id'];
|
$id = $id['chat_id'];
|
||||||
if (!isset($this->secret_chats[$id])) {
|
if (!isset($this->secret_chats[$id])) {
|
||||||
throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['sec_peer_not_in_db']);
|
throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['sec_peer_not_in_db']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->secret_chats[$id];
|
return $this->secret_chats[$id];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -499,13 +466,11 @@ trait PeerHandler
|
|||||||
if ($try_id !== false) {
|
if ($try_id !== false) {
|
||||||
$id = $try_id;
|
$id = $try_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
$tried_simple = false;
|
$tried_simple = false;
|
||||||
|
|
||||||
if (\is_numeric($id)) {
|
if (\is_numeric($id)) {
|
||||||
if (!isset($this->chats[$id])) {
|
if (!isset($this->chats[$id])) {
|
||||||
try {
|
try {
|
||||||
$this->logger->logger("Try fetching $id with access hash 0");
|
$this->logger->logger("Try fetching {$id} with access hash 0");
|
||||||
$this->caching_simple[$id] = true;
|
$this->caching_simple[$id] = true;
|
||||||
if ($id < 0) {
|
if ($id < 0) {
|
||||||
if ($this->isSupergroup($id)) {
|
if ($this->isSupergroup($id)) {
|
||||||
@ -530,7 +495,7 @@ trait PeerHandler
|
|||||||
if (isset($this->chats[$id])) {
|
if (isset($this->chats[$id])) {
|
||||||
if (($this->chats[$id]['min'] ?? false) && $this->minDatabase->hasPeer($id) && !isset($this->caching_full_info[$id])) {
|
if (($this->chats[$id]['min'] ?? false) && $this->minDatabase->hasPeer($id) && !isset($this->caching_full_info[$id])) {
|
||||||
$this->caching_full_info[$id] = true;
|
$this->caching_full_info[$id] = true;
|
||||||
$this->logger->logger("Only have min peer for $id in database, trying to fetch full info");
|
$this->logger->logger("Only have min peer for {$id} in database, trying to fetch full info");
|
||||||
try {
|
try {
|
||||||
if ($id < 0) {
|
if ($id < 0) {
|
||||||
yield $this->methodCallAsyncRead('channels.getChannels', ['id' => [$this->genAll($this->chats[$id], $folder_id)['InputChannel']]], ['datacenter' => $this->datacenter->curdc]);
|
yield $this->methodCallAsyncRead('channels.getChannels', ['id' => [$this->genAll($this->chats[$id], $folder_id)['InputChannel']]], ['datacenter' => $this->datacenter->curdc]);
|
||||||
@ -545,7 +510,6 @@ trait PeerHandler
|
|||||||
unset($this->caching_full_info[$id]);
|
unset($this->caching_full_info[$id]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return $this->genAll($this->chats[$id], $folder_id);
|
return $this->genAll($this->chats[$id], $folder_id);
|
||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
@ -558,56 +522,50 @@ trait PeerHandler
|
|||||||
}
|
}
|
||||||
if (!isset($this->settings['pwr']['requests']) || $this->settings['pwr']['requests'] === true && $recursive) {
|
if (!isset($this->settings['pwr']['requests']) || $this->settings['pwr']['requests'] === true && $recursive) {
|
||||||
$dbres = [];
|
$dbres = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$dbres = \json_decode(yield $this->datacenter->fileGetContents('https://id.pwrtelegram.xyz/db/getusername?id='.$id), true);
|
$dbres = \json_decode(yield $this->datacenter->fileGetContents('https://id.pwrtelegram.xyz/db/getusername?id=' . $id), true);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->logger->logger($e);
|
$this->logger->logger($e);
|
||||||
}
|
}
|
||||||
if (isset($dbres['ok']) && $dbres['ok']) {
|
if (isset($dbres['ok']) && $dbres['ok']) {
|
||||||
yield $this->resolveUsername('@'.$dbres['result']);
|
yield from $this->resolveUsername('@' . $dbres['result']);
|
||||||
|
return yield from $this->getInfo($id, false);
|
||||||
return yield $this->getInfo($id, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($tried_simple && isset($this->caching_possible_username[$id])) {
|
if ($tried_simple && isset($this->caching_possible_username[$id])) {
|
||||||
$this->logger->logger("No access hash with $id, trying to fetch by username...");
|
$this->logger->logger("No access hash with {$id}, trying to fetch by username...");
|
||||||
|
|
||||||
$user = $this->caching_possible_username[$id];
|
$user = $this->caching_possible_username[$id];
|
||||||
unset($this->caching_possible_username[$id]);
|
unset($this->caching_possible_username[$id]);
|
||||||
|
return yield from $this->getInfo($user);
|
||||||
return yield $this->getInfo($user);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database');
|
throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database');
|
||||||
}
|
}
|
||||||
if (\preg_match('@(?:t|telegram)\.(?:me|dog)/(joinchat/)?([a-z0-9_-]*)@i', $id, $matches)) {
|
if (\preg_match('@(?:t|telegram)\\.(?:me|dog)/(joinchat/)?([a-z0-9_-]*)@i', $id, $matches)) {
|
||||||
if ($matches[1] === '') {
|
if ($matches[1] === '') {
|
||||||
$id = $matches[2];
|
$id = $matches[2];
|
||||||
} else {
|
} else {
|
||||||
$invite = yield $this->methodCallAsyncRead('messages.checkChatInvite', ['hash' => $matches[2]], ['datacenter' => $this->datacenter->curdc]);
|
$invite = yield $this->methodCallAsyncRead('messages.checkChatInvite', ['hash' => $matches[2]], ['datacenter' => $this->datacenter->curdc]);
|
||||||
if (isset($invite['chat'])) {
|
if (isset($invite['chat'])) {
|
||||||
return yield $this->getInfo($invite['chat']);
|
return yield from $this->getInfo($invite['chat']);
|
||||||
}
|
}
|
||||||
throw new \danog\MadelineProto\Exception('You have not joined this chat');
|
throw new \danog\MadelineProto\Exception('You have not joined this chat');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$id = \strtolower(\str_replace('@', '', $id));
|
$id = \strtolower(\str_replace('@', '', $id));
|
||||||
if ($id === 'me') {
|
if ($id === 'me') {
|
||||||
return yield $this->getInfo($this->authorization['user']['id']);
|
return yield from $this->getInfo($this->authorization['user']['id']);
|
||||||
}
|
}
|
||||||
if ($id === 'support') {
|
if ($id === 'support') {
|
||||||
if (!$this->supportUser) {
|
if (!$this->supportUser) {
|
||||||
yield $this->methodCallAsyncRead('help.getSupport', [], ['datacenter' => $this->settings['connection_settings']['default_dc']]);
|
yield $this->methodCallAsyncRead('help.getSupport', [], ['datacenter' => $this->settings['connection_settings']['default_dc']]);
|
||||||
}
|
}
|
||||||
|
return yield from $this->getInfo($this->supportUser);
|
||||||
return yield $this->getInfo($this->supportUser);
|
|
||||||
}
|
}
|
||||||
foreach ($this->chats as $bot_api_id => $chat) {
|
foreach ($this->chats as $bot_api_id => $chat) {
|
||||||
if (isset($chat['username']) && \strtolower($chat['username']) === $id) {
|
if (isset($chat['username']) && \strtolower($chat['username']) === $id) {
|
||||||
if ($chat['min'] ?? false && !isset($this->caching_full_info[$bot_api_id])) {
|
if ($chat['min'] ?? false && !isset($this->caching_full_info[$bot_api_id])) {
|
||||||
$this->caching_full_info[$bot_api_id] = true;
|
$this->caching_full_info[$bot_api_id] = true;
|
||||||
$this->logger->logger("Only have min peer for $bot_api_id in database, trying to fetch full info");
|
$this->logger->logger("Only have min peer for {$bot_api_id} in database, trying to fetch full info");
|
||||||
try {
|
try {
|
||||||
if ($bot_api_id < 0) {
|
if ($bot_api_id < 0) {
|
||||||
yield $this->methodCallAsyncRead('channels.getChannels', ['id' => [$this->genAll($this->chats[$bot_api_id], $folder_id)['InputChannel']]], ['datacenter' => $this->datacenter->curdc]);
|
yield $this->methodCallAsyncRead('channels.getChannels', ['id' => [$this->genAll($this->chats[$bot_api_id], $folder_id)['InputChannel']]], ['datacenter' => $this->datacenter->curdc]);
|
||||||
@ -622,19 +580,15 @@ trait PeerHandler
|
|||||||
unset($this->caching_full_info[$bot_api_id]);
|
unset($this->caching_full_info[$bot_api_id]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->genAll($this->chats[$bot_api_id], $folder_id);
|
return $this->genAll($this->chats[$bot_api_id], $folder_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($recursive) {
|
if ($recursive) {
|
||||||
yield $this->resolveUsername($id);
|
yield from $this->resolveUsername($id);
|
||||||
|
return yield from $this->getInfo($id, false);
|
||||||
return yield $this->getInfo($id, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database');
|
throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function genAll($constructor, $folder_id = null)
|
private function genAll($constructor, $folder_id = null)
|
||||||
{
|
{
|
||||||
$res = [$this->TL->getConstructors()->findByPredicate($constructor['_'])['type'] => $constructor];
|
$res = [$this->TL->getConstructors()->findByPredicate($constructor['_'])['type'] => $constructor];
|
||||||
@ -656,7 +610,7 @@ trait PeerHandler
|
|||||||
$res['InputNotifyPeer'] = ['_' => 'inputNotifyPeer', 'peer' => $res['InputPeer']];
|
$res['InputNotifyPeer'] = ['_' => 'inputNotifyPeer', 'peer' => $res['InputPeer']];
|
||||||
$res['user_id'] = $constructor['id'];
|
$res['user_id'] = $constructor['id'];
|
||||||
$res['bot_api_id'] = $constructor['id'];
|
$res['bot_api_id'] = $constructor['id'];
|
||||||
$res['type'] = ($constructor['bot'] ?? false) ? 'bot' : 'user';
|
$res['type'] = $constructor['bot'] ?? false ? 'bot' : 'user';
|
||||||
break;
|
break;
|
||||||
case 'chat':
|
case 'chat':
|
||||||
case 'chatForbidden':
|
case 'chatForbidden':
|
||||||
@ -683,12 +637,12 @@ trait PeerHandler
|
|||||||
$res['InputChannel'] = ['_' => 'inputChannel', 'channel_id' => $constructor['id'], 'access_hash' => $constructor['access_hash'], 'min' => $constructor['min']];
|
$res['InputChannel'] = ['_' => 'inputChannel', 'channel_id' => $constructor['id'], 'access_hash' => $constructor['access_hash'], 'min' => $constructor['min']];
|
||||||
$res['channel_id'] = $constructor['id'];
|
$res['channel_id'] = $constructor['id'];
|
||||||
$res['bot_api_id'] = $this->toSupergroup($constructor['id']);
|
$res['bot_api_id'] = $this->toSupergroup($constructor['id']);
|
||||||
$res['type'] = ($constructor['megagroup'] ?? false) ? 'supergroup' : 'channel';
|
$res['type'] = $constructor['megagroup'] ?? false ? 'supergroup' : 'channel';
|
||||||
break;
|
break;
|
||||||
case 'channelForbidden':
|
case 'channelForbidden':
|
||||||
throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database');
|
throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database');
|
||||||
default:
|
default:
|
||||||
throw new \danog\MadelineProto\Exception('Invalid constructor given '.\var_export($constructor, true));
|
throw new \danog\MadelineProto\Exception('Invalid constructor given ' . \var_export($constructor, true));
|
||||||
}
|
}
|
||||||
if ($folder_id) {
|
if ($folder_id) {
|
||||||
$res['FolderPeer'] = ['_' => 'folderPeer', 'peer' => $res['Peer'], 'folder_id' => $folder_id];
|
$res['FolderPeer'] = ['_' => 'folderPeer', 'peer' => $res['Peer'], 'folder_id' => $folder_id];
|
||||||
@ -696,7 +650,6 @@ trait PeerHandler
|
|||||||
}
|
}
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When were full info for this chat last cached.
|
* When were full info for this chat last cached.
|
||||||
*
|
*
|
||||||
@ -708,7 +661,6 @@ trait PeerHandler
|
|||||||
{
|
{
|
||||||
return isset($this->full_chats[$id]['last_update']) ? $this->full_chats[$id]['last_update'] : 0;
|
return isset($this->full_chats[$id]['last_update']) ? $this->full_chats[$id]['last_update'] : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get full info about peer, returns an FullInfo object.
|
* Get full info about peer, returns an FullInfo object.
|
||||||
*
|
*
|
||||||
@ -720,7 +672,7 @@ trait PeerHandler
|
|||||||
*/
|
*/
|
||||||
public function getFullInfo($id): \Generator
|
public function getFullInfo($id): \Generator
|
||||||
{
|
{
|
||||||
$partial = yield $this->getInfo($id);
|
$partial = (yield from $this->getInfo($id));
|
||||||
if (\time() - $this->fullChatLastUpdated($partial['bot_api_id']) < (isset($this->settings['peer']['full_info_cache_time']) ? $this->settings['peer']['full_info_cache_time'] : 0)) {
|
if (\time() - $this->fullChatLastUpdated($partial['bot_api_id']) < (isset($this->settings['peer']['full_info_cache_time']) ? $this->settings['peer']['full_info_cache_time'] : 0)) {
|
||||||
return \array_merge($partial, $this->full_chats[$partial['bot_api_id']]);
|
return \array_merge($partial, $this->full_chats[$partial['bot_api_id']]);
|
||||||
}
|
}
|
||||||
@ -737,17 +689,13 @@ trait PeerHandler
|
|||||||
$full = (yield $this->methodCallAsyncRead('channels.getFullChannel', ['channel' => $partial['InputChannel']], ['datacenter' => $this->datacenter->curdc]))['full_chat'];
|
$full = (yield $this->methodCallAsyncRead('channels.getFullChannel', ['channel' => $partial['InputChannel']], ['datacenter' => $this->datacenter->curdc]))['full_chat'];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$res = [];
|
$res = [];
|
||||||
$res['full'] = $full;
|
$res['full'] = $full;
|
||||||
$res['last_update'] = \time();
|
$res['last_update'] = \time();
|
||||||
$this->full_chats[$partial['bot_api_id']] = $res;
|
$this->full_chats[$partial['bot_api_id']] = $res;
|
||||||
|
$partial = (yield from $this->getInfo($id));
|
||||||
$partial = yield $this->getInfo($id);
|
|
||||||
|
|
||||||
return \array_merge($partial, $res);
|
return \array_merge($partial, $res);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get full info about peer (including full list of channel members), returns a Chat object.
|
* Get full info about peer (including full list of channel members), returns a Chat object.
|
||||||
*
|
*
|
||||||
@ -759,7 +707,7 @@ trait PeerHandler
|
|||||||
*/
|
*/
|
||||||
public function getPwrChat($id, $fullfetch = true, $send = true): \Generator
|
public function getPwrChat($id, $fullfetch = true, $send = true): \Generator
|
||||||
{
|
{
|
||||||
$full = $fullfetch ? yield $this->getFullInfo($id) : yield $this->getInfo($id);
|
$full = $fullfetch ? yield from $this->getFullInfo($id) : (yield from $this->getInfo($id));
|
||||||
$res = ['id' => $full['bot_api_id'], 'type' => $full['type']];
|
$res = ['id' => $full['bot_api_id'], 'type' => $full['type']];
|
||||||
switch ($full['type']) {
|
switch ($full['type']) {
|
||||||
case 'user':
|
case 'user':
|
||||||
@ -828,15 +776,15 @@ trait PeerHandler
|
|||||||
if (isset($res['participants']) && $fullfetch) {
|
if (isset($res['participants']) && $fullfetch) {
|
||||||
foreach ($res['participants'] as $key => $participant) {
|
foreach ($res['participants'] as $key => $participant) {
|
||||||
$newres = [];
|
$newres = [];
|
||||||
$newres['user'] = yield $this->getPwrChat($participant['user_id'], false, true);
|
$newres['user'] = (yield from $this->getPwrChat($participant['user_id'], false, true));
|
||||||
if (isset($participant['inviter_id'])) {
|
if (isset($participant['inviter_id'])) {
|
||||||
$newres['inviter'] = yield $this->getPwrChat($participant['inviter_id'], false, true);
|
$newres['inviter'] = (yield from $this->getPwrChat($participant['inviter_id'], false, true));
|
||||||
}
|
}
|
||||||
if (isset($participant['promoted_by'])) {
|
if (isset($participant['promoted_by'])) {
|
||||||
$newres['promoted_by'] = yield $this->getPwrChat($participant['promoted_by'], false, true);
|
$newres['promoted_by'] = (yield from $this->getPwrChat($participant['promoted_by'], false, true));
|
||||||
}
|
}
|
||||||
if (isset($participant['kicked_by'])) {
|
if (isset($participant['kicked_by'])) {
|
||||||
$newres['kicked_by'] = yield $this->getPwrChat($participant['kicked_by'], false, true);
|
$newres['kicked_by'] = (yield from $this->getPwrChat($participant['kicked_by'], false, true));
|
||||||
}
|
}
|
||||||
if (isset($participant['date'])) {
|
if (isset($participant['date'])) {
|
||||||
$newres['date'] = $participant['date'];
|
$newres['date'] = $participant['date'];
|
||||||
@ -873,15 +821,14 @@ trait PeerHandler
|
|||||||
$limit = 200;
|
$limit = 200;
|
||||||
$filters = ['channelParticipantsAdmins', 'channelParticipantsBots'];
|
$filters = ['channelParticipantsAdmins', 'channelParticipantsBots'];
|
||||||
foreach ($filters as $filter) {
|
foreach ($filters as $filter) {
|
||||||
yield $this->fetchParticipants($full['InputChannel'], $filter, '', $total_count, $res);
|
yield from $this->fetchParticipants($full['InputChannel'], $filter, '', $total_count, $res);
|
||||||
}
|
}
|
||||||
$q = '';
|
$q = '';
|
||||||
|
|
||||||
$filters = ['channelParticipantsSearch', 'channelParticipantsKicked', 'channelParticipantsBanned'];
|
$filters = ['channelParticipantsSearch', 'channelParticipantsKicked', 'channelParticipantsBanned'];
|
||||||
foreach ($filters as $filter) {
|
foreach ($filters as $filter) {
|
||||||
yield $this->recurseAlphabetSearchParticipants($full['InputChannel'], $filter, $q, $total_count, $res);
|
yield from $this->recurseAlphabetSearchParticipants($full['InputChannel'], $filter, $q, $total_count, $res);
|
||||||
}
|
}
|
||||||
$this->logger->logger('Fetched '.\count($res['participants'])." out of $total_count");
|
$this->logger->logger('Fetched ' . \count($res['participants']) . " out of {$total_count}");
|
||||||
$res['participants'] = \array_values($res['participants']);
|
$res['participants'] = \array_values($res['participants']);
|
||||||
}
|
}
|
||||||
if (!$fullfetch) {
|
if (!$fullfetch) {
|
||||||
@ -890,64 +837,55 @@ trait PeerHandler
|
|||||||
if ($fullfetch || $send) {
|
if ($fullfetch || $send) {
|
||||||
$this->storeDb($res);
|
$this->storeDb($res);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
private function recurseAlphabetSearchParticipants($channel, $filter, $q, $total_count, &$res): \Generator
|
||||||
private function recurseAlphabetSearchParticipants($channel, $filter, $q, $total_count, &$res)
|
|
||||||
{
|
{
|
||||||
if (!yield $this->fetchParticipants($channel, $filter, $q, $total_count, $res)) {
|
if (!(yield from $this->fetchParticipants($channel, $filter, $q, $total_count, $res))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ($x = 'a'; $x !== 'aa' && $total_count > \count($res['participants']); $x++) {
|
for ($x = 'a'; $x !== 'aa' && $total_count > \count($res['participants']); $x++) {
|
||||||
yield $this->recurseAlphabetSearchParticipants($channel, $filter, $q.$x, $total_count, $res);
|
yield from $this->recurseAlphabetSearchParticipants($channel, $filter, $q . $x, $total_count, $res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private function fetchParticipants($channel, $filter, $q, $total_count, &$res): \Generator
|
||||||
private function fetchParticipants($channel, $filter, $q, $total_count, &$res)
|
|
||||||
{
|
{
|
||||||
$offset = 0;
|
$offset = 0;
|
||||||
$limit = 200;
|
$limit = 200;
|
||||||
$has_more = false;
|
$has_more = false;
|
||||||
$cached = false;
|
$cached = false;
|
||||||
$last_count = -1;
|
$last_count = -1;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try {
|
try {
|
||||||
$gres = yield $this->methodCallAsyncRead('channels.getParticipants', ['channel' => $channel, 'filter' => ['_' => $filter, 'q' => $q], 'offset' => $offset, 'limit' => $limit, 'hash' => $hash = $this->getParticipantsHash($channel, $filter, $q, $offset, $limit)], ['datacenter' => $this->datacenter->curdc, 'heavy' => true]);
|
$gres = yield $this->methodCallAsyncRead('channels.getParticipants', ['channel' => $channel, 'filter' => ['_' => $filter, 'q' => $q], 'offset' => $offset, 'limit' => $limit, 'hash' => $hash = $this->getParticipantsHash($channel, $filter, $q, $offset, $limit)], ['datacenter' => $this->datacenter->curdc, 'heavy' => true]);
|
||||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||||
if ($e->rpc === 'CHAT_ADMIN_REQUIRED') {
|
if ($e->rpc === 'CHAT_ADMIN_REQUIRED') {
|
||||||
$this->logger->logger($e->rpc);
|
$this->logger->logger($e->rpc);
|
||||||
|
|
||||||
return $has_more;
|
return $has_more;
|
||||||
}
|
}
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($cached = $gres['_'] === 'channels.channelParticipantsNotModified') {
|
if ($cached = $gres['_'] === 'channels.channelParticipantsNotModified') {
|
||||||
$gres = $this->fetchParticipantsCache($channel, $filter, $q, $offset, $limit);
|
$gres = $this->fetchParticipantsCache($channel, $filter, $q, $offset, $limit);
|
||||||
} else {
|
} else {
|
||||||
$this->storeParticipantsCache($gres, $channel, $filter, $q, $offset, $limit);
|
$this->storeParticipantsCache($gres, $channel, $filter, $q, $offset, $limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($last_count !== -1 && $last_count !== $gres['count']) {
|
if ($last_count !== -1 && $last_count !== $gres['count']) {
|
||||||
$has_more = true;
|
$has_more = true;
|
||||||
} else {
|
} else {
|
||||||
$last_count = $gres['count'];
|
$last_count = $gres['count'];
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($gres['participants'] as $participant) {
|
foreach ($gres['participants'] as $participant) {
|
||||||
$newres = [];
|
$newres = [];
|
||||||
$newres['user'] = yield $this->getPwrChat($participant['user_id'], false, true);
|
$newres['user'] = (yield from $this->getPwrChat($participant['user_id'], false, true));
|
||||||
if (isset($participant['inviter_id'])) {
|
if (isset($participant['inviter_id'])) {
|
||||||
$newres['inviter'] = yield $this->getPwrChat($participant['inviter_id'], false, true);
|
$newres['inviter'] = (yield from $this->getPwrChat($participant['inviter_id'], false, true));
|
||||||
}
|
}
|
||||||
if (isset($participant['kicked_by'])) {
|
if (isset($participant['kicked_by'])) {
|
||||||
$newres['kicked_by'] = yield $this->getPwrChat($participant['kicked_by'], false, true);
|
$newres['kicked_by'] = (yield from $this->getPwrChat($participant['kicked_by'], false, true));
|
||||||
}
|
}
|
||||||
if (isset($participant['promoted_by'])) {
|
if (isset($participant['promoted_by'])) {
|
||||||
$newres['promoted_by'] = yield $this->getPwrChat($participant['promoted_by'], false, true);
|
$newres['promoted_by'] = (yield from $this->getPwrChat($participant['promoted_by'], false, true));
|
||||||
}
|
}
|
||||||
if (isset($participant['date'])) {
|
if (isset($participant['date'])) {
|
||||||
$newres['date'] = $participant['date'];
|
$newres['date'] = $participant['date'];
|
||||||
@ -980,22 +918,18 @@ trait PeerHandler
|
|||||||
}
|
}
|
||||||
$res['participants'][$participant['user_id']] = $newres;
|
$res['participants'][$participant['user_id']] = $newres;
|
||||||
}
|
}
|
||||||
$this->logger->logger('Fetched '.\count($gres['participants'])." channel participants with filter $filter, query $q, offset $offset, limit $limit, hash $hash: ".($cached ? 'cached' : 'not cached').', '.($offset + \count($gres['participants'])).' participants out of '.$gres['count'].', in total fetched '.\count($res['participants']).' out of '.$total_count);
|
$this->logger->logger('Fetched ' . \count($gres['participants']) . " channel participants with filter {$filter}, query {$q}, offset {$offset}, limit {$limit}, hash {$hash}: " . ($cached ? 'cached' : 'not cached') . ', ' . ($offset + \count($gres['participants'])) . ' participants out of ' . $gres['count'] . ', in total fetched ' . \count($res['participants']) . ' out of ' . $total_count);
|
||||||
$offset += \count($gres['participants']);
|
$offset += \count($gres['participants']);
|
||||||
} while (\count($gres['participants']));
|
} while (\count($gres['participants']));
|
||||||
|
|
||||||
if ($offset === $limit) {
|
if ($offset === $limit) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $has_more;
|
return $has_more;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function fetchParticipantsCache($channel, $filter, $q, $offset, $limit)
|
private function fetchParticipantsCache($channel, $filter, $q, $offset, $limit)
|
||||||
{
|
{
|
||||||
return $this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit];
|
return $this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit];
|
||||||
}
|
}
|
||||||
|
|
||||||
private function storeParticipantsCache($gres, $channel, $filter, $q, $offset, $limit)
|
private function storeParticipantsCache($gres, $channel, $filter, $q, $offset, $limit)
|
||||||
{
|
{
|
||||||
//return;
|
//return;
|
||||||
@ -1008,13 +942,11 @@ trait PeerHandler
|
|||||||
$gres['hash'] = \danog\MadelineProto\Tools::genVectorHash($ids);
|
$gres['hash'] = \danog\MadelineProto\Tools::genVectorHash($ids);
|
||||||
$this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit] = $gres;
|
$this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit] = $gres;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getParticipantsHash($channel, $filter, $q, $offset, $limit)
|
private function getParticipantsHash($channel, $filter, $q, $offset, $limit)
|
||||||
{
|
{
|
||||||
return isset($this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit]) ? $this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit]['hash'] : 0;
|
return isset($this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit]) ? $this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit]['hash'] : 0;
|
||||||
}
|
}
|
||||||
|
private function storeDb($res, $force = false): \Generator
|
||||||
private function storeDb($res, $force = false)
|
|
||||||
{
|
{
|
||||||
$settings = isset($this->settings['connection_settings'][$this->datacenter->curdc]) ? $this->settings['connection_settings'][$this->datacenter->curdc] : $this->settings['connection_settings']['all'];
|
$settings = isset($this->settings['connection_settings'][$this->datacenter->curdc]) ? $this->settings['connection_settings'][$this->datacenter->curdc] : $this->settings['connection_settings']['all'];
|
||||||
if (!isset($this->settings['pwr']) || $this->settings['pwr']['pwr'] === false || $settings['test_mode']) {
|
if (!isset($this->settings['pwr']) || $this->settings['pwr']['pwr'] === false || $settings['test_mode']) {
|
||||||
@ -1033,29 +965,22 @@ trait PeerHandler
|
|||||||
if (empty($this->qres)) {
|
if (empty($this->qres)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$payload = \json_encode($this->qres);
|
$payload = \json_encode($this->qres);
|
||||||
//$path = '/tmp/ids'.hash('sha256', $payload);
|
//$path = '/tmp/ids'.hash('sha256', $payload);
|
||||||
//file_put_contents($path, $payload);
|
//file_put_contents($path, $payload);
|
||||||
$id = isset($this->authorization['user']['username']) ? $this->authorization['user']['username'] : $this->authorization['user']['id'];
|
$id = isset($this->authorization['user']['username']) ? $this->authorization['user']['username'] : $this->authorization['user']['id'];
|
||||||
|
$request = new Request('https://id.pwrtelegram.xyz/db' . $this->settings['pwr']['db_token'] . '/addnewmadeline?d=pls&from=' . $id, 'POST');
|
||||||
$request = new Request('https://id.pwrtelegram.xyz/db'.$this->settings['pwr']['db_token'].'/addnewmadeline?d=pls&from='.$id, 'POST');
|
|
||||||
$request->setHeader('content-type', 'application/json');
|
$request->setHeader('content-type', 'application/json');
|
||||||
$request->setBody($payload);
|
$request->setBody($payload);
|
||||||
|
$result = yield (yield $this->datacenter->getHTTPClient()->request($request))->getBody()->buffer();
|
||||||
$result = yield (
|
$this->logger->logger("============ {$result} =============", \danog\MadelineProto\Logger::VERBOSE);
|
||||||
yield $this->datacenter->getHTTPClient()->request($request)
|
|
||||||
)->getBody()->buffer();
|
|
||||||
|
|
||||||
$this->logger->logger("============ $result =============", \danog\MadelineProto\Logger::VERBOSE);
|
|
||||||
$this->qres = [];
|
$this->qres = [];
|
||||||
$this->last_stored = \time() + 10;
|
$this->last_stored = \time() + 10;
|
||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
$this->logger->logger('======= COULD NOT STORE IN DB DUE TO '.$e->getMessage().' =============', \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('======= COULD NOT STORE IN DB DUE TO ' . $e->getMessage() . ' =============', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve username (use getInfo instead).
|
* Resolve username (use getInfo instead).
|
||||||
*
|
*
|
||||||
@ -1069,11 +994,10 @@ trait PeerHandler
|
|||||||
$this->caching_simple_username[$username] = true;
|
$this->caching_simple_username[$username] = true;
|
||||||
$res = yield $this->methodCallAsyncRead('contacts.resolveUsername', ['username' => \str_replace('@', '', $username)], ['datacenter' => $this->datacenter->curdc]);
|
$res = yield $this->methodCallAsyncRead('contacts.resolveUsername', ['username' => \str_replace('@', '', $username)], ['datacenter' => $this->datacenter->curdc]);
|
||||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||||
$this->logger->logger('Username resolution failed with error '.$e->getMessage(), \danog\MadelineProto\Logger::ERROR);
|
$this->logger->logger('Username resolution failed with error ' . $e->getMessage(), \danog\MadelineProto\Logger::ERROR);
|
||||||
if (\strpos($e->rpc, 'FLOOD_WAIT_') === 0 || $e->rpc === 'AUTH_KEY_UNREGISTERED' || $e->rpc === 'USERNAME_INVALID') {
|
if (\strpos($e->rpc, 'FLOOD_WAIT_') === 0 || $e->rpc === 'AUTH_KEY_UNREGISTERED' || $e->rpc === 'USERNAME_INVALID') {
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
if (isset($this->caching_simple_username[$username])) {
|
if (isset($this->caching_simple_username[$username])) {
|
||||||
@ -1083,7 +1007,6 @@ trait PeerHandler
|
|||||||
if ($res['_'] === 'contacts.resolvedPeer') {
|
if ($res['_'] === 'contacts.resolvedPeer') {
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,6 @@ class ReferenceDatabase implements TLCallback
|
|||||||
const PHOTO_LOCATION_LOCATION = 2;
|
const PHOTO_LOCATION_LOCATION = 2;
|
||||||
// DEPRECATED: Reference from a location (can only be document location)
|
// DEPRECATED: Reference from a location (can only be document location)
|
||||||
const DOCUMENT_LOCATION_LOCATION = 0;
|
const DOCUMENT_LOCATION_LOCATION = 0;
|
||||||
|
|
||||||
// Peer + photo ID
|
// Peer + photo ID
|
||||||
const USER_PHOTO_ORIGIN = 0;
|
const USER_PHOTO_ORIGIN = 0;
|
||||||
// Peer (default photo ID)
|
// Peer (default photo ID)
|
||||||
@ -57,42 +56,15 @@ class ReferenceDatabase implements TLCallback
|
|||||||
const STICKER_SET_EMOTICON_ORIGIN = 8;
|
const STICKER_SET_EMOTICON_ORIGIN = 8;
|
||||||
//
|
//
|
||||||
const WALLPAPER_ORIGIN = 9;
|
const WALLPAPER_ORIGIN = 9;
|
||||||
|
|
||||||
const LOCATION_CONTEXT = [
|
const LOCATION_CONTEXT = [
|
||||||
//'inputFileLocation' => self::PHOTO_LOCATION_LOCATION, // DEPRECATED
|
//'inputFileLocation' => self::PHOTO_LOCATION_LOCATION, // DEPRECATED
|
||||||
'inputDocumentFileLocation' => self::DOCUMENT_LOCATION,
|
'inputDocumentFileLocation' => self::DOCUMENT_LOCATION,
|
||||||
'inputPhotoFileLocation' => self::PHOTO_LOCATION,
|
'inputPhotoFileLocation' => self::PHOTO_LOCATION,
|
||||||
'inputPhoto' => self::PHOTO_LOCATION,
|
'inputPhoto' => self::PHOTO_LOCATION,
|
||||||
'inputDocument' => self::DOCUMENT_LOCATION,
|
'inputDocument' => self::DOCUMENT_LOCATION,
|
||||||
];
|
|
||||||
const METHOD_CONTEXT = [
|
|
||||||
'photos.updateProfilePhoto' => self::USER_PHOTO_ORIGIN,
|
|
||||||
'photos.getUserPhotos' => self::USER_PHOTO_ORIGIN,
|
|
||||||
'photos.uploadProfilePhoto' => self::USER_PHOTO_ORIGIN,
|
|
||||||
'messages.getStickers' => self::STICKER_SET_EMOTICON_ORIGIN,
|
|
||||||
];
|
|
||||||
const CONSTRUCTOR_CONTEXT = [
|
|
||||||
'message' => self::MESSAGE_ORIGIN,
|
|
||||||
'messageService' => self::MESSAGE_ORIGIN,
|
|
||||||
|
|
||||||
'chatFull' => self::PEER_PHOTO_ORIGIN,
|
|
||||||
'channelFull' => self::PEER_PHOTO_ORIGIN,
|
|
||||||
'chat' => self::PEER_PHOTO_ORIGIN,
|
|
||||||
'channel' => self::PEER_PHOTO_ORIGIN,
|
|
||||||
|
|
||||||
'updateUserPhoto' => self::USER_PHOTO_ORIGIN,
|
|
||||||
'user' => self::USER_PHOTO_ORIGIN,
|
|
||||||
'userFull' => self::USER_PHOTO_ORIGIN,
|
|
||||||
|
|
||||||
'wallPaper' => self::WALLPAPER_ORIGIN,
|
|
||||||
|
|
||||||
'messages.savedGifs' => self::SAVED_GIFS_ORIGIN,
|
|
||||||
|
|
||||||
'messages.recentStickers' => self::STICKER_SET_RECENT_ORIGIN,
|
|
||||||
'messages.favedStickers' => self::STICKER_SET_FAVED_ORIGIN,
|
|
||||||
'messages.stickerSet' => self::STICKER_SET_ID_ORIGIN,
|
|
||||||
'document' => self::STICKER_SET_ID_ORIGIN,
|
|
||||||
];
|
];
|
||||||
|
const METHOD_CONTEXT = ['photos.updateProfilePhoto' => self::USER_PHOTO_ORIGIN, 'photos.getUserPhotos' => self::USER_PHOTO_ORIGIN, 'photos.uploadProfilePhoto' => self::USER_PHOTO_ORIGIN, 'messages.getStickers' => self::STICKER_SET_EMOTICON_ORIGIN];
|
||||||
|
const CONSTRUCTOR_CONTEXT = ['message' => self::MESSAGE_ORIGIN, 'messageService' => self::MESSAGE_ORIGIN, 'chatFull' => self::PEER_PHOTO_ORIGIN, 'channelFull' => self::PEER_PHOTO_ORIGIN, 'chat' => self::PEER_PHOTO_ORIGIN, 'channel' => self::PEER_PHOTO_ORIGIN, 'updateUserPhoto' => self::USER_PHOTO_ORIGIN, 'user' => self::USER_PHOTO_ORIGIN, 'userFull' => self::USER_PHOTO_ORIGIN, 'wallPaper' => self::WALLPAPER_ORIGIN, 'messages.savedGifs' => self::SAVED_GIFS_ORIGIN, 'messages.recentStickers' => self::STICKER_SET_RECENT_ORIGIN, 'messages.favedStickers' => self::STICKER_SET_FAVED_ORIGIN, 'messages.stickerSet' => self::STICKER_SET_ID_ORIGIN, 'document' => self::STICKER_SET_ID_ORIGIN];
|
||||||
/**
|
/**
|
||||||
* References indexed by location.
|
* References indexed by location.
|
||||||
*
|
*
|
||||||
@ -105,70 +77,56 @@ class ReferenceDatabase implements TLCallback
|
|||||||
private $API;
|
private $API;
|
||||||
private $refresh = false;
|
private $refresh = false;
|
||||||
private $refreshCount = 0;
|
private $refreshCount = 0;
|
||||||
|
|
||||||
public function __construct(MTProto $API)
|
public function __construct(MTProto $API)
|
||||||
{
|
{
|
||||||
$this->API = $API;
|
$this->API = $API;
|
||||||
$this->init();
|
$this->init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __wakeup()
|
public function __wakeup()
|
||||||
{
|
{
|
||||||
$this->init();
|
$this->init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __sleep()
|
public function __sleep()
|
||||||
{
|
{
|
||||||
return ['db', 'API'];
|
return ['db', 'API'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function init()
|
public function init()
|
||||||
{
|
{
|
||||||
foreach ($this->db as $key => $value) {
|
foreach ($this->db as $key => $value) {
|
||||||
if ($key[0] === "0") { // Unsetting deprecated DOCUMENT_LOCATION_LOCATION
|
if ($key[0] === "0") {
|
||||||
|
// Unsetting deprecated DOCUMENT_LOCATION_LOCATION
|
||||||
unset($this->db[$key]);
|
unset($this->db[$key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMethodCallbacks(): array
|
public function getMethodCallbacks(): array
|
||||||
{
|
{
|
||||||
return \array_fill_keys(\array_keys(self::METHOD_CONTEXT), [[$this, 'addOriginMethod']]);
|
return \array_fill_keys(\array_keys(self::METHOD_CONTEXT), [[$this, 'addOriginMethod']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMethodBeforeCallbacks(): array
|
public function getMethodBeforeCallbacks(): array
|
||||||
{
|
{
|
||||||
return \array_fill_keys(\array_keys(self::METHOD_CONTEXT), [[$this, 'addOriginMethodContext']]);
|
return \array_fill_keys(\array_keys(self::METHOD_CONTEXT), [[$this, 'addOriginMethodContext']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getConstructorCallbacks(): array
|
public function getConstructorCallbacks(): array
|
||||||
{
|
{
|
||||||
return \array_merge(
|
return \array_merge(\array_fill_keys(['document', 'photo', 'fileLocation'], [[$this, 'addReference']]), \array_fill_keys(\array_keys(self::CONSTRUCTOR_CONTEXT), [[$this, 'addOrigin']]), ['document' => [[$this, 'addReference'], [$this, 'addOrigin']]]);
|
||||||
\array_fill_keys(['document', 'photo', 'fileLocation'], [[$this, 'addReference']]),
|
|
||||||
\array_fill_keys(\array_keys(self::CONSTRUCTOR_CONTEXT), [[$this, 'addOrigin']]),
|
|
||||||
['document' => [[$this, 'addReference'], [$this, 'addOrigin']]]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getConstructorBeforeCallbacks(): array
|
public function getConstructorBeforeCallbacks(): array
|
||||||
{
|
{
|
||||||
return \array_fill_keys(\array_keys(self::CONSTRUCTOR_CONTEXT), [[$this, 'addOriginContext']]);
|
return \array_fill_keys(\array_keys(self::CONSTRUCTOR_CONTEXT), [[$this, 'addOriginContext']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getConstructorSerializeCallbacks(): array
|
public function getConstructorSerializeCallbacks(): array
|
||||||
{
|
{
|
||||||
return \array_fill_keys(\array_keys(self::LOCATION_CONTEXT), [$this, 'populateReference']);
|
return \array_fill_keys(\array_keys(self::LOCATION_CONTEXT), [$this, 'populateReference']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTypeMismatchCallbacks(): array
|
public function getTypeMismatchCallbacks(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function reset()
|
public function reset()
|
||||||
{
|
{
|
||||||
if ($this->cacheContexts) {
|
if ($this->cacheContexts) {
|
||||||
$this->API->logger->logger('Found '.\count($this->cacheContexts).' pending contexts', \danog\MadelineProto\Logger::ERROR);
|
$this->API->logger->logger('Found ' . \count($this->cacheContexts) . ' pending contexts', \danog\MadelineProto\Logger::ERROR);
|
||||||
$this->cacheContexts = [];
|
$this->cacheContexts = [];
|
||||||
}
|
}
|
||||||
if ($this->cache) {
|
if ($this->cache) {
|
||||||
@ -176,7 +134,6 @@ class ReferenceDatabase implements TLCallback
|
|||||||
$this->cache = [];
|
$this->cache = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addReference(array $location)
|
public function addReference(array $location)
|
||||||
{
|
{
|
||||||
if (!$this->cacheContexts) {
|
if (!$this->cacheContexts) {
|
||||||
@ -189,18 +146,15 @@ class ReferenceDatabase implements TLCallback
|
|||||||
if ($frame['args'][1]['subtype'] === $previous) {
|
if ($frame['args'][1]['subtype'] === $previous) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$frames[] = $frame['args'][1]['subtype'];
|
$frames[] = $frame['args'][1]['subtype'];
|
||||||
$previous = $frame['args'][1]['subtype'];
|
$previous = $frame['args'][1]['subtype'];
|
||||||
} elseif (isset($frame['args'][1]['type'])) {
|
} elseif (isset($frame['args'][1]['type'])) {
|
||||||
if ($frame['args'][1]['type'] === '') {
|
if ($frame['args'][1]['type'] === '') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($frame['args'][1]['type'] === $previous) {
|
if ($frame['args'][1]['type'] === $previous) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$frames[] = $frame['args'][1]['type'];
|
$frames[] = $frame['args'][1]['type'];
|
||||||
$previous = $frame['args'][1]['type'];
|
$previous = $frame['args'][1]['type'];
|
||||||
}
|
}
|
||||||
@ -209,15 +163,13 @@ class ReferenceDatabase implements TLCallback
|
|||||||
$frames = \array_reverse($frames);
|
$frames = \array_reverse($frames);
|
||||||
$tl_trace = \array_shift($frames);
|
$tl_trace = \array_shift($frames);
|
||||||
foreach ($frames as $frame) {
|
foreach ($frames as $frame) {
|
||||||
$tl_trace .= "['".$frame."']";
|
$tl_trace .= "['" . $frame . "']";
|
||||||
}
|
}
|
||||||
$this->API->logger->logger($tl_trace, \danog\MadelineProto\Logger::ERROR);
|
$this->API->logger->logger($tl_trace, \danog\MadelineProto\Logger::ERROR);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!isset($location['file_reference'])) {
|
if (!isset($location['file_reference'])) {
|
||||||
$this->API->logger->logger("Object {$location['_']} does not have reference", \danog\MadelineProto\Logger::ERROR);
|
$this->API->logger->logger("Object {$location['_']} does not have reference", \danog\MadelineProto\Logger::ERROR);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$key = \count($this->cacheContexts) - 1;
|
$key = \count($this->cacheContexts) - 1;
|
||||||
@ -232,27 +184,24 @@ class ReferenceDatabase implements TLCallback
|
|||||||
$locationType = self::PHOTO_LOCATION_LOCATION;
|
$locationType = self::PHOTO_LOCATION_LOCATION;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Exception('Unknown location type provided: '.$location['_']);
|
throw new Exception('Unknown location type provided: ' . $location['_']);
|
||||||
}
|
}
|
||||||
$this->API->logger->logger("Caching reference from location of type $locationType from {$location['_']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->API->logger->logger("Caching reference from location of type {$locationType} from {$location['_']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
if (!isset($this->cache[$key])) {
|
if (!isset($this->cache[$key])) {
|
||||||
$this->cache[$key] = [];
|
$this->cache[$key] = [];
|
||||||
}
|
}
|
||||||
$this->cache[$key][$this->serializeLocation($locationType, $location)] = (string) $location['file_reference'];
|
$this->cache[$key][$this->serializeLocation($locationType, $location)] = (string) $location['file_reference'];
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addOriginContext(string $type)
|
public function addOriginContext(string $type)
|
||||||
{
|
{
|
||||||
if (!isset(self::CONSTRUCTOR_CONTEXT[$type])) {
|
if (!isset(self::CONSTRUCTOR_CONTEXT[$type])) {
|
||||||
throw new \danog\MadelineProto\Exception("Unknown origin type provided: $type");
|
throw new \danog\MadelineProto\Exception("Unknown origin type provided: {$type}");
|
||||||
}
|
}
|
||||||
$originContext = self::CONSTRUCTOR_CONTEXT[$type];
|
$originContext = self::CONSTRUCTOR_CONTEXT[$type];
|
||||||
$this->API->logger->logger("Adding origin context $originContext for {$type}!", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->API->logger->logger("Adding origin context {$originContext} for {$type}!", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
$this->cacheContexts[] = $originContext;
|
$this->cacheContexts[] = $originContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addOrigin(array $data = [])
|
public function addOrigin(array $data = [])
|
||||||
{
|
{
|
||||||
$key = \count($this->cacheContexts) - 1;
|
$key = \count($this->cacheContexts) - 1;
|
||||||
@ -261,8 +210,7 @@ class ReferenceDatabase implements TLCallback
|
|||||||
}
|
}
|
||||||
$originType = \array_pop($this->cacheContexts);
|
$originType = \array_pop($this->cacheContexts);
|
||||||
if (!isset($this->cache[$key])) {
|
if (!isset($this->cache[$key])) {
|
||||||
$this->API->logger->logger("Removing origin context $originType for {$data['_']}, nothing in the reference cache!", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->API->logger->logger("Removing origin context {$originType} for {$data['_']}, nothing in the reference cache!", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$cache = $this->cache[$key];
|
$cache = $this->cache[$key];
|
||||||
@ -316,12 +264,10 @@ class ReferenceDatabase implements TLCallback
|
|||||||
if (!isset($this->cache[$key])) {
|
if (!isset($this->cache[$key])) {
|
||||||
$this->cache[$key] = [];
|
$this->cache[$key] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($cache as $location => $reference) {
|
foreach ($cache as $location => $reference) {
|
||||||
$this->cache[$key][$location] = $reference;
|
$this->cache[$key][$location] = $reference;
|
||||||
}
|
}
|
||||||
$this->API->logger->logger("Skipped origin $originType ({$data['_']}) for ".\count($cache).' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->API->logger->logger("Skipped origin {$originType} ({$data['_']}) for " . \count($cache) . ' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -334,19 +280,17 @@ class ReferenceDatabase implements TLCallback
|
|||||||
foreach ($cache as $location => $reference) {
|
foreach ($cache as $location => $reference) {
|
||||||
$this->storeReference($location, $reference, $originType, $origin);
|
$this->storeReference($location, $reference, $originType, $origin);
|
||||||
}
|
}
|
||||||
$this->API->logger->logger("Added origin $originType ({$data['_']}) to ".\count($cache).' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->API->logger->logger("Added origin {$originType} ({$data['_']}) to " . \count($cache) . ' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addOriginMethodContext(string $type)
|
public function addOriginMethodContext(string $type)
|
||||||
{
|
{
|
||||||
if (!isset(self::METHOD_CONTEXT[$type])) {
|
if (!isset(self::METHOD_CONTEXT[$type])) {
|
||||||
throw new \danog\MadelineProto\Exception("Unknown origin type provided: {$type}");
|
throw new \danog\MadelineProto\Exception("Unknown origin type provided: {$type}");
|
||||||
}
|
}
|
||||||
$originContext = self::METHOD_CONTEXT[$type];
|
$originContext = self::METHOD_CONTEXT[$type];
|
||||||
$this->API->logger->logger("Adding origin context $originContext for {$type}!", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->API->logger->logger("Adding origin context {$originContext} for {$type}!", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
$this->cacheContexts[] = $originContext;
|
$this->cacheContexts[] = $originContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addOriginMethod(array $data, array $res)
|
public function addOriginMethod(array $data, array $res)
|
||||||
{
|
{
|
||||||
$key = \count($this->cacheContexts) - 1;
|
$key = \count($this->cacheContexts) - 1;
|
||||||
@ -355,8 +299,7 @@ class ReferenceDatabase implements TLCallback
|
|||||||
}
|
}
|
||||||
$originType = \array_pop($this->cacheContexts);
|
$originType = \array_pop($this->cacheContexts);
|
||||||
if (!isset($this->cache[$key])) {
|
if (!isset($this->cache[$key])) {
|
||||||
$this->API->logger->logger("Removing origin context $originType for {$data['_']}, nothing in the reference cache!", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->API->logger->logger("Removing origin context {$originType} for {$data['_']}, nothing in the reference cache!", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$cache = $this->cache[$key];
|
$cache = $this->cache[$key];
|
||||||
@ -384,16 +327,13 @@ class ReferenceDatabase implements TLCallback
|
|||||||
foreach ($res['photos'] as $photo) {
|
foreach ($res['photos'] as $photo) {
|
||||||
$origin['max_id'] = $photo['id'];
|
$origin['max_id'] = $photo['id'];
|
||||||
$dc_id = $photo['dc_id'];
|
$dc_id = $photo['dc_id'];
|
||||||
|
|
||||||
$location = $this->serializeLocation(self::PHOTO_LOCATION, $photo);
|
$location = $this->serializeLocation(self::PHOTO_LOCATION, $photo);
|
||||||
if (isset($cache[$location])) {
|
if (isset($cache[$location])) {
|
||||||
$reference = $cache[$location];
|
$reference = $cache[$location];
|
||||||
unset($cache[$location]);
|
unset($cache[$location]);
|
||||||
|
|
||||||
$this->storeReference($location, $reference, $originType, $origin);
|
$this->storeReference($location, $reference, $originType, $origin);
|
||||||
$count++;
|
$count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($photo['sizes'])) {
|
if (isset($photo['sizes'])) {
|
||||||
foreach ($photo['sizes'] as $size) {
|
foreach ($photo['sizes'] as $size) {
|
||||||
if (isset($size['location'])) {
|
if (isset($size['location'])) {
|
||||||
@ -409,8 +349,7 @@ class ReferenceDatabase implements TLCallback
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->API->logger->logger("Added origin $originType ({$data['_']}) to $count references", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->API->logger->logger("Added origin {$originType} ({$data['_']}) to {$count} references", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
case 'messages.getStickers':
|
case 'messages.getStickers':
|
||||||
$origin['emoticon'] = $body['emoticon'];
|
$origin['emoticon'] = $body['emoticon'];
|
||||||
@ -421,9 +360,8 @@ class ReferenceDatabase implements TLCallback
|
|||||||
foreach ($cache as $location => $reference) {
|
foreach ($cache as $location => $reference) {
|
||||||
$this->storeReference($location, $reference, $originType, $origin);
|
$this->storeReference($location, $reference, $originType, $origin);
|
||||||
}
|
}
|
||||||
$this->API->logger->logger("Added origin $originType ({$data['_']}) to ".\count($cache).' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->API->logger->logger("Added origin {$originType} ({$data['_']}) to " . \count($cache) . ' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function storeReference(string $location, string $reference, int $originType, array $origin)
|
public function storeReference(string $location, string $reference, int $originType, array $origin)
|
||||||
{
|
{
|
||||||
if (!isset($this->db[$location])) {
|
if (!isset($this->db[$location])) {
|
||||||
@ -431,17 +369,14 @@ class ReferenceDatabase implements TLCallback
|
|||||||
}
|
}
|
||||||
$this->db[$location]['reference'] = $reference;
|
$this->db[$location]['reference'] = $reference;
|
||||||
$this->db[$location]['origins'][$originType] = $origin;
|
$this->db[$location]['origins'][$originType] = $origin;
|
||||||
|
|
||||||
if ($this->refresh) {
|
if ($this->refresh) {
|
||||||
$this->refreshed[$location] = true;
|
$this->refreshed[$location] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$key = \count($this->cacheContexts) - 1;
|
$key = \count($this->cacheContexts) - 1;
|
||||||
if ($key >= 0) {
|
if ($key >= 0) {
|
||||||
$this->cache[$key][$location] = $reference;
|
$this->cache[$key][$location] = $reference;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function refreshNext($refresh = false)
|
public function refreshNext($refresh = false)
|
||||||
{
|
{
|
||||||
if ($this->refreshCount === 1 && !$refresh) {
|
if ($this->refreshCount === 1 && !$refresh) {
|
||||||
@ -459,23 +394,18 @@ class ReferenceDatabase implements TLCallback
|
|||||||
$this->refreshCount--;
|
$this->refreshCount--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function refreshReference(int $locationType, array $location)
|
public function refreshReference(int $locationType, array $location)
|
||||||
{
|
{
|
||||||
return $this->refreshReferenceInternal($this->serializeLocation($locationType, $location));
|
return $this->refreshReferenceInternal($this->serializeLocation($locationType, $location));
|
||||||
}
|
}
|
||||||
|
public function refreshReferenceInternal(string $location): \Generator
|
||||||
public function refreshReferenceInternal(string $location)
|
|
||||||
{
|
{
|
||||||
if (isset($this->refreshed[$location])) {
|
if (isset($this->refreshed[$location])) {
|
||||||
$this->API->logger->logger('Reference already refreshed!', \danog\MadelineProto\Logger::VERBOSE);
|
$this->API->logger->logger('Reference already refreshed!', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
|
|
||||||
return $this->db[$location]['reference'];
|
return $this->db[$location]['reference'];
|
||||||
}
|
}
|
||||||
|
|
||||||
\ksort($this->db[$location]['origins']);
|
\ksort($this->db[$location]['origins']);
|
||||||
$count = 0;
|
$count = 0;
|
||||||
|
|
||||||
foreach ($this->db[$location]['origins'] as $originType => &$origin) {
|
foreach ($this->db[$location]['origins'] as $originType => &$origin) {
|
||||||
$count++;
|
$count++;
|
||||||
$this->API->logger->logger("Try {$count} refreshing file reference with origin type {$originType}", \danog\MadelineProto\Logger::VERBOSE);
|
$this->API->logger->logger("Try {$count} refreshing file reference with origin type {$originType}", \danog\MadelineProto\Logger::VERBOSE);
|
||||||
@ -521,67 +451,54 @@ class ReferenceDatabase implements TLCallback
|
|||||||
yield $this->API->methodCallAsyncRead('account.getWallPapers', $origin, ['datacenter' => $this->API->settings['connection_settings']['default_dc']]);
|
yield $this->API->methodCallAsyncRead('account.getWallPapers', $origin, ['datacenter' => $this->API->settings['connection_settings']['default_dc']]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new \danog\MadelineProto\Exception("Unknown origin type $originType");
|
throw new \danog\MadelineProto\Exception("Unknown origin type {$originType}");
|
||||||
}
|
}
|
||||||
if (isset($this->refreshed[$location])) {
|
if (isset($this->refreshed[$location])) {
|
||||||
return $this->db[$location]['reference'];
|
return $this->db[$location]['reference'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Exception('Did not refresh reference');
|
throw new Exception('Did not refresh reference');
|
||||||
}
|
}
|
||||||
|
public function populateReference(array $object): \Generator
|
||||||
public function populateReference(array $object)
|
|
||||||
{
|
{
|
||||||
$object['file_reference'] = yield $this->getReference(self::LOCATION_CONTEXT[$object['_']], $object);
|
$object['file_reference'] = yield $this->getReference(self::LOCATION_CONTEXT[$object['_']], $object);
|
||||||
|
|
||||||
return $object;
|
return $object;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getReference(int $locationType, array $location)
|
public function getReference(int $locationType, array $location)
|
||||||
{
|
{
|
||||||
$locationString = $this->serializeLocation($locationType, $location);
|
$locationString = $this->serializeLocation($locationType, $location);
|
||||||
if (!isset($this->db[$locationString]['reference'])) {
|
if (!isset($this->db[$locationString]['reference'])) {
|
||||||
if (isset($location['file_reference'])) {
|
if (isset($location['file_reference'])) {
|
||||||
$this->API->logger->logger("Using outdated file reference for location of type $locationType object {$location['_']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->API->logger->logger("Using outdated file reference for location of type {$locationType} object {$location['_']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
|
|
||||||
return $location['file_reference'];
|
return $location['file_reference'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->refresh) {
|
if (!$this->refresh) {
|
||||||
$this->API->logger->logger("Using null file reference for location of type $locationType object {$location['_']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->API->logger->logger("Using null file reference for location of type {$locationType} object {$location['_']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
throw new \danog\MadelineProto\Exception("Could not find file reference for location of type {$locationType} object {$location['_']}");
|
||||||
throw new \danog\MadelineProto\Exception("Could not find file reference for location of type $locationType object {$location['_']}");
|
|
||||||
}
|
}
|
||||||
$this->API->logger->logger("Getting file reference for location of type $locationType object {$location['_']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->API->logger->logger("Getting file reference for location of type {$locationType} object {$location['_']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
|
|
||||||
if ($this->refresh) {
|
if ($this->refresh) {
|
||||||
return $this->refreshReferenceInternal($locationString);
|
return $this->refreshReferenceInternal($locationString);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->db[$locationString]['reference'];
|
return $this->db[$locationString]['reference'];
|
||||||
}
|
}
|
||||||
|
|
||||||
private function serializeLocation(int $locationType, array $location)
|
private function serializeLocation(int $locationType, array $location)
|
||||||
{
|
{
|
||||||
switch ($locationType) {
|
switch ($locationType) {
|
||||||
case self::DOCUMENT_LOCATION:
|
case self::DOCUMENT_LOCATION:
|
||||||
case self::PHOTO_LOCATION:
|
case self::PHOTO_LOCATION:
|
||||||
return $locationType.(\is_int($location['id']) ? \danog\MadelineProto\Tools::packSignedLong($location['id']) : $location['id']);
|
return $locationType . (\is_int($location['id']) ? \danog\MadelineProto\Tools::packSignedLong($location['id']) : $location['id']);
|
||||||
case self::PHOTO_LOCATION_LOCATION:
|
case self::PHOTO_LOCATION_LOCATION:
|
||||||
$dc_id = \danog\MadelineProto\Tools::packSignedInt($location['dc_id']);
|
$dc_id = \danog\MadelineProto\Tools::packSignedInt($location['dc_id']);
|
||||||
$volume_id = \is_int($location['volume_id']) ? \danog\MadelineProto\Tools::packSignedLong($location['volume_id']) : $location['volume_id'];
|
$volume_id = \is_int($location['volume_id']) ? \danog\MadelineProto\Tools::packSignedLong($location['volume_id']) : $location['volume_id'];
|
||||||
$local_id = \danog\MadelineProto\Tools::packSignedInt($location['local_id']);
|
$local_id = \danog\MadelineProto\Tools::packSignedInt($location['local_id']);
|
||||||
|
return $locationType . $dc_id . $volume_id . $local_id;
|
||||||
return $locationType.$dc_id.$volume_id.$local_id;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __debugInfo()
|
public function __debugInfo()
|
||||||
{
|
{
|
||||||
return ['ReferenceDatabase instance '.\spl_object_hash($this)];
|
return ['ReferenceDatabase instance ' . \spl_object_hash($this)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,6 @@ trait UpdateHandler
|
|||||||
private $channels_state;
|
private $channels_state;
|
||||||
public $updates = [];
|
public $updates = [];
|
||||||
public $updates_key = 0;
|
public $updates_key = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PWR update handler.
|
* PWR update handler.
|
||||||
*
|
*
|
||||||
@ -56,7 +55,6 @@ trait UpdateHandler
|
|||||||
\in_array($this->settings['pwr']['updateHandler'], [['danog\\MadelineProto\\API', 'getUpdatesUpdateHandler'], 'getUpdatesUpdateHandler']) ? $this->getUpdatesUpdateHandler($update) : $this->settings['pwr']['updateHandler']($update);
|
\in_array($this->settings['pwr']['updateHandler'], [['danog\\MadelineProto\\API', 'getUpdatesUpdateHandler'], 'getUpdatesUpdateHandler']) ? $this->getUpdatesUpdateHandler($update) : $this->settings['pwr']['updateHandler']($update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Getupdates update handler.
|
* Getupdates update handler.
|
||||||
*
|
*
|
||||||
@ -73,7 +71,6 @@ trait UpdateHandler
|
|||||||
}
|
}
|
||||||
$this->updates[$this->updates_key++] = $update;
|
$this->updates[$this->updates_key++] = $update;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get updates.
|
* Get updates.
|
||||||
*
|
*
|
||||||
@ -92,9 +89,7 @@ trait UpdateHandler
|
|||||||
if (!$this->settings['updates']['run_callback']) {
|
if (!$this->settings['updates']['run_callback']) {
|
||||||
$this->settings['updates']['run_callback'] = true;
|
$this->settings['updates']['run_callback'] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$params = \array_merge(self::DEFAULT_GETUPDATES_PARAMS, $params);
|
$params = \array_merge(self::DEFAULT_GETUPDATES_PARAMS, $params);
|
||||||
|
|
||||||
if (empty($this->updates)) {
|
if (empty($this->updates)) {
|
||||||
$this->update_deferred = new Deferred();
|
$this->update_deferred = new Deferred();
|
||||||
if (!$params['timeout']) {
|
if (!$params['timeout']) {
|
||||||
@ -102,11 +97,9 @@ trait UpdateHandler
|
|||||||
}
|
}
|
||||||
yield \danog\MadelineProto\Tools::first([$this->waitUpdate(), \danog\MadelineProto\Tools::sleep($params['timeout'])]);
|
yield \danog\MadelineProto\Tools::first([$this->waitUpdate(), \danog\MadelineProto\Tools::sleep($params['timeout'])]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($this->updates)) {
|
if (empty($this->updates)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($params['offset'] < 0) {
|
if ($params['offset'] < 0) {
|
||||||
$params['offset'] = \array_reverse(\array_keys((array) $this->updates))[\abs($params['offset']) - 1];
|
$params['offset'] = \array_reverse(\array_keys((array) $this->updates))[\abs($params['offset']) - 1];
|
||||||
}
|
}
|
||||||
@ -118,13 +111,10 @@ trait UpdateHandler
|
|||||||
$updates[] = ['update_id' => $key, 'update' => $value];
|
$updates[] = ['update_id' => $key, 'update' => $value];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $updates;
|
return $updates;
|
||||||
}
|
}
|
||||||
|
|
||||||
public $update_resolved = false;
|
public $update_resolved = false;
|
||||||
public $update_deferred;
|
public $update_deferred;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wait for update.
|
* Wait for update.
|
||||||
*
|
*
|
||||||
@ -141,7 +131,6 @@ trait UpdateHandler
|
|||||||
$this->update_resolved = false;
|
$this->update_resolved = false;
|
||||||
$this->update_deferred = new Deferred();
|
$this->update_deferred = new Deferred();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signal update.
|
* Signal update.
|
||||||
*
|
*
|
||||||
@ -161,8 +150,6 @@ trait UpdateHandler
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check message ID.
|
* Check message ID.
|
||||||
*
|
*
|
||||||
@ -177,7 +164,6 @@ trait UpdateHandler
|
|||||||
if (!isset($message['to_id'])) {
|
if (!isset($message['to_id'])) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$peer_id = $this->getId($message['to_id']);
|
$peer_id = $this->getId($message['to_id']);
|
||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
@ -188,13 +174,10 @@ trait UpdateHandler
|
|||||||
$message_id = $message['id'];
|
$message_id = $message['id'];
|
||||||
if (!isset($this->msg_ids[$peer_id]) || $message_id > $this->msg_ids[$peer_id]) {
|
if (!isset($this->msg_ids[$peer_id]) || $message_id > $this->msg_ids[$peer_id]) {
|
||||||
$this->msg_ids[$peer_id] = $message_id;
|
$this->msg_ids[$peer_id] = $message_id;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get channel state.
|
* Get channel state.
|
||||||
*
|
*
|
||||||
@ -202,16 +185,14 @@ trait UpdateHandler
|
|||||||
*
|
*
|
||||||
* @return UpdatesState|UpdatesState[]
|
* @return UpdatesState|UpdatesState[]
|
||||||
*/
|
*/
|
||||||
public function loadUpdateState()
|
public function loadUpdateState(): \Generator
|
||||||
{
|
{
|
||||||
if (!$this->got_state) {
|
if (!$this->got_state) {
|
||||||
$this->got_state = true;
|
$this->got_state = true;
|
||||||
$this->channels_state->get(false, yield $this->getUpdatesState());
|
$this->channels_state->get(false, yield from $this->getUpdatesState());
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->channels_state->get(false);
|
return $this->channels_state->get(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load channel state.
|
* Load channel state.
|
||||||
*
|
*
|
||||||
@ -226,7 +207,6 @@ trait UpdateHandler
|
|||||||
{
|
{
|
||||||
return $this->channels_state->get($channelId, $init);
|
return $this->channels_state->get($channelId, $init);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get channel states.
|
* Get channel states.
|
||||||
*
|
*
|
||||||
@ -238,7 +218,6 @@ trait UpdateHandler
|
|||||||
{
|
{
|
||||||
return $this->channels_state;
|
return $this->channels_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get update state.
|
* Get update state.
|
||||||
*
|
*
|
||||||
@ -250,11 +229,8 @@ trait UpdateHandler
|
|||||||
{
|
{
|
||||||
$data = yield $this->methodCallAsyncRead('updates.getState', [], ['datacenter' => $this->settings['connection_settings']['default_dc']]);
|
$data = yield $this->methodCallAsyncRead('updates.getState', [], ['datacenter' => $this->settings['connection_settings']['default_dc']]);
|
||||||
yield $this->getCdnConfig($this->settings['connection_settings']['default_dc']);
|
yield $this->getCdnConfig($this->settings['connection_settings']['default_dc']);
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Undocumented function.
|
* Undocumented function.
|
||||||
*
|
*
|
||||||
@ -273,16 +249,13 @@ trait UpdateHandler
|
|||||||
if ($actual_updates) {
|
if ($actual_updates) {
|
||||||
$updates = $actual_updates;
|
$updates = $actual_updates;
|
||||||
}
|
}
|
||||||
$this->logger->logger('Parsing updates ('.$updates['_'].') received via the socket...', \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('Parsing updates (' . $updates['_'] . ') received via the socket...', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
switch ($updates['_']) {
|
switch ($updates['_']) {
|
||||||
case 'updates':
|
case 'updates':
|
||||||
case 'updatesCombined':
|
case 'updatesCombined':
|
||||||
$result = [];
|
$result = [];
|
||||||
foreach ($updates['updates'] as $key => $update) {
|
foreach ($updates['updates'] as $key => $update) {
|
||||||
if ($update['_'] === 'updateNewMessage' || $update['_'] === 'updateReadMessagesContents' ||
|
if ($update['_'] === 'updateNewMessage' || $update['_'] === 'updateReadMessagesContents' || $update['_'] === 'updateEditMessage' || $update['_'] === 'updateDeleteMessages' || $update['_'] === 'updateReadHistoryInbox' || $update['_'] === 'updateReadHistoryOutbox' || $update['_'] === 'updateWebPage' || $update['_'] === 'updateMessageID') {
|
||||||
$update['_'] === 'updateEditMessage' || $update['_'] === 'updateDeleteMessages' ||
|
|
||||||
$update['_'] === 'updateReadHistoryInbox' || $update['_'] === 'updateReadHistoryOutbox' ||
|
|
||||||
$update['_'] === 'updateWebPage' || $update['_'] === 'updateMessageID') {
|
|
||||||
$result[yield $this->feeders[false]->feedSingle($update)] = true;
|
$result[yield $this->feeders[false]->feedSingle($update)] = true;
|
||||||
unset($updates['updates'][$key]);
|
unset($updates['updates'][$key]);
|
||||||
}
|
}
|
||||||
@ -308,20 +281,18 @@ trait UpdateHandler
|
|||||||
$updates['user_id'] = (yield $this->getInfo($updates['request']['body']['peer']))['bot_api_id'];
|
$updates['user_id'] = (yield $this->getInfo($updates['request']['body']['peer']))['bot_api_id'];
|
||||||
$updates['message'] = $updates['request']['body']['message'];
|
$updates['message'] = $updates['request']['body']['message'];
|
||||||
unset($updates['request']);
|
unset($updates['request']);
|
||||||
// no break
|
// no break
|
||||||
case 'updateShortMessage':
|
case 'updateShortMessage':
|
||||||
case 'updateShortChatMessage':
|
case 'updateShortChatMessage':
|
||||||
$from_id = isset($updates['from_id']) ? $updates['from_id'] : ($updates['out'] ? $this->authorization['user']['id'] : $updates['user_id']);
|
$from_id = isset($updates['from_id']) ? $updates['from_id'] : ($updates['out'] ? $this->authorization['user']['id'] : $updates['user_id']);
|
||||||
$to_id = isset($updates['chat_id']) ? -$updates['chat_id'] : ($updates['out'] ? $updates['user_id'] : $this->authorization['user']['id']);
|
$to_id = isset($updates['chat_id']) ? -$updates['chat_id'] : ($updates['out'] ? $updates['user_id'] : $this->authorization['user']['id']);
|
||||||
if (!yield $this->peerIsset($from_id) || !yield $this->peerIsset($to_id) || isset($updates['via_bot_id']) && !yield $this->peerIsset($updates['via_bot_id']) || isset($updates['entities']) && !yield $this->entitiesPeerIsset($updates['entities']) || isset($updates['fwd_from']) && !yield $this->fwdPeerIsset($updates['fwd_from'])) {
|
if (!(yield from $this->peerIsset($from_id) || !(yield from $this->peerIsset($to_id) || isset($updates['via_bot_id']) && !(yield from $this->peerIsset($updates['via_bot_id']) || isset($updates['entities']) && !(yield from $this->entitiesPeerIsset($updates['entities']) || isset($updates['fwd_from']) && !yield $this->fwdPeerIsset($updates['fwd_from'])))))) {
|
||||||
yield $this->updaters[false]->resume();
|
yield $this->updaters[false]->resume();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$message = $updates;
|
$message = $updates;
|
||||||
$message['_'] = 'message';
|
$message['_'] = 'message';
|
||||||
$message['from_id'] = $from_id;
|
$message['from_id'] = $from_id;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$message['to_id'] = (yield $this->getInfo($to_id))['Peer'];
|
$message['to_id'] = (yield $this->getInfo($to_id))['Peer'];
|
||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
@ -340,7 +311,7 @@ trait UpdateHandler
|
|||||||
$this->updaters[false]->resume();
|
$this->updaters[false]->resume();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new \danog\MadelineProto\ResponseException('Unrecognized update received: '.\var_export($updates, true));
|
throw new \danog\MadelineProto\ResponseException('Unrecognized update received: ' . \var_export($updates, true));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -368,13 +339,11 @@ trait UpdateHandler
|
|||||||
$this->logger->logger('Got new dc options', \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('Got new dc options', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
$this->config['dc_options'] = $update['dc_options'];
|
$this->config['dc_options'] = $update['dc_options'];
|
||||||
yield $this->parseConfig();
|
yield $this->parseConfig();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($update['_'] === 'updatePhoneCall') {
|
if ($update['_'] === 'updatePhoneCall') {
|
||||||
if (!\class_exists('\\danog\\MadelineProto\\VoIP')) {
|
if (!\class_exists('\\danog\\MadelineProto\\VoIP')) {
|
||||||
$this->logger->logger('The php-libtgvoip extension is required to accept and manage calls. See daniil.it/MadelineProto for more info.', \danog\MadelineProto\Logger::WARNING);
|
$this->logger->logger('The php-libtgvoip extension is required to accept and manage calls. See daniil.it/MadelineProto for more info.', \danog\MadelineProto\Logger::WARNING);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch ($update['phone_call']['_']) {
|
switch ($update['phone_call']['_']) {
|
||||||
@ -403,54 +372,50 @@ trait UpdateHandler
|
|||||||
if (!isset($this->calls[$update['phone_call']['id']])) {
|
if (!isset($this->calls[$update['phone_call']['id']])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->calls[$update['phone_call']['id']]->discard($update['phone_call']['reason'], [], $update['phone_call']['need_debug']);
|
return $this->calls[$update['phone_call']['id']]->discard($update['phone_call']['reason'], [], $update['phone_call']['need_debug']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($update['_'] === 'updateNewEncryptedMessage' && !isset($update['message']['decrypted_message'])) {
|
if ($update['_'] === 'updateNewEncryptedMessage' && !isset($update['message']['decrypted_message'])) {
|
||||||
if (isset($update['qts'])) {
|
if (isset($update['qts'])) {
|
||||||
$cur_state = yield $this->loadUpdateState();
|
$cur_state = (yield from $this->loadUpdateState());
|
||||||
if ($cur_state->qts() === -1) {
|
if ($cur_state->qts() === -1) {
|
||||||
$cur_state->qts($update['qts']);
|
$cur_state->qts($update['qts']);
|
||||||
}
|
}
|
||||||
if ($update['qts'] < $cur_state->qts()) {
|
if ($update['qts'] < $cur_state->qts()) {
|
||||||
$this->logger->logger('Duplicate update. update qts: '.$update['qts'].' <= current qts '.$cur_state->qts().', chat id: '.$update['message']['chat_id'], \danog\MadelineProto\Logger::ERROR);
|
$this->logger->logger('Duplicate update. update qts: ' . $update['qts'] . ' <= current qts ' . $cur_state->qts() . ', chat id: ' . $update['message']['chat_id'], \danog\MadelineProto\Logger::ERROR);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ($update['qts'] > $cur_state->qts() + 1) {
|
if ($update['qts'] > $cur_state->qts() + 1) {
|
||||||
$this->logger->logger('Qts hole. Fetching updates manually: update qts: '.$update['qts'].' > current qts '.$cur_state->qts().'+1, chat id: '.$update['message']['chat_id'], \danog\MadelineProto\Logger::ERROR);
|
$this->logger->logger('Qts hole. Fetching updates manually: update qts: ' . $update['qts'] . ' > current qts ' . $cur_state->qts() . '+1, chat id: ' . $update['message']['chat_id'], \danog\MadelineProto\Logger::ERROR);
|
||||||
$this->updaters[false]->resumeDefer();
|
$this->updaters[false]->resumeDefer();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$this->logger->logger('Applying qts: '.$update['qts'].' over current qts '.$cur_state->qts().', chat id: '.$update['message']['chat_id'], \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('Applying qts: ' . $update['qts'] . ' over current qts ' . $cur_state->qts() . ', chat id: ' . $update['message']['chat_id'], \danog\MadelineProto\Logger::VERBOSE);
|
||||||
yield $this->methodCallAsyncRead('messages.receivedQueue', ['max_qts' => $cur_state->qts($update['qts'])], ['datacenter' => $this->settings['connection_settings']['default_dc']]);
|
yield $this->methodCallAsyncRead('messages.receivedQueue', ['max_qts' => $cur_state->qts($update['qts'])], ['datacenter' => $this->settings['connection_settings']['default_dc']]);
|
||||||
}
|
}
|
||||||
yield $this->handleEncryptedUpdate($update);
|
yield $this->handleEncryptedUpdate($update);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
if ($update['_'] === 'updateEncryptedChatTyping') {
|
if ($update['_'] === 'updateEncryptedChatTyping') {
|
||||||
$update = ['_' => 'updateUserTyping', 'user_id' => $this->encrypted_chats[$update['chat_id']]['user_id'], 'action' => ['_' => 'sendMessageTypingAction']];
|
$update = ['_' => 'updateUserTyping', 'user_id' => $this->encrypted_chats[$update['chat_id']]['user_id'], 'action' => ['_' => 'sendMessageTypingAction']];
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if ($update['_'] === 'updateEncryption') {
|
if ($update['_'] === 'updateEncryption') {
|
||||||
switch ($update['chat']['_']) {
|
switch ($update['chat']['_']) {
|
||||||
case 'encryptedChatRequested':
|
case 'encryptedChatRequested':
|
||||||
if ($this->settings['secret_chats']['accept_chats'] === false || \is_array($this->settings['secret_chats']['accept_chats']) && !\in_array($update['chat']['admin_id'], $this->settings['secret_chats']['accept_chats'])) {
|
if ($this->settings['secret_chats']['accept_chats'] === false || \is_array($this->settings['secret_chats']['accept_chats']) && !\in_array($update['chat']['admin_id'], $this->settings['secret_chats']['accept_chats'])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->logger->logger('Accepting secret chat '.$update['chat']['id'], \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('Accepting secret chat ' . $update['chat']['id'], \danog\MadelineProto\Logger::NOTICE);
|
||||||
try {
|
try {
|
||||||
yield $this->acceptSecretChat($update['chat']);
|
yield $this->acceptSecretChat($update['chat']);
|
||||||
} catch (RPCErrorException $e) {
|
} catch (RPCErrorException $e) {
|
||||||
$this->logger->logger("Error while accepting secret chat: $e", Logger::FATAL_ERROR);
|
$this->logger->logger("Error while accepting secret chat: {$e}", Logger::FATAL_ERROR);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'encryptedChatDiscarded':
|
case 'encryptedChatDiscarded':
|
||||||
$this->logger->logger('Deleting secret chat '.$update['chat']['id'].' because it was revoked by the other user', \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('Deleting secret chat ' . $update['chat']['id'] . ' because it was revoked by the other user', \danog\MadelineProto\Logger::NOTICE);
|
||||||
if (isset($this->secret_chats[$update['chat']['id']])) {
|
if (isset($this->secret_chats[$update['chat']['id']])) {
|
||||||
unset($this->secret_chats[$update['chat']['id']]);
|
unset($this->secret_chats[$update['chat']['id']]);
|
||||||
}
|
}
|
||||||
@ -460,17 +425,15 @@ trait UpdateHandler
|
|||||||
if (isset($this->temp_rekeyed_secret_chats[$update['chat']['id']])) {
|
if (isset($this->temp_rekeyed_secret_chats[$update['chat']['id']])) {
|
||||||
unset($this->temp_rekeyed_secret_chats[$update['chat']['id']]);
|
unset($this->temp_rekeyed_secret_chats[$update['chat']['id']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'encryptedChat':
|
case 'encryptedChat':
|
||||||
$this->logger->logger('Completing creation of secret chat '.$update['chat']['id'], \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('Completing creation of secret chat ' . $update['chat']['id'], \danog\MadelineProto\Logger::NOTICE);
|
||||||
yield $this->completeSecretChat($update['chat']);
|
yield $this->completeSecretChat($update['chat']);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//$this->logger->logger($update, \danog\MadelineProto\Logger::NOTICE);
|
//$this->logger->logger($update, \danog\MadelineProto\Logger::NOTICE);
|
||||||
}
|
}
|
||||||
//if ($update['_'] === 'updateServiceNotification' && strpos($update['type'], 'AUTH_KEY_DROP_') === 0) {
|
//if ($update['_'] === 'updateServiceNotification' && strpos($update['type'], 'AUTH_KEY_DROP_') === 0) {
|
||||||
|
|
||||||
//}
|
//}
|
||||||
if (!$this->settings['updates']['handle_updates']) {
|
if (!$this->settings['updates']['handle_updates']) {
|
||||||
return;
|
return;
|
||||||
@ -488,7 +451,6 @@ trait UpdateHandler
|
|||||||
$this->getUpdatesUpdateHandler($update);
|
$this->getUpdatesUpdateHandler($update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send update to webhook.
|
* Send update to webhook.
|
||||||
*
|
*
|
||||||
@ -502,23 +464,20 @@ trait UpdateHandler
|
|||||||
//$this->logger->logger($update, $payload, json_last_error());
|
//$this->logger->logger($update, $payload, json_last_error());
|
||||||
if ($payload === '') {
|
if ($payload === '') {
|
||||||
$this->logger->logger('EMPTY UPDATE');
|
$this->logger->logger('EMPTY UPDATE');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
\danog\MadelineProto\Tools::callFork((function () use ($payload) {
|
\danog\MadelineProto\Tools::callFork((function () use ($payload): \Generator {
|
||||||
$request = new Request($this->hook_url, 'POST');
|
$request = new Request($this->hook_url, 'POST');
|
||||||
$request->setHeader('content-type', 'application/json');
|
$request->setHeader('content-type', 'application/json');
|
||||||
$request->setBody($payload);
|
$request->setBody($payload);
|
||||||
|
|
||||||
$result = yield (yield $this->datacenter->getHTTPClient()->request($request))->getBody()->buffer();
|
$result = yield (yield $this->datacenter->getHTTPClient()->request($request))->getBody()->buffer();
|
||||||
|
$this->logger->logger('Result of webhook query is ' . $result, \danog\MadelineProto\Logger::NOTICE);
|
||||||
$this->logger->logger('Result of webhook query is '.$result, \danog\MadelineProto\Logger::NOTICE);
|
|
||||||
$result = \json_decode($result, true);
|
$result = \json_decode($result, true);
|
||||||
if (\is_array($result) && isset($result['method']) && $result['method'] != '' && \is_string($result['method'])) {
|
if (\is_array($result) && isset($result['method']) && $result['method'] != '' && \is_string($result['method'])) {
|
||||||
try {
|
try {
|
||||||
$this->logger->logger('Reverse webhook command returned', yield $this->methodCallAsyncRead($result['method'], $result, ['datacenter' => $this->datacenter->curdc]));
|
$this->logger->logger('Reverse webhook command returned', yield $this->methodCallAsyncRead($result['method'], $result, ['datacenter' => $this->datacenter->curdc]));
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->logger->logger("Reverse webhook command returned: $e");
|
$this->logger->logger("Reverse webhook command returned: {$e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})());
|
})());
|
||||||
|
@ -48,21 +48,18 @@ class UpdatesState
|
|||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
private $date = 1;
|
private $date = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Channel ID.
|
* Channel ID.
|
||||||
*
|
*
|
||||||
* @var int|bool
|
* @var int|bool
|
||||||
*/
|
*/
|
||||||
private $channelId;
|
private $channelId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is busy?
|
* Is busy?
|
||||||
*
|
*
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
private $syncLoading = false;
|
private $syncLoading = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Init function.
|
* Init function.
|
||||||
*
|
*
|
||||||
@ -74,7 +71,6 @@ class UpdatesState
|
|||||||
$this->channelId = $channelId;
|
$this->channelId = $channelId;
|
||||||
$this->update($init);
|
$this->update($init);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sleep function.
|
* Sleep function.
|
||||||
*
|
*
|
||||||
@ -84,7 +80,6 @@ class UpdatesState
|
|||||||
{
|
{
|
||||||
return $this->channelId ? ['pts', 'channelId'] : ['pts', 'qts', 'seq', 'date', 'channelId'];
|
return $this->channelId ? ['pts', 'channelId'] : ['pts', 'qts', 'seq', 'date', 'channelId'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this state relative to a channel?
|
* Is this state relative to a channel?
|
||||||
*
|
*
|
||||||
@ -94,7 +89,6 @@ class UpdatesState
|
|||||||
{
|
{
|
||||||
return (bool) $this->channelId;
|
return (bool) $this->channelId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the channel ID.
|
* Get the channel ID.
|
||||||
*
|
*
|
||||||
@ -104,7 +98,6 @@ class UpdatesState
|
|||||||
{
|
{
|
||||||
return $this->channelId;
|
return $this->channelId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Are we currently busy?
|
* Are we currently busy?
|
||||||
*
|
*
|
||||||
@ -117,10 +110,8 @@ class UpdatesState
|
|||||||
if ($set !== null) {
|
if ($set !== null) {
|
||||||
$this->syncLoading = $set;
|
$this->syncLoading = $set;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->syncLoading;
|
return $this->syncLoading;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update multiple parameters.
|
* Update multiple parameters.
|
||||||
*
|
*
|
||||||
@ -135,10 +126,8 @@ class UpdatesState
|
|||||||
$this->{$param}($init[$param]);
|
$this->{$param}($init[$param]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get/set PTS.
|
* Get/set PTS.
|
||||||
*
|
*
|
||||||
@ -151,10 +140,8 @@ class UpdatesState
|
|||||||
if ($set !== 0 && $set > $this->pts) {
|
if ($set !== 0 && $set > $this->pts) {
|
||||||
$this->pts = $set;
|
$this->pts = $set;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->pts;
|
return $this->pts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get/set QTS.
|
* Get/set QTS.
|
||||||
*
|
*
|
||||||
@ -167,10 +154,8 @@ class UpdatesState
|
|||||||
if ($set !== 0 && $set > $this->qts) {
|
if ($set !== 0 && $set > $this->qts) {
|
||||||
$this->qts = $set;
|
$this->qts = $set;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->qts;
|
return $this->qts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get/set seq.
|
* Get/set seq.
|
||||||
*
|
*
|
||||||
@ -183,10 +168,8 @@ class UpdatesState
|
|||||||
if ($set !== 0 && $set > $this->seq) {
|
if ($set !== 0 && $set > $this->seq) {
|
||||||
$this->seq = $set;
|
$this->seq = $set;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->seq;
|
return $this->seq;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get/set date.
|
* Get/set date.
|
||||||
*
|
*
|
||||||
@ -199,10 +182,8 @@ class UpdatesState
|
|||||||
if ($set !== 0 && $set > $this->date) {
|
if ($set !== 0 && $set > $this->date) {
|
||||||
$this->date = $set;
|
$this->date = $set;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->date;
|
return $this->date;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check validity of PTS contained in update.
|
* Check validity of PTS contained in update.
|
||||||
*
|
*
|
||||||
@ -214,7 +195,6 @@ class UpdatesState
|
|||||||
{
|
{
|
||||||
return $update['pts'] - ($this->pts + $update['pts_count']);
|
return $update['pts'] - ($this->pts + $update['pts_count']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check validity of seq contained in update.
|
* Check validity of seq contained in update.
|
||||||
*
|
*
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MyTelegramOrgWrapper module.
|
* MyTelegramOrgWrapper module.
|
||||||
*
|
*
|
||||||
@ -27,7 +28,6 @@ use Amp\Http\Client\Request;
|
|||||||
class MyTelegramOrgWrapper
|
class MyTelegramOrgWrapper
|
||||||
{
|
{
|
||||||
use Tools;
|
use Tools;
|
||||||
|
|
||||||
private $logged = false;
|
private $logged = false;
|
||||||
private $hash = '';
|
private $hash = '';
|
||||||
private $number;
|
private $number;
|
||||||
@ -36,75 +36,60 @@ class MyTelegramOrgWrapper
|
|||||||
private $async = true;
|
private $async = true;
|
||||||
private $jar;
|
private $jar;
|
||||||
const MY_TELEGRAM_URL = 'https://my.telegram.org';
|
const MY_TELEGRAM_URL = 'https://my.telegram.org';
|
||||||
|
|
||||||
public function __sleep()
|
public function __sleep()
|
||||||
{
|
{
|
||||||
return ['logged', 'hash', 'number', 'creation_hash', 'settings', 'async', 'jar'];
|
return ['logged', 'hash', 'number', 'creation_hash', 'settings', 'async', 'jar'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __construct($settings = [])
|
public function __construct($settings = [])
|
||||||
{
|
{
|
||||||
$this->settings = MTProto::getSettings($settings, $this->settings);
|
$this->settings = MTProto::getSettings($settings, $this->settings);
|
||||||
$this->__wakeup();
|
$this->__wakeup();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __wakeup()
|
public function __wakeup()
|
||||||
{
|
{
|
||||||
if ($this->settings === null) {
|
if ($this->settings === null) {
|
||||||
$this->settings = [];
|
$this->settings = [];
|
||||||
}
|
}
|
||||||
if (!$this->jar || !($this->jar instanceof InMemoryCookieJar)) {
|
if (!$this->jar || !$this->jar instanceof InMemoryCookieJar) {
|
||||||
$this->jar = new InMemoryCookieJar;
|
$this->jar = new InMemoryCookieJar();
|
||||||
}
|
}
|
||||||
$this->settings = MTProto::getSettings($this->settings);
|
$this->settings = MTProto::getSettings($this->settings);
|
||||||
$this->datacenter = new DataCenter(
|
$this->datacenter = new DataCenter(new class($this->settings) {
|
||||||
new class($this->settings) {
|
public function __construct($settings)
|
||||||
public function __construct($settings)
|
{
|
||||||
{
|
$this->logger = Logger::getLoggerFromSettings($settings);
|
||||||
$this->logger = Logger::getLoggerFromSettings($settings);
|
}
|
||||||
}
|
public function getLogger()
|
||||||
public function getLogger()
|
{
|
||||||
{
|
return $this->logger;
|
||||||
return $this->logger;
|
}
|
||||||
}
|
}, [], $this->settings['connection_settings'], true, $this->jar);
|
||||||
},
|
|
||||||
[],
|
|
||||||
$this->settings['connection_settings'],
|
|
||||||
true,
|
|
||||||
$this->jar
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
public function login($number): \Generator
|
||||||
public function login($number)
|
|
||||||
{
|
{
|
||||||
$this->number = $number;
|
$this->number = $number;
|
||||||
$request = new Request(self::MY_TELEGRAM_URL.'/auth/send_password', 'POST');
|
$request = new Request(self::MY_TELEGRAM_URL . '/auth/send_password', 'POST');
|
||||||
$request->setBody(\http_build_query(['phone' => $number]));
|
$request->setBody(\http_build_query(['phone' => $number]));
|
||||||
$request->setHeaders($this->getHeaders('origin'));
|
$request->setHeaders($this->getHeaders('origin'));
|
||||||
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
||||||
$result = yield $response->getBody()->buffer();
|
$result = yield $response->getBody()->buffer();
|
||||||
$resulta = \json_decode($result, true);
|
$resulta = \json_decode($result, true);
|
||||||
|
|
||||||
if (!isset($resulta['random_hash'])) {
|
if (!isset($resulta['random_hash'])) {
|
||||||
throw new Exception($result);
|
throw new Exception($result);
|
||||||
}
|
}
|
||||||
$this->hash = $resulta['random_hash'];
|
$this->hash = $resulta['random_hash'];
|
||||||
}
|
}
|
||||||
|
public function completeLogin($password): \Generator
|
||||||
public function completeLogin($password)
|
|
||||||
{
|
{
|
||||||
if ($this->logged) {
|
if ($this->logged) {
|
||||||
throw new Exception('Already logged in!');
|
throw new Exception('Already logged in!');
|
||||||
}
|
}
|
||||||
|
$request = new Request(self::MY_TELEGRAM_URL . '/auth/login', 'POST');
|
||||||
$request = new Request(self::MY_TELEGRAM_URL.'/auth/login', 'POST');
|
|
||||||
$request->setBody(\http_build_query(['phone' => $this->number, 'random_hash' => $this->hash, 'password' => $password]));
|
$request->setBody(\http_build_query(['phone' => $this->number, 'random_hash' => $this->hash, 'password' => $password]));
|
||||||
$request->setHeaders($this->getHeaders('origin'));
|
$request->setHeaders($this->getHeaders('origin'));
|
||||||
$request->setHeader('user-agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13');
|
$request->setHeader('user-agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13');
|
||||||
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
||||||
$result = yield $response->getBody()->buffer();
|
$result = yield $response->getBody()->buffer();
|
||||||
|
|
||||||
|
|
||||||
switch ($result) {
|
switch ($result) {
|
||||||
case 'true':
|
case 'true':
|
||||||
//Logger::log(['Login OK'], Logger::VERBOSE);
|
//Logger::log(['Login OK'], Logger::VERBOSE);
|
||||||
@ -112,52 +97,41 @@ class MyTelegramOrgWrapper
|
|||||||
default:
|
default:
|
||||||
throw new Exception($result);
|
throw new Exception($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->logged = true;
|
return $this->logged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loggedIn()
|
public function loggedIn()
|
||||||
{
|
{
|
||||||
return $this->logged;
|
return $this->logged;
|
||||||
}
|
}
|
||||||
|
public function hasApp(): \Generator
|
||||||
public function hasApp()
|
|
||||||
{
|
{
|
||||||
if (!$this->logged) {
|
if (!$this->logged) {
|
||||||
throw new Exception('Not logged in!');
|
throw new Exception('Not logged in!');
|
||||||
}
|
}
|
||||||
|
$request = new Request(self::MY_TELEGRAM_URL . '/apps');
|
||||||
$request = new Request(self::MY_TELEGRAM_URL.'/apps');
|
|
||||||
$request->setHeaders($this->getHeaders('refer'));
|
$request->setHeaders($this->getHeaders('refer'));
|
||||||
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
||||||
$result = yield $response->getBody()->buffer();
|
$result = yield $response->getBody()->buffer();
|
||||||
|
|
||||||
$title = \explode('</title>', \explode('<title>', $result)[1])[0];
|
$title = \explode('</title>', \explode('<title>', $result)[1])[0];
|
||||||
switch ($title) {
|
switch ($title) {
|
||||||
case 'App configuration':
|
case 'App configuration':
|
||||||
return true;
|
return true;
|
||||||
case 'Create new application':
|
case 'Create new application':
|
||||||
$this->creation_hash = \explode('"/>', \explode('<input type="hidden" name="hash" value="', $result)[1])[0];
|
$this->creation_hash = \explode('"/>', \explode('<input type="hidden" name="hash" value="', $result)[1])[0];
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logged = false;
|
$this->logged = false;
|
||||||
|
|
||||||
throw new Exception($title);
|
throw new Exception($title);
|
||||||
}
|
}
|
||||||
|
public function getApp(): \Generator
|
||||||
public function getApp()
|
|
||||||
{
|
{
|
||||||
if (!$this->logged) {
|
if (!$this->logged) {
|
||||||
throw new Exception('Not logged in!');
|
throw new Exception('Not logged in!');
|
||||||
}
|
}
|
||||||
|
$request = new Request(self::MY_TELEGRAM_URL . '/apps');
|
||||||
$request = new Request(self::MY_TELEGRAM_URL.'/apps');
|
|
||||||
$request->setHeaders($this->getHeaders('refer'));
|
$request->setHeaders($this->getHeaders('refer'));
|
||||||
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
||||||
$result = yield $response->getBody()->buffer();
|
$result = yield $response->getBody()->buffer();
|
||||||
|
|
||||||
$cose = \explode('<label for="app_id" class="col-md-4 text-right control-label">App api_id:</label>
|
$cose = \explode('<label for="app_id" class="col-md-4 text-right control-label">App api_id:</label>
|
||||||
<div class="col-md-7">
|
<div class="col-md-7">
|
||||||
<span class="form-control input-xlarge uneditable-input" onclick="this.select();"><strong>', $result);
|
<span class="form-control input-xlarge uneditable-input" onclick="this.select();"><strong>', $result);
|
||||||
@ -168,41 +142,33 @@ class MyTelegramOrgWrapper
|
|||||||
<span class="form-control input-xlarge uneditable-input" onclick="this.select();">', $result);
|
<span class="form-control input-xlarge uneditable-input" onclick="this.select();">', $result);
|
||||||
$asd = \explode('</span>', $cose[1]);
|
$asd = \explode('</span>', $cose[1]);
|
||||||
$api_hash = $asd[0];
|
$api_hash = $asd[0];
|
||||||
|
|
||||||
return ['api_id' => (int) $api_id, 'api_hash' => $api_hash];
|
return ['api_id' => (int) $api_id, 'api_hash' => $api_hash];
|
||||||
}
|
}
|
||||||
|
public function createApp($settings): \Generator
|
||||||
public function createApp($settings)
|
|
||||||
{
|
{
|
||||||
if (!$this->logged) {
|
if (!$this->logged) {
|
||||||
throw new Exception('Not logged in!');
|
throw new Exception('Not logged in!');
|
||||||
}
|
}
|
||||||
if (yield $this->hasApp()) {
|
if (yield from $this->hasApp()) {
|
||||||
throw new Exception('The app was already created!');
|
throw new Exception('The app was already created!');
|
||||||
}
|
}
|
||||||
|
$request = new Request(self::MY_TELEGRAM_URL . '/apps/create', 'POST');
|
||||||
$request = new Request(self::MY_TELEGRAM_URL.'/apps/create', 'POST');
|
|
||||||
$request->setHeaders($this->getHeaders('app'));
|
$request->setHeaders($this->getHeaders('app'));
|
||||||
$request->setBody(\http_build_query(['hash' => $this->creation_hash, 'app_title' => $settings['app_title'], 'app_shortname' => $settings['app_shortname'], 'app_url' => $settings['app_url'], 'app_platform' => $settings['app_platform'], 'app_desc' => $settings['app_desc']]));
|
$request->setBody(\http_build_query(['hash' => $this->creation_hash, 'app_title' => $settings['app_title'], 'app_shortname' => $settings['app_shortname'], 'app_url' => $settings['app_url'], 'app_platform' => $settings['app_platform'], 'app_desc' => $settings['app_desc']]));
|
||||||
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
||||||
$result = yield $response->getBody()->buffer();
|
$result = yield $response->getBody()->buffer();
|
||||||
|
|
||||||
if ($result) {
|
if ($result) {
|
||||||
throw new Exception(\html_entity_decode($result));
|
throw new Exception(\html_entity_decode($result));
|
||||||
}
|
}
|
||||||
|
$request = new Request(self::MY_TELEGRAM_URL . '/apps');
|
||||||
$request = new Request(self::MY_TELEGRAM_URL.'/apps');
|
|
||||||
$request->setHeaders($this->getHeaders('refer'));
|
$request->setHeaders($this->getHeaders('refer'));
|
||||||
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
||||||
$result = yield $response->getBody()->buffer();
|
$result = yield $response->getBody()->buffer();
|
||||||
|
|
||||||
$title = \explode('</title>', \explode('<title>', $result)[1])[0];
|
$title = \explode('</title>', \explode('<title>', $result)[1])[0];
|
||||||
if ($title === 'Create new application') {
|
if ($title === 'Create new application') {
|
||||||
$this->creation_hash = \explode('"/>', \explode('<input type="hidden" name="hash" value="', $result)[1])[0];
|
$this->creation_hash = \explode('"/>', \explode('<input type="hidden" name="hash" value="', $result)[1])[0];
|
||||||
|
|
||||||
throw new \danog\MadelineProto\Exception('App creation failed');
|
throw new \danog\MadelineProto\Exception('App creation failed');
|
||||||
}
|
}
|
||||||
|
|
||||||
$cose = \explode('<label for="app_id" class="col-md-4 text-right control-label">App api_id:</label>
|
$cose = \explode('<label for="app_id" class="col-md-4 text-right control-label">App api_id:</label>
|
||||||
<div class="col-md-7">
|
<div class="col-md-7">
|
||||||
<span class="form-control input-xlarge uneditable-input" onclick="this.select();"><strong>', $result);
|
<span class="form-control input-xlarge uneditable-input" onclick="this.select();"><strong>', $result);
|
||||||
@ -213,10 +179,8 @@ class MyTelegramOrgWrapper
|
|||||||
<span class="form-control input-xlarge uneditable-input" onclick="this.select();">', $result);
|
<span class="form-control input-xlarge uneditable-input" onclick="this.select();">', $result);
|
||||||
$asd = \explode('</span>', $cose['1']);
|
$asd = \explode('</span>', $cose['1']);
|
||||||
$api_hash = $asd['0'];
|
$api_hash = $asd['0'];
|
||||||
|
|
||||||
return ['api_id' => (int) $api_id, 'api_hash' => $api_hash];
|
return ['api_id' => (int) $api_id, 'api_hash' => $api_hash];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function for generating curl request headers.
|
* Function for generating curl request headers.
|
||||||
*/
|
*/
|
||||||
@ -228,43 +192,39 @@ class MyTelegramOrgWrapper
|
|||||||
$headers[] = 'Connection: keep-alive';
|
$headers[] = 'Connection: keep-alive';
|
||||||
$headers[] = 'Accept-Language: it-IT,it;q=0.8,en-US;q=0.6,en;q=0.4';
|
$headers[] = 'Accept-Language: it-IT,it;q=0.8,en-US;q=0.6,en;q=0.4';
|
||||||
$headers[] = 'User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36';
|
$headers[] = 'User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36';
|
||||||
|
|
||||||
// Add additional headers based on the type of request.
|
// Add additional headers based on the type of request.
|
||||||
switch ($httpType) {
|
switch ($httpType) {
|
||||||
case 'origin':
|
case 'origin':
|
||||||
$headers[] = 'Origin: '.self::MY_TELEGRAM_URL;
|
$headers[] = 'Origin: ' . self::MY_TELEGRAM_URL;
|
||||||
//$headers[] = 'Accept-Encoding: gzip, deflate, br';
|
//$headers[] = 'Accept-Encoding: gzip, deflate, br';
|
||||||
$headers[] = 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8';
|
$headers[] = 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8';
|
||||||
$headers[] = 'Accept: application/json, text/javascript, */*; q=0.01';
|
$headers[] = 'Accept: application/json, text/javascript, */*; q=0.01';
|
||||||
$headers[] = 'Referer: '.self::MY_TELEGRAM_URL.'/auth';
|
$headers[] = 'Referer: ' . self::MY_TELEGRAM_URL . '/auth';
|
||||||
$headers[] = 'X-Requested-With: XMLHttpRequest';
|
$headers[] = 'X-Requested-With: XMLHttpRequest';
|
||||||
break;
|
break;
|
||||||
case 'refer':
|
case 'refer':
|
||||||
//$headers[] = 'Accept-Encoding: gzip, deflate, sdch, br';
|
//$headers[] = 'Accept-Encoding: gzip, deflate, sdch, br';
|
||||||
$headers[] = 'Upgrade-Insecure-Requests: 1';
|
$headers[] = 'Upgrade-Insecure-Requests: 1';
|
||||||
$headers[] = 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8';
|
$headers[] = 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8';
|
||||||
$headers[] = 'Referer: '.self::MY_TELEGRAM_URL;
|
$headers[] = 'Referer: ' . self::MY_TELEGRAM_URL;
|
||||||
$headers[] = 'Cache-Control: max-age=0';
|
$headers[] = 'Cache-Control: max-age=0';
|
||||||
break;
|
break;
|
||||||
case 'app':
|
case 'app':
|
||||||
$headers[] = 'Origin: '.self::MY_TELEGRAM_URL;
|
$headers[] = 'Origin: ' . self::MY_TELEGRAM_URL;
|
||||||
//$headers[] = 'Accept-Encoding: gzip, deflate, br';
|
//$headers[] = 'Accept-Encoding: gzip, deflate, br';
|
||||||
$headers[] = 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8';
|
$headers[] = 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8';
|
||||||
$headers[] = 'Accept: */*';
|
$headers[] = 'Accept: */*';
|
||||||
$headers[] = 'Referer: '.self::MY_TELEGRAM_URL.'/apps';
|
$headers[] = 'Referer: ' . self::MY_TELEGRAM_URL . '/apps';
|
||||||
$headers[] = 'X-Requested-With: XMLHttpRequest';
|
$headers[] = 'X-Requested-With: XMLHttpRequest';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$final_headers = [];
|
$final_headers = [];
|
||||||
foreach ($headers as $header) {
|
foreach ($headers as $header) {
|
||||||
list($key, $value) = \explode(':', $header, 2);
|
list($key, $value) = \explode(':', $header, 2);
|
||||||
$final_headers[\trim($key)] = \trim($value);
|
$final_headers[\trim($key)] = \trim($value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $final_headers;
|
return $final_headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function async($async)
|
public function async($async)
|
||||||
{
|
{
|
||||||
$this->async = $async;
|
$this->async = $async;
|
||||||
@ -277,9 +237,8 @@ class MyTelegramOrgWrapper
|
|||||||
{
|
{
|
||||||
$name .= '_async';
|
$name .= '_async';
|
||||||
$async = \is_array(\end($arguments)) && isset(\end($arguments)['async']) ? \end($arguments)['async'] : $this->async;
|
$async = \is_array(\end($arguments)) && isset(\end($arguments)['async']) ? \end($arguments)['async'] : $this->async;
|
||||||
|
|
||||||
if (!\method_exists($this, $name)) {
|
if (!\method_exists($this, $name)) {
|
||||||
throw new Exception("$name does not exist!");
|
throw new Exception("{$name} does not exist!");
|
||||||
}
|
}
|
||||||
return $async ? $this->{$name}(...$arguments) : Tools::wait($this->{$name}(...$arguments));
|
return $async ? $this->{$name}(...$arguments) : Tools::wait($this->{$name}(...$arguments));
|
||||||
}
|
}
|
||||||
|
@ -22,12 +22,10 @@ namespace danog\MadelineProto;
|
|||||||
class PTSException extends \Exception
|
class PTSException extends \Exception
|
||||||
{
|
{
|
||||||
use TL\PrettyException;
|
use TL\PrettyException;
|
||||||
|
|
||||||
public function __toString()
|
public function __toString()
|
||||||
{
|
{
|
||||||
return \get_class($this).($this->message !== '' ? ': ' : '').$this->message.PHP_EOL.'TL Trace:'.PHP_EOL.PHP_EOL.$this->getTLTrace().PHP_EOL;
|
return \get_class($this) . ($this->message !== '' ? ': ' : '') . $this->message . PHP_EOL . 'TL Trace:' . PHP_EOL . PHP_EOL . $this->getTLTrace() . PHP_EOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __construct($message, $file = '')
|
public function __construct($message, $file = '')
|
||||||
{
|
{
|
||||||
parent::__construct($message);
|
parent::__construct($message);
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
<?php
|
@ -24,101 +24,43 @@ class RPCErrorException extends \Exception
|
|||||||
use TL\PrettyException;
|
use TL\PrettyException;
|
||||||
private $fetched = false;
|
private $fetched = false;
|
||||||
public static $rollbar = true;
|
public static $rollbar = true;
|
||||||
|
public static $descriptions = ['RPC_MCGET_FAIL' => 'Telegram is having internal issues, please try again later.', 'RPC_CALL_FAIL' => 'Telegram is having internal issues, please try again later.', 'USER_PRIVACY_RESTRICTED' => "The user's privacy settings do not allow you to do this", 'CHANNEL_PRIVATE' => "You haven't joined this channel/supergroup", 'USER_IS_BOT' => "Bots can't send messages to other bots", 'BOT_METHOD_INVALID' => 'This method cannot be run by a bot', 'PHONE_CODE_EXPIRED' => 'The phone code you provided has expired, this may happen if it was sent to any chat on telegram (if the code is sent through a telegram chat (not the official account) to avoid it append or prepend to the code some chars)', 'USERNAME_INVALID' => 'The provided username is not valid', 'ACCESS_TOKEN_INVALID' => 'The provided token is not valid', 'ACTIVE_USER_REQUIRED' => 'The method is only available to already activated users', 'FIRSTNAME_INVALID' => 'The first name is invalid', 'LASTNAME_INVALID' => 'The last name is invalid', 'PHONE_NUMBER_INVALID' => 'The phone number is invalid', 'PHONE_CODE_HASH_EMPTY' => 'phone_code_hash is missing', 'PHONE_CODE_EMPTY' => 'phone_code is missing', 'PHONE_CODE_EXPIRED' => 'The confirmation code has expired', 'API_ID_INVALID' => 'The api_id/api_hash combination is invalid', 'PHONE_NUMBER_OCCUPIED' => 'The phone number is already in use', 'PHONE_NUMBER_UNOCCUPIED' => 'The phone number is not yet being used', 'USERS_TOO_FEW' => 'Not enough users (to create a chat, for example)', 'USERS_TOO_MUCH' => 'The maximum number of users has been exceeded (to create a chat, for example)', 'TYPE_CONSTRUCTOR_INVALID' => 'The type constructor is invalid', 'FILE_PART_INVALID' => 'The file part number is invalid', 'FILE_PARTS_INVALID' => 'The number of file parts is invalid', 'MD5_CHECKSUM_INVALID' => 'The MD5 checksums do not match', 'PHOTO_INVALID_DIMENSIONS' => 'The photo dimensions are invalid', 'FIELD_NAME_INVALID' => 'The field with the name FIELD_NAME is invalid', 'FIELD_NAME_EMPTY' => 'The field with the name FIELD_NAME is missing', 'MSG_WAIT_FAILED' => 'A waiting call returned an error', 'USERNAME_NOT_OCCUPIED' => 'The provided username is not occupied', 'PHONE_NUMBER_BANNED' => 'The provided phone number is banned from telegram', 'AUTH_KEY_UNREGISTERED' => 'The authorization key has expired', 'INVITE_HASH_EXPIRED' => 'The invite link has expired', 'USER_DEACTIVATED' => 'The user was deactivated', 'USER_ALREADY_PARTICIPANT' => 'The user is already in the group', 'MESSAGE_ID_INVALID' => 'The provided message id is invalid', 'PEER_ID_INVALID' => 'The provided peer id is invalid', 'CHAT_ID_INVALID' => 'The provided chat id is invalid', 'MESSAGE_DELETE_FORBIDDEN' => "You can't delete one of the messages you tried to delete, most likely because it is a service message.", 'CHAT_ADMIN_REQUIRED' => 'You must be an admin in this chat to do this', -429 => 'Too many requests', 'PEER_FLOOD' => "You are spamreported, you can't do this"];
|
||||||
public static $descriptions = [
|
|
||||||
'RPC_MCGET_FAIL' => 'Telegram is having internal issues, please try again later.',
|
|
||||||
'RPC_CALL_FAIL' => 'Telegram is having internal issues, please try again later.',
|
|
||||||
'USER_PRIVACY_RESTRICTED' => "The user's privacy settings do not allow you to do this",
|
|
||||||
'CHANNEL_PRIVATE' => "You haven't joined this channel/supergroup",
|
|
||||||
'USER_IS_BOT' => "Bots can't send messages to other bots",
|
|
||||||
'BOT_METHOD_INVALID' => 'This method cannot be run by a bot',
|
|
||||||
'PHONE_CODE_EXPIRED' => 'The phone code you provided has expired, this may happen if it was sent to any chat on telegram (if the code is sent through a telegram chat (not the official account) to avoid it append or prepend to the code some chars)',
|
|
||||||
'USERNAME_INVALID' => 'The provided username is not valid',
|
|
||||||
'ACCESS_TOKEN_INVALID' => 'The provided token is not valid',
|
|
||||||
'ACTIVE_USER_REQUIRED' => 'The method is only available to already activated users',
|
|
||||||
'FIRSTNAME_INVALID' => 'The first name is invalid',
|
|
||||||
'LASTNAME_INVALID' => 'The last name is invalid',
|
|
||||||
'PHONE_NUMBER_INVALID' => 'The phone number is invalid',
|
|
||||||
'PHONE_CODE_HASH_EMPTY' => 'phone_code_hash is missing',
|
|
||||||
'PHONE_CODE_EMPTY' => 'phone_code is missing',
|
|
||||||
'PHONE_CODE_EXPIRED' => 'The confirmation code has expired',
|
|
||||||
'API_ID_INVALID' => 'The api_id/api_hash combination is invalid',
|
|
||||||
'PHONE_NUMBER_OCCUPIED' => 'The phone number is already in use',
|
|
||||||
'PHONE_NUMBER_UNOCCUPIED' => 'The phone number is not yet being used',
|
|
||||||
'USERS_TOO_FEW' => 'Not enough users (to create a chat, for example)',
|
|
||||||
'USERS_TOO_MUCH' => 'The maximum number of users has been exceeded (to create a chat, for example)',
|
|
||||||
'TYPE_CONSTRUCTOR_INVALID' => 'The type constructor is invalid',
|
|
||||||
'FILE_PART_INVALID' => 'The file part number is invalid',
|
|
||||||
'FILE_PARTS_INVALID' => 'The number of file parts is invalid',
|
|
||||||
'MD5_CHECKSUM_INVALID' => 'The MD5 checksums do not match',
|
|
||||||
'PHOTO_INVALID_DIMENSIONS' => 'The photo dimensions are invalid',
|
|
||||||
'FIELD_NAME_INVALID' => 'The field with the name FIELD_NAME is invalid',
|
|
||||||
'FIELD_NAME_EMPTY' => 'The field with the name FIELD_NAME is missing',
|
|
||||||
'MSG_WAIT_FAILED' => 'A waiting call returned an error',
|
|
||||||
'USERNAME_NOT_OCCUPIED' => 'The provided username is not occupied',
|
|
||||||
'PHONE_NUMBER_BANNED' => 'The provided phone number is banned from telegram',
|
|
||||||
'AUTH_KEY_UNREGISTERED' => 'The authorization key has expired',
|
|
||||||
'INVITE_HASH_EXPIRED' => 'The invite link has expired',
|
|
||||||
'USER_DEACTIVATED' => 'The user was deactivated',
|
|
||||||
'USER_ALREADY_PARTICIPANT' => 'The user is already in the group',
|
|
||||||
'MESSAGE_ID_INVALID' => 'The provided message id is invalid',
|
|
||||||
'PEER_ID_INVALID' => 'The provided peer id is invalid',
|
|
||||||
'CHAT_ID_INVALID' => 'The provided chat id is invalid',
|
|
||||||
'MESSAGE_DELETE_FORBIDDEN' => "You can't delete one of the messages you tried to delete, most likely because it is a service message.",
|
|
||||||
'CHAT_ADMIN_REQUIRED' => 'You must be an admin in this chat to do this',
|
|
||||||
-429 => 'Too many requests',
|
|
||||||
'PEER_FLOOD' => "You are spamreported, you can't do this",
|
|
||||||
];
|
|
||||||
public static $errorMethodMap = [];
|
public static $errorMethodMap = [];
|
||||||
|
|
||||||
private $caller = '';
|
private $caller = '';
|
||||||
public static function localizeMessage($method, $code, $error)
|
public static function localizeMessage($method, $code, $error)
|
||||||
{
|
{
|
||||||
if (!$method || !$code || !$error) {
|
if (!$method || !$code || !$error) {
|
||||||
return $error;
|
return $error;
|
||||||
}
|
}
|
||||||
|
$error = \preg_replace('/\\d+$/', "X", $error);
|
||||||
$error = \preg_replace('/\d+$/', "X", $error);
|
|
||||||
|
|
||||||
$description = self::$descriptions[$error] ?? '';
|
$description = self::$descriptions[$error] ?? '';
|
||||||
|
if (!isset(self::$errorMethodMap[$code][$method][$error]) || !isset(self::$descriptions[$error]) || $code === 500) {
|
||||||
|
$res = \json_decode(@\file_get_contents('https://rpc.pwrtelegram.xyz/?method=' . $method . '&code=' . $code . '&error=' . $error, false, \stream_context_create(['http' => ['timeout' => 3]])), true);
|
||||||
if (!isset(self::$errorMethodMap[$code][$method][$error])
|
|
||||||
|| !isset(self::$descriptions[$error])
|
|
||||||
|| $code === 500
|
|
||||||
) {
|
|
||||||
$res = \json_decode(@\file_get_contents('https://rpc.pwrtelegram.xyz/?method='.$method.'&code='.$code.'&error='.$error, false, \stream_context_create(['http'=>['timeout' => 3]])), true);
|
|
||||||
if (isset($res['ok']) && $res['ok'] && isset($res['result'])) {
|
if (isset($res['ok']) && $res['ok'] && isset($res['result'])) {
|
||||||
$description = $res['result'];
|
$description = $res['result'];
|
||||||
|
|
||||||
self::$descriptions[$error] = $description;
|
self::$descriptions[$error] = $description;
|
||||||
self::$errorMethodMap[$code][$method][$error] = $error;
|
self::$errorMethodMap[$code][$method][$error] = $error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$description) {
|
if (!$description) {
|
||||||
return $error;
|
return $error;
|
||||||
}
|
}
|
||||||
return $description;
|
return $description;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __toString()
|
public function __toString()
|
||||||
{
|
{
|
||||||
$result = \sprintf(\danog\MadelineProto\Lang::$current_lang['rpc_tg_error'], self::localizeMessage($this->caller, $this->code, $this->message)." ({$this->code})", $this->rpc, $this->file, $this->line.PHP_EOL, \danog\MadelineProto\Magic::$revision.PHP_EOL.PHP_EOL).PHP_EOL.$this->getTLTrace().PHP_EOL;
|
$result = \sprintf(\danog\MadelineProto\Lang::$current_lang['rpc_tg_error'], self::localizeMessage($this->caller, $this->code, $this->message) . " ({$this->code})", $this->rpc, $this->file, $this->line . PHP_EOL, \danog\MadelineProto\Magic::$revision . PHP_EOL . PHP_EOL) . PHP_EOL . $this->getTLTrace() . PHP_EOL;
|
||||||
if (PHP_SAPI !== 'cli') {
|
if (PHP_SAPI !== 'cli') {
|
||||||
$result = \str_replace(PHP_EOL, '<br>'.PHP_EOL, $result);
|
$result = \str_replace(PHP_EOL, '<br>' . PHP_EOL, $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __construct($message = null, $code = 0, $caller = '', Exception $previous = null)
|
public function __construct($message = null, $code = 0, $caller = '', Exception $previous = null)
|
||||||
{
|
{
|
||||||
$this->rpc = $message;
|
$this->rpc = $message;
|
||||||
parent::__construct($message, $code, $previous);
|
parent::__construct($message, $code, $previous);
|
||||||
$this->prettifyTL($caller);
|
$this->prettifyTL($caller);
|
||||||
$this->caller = $caller;
|
$this->caller = $caller;
|
||||||
|
|
||||||
$additional = [];
|
$additional = [];
|
||||||
foreach ($this->getTrace() as $level) {
|
foreach ($this->getTrace() as $level) {
|
||||||
if (isset($level['function']) && $level['function'] === 'methodCall') {
|
if (isset($level['function']) && $level['function'] === 'methodCall') {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RSA module.
|
* RSA module.
|
||||||
*
|
*
|
||||||
@ -45,7 +46,6 @@ class RSA
|
|||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
public $fp;
|
public $fp;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load RSA key.
|
* Load RSA key.
|
||||||
*
|
*
|
||||||
@ -62,11 +62,9 @@ class RSA
|
|||||||
$this->n = Tools::getVar($key, 'modulus');
|
$this->n = Tools::getVar($key, 'modulus');
|
||||||
$this->e = Tools::getVar($key, 'exponent');
|
$this->e = Tools::getVar($key, 'exponent');
|
||||||
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['computing_fingerprint'], Logger::ULTRA_VERBOSE);
|
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['computing_fingerprint'], Logger::ULTRA_VERBOSE);
|
||||||
$this->fp = \substr(\sha1((yield $TL->serializeObject(['type' => 'bytes'], $this->n->toBytes(), 'key')).(yield $TL->serializeObject(['type' => 'bytes'], $this->e->toBytes(), 'key')), true), -8);
|
$this->fp = \substr(\sha1(yield $TL->serializeObject(['type' => 'bytes'], $this->n->toBytes(), 'key') . yield $TL->serializeObject(['type' => 'bytes'], $this->e->toBytes(), 'key'), true), -8);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sleep function.
|
* Sleep function.
|
||||||
*
|
*
|
||||||
@ -76,7 +74,6 @@ class RSA
|
|||||||
{
|
{
|
||||||
return ['e', 'n', 'fp'];
|
return ['e', 'n', 'fp'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encrypt data.
|
* Encrypt data.
|
||||||
*
|
*
|
||||||
@ -87,7 +84,6 @@ class RSA
|
|||||||
public function encrypt($data): string
|
public function encrypt($data): string
|
||||||
{
|
{
|
||||||
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['rsa_encrypting'], Logger::VERBOSE);
|
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['rsa_encrypting'], Logger::VERBOSE);
|
||||||
|
|
||||||
return (new \tgseclib\Math\BigInteger((string) $data, 256))->powMod($this->e, $this->n)->toBytes();
|
return (new \tgseclib\Math\BigInteger((string) $data, 256))->powMod($this->e, $this->n)->toBytes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,6 @@ trait AuthKeyHandler
|
|||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $secret_chats = [];
|
protected $secret_chats = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accept secret chat.
|
* Accept secret chat.
|
||||||
*
|
*
|
||||||
@ -53,8 +52,7 @@ trait AuthKeyHandler
|
|||||||
//$this->logger->logger($params['id'],$this->secretChatStatus($params['id']));
|
//$this->logger->logger($params['id'],$this->secretChatStatus($params['id']));
|
||||||
if ($this->secretChatStatus($params['id']) !== 0) {
|
if ($this->secretChatStatus($params['id']) !== 0) {
|
||||||
//$this->logger->logger($this->secretChatStatus($params['id']));
|
//$this->logger->logger($this->secretChatStatus($params['id']));
|
||||||
$this->logger->logger("I've already accepted secret chat ".$params['id']);
|
$this->logger->logger("I've already accepted secret chat " . $params['id']);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$dh_config = yield $this->getDhConfig();
|
$dh_config = yield $this->getDhConfig();
|
||||||
@ -71,10 +69,9 @@ trait AuthKeyHandler
|
|||||||
$g_b = $dh_config['g']->powMod($b, $dh_config['p']);
|
$g_b = $dh_config['g']->powMod($b, $dh_config['p']);
|
||||||
$this->checkG($g_b, $dh_config['p']);
|
$this->checkG($g_b, $dh_config['p']);
|
||||||
yield $this->methodCallAsyncRead('messages.acceptEncryption', ['peer' => $params['id'], 'g_b' => $g_b->toBytes(), 'key_fingerprint' => $key['fingerprint']], ['datacenter' => $this->datacenter->curdc]);
|
yield $this->methodCallAsyncRead('messages.acceptEncryption', ['peer' => $params['id'], 'g_b' => $g_b->toBytes(), 'key_fingerprint' => $key['fingerprint']], ['datacenter' => $this->datacenter->curdc]);
|
||||||
yield $this->notifyLayer($params['id']);
|
yield from $this->notifyLayer($params['id']);
|
||||||
$this->logger->logger('Secret chat '.$params['id'].' accepted successfully!', \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('Secret chat ' . $params['id'] . ' accepted successfully!', \danog\MadelineProto\Logger::NOTICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request secret chat.
|
* Request secret chat.
|
||||||
*
|
*
|
||||||
@ -89,7 +86,7 @@ trait AuthKeyHandler
|
|||||||
throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database');
|
throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database');
|
||||||
}
|
}
|
||||||
$user = $user['InputUser'];
|
$user = $user['InputUser'];
|
||||||
$this->logger->logger('Creating secret chat with '.$user['user_id'].'...', \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('Creating secret chat with ' . $user['user_id'] . '...', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
$dh_config = yield $this->getDhConfig();
|
$dh_config = yield $this->getDhConfig();
|
||||||
$this->logger->logger('Generating a...', \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('Generating a...', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
$a = new \tgseclib\Math\BigInteger(\danog\MadelineProto\Tools::random(256), 256);
|
$a = new \tgseclib\Math\BigInteger(\danog\MadelineProto\Tools::random(256), 256);
|
||||||
@ -99,11 +96,9 @@ trait AuthKeyHandler
|
|||||||
$res = yield $this->methodCallAsyncRead('messages.requestEncryption', ['user_id' => $user, 'g_a' => $g_a->toBytes()], ['datacenter' => $this->datacenter->curdc]);
|
$res = yield $this->methodCallAsyncRead('messages.requestEncryption', ['user_id' => $user, 'g_a' => $g_a->toBytes()], ['datacenter' => $this->datacenter->curdc]);
|
||||||
$this->temp_requested_secret_chats[$res['id']] = $a;
|
$this->temp_requested_secret_chats[$res['id']] = $a;
|
||||||
$this->updaters[false]->resume();
|
$this->updaters[false]->resume();
|
||||||
$this->logger->logger('Secret chat '.$res['id'].' requested successfully!', \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('Secret chat ' . $res['id'] . ' requested successfully!', \danog\MadelineProto\Logger::NOTICE);
|
||||||
|
|
||||||
return $res['id'];
|
return $res['id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Complete secret chat.
|
* Complete secret chat.
|
||||||
*
|
*
|
||||||
@ -115,8 +110,7 @@ trait AuthKeyHandler
|
|||||||
{
|
{
|
||||||
if ($this->secretChatStatus($params['id']) !== 1) {
|
if ($this->secretChatStatus($params['id']) !== 1) {
|
||||||
//$this->logger->logger($this->secretChatStatus($params['id']));
|
//$this->logger->logger($this->secretChatStatus($params['id']));
|
||||||
$this->logger->logger('Could not find and complete secret chat '.$params['id']);
|
$this->logger->logger('Could not find and complete secret chat ' . $params['id']);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$dh_config = yield $this->getDhConfig();
|
$dh_config = yield $this->getDhConfig();
|
||||||
@ -127,29 +121,25 @@ trait AuthKeyHandler
|
|||||||
$key['fingerprint'] = \substr(\sha1($key['auth_key'], true), -8);
|
$key['fingerprint'] = \substr(\sha1($key['auth_key'], true), -8);
|
||||||
//$this->logger->logger($key);
|
//$this->logger->logger($key);
|
||||||
if ($key['fingerprint'] !== $params['key_fingerprint']) {
|
if ($key['fingerprint'] !== $params['key_fingerprint']) {
|
||||||
yield $this->discardSecretChat($params['id']);
|
yield from $this->discardSecretChat($params['id']);
|
||||||
|
|
||||||
throw new \danog\MadelineProto\SecurityException('Invalid key fingerprint!');
|
throw new \danog\MadelineProto\SecurityException('Invalid key fingerprint!');
|
||||||
}
|
}
|
||||||
$key['visualization_orig'] = \substr(\sha1($key['auth_key'], true), 16);
|
$key['visualization_orig'] = \substr(\sha1($key['auth_key'], true), 16);
|
||||||
$key['visualization_46'] = \substr(\hash('sha256', $key['auth_key'], true), 20);
|
$key['visualization_46'] = \substr(\hash('sha256', $key['auth_key'], true), 20);
|
||||||
$this->secret_chats[$params['id']] = ['key' => $key, 'admin' => true, 'user_id' => $params['participant_id'], 'InputEncryptedChat' => ['chat_id' => $params['id'], 'access_hash' => $params['access_hash'], '_' => 'inputEncryptedChat'], 'in_seq_no_x' => 0, 'out_seq_no_x' => 1, 'in_seq_no' => 0, 'out_seq_no' => 0, 'layer' => 8, 'ttl' => 0, 'ttr' => 100, 'updated' => \time(), 'incoming' => [], 'outgoing' => [], 'created' => \time(), 'rekeying' => [0], 'key_x' => 'to server', 'mtproto' => 1];
|
$this->secret_chats[$params['id']] = ['key' => $key, 'admin' => true, 'user_id' => $params['participant_id'], 'InputEncryptedChat' => ['chat_id' => $params['id'], 'access_hash' => $params['access_hash'], '_' => 'inputEncryptedChat'], 'in_seq_no_x' => 0, 'out_seq_no_x' => 1, 'in_seq_no' => 0, 'out_seq_no' => 0, 'layer' => 8, 'ttl' => 0, 'ttr' => 100, 'updated' => \time(), 'incoming' => [], 'outgoing' => [], 'created' => \time(), 'rekeying' => [0], 'key_x' => 'to server', 'mtproto' => 1];
|
||||||
yield $this->notifyLayer($params['id']);
|
yield from $this->notifyLayer($params['id']);
|
||||||
$this->logger->logger('Secret chat '.$params['id'].' completed successfully!', \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('Secret chat ' . $params['id'] . ' completed successfully!', \danog\MadelineProto\Logger::NOTICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function notifyLayer($chat): \Generator
|
private function notifyLayer($chat): \Generator
|
||||||
{
|
{
|
||||||
yield $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionNotifyLayer', 'layer' => $this->TL->getSecretLayer()]]], ['datacenter' => $this->datacenter->curdc]);
|
yield $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionNotifyLayer', 'layer' => $this->TL->getSecretLayer()]]], ['datacenter' => $this->datacenter->curdc]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Temporary rekeyed secret chats.
|
* Temporary rekeyed secret chats.
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $temp_rekeyed_secret_chats = [];
|
protected $temp_rekeyed_secret_chats = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rekey secret chat.
|
* Rekey secret chat.
|
||||||
*
|
*
|
||||||
@ -162,7 +152,7 @@ trait AuthKeyHandler
|
|||||||
if ($this->secret_chats[$chat]['rekeying'][0] !== 0) {
|
if ($this->secret_chats[$chat]['rekeying'][0] !== 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->logger->logger('Rekeying secret chat '.$chat.'...', \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('Rekeying secret chat ' . $chat . '...', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
$dh_config = yield $this->getDhConfig();
|
$dh_config = yield $this->getDhConfig();
|
||||||
$this->logger->logger('Generating a...', \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('Generating a...', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
$a = new \tgseclib\Math\BigInteger(\danog\MadelineProto\Tools::random(256), 256);
|
$a = new \tgseclib\Math\BigInteger(\danog\MadelineProto\Tools::random(256), 256);
|
||||||
@ -174,10 +164,8 @@ trait AuthKeyHandler
|
|||||||
$this->secret_chats[$chat]['rekeying'] = [1, $e];
|
$this->secret_chats[$chat]['rekeying'] = [1, $e];
|
||||||
yield $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionRequestKey', 'g_a' => $g_a->toBytes(), 'exchange_id' => $e]]], ['datacenter' => $this->datacenter->curdc]);
|
yield $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionRequestKey', 'g_a' => $g_a->toBytes(), 'exchange_id' => $e]]], ['datacenter' => $this->datacenter->curdc]);
|
||||||
$this->updaters[false]->resume();
|
$this->updaters[false]->resume();
|
||||||
|
|
||||||
return $e;
|
return $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accept rekeying.
|
* Accept rekeying.
|
||||||
*
|
*
|
||||||
@ -197,11 +185,10 @@ trait AuthKeyHandler
|
|||||||
}
|
}
|
||||||
if ($my_exchange_id->compare($other_exchange_id) === 0) {
|
if ($my_exchange_id->compare($other_exchange_id) === 0) {
|
||||||
$this->secret_chats[$chat]['rekeying'] = [0];
|
$this->secret_chats[$chat]['rekeying'] = [0];
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->logger->logger('Accepting rekeying of secret chat '.$chat.'...', \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('Accepting rekeying of secret chat ' . $chat . '...', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
$dh_config = yield $this->getDhConfig();
|
$dh_config = yield $this->getDhConfig();
|
||||||
$this->logger->logger('Generating b...', \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('Generating b...', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
$b = new \tgseclib\Math\BigInteger(\danog\MadelineProto\Tools::random(256), 256);
|
$b = new \tgseclib\Math\BigInteger(\danog\MadelineProto\Tools::random(256), 256);
|
||||||
@ -218,7 +205,6 @@ trait AuthKeyHandler
|
|||||||
yield $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionAcceptKey', 'g_b' => $g_b->toBytes(), 'exchange_id' => $params['exchange_id'], 'key_fingerprint' => $key['fingerprint']]]], ['datacenter' => $this->datacenter->curdc]);
|
yield $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionAcceptKey', 'g_b' => $g_b->toBytes(), 'exchange_id' => $params['exchange_id'], 'key_fingerprint' => $key['fingerprint']]]], ['datacenter' => $this->datacenter->curdc]);
|
||||||
$this->updaters[false]->resume();
|
$this->updaters[false]->resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Commit rekeying of secret chat.
|
* Commit rekeying of secret chat.
|
||||||
*
|
*
|
||||||
@ -231,10 +217,9 @@ trait AuthKeyHandler
|
|||||||
{
|
{
|
||||||
if ($this->secret_chats[$chat]['rekeying'][0] !== 1 || !isset($this->temp_rekeyed_secret_chats[$params['exchange_id']])) {
|
if ($this->secret_chats[$chat]['rekeying'][0] !== 1 || !isset($this->temp_rekeyed_secret_chats[$params['exchange_id']])) {
|
||||||
$this->secret_chats[$chat]['rekeying'] = [0];
|
$this->secret_chats[$chat]['rekeying'] = [0];
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->logger->logger('Committing rekeying of secret chat '.$chat.'...', \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('Committing rekeying of secret chat ' . $chat . '...', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
$dh_config = yield $this->getDhConfig();
|
$dh_config = yield $this->getDhConfig();
|
||||||
$params['g_b'] = new \tgseclib\Math\BigInteger((string) $params['g_b'], 256);
|
$params['g_b'] = new \tgseclib\Math\BigInteger((string) $params['g_b'], 256);
|
||||||
$this->checkG($params['g_b'], $dh_config['p']);
|
$this->checkG($params['g_b'], $dh_config['p']);
|
||||||
@ -244,7 +229,6 @@ trait AuthKeyHandler
|
|||||||
$key['visualization_46'] = \substr(\hash('sha256', $key['auth_key'], true), 20);
|
$key['visualization_46'] = \substr(\hash('sha256', $key['auth_key'], true), 20);
|
||||||
if ($key['fingerprint'] !== $params['key_fingerprint']) {
|
if ($key['fingerprint'] !== $params['key_fingerprint']) {
|
||||||
yield $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionAbortKey', 'exchange_id' => $params['exchange_id']]]], ['datacenter' => $this->datacenter->curdc]);
|
yield $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionAbortKey', 'exchange_id' => $params['exchange_id']]]], ['datacenter' => $this->datacenter->curdc]);
|
||||||
|
|
||||||
throw new \danog\MadelineProto\SecurityException('Invalid key fingerprint!');
|
throw new \danog\MadelineProto\SecurityException('Invalid key fingerprint!');
|
||||||
}
|
}
|
||||||
yield $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionCommitKey', 'exchange_id' => $params['exchange_id'], 'key_fingerprint' => $key['fingerprint']]]], ['datacenter' => $this->datacenter->curdc]);
|
yield $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionCommitKey', 'exchange_id' => $params['exchange_id'], 'key_fingerprint' => $key['fingerprint']]]], ['datacenter' => $this->datacenter->curdc]);
|
||||||
@ -256,7 +240,6 @@ trait AuthKeyHandler
|
|||||||
$this->secret_chats[$chat]['updated'] = \time();
|
$this->secret_chats[$chat]['updated'] = \time();
|
||||||
$this->updaters[false]->resume();
|
$this->updaters[false]->resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Complete rekeying.
|
* Complete rekeying.
|
||||||
*
|
*
|
||||||
@ -272,10 +255,9 @@ trait AuthKeyHandler
|
|||||||
}
|
}
|
||||||
if ($this->temp_rekeyed_secret_chats[$params['exchange_id']]['fingerprint'] !== $params['key_fingerprint']) {
|
if ($this->temp_rekeyed_secret_chats[$params['exchange_id']]['fingerprint'] !== $params['key_fingerprint']) {
|
||||||
yield $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionAbortKey', 'exchange_id' => $params['exchange_id']]]], ['datacenter' => $this->datacenter->curdc]);
|
yield $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionAbortKey', 'exchange_id' => $params['exchange_id']]]], ['datacenter' => $this->datacenter->curdc]);
|
||||||
|
|
||||||
throw new \danog\MadelineProto\SecurityException('Invalid key fingerprint!');
|
throw new \danog\MadelineProto\SecurityException('Invalid key fingerprint!');
|
||||||
}
|
}
|
||||||
$this->logger->logger('Completing rekeying of secret chat '.$chat.'...', \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('Completing rekeying of secret chat ' . $chat . '...', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
$this->secret_chats[$chat]['rekeying'] = [0];
|
$this->secret_chats[$chat]['rekeying'] = [0];
|
||||||
$this->secret_chats[$chat]['old_key'] = $this->secret_chats[$chat]['key'];
|
$this->secret_chats[$chat]['old_key'] = $this->secret_chats[$chat]['key'];
|
||||||
$this->secret_chats[$chat]['key'] = $this->temp_rekeyed_secret_chats[$params['exchange_id']];
|
$this->secret_chats[$chat]['key'] = $this->temp_rekeyed_secret_chats[$params['exchange_id']];
|
||||||
@ -283,11 +265,9 @@ trait AuthKeyHandler
|
|||||||
$this->secret_chats[$chat]['updated'] = \time();
|
$this->secret_chats[$chat]['updated'] = \time();
|
||||||
unset($this->temp_rekeyed_secret_chats[$params['exchange_id']]);
|
unset($this->temp_rekeyed_secret_chats[$params['exchange_id']]);
|
||||||
yield $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionNoop']]], ['datacenter' => $this->datacenter->curdc]);
|
yield $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionNoop']]], ['datacenter' => $this->datacenter->curdc]);
|
||||||
$this->logger->logger('Secret chat '.$chat.' rekeyed successfully!', \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('Secret chat ' . $chat . ' rekeyed successfully!', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get secret chat status.
|
* Get secret chat status.
|
||||||
*
|
*
|
||||||
@ -303,10 +283,8 @@ trait AuthKeyHandler
|
|||||||
if (isset($this->temp_requested_secret_chats[$chat])) {
|
if (isset($this->temp_requested_secret_chats[$chat])) {
|
||||||
return MTProto::SECRET_REQUESTED;
|
return MTProto::SECRET_REQUESTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MTProto::SECRET_EMPTY;
|
return MTProto::SECRET_EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get secret chat.
|
* Get secret chat.
|
||||||
*
|
*
|
||||||
@ -318,7 +296,6 @@ trait AuthKeyHandler
|
|||||||
{
|
{
|
||||||
return $this->secret_chats[\is_array($chat) ? $chat['chat_id'] : $chat];
|
return $this->secret_chats[\is_array($chat) ? $chat['chat_id'] : $chat];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether secret chat exists.
|
* Check whether secret chat exists.
|
||||||
*
|
*
|
||||||
@ -330,7 +307,6 @@ trait AuthKeyHandler
|
|||||||
{
|
{
|
||||||
return isset($this->secret_chats[\is_array($chat) ? $chat['chat_id'] : $chat]);
|
return isset($this->secret_chats[\is_array($chat) ? $chat['chat_id'] : $chat]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Discard secret chat.
|
* Discard secret chat.
|
||||||
*
|
*
|
||||||
@ -340,15 +316,13 @@ trait AuthKeyHandler
|
|||||||
*/
|
*/
|
||||||
public function discardSecretChat(int $chat): \Generator
|
public function discardSecretChat(int $chat): \Generator
|
||||||
{
|
{
|
||||||
$this->logger->logger('Discarding secret chat '.$chat.'...', \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('Discarding secret chat ' . $chat . '...', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
if (isset($this->secret_chats[$chat])) {
|
if (isset($this->secret_chats[$chat])) {
|
||||||
unset($this->secret_chats[$chat]);
|
unset($this->secret_chats[$chat]);
|
||||||
}
|
}
|
||||||
if (isset($this->temp_requested_secret_chats[$chat])) {
|
if (isset($this->temp_requested_secret_chats[$chat])) {
|
||||||
unset($this->temp_requested_secret_chats[$chat]);
|
unset($this->temp_requested_secret_chats[$chat]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
yield $this->methodCallAsyncRead('messages.discardEncryption', ['chat_id' => $chat], ['datacenter' => $this->datacenter->curdc]);
|
yield $this->methodCallAsyncRead('messages.discardEncryption', ['chat_id' => $chat], ['datacenter' => $this->datacenter->curdc]);
|
||||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||||
|
@ -38,7 +38,6 @@ trait MessageHandler
|
|||||||
{
|
{
|
||||||
if (!isset($this->secret_chats[$chat_id])) {
|
if (!isset($this->secret_chats[$chat_id])) {
|
||||||
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['secret_chat_skipping'], $chat_id));
|
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['secret_chat_skipping'], $chat_id));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$message['random_id'] = \danog\MadelineProto\Tools::random(8);
|
$message['random_id'] = \danog\MadelineProto\Tools::random(8);
|
||||||
@ -52,30 +51,27 @@ trait MessageHandler
|
|||||||
}
|
}
|
||||||
$this->secret_chats[$chat_id]['outgoing'][$this->secret_chats[$chat_id]['out_seq_no']] = $message;
|
$this->secret_chats[$chat_id]['outgoing'][$this->secret_chats[$chat_id]['out_seq_no']] = $message;
|
||||||
$message = yield $this->TL->serializeObject(['type' => $constructor = $this->secret_chats[$chat_id]['layer'] === 8 ? 'DecryptedMessage' : 'DecryptedMessageLayer'], $message, $constructor, $this->secret_chats[$chat_id]['layer']);
|
$message = yield $this->TL->serializeObject(['type' => $constructor = $this->secret_chats[$chat_id]['layer'] === 8 ? 'DecryptedMessage' : 'DecryptedMessageLayer'], $message, $constructor, $this->secret_chats[$chat_id]['layer']);
|
||||||
$message = \danog\MadelineProto\Tools::packUnsignedInt(\strlen($message)).$message;
|
$message = \danog\MadelineProto\Tools::packUnsignedInt(\strlen($message)) . $message;
|
||||||
if ($this->secret_chats[$chat_id]['mtproto'] === 2) {
|
if ($this->secret_chats[$chat_id]['mtproto'] === 2) {
|
||||||
$padding = \danog\MadelineProto\Tools::posmod(-\strlen($message), 16);
|
$padding = \danog\MadelineProto\Tools::posmod(-\strlen($message), 16);
|
||||||
if ($padding < 12) {
|
if ($padding < 12) {
|
||||||
$padding += 16;
|
$padding += 16;
|
||||||
}
|
}
|
||||||
$message .= \danog\MadelineProto\Tools::random($padding);
|
$message .= \danog\MadelineProto\Tools::random($padding);
|
||||||
$message_key = \substr(\hash('sha256', \substr($this->secret_chats[$chat_id]['key']['auth_key'], 88 + ($this->secret_chats[$chat_id]['admin'] ? 0 : 8), 32).$message, true), 8, 16);
|
$message_key = \substr(\hash('sha256', \substr($this->secret_chats[$chat_id]['key']['auth_key'], 88 + ($this->secret_chats[$chat_id]['admin'] ? 0 : 8), 32) . $message, true), 8, 16);
|
||||||
list($aes_key, $aes_iv) = $this->aesCalculate($message_key, $this->secret_chats[$chat_id]['key']['auth_key'], $this->secret_chats[$chat_id]['admin']);
|
list($aes_key, $aes_iv) = $this->aesCalculate($message_key, $this->secret_chats[$chat_id]['key']['auth_key'], $this->secret_chats[$chat_id]['admin']);
|
||||||
} else {
|
} else {
|
||||||
$message_key = \substr(\sha1($message, true), -16);
|
$message_key = \substr(\sha1($message, true), -16);
|
||||||
list($aes_key, $aes_iv) = $this->oldAesCalculate($message_key, $this->secret_chats[$chat_id]['key']['auth_key'], true);
|
list($aes_key, $aes_iv) = $this->oldAesCalculate($message_key, $this->secret_chats[$chat_id]['key']['auth_key'], true);
|
||||||
$message .= \danog\MadelineProto\Tools::random(\danog\MadelineProto\Tools::posmod(-\strlen($message), 16));
|
$message .= \danog\MadelineProto\Tools::random(\danog\MadelineProto\Tools::posmod(-\strlen($message), 16));
|
||||||
}
|
}
|
||||||
$message = $this->secret_chats[$chat_id]['key']['fingerprint'].$message_key.$this->igeEncrypt($message, $aes_key, $aes_iv);
|
$message = $this->secret_chats[$chat_id]['key']['fingerprint'] . $message_key . $this->igeEncrypt($message, $aes_key, $aes_iv);
|
||||||
|
|
||||||
return $message;
|
return $message;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function handleEncryptedUpdate(array $message): \Generator
|
private function handleEncryptedUpdate(array $message): \Generator
|
||||||
{
|
{
|
||||||
if (!isset($this->secret_chats[$message['message']['chat_id']])) {
|
if (!isset($this->secret_chats[$message['message']['chat_id']])) {
|
||||||
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['secret_chat_skipping'], $message['message']['chat_id']));
|
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['secret_chat_skipping'], $message['message']['chat_id']));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$auth_key_id = \substr($message['message']['bytes'], 0, 8);
|
$auth_key_id = \substr($message['message']['bytes'], 0, 8);
|
||||||
@ -84,40 +80,36 @@ trait MessageHandler
|
|||||||
if (isset($this->secret_chats[$message['message']['chat_id']]['old_key']['fingerprint'])) {
|
if (isset($this->secret_chats[$message['message']['chat_id']]['old_key']['fingerprint'])) {
|
||||||
if ($auth_key_id !== $this->secret_chats[$message['message']['chat_id']]['old_key']['fingerprint']) {
|
if ($auth_key_id !== $this->secret_chats[$message['message']['chat_id']]['old_key']['fingerprint']) {
|
||||||
yield $this->discardSecretChat($message['message']['chat_id']);
|
yield $this->discardSecretChat($message['message']['chat_id']);
|
||||||
|
|
||||||
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['fingerprint_mismatch']);
|
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['fingerprint_mismatch']);
|
||||||
}
|
}
|
||||||
$old = true;
|
$old = true;
|
||||||
} else {
|
} else {
|
||||||
yield $this->discardSecretChat($message['message']['chat_id']);
|
yield $this->discardSecretChat($message['message']['chat_id']);
|
||||||
|
|
||||||
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['fingerprint_mismatch']);
|
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['fingerprint_mismatch']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$message_key = \substr($message['message']['bytes'], 8, 16);
|
$message_key = \substr($message['message']['bytes'], 8, 16);
|
||||||
$encrypted_data = \substr($message['message']['bytes'], 24);
|
$encrypted_data = \substr($message['message']['bytes'], 24);
|
||||||
if ($this->secret_chats[$message['message']['chat_id']]['mtproto'] === 2) {
|
if ($this->secret_chats[$message['message']['chat_id']]['mtproto'] === 2) {
|
||||||
$this->logger->logger('Trying MTProto v2 decryption for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('Trying MTProto v2 decryption for chat ' . $message['message']['chat_id'] . '...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$message_data = $this->tryMTProtoV2Decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data);
|
$message_data = $this->tryMTProtoV2Decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data);
|
||||||
$this->logger->logger('MTProto v2 decryption OK for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('MTProto v2 decryption OK for chat ' . $message['message']['chat_id'] . '...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
} catch (\danog\MadelineProto\SecurityException $e) {
|
} catch (\danog\MadelineProto\SecurityException $e) {
|
||||||
$this->logger->logger('MTProto v2 decryption failed with message '.$e->getMessage().', trying MTProto v1 decryption for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('MTProto v2 decryption failed with message ' . $e->getMessage() . ', trying MTProto v1 decryption for chat ' . $message['message']['chat_id'] . '...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
$message_data = $this->tryMTProtoV1Decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data);
|
$message_data = $this->tryMTProtoV1Decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data);
|
||||||
$this->logger->logger('MTProto v1 decryption OK for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('MTProto v1 decryption OK for chat ' . $message['message']['chat_id'] . '...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
$this->secret_chats[$message['message']['chat_id']]['mtproto'] = 1;
|
$this->secret_chats[$message['message']['chat_id']]['mtproto'] = 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$this->logger->logger('Trying MTProto v1 decryption for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('Trying MTProto v1 decryption for chat ' . $message['message']['chat_id'] . '...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$message_data = $this->tryMTProtoV1Decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data);
|
$message_data = $this->tryMTProtoV1Decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data);
|
||||||
$this->logger->logger('MTProto v1 decryption OK for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('MTProto v1 decryption OK for chat ' . $message['message']['chat_id'] . '...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
} catch (\danog\MadelineProto\SecurityException $e) {
|
} catch (\danog\MadelineProto\SecurityException $e) {
|
||||||
$this->logger->logger('MTProto v1 decryption failed with message '.$e->getMessage().', trying MTProto v2 decryption for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('MTProto v1 decryption failed with message ' . $e->getMessage() . ', trying MTProto v2 decryption for chat ' . $message['message']['chat_id'] . '...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
$message_data = $this->tryMTProtoV2Decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data);
|
$message_data = $this->tryMTProtoV2Decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data);
|
||||||
$this->logger->logger('MTProto v2 decryption OK for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('MTProto v2 decryption OK for chat ' . $message['message']['chat_id'] . '...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
$this->secret_chats[$message['message']['chat_id']]['mtproto'] = 2;
|
$this->secret_chats[$message['message']['chat_id']]['mtproto'] = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -131,7 +123,6 @@ trait MessageHandler
|
|||||||
$this->secret_chats[$message['message']['chat_id']]['incoming'][$this->secret_chats[$message['message']['chat_id']]['in_seq_no']] = $message['message'];
|
$this->secret_chats[$message['message']['chat_id']]['incoming'][$this->secret_chats[$message['message']['chat_id']]['in_seq_no']] = $message['message'];
|
||||||
yield $this->handleDecryptedUpdate($message);
|
yield $this->handleDecryptedUpdate($message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function tryMTProtoV1Decrypt($message_key, $chat_id, $old, $encrypted_data)
|
private function tryMTProtoV1Decrypt($message_key, $chat_id, $old, $encrypted_data)
|
||||||
{
|
{
|
||||||
list($aes_key, $aes_iv) = $this->oldAesCalculate($message_key, $this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], true);
|
list($aes_key, $aes_iv) = $this->oldAesCalculate($message_key, $this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], true);
|
||||||
@ -150,10 +141,8 @@ trait MessageHandler
|
|||||||
if (\strlen($decrypted_data) % 16 != 0) {
|
if (\strlen($decrypted_data) % 16 != 0) {
|
||||||
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['length_not_divisible_16']);
|
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['length_not_divisible_16']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $message_data;
|
return $message_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function tryMTProtoV2Decrypt($message_key, $chat_id, $old, $encrypted_data)
|
private function tryMTProtoV2Decrypt($message_key, $chat_id, $old, $encrypted_data)
|
||||||
{
|
{
|
||||||
list($aes_key, $aes_iv) = $this->aesCalculate($message_key, $this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], !$this->secret_chats[$chat_id]['admin']);
|
list($aes_key, $aes_iv) = $this->aesCalculate($message_key, $this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], !$this->secret_chats[$chat_id]['admin']);
|
||||||
@ -163,7 +152,7 @@ trait MessageHandler
|
|||||||
if ($message_data_length > \strlen($decrypted_data)) {
|
if ($message_data_length > \strlen($decrypted_data)) {
|
||||||
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_data_length_too_big']);
|
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_data_length_too_big']);
|
||||||
}
|
}
|
||||||
if ($message_key != \substr(\hash('sha256', \substr($this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], 88 + ($this->secret_chats[$chat_id]['admin'] ? 8 : 0), 32).$decrypted_data, true), 8, 16)) {
|
if ($message_key != \substr(\hash('sha256', \substr($this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], 88 + ($this->secret_chats[$chat_id]['admin'] ? 8 : 0), 32) . $decrypted_data, true), 8, 16)) {
|
||||||
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_key_mismatch']);
|
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_key_mismatch']);
|
||||||
}
|
}
|
||||||
if (\strlen($decrypted_data) - 4 - $message_data_length < 12) {
|
if (\strlen($decrypted_data) - 4 - $message_data_length < 12) {
|
||||||
@ -175,7 +164,6 @@ trait MessageHandler
|
|||||||
if (\strlen($decrypted_data) % 16 != 0) {
|
if (\strlen($decrypted_data) % 16 != 0) {
|
||||||
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['length_not_divisible_16']);
|
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['length_not_divisible_16']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $message_data;
|
return $message_data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ namespace danog\MadelineProto\SecretChats;
|
|||||||
*/
|
*/
|
||||||
trait ResponseHandler
|
trait ResponseHandler
|
||||||
{
|
{
|
||||||
private function handleDecryptedUpdate($update)
|
private function handleDecryptedUpdate($update): \Generator
|
||||||
{
|
{
|
||||||
/*if (isset($update['message']['decrypted_message']['random_bytes']) && strlen($update['message']['decrypted_message']['random_bytes']) < 15) {
|
/*if (isset($update['message']['decrypted_message']['random_bytes']) && strlen($update['message']['decrypted_message']['random_bytes']) < 15) {
|
||||||
throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['rand_bytes_too_short']);
|
throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['rand_bytes_too_short']);
|
||||||
@ -35,15 +35,12 @@ trait ResponseHandler
|
|||||||
switch ($update['message']['decrypted_message']['action']['_']) {
|
switch ($update['message']['decrypted_message']['action']['_']) {
|
||||||
case 'decryptedMessageActionRequestKey':
|
case 'decryptedMessageActionRequestKey':
|
||||||
yield $this->acceptRekey($update['message']['chat_id'], $update['message']['decrypted_message']['action']);
|
yield $this->acceptRekey($update['message']['chat_id'], $update['message']['decrypted_message']['action']);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
case 'decryptedMessageActionAcceptKey':
|
case 'decryptedMessageActionAcceptKey':
|
||||||
yield $this->commitRekey($update['message']['chat_id'], $update['message']['decrypted_message']['action']);
|
yield $this->commitRekey($update['message']['chat_id'], $update['message']['decrypted_message']['action']);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
case 'decryptedMessageActionCommitKey':
|
case 'decryptedMessageActionCommitKey':
|
||||||
yield $this->completeRekey($update['message']['chat_id'], $update['message']['decrypted_message']['action']);
|
yield $this->completeRekey($update['message']['chat_id'], $update['message']['decrypted_message']['action']);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
case 'decryptedMessageActionNotifyLayer':
|
case 'decryptedMessageActionNotifyLayer':
|
||||||
$this->secret_chats[$update['message']['chat_id']]['layer'] = $update['message']['decrypted_message']['action']['layer'];
|
$this->secret_chats[$update['message']['chat_id']]['layer'] = $update['message']['decrypted_message']['action']['layer'];
|
||||||
@ -53,13 +50,10 @@ trait ResponseHandler
|
|||||||
if ($update['message']['decrypted_message']['action']['layer'] >= 73) {
|
if ($update['message']['decrypted_message']['action']['layer'] >= 73) {
|
||||||
$this->secret_chats[$update['message']['chat_id']]['mtproto'] = 2;
|
$this->secret_chats[$update['message']['chat_id']]['mtproto'] = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
case 'decryptedMessageActionSetMessageTTL':
|
case 'decryptedMessageActionSetMessageTTL':
|
||||||
$this->secret_chats[$update['message']['chat_id']]['ttl'] = $update['message']['decrypted_message']['action']['ttl_seconds'];
|
$this->secret_chats[$update['message']['chat_id']]['ttl'] = $update['message']['decrypted_message']['action']['ttl_seconds'];
|
||||||
|
|
||||||
yield $this->saveUpdate($update);
|
yield $this->saveUpdate($update);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
case 'decryptedMessageActionNoop':
|
case 'decryptedMessageActionNoop':
|
||||||
return;
|
return;
|
||||||
@ -68,14 +62,13 @@ trait ResponseHandler
|
|||||||
$update['message']['decrypted_message']['action']['end_seq_no'] -= $this->secret_chats[$update['message']['chat_id']]['out_seq_no_x'];
|
$update['message']['decrypted_message']['action']['end_seq_no'] -= $this->secret_chats[$update['message']['chat_id']]['out_seq_no_x'];
|
||||||
$update['message']['decrypted_message']['action']['start_seq_no'] /= 2;
|
$update['message']['decrypted_message']['action']['start_seq_no'] /= 2;
|
||||||
$update['message']['decrypted_message']['action']['end_seq_no'] /= 2;
|
$update['message']['decrypted_message']['action']['end_seq_no'] /= 2;
|
||||||
$this->logger->logger('Resending messages for secret chat '.$update['message']['chat_id'], \danog\MadelineProto\Logger::WARNING);
|
$this->logger->logger('Resending messages for secret chat ' . $update['message']['chat_id'], \danog\MadelineProto\Logger::WARNING);
|
||||||
foreach ($this->secret_chats[$update['message']['chat_id']]['outgoing'] as $seq => $message) {
|
foreach ($this->secret_chats[$update['message']['chat_id']]['outgoing'] as $seq => $message) {
|
||||||
if ($seq >= $update['message']['decrypted_message']['action']['start_seq_no'] && $seq <= $update['message']['decrypted_message']['action']['end_seq_no']) {
|
if ($seq >= $update['message']['decrypted_message']['action']['start_seq_no'] && $seq <= $update['message']['decrypted_message']['action']['end_seq_no']) {
|
||||||
//throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['resending_unsupported']);
|
//throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['resending_unsupported']);
|
||||||
yield $this->methodCallAsyncRead('messages.sendEncrypted', ['peer' => $update['message']['chat_id'], 'message' => $update['message']['decrypted_message']], ['datacenter' => $this->datacenter->curdc]);
|
yield $this->methodCallAsyncRead('messages.sendEncrypted', ['peer' => $update['message']['chat_id'], 'message' => $update['message']['decrypted_message']], ['datacenter' => $this->datacenter->curdc]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
// yield $this->saveUpdate(['_' => 'updateNewDecryptedMessage', 'peer' => $this->secret_chats[$update['message']['chat_id']]['InputEncryptedChat'], 'in_seq_no' => $this->get_in_seq_no($update['message']['chat_id']), 'out_seq_no' => $this->get_out_seq_no($update['message']['chat_id']), 'message' => $update['message']['decrypted_message']]);
|
// yield $this->saveUpdate(['_' => 'updateNewDecryptedMessage', 'peer' => $this->secret_chats[$update['message']['chat_id']]['InputEncryptedChat'], 'in_seq_no' => $this->get_in_seq_no($update['message']['chat_id']), 'out_seq_no' => $this->get_out_seq_no($update['message']['chat_id']), 'message' => $update['message']['decrypted_message']]);
|
||||||
@ -95,11 +88,11 @@ trait ResponseHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$update['message']['decrypted_message'] = $update['message']['decrypted_message']['message'];
|
$update['message']['decrypted_message'] = $update['message']['decrypted_message']['message'];
|
||||||
yield $this->handleDecryptedUpdate($update);
|
yield from $this->handleDecryptedUpdate($update);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['unrecognized_dec_msg'].\var_export($update, true));
|
throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['unrecognized_dec_msg'] . \var_export($update, true));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ namespace danog\MadelineProto\SecretChats;
|
|||||||
*/
|
*/
|
||||||
trait SeqNoHandler
|
trait SeqNoHandler
|
||||||
{
|
{
|
||||||
private function checkSecretInSeqNo($chat_id, $seqno)
|
private function checkSecretInSeqNo($chat_id, $seqno): \Generator
|
||||||
{
|
{
|
||||||
$seqno = ($seqno - $this->secret_chats[$chat_id]['out_seq_no_x']) / 2;
|
$seqno = ($seqno - $this->secret_chats[$chat_id]['out_seq_no_x']) / 2;
|
||||||
$last = 0;
|
$last = 0;
|
||||||
@ -32,7 +32,6 @@ trait SeqNoHandler
|
|||||||
if (isset($message['decrypted_message']['in_seq_no'])) {
|
if (isset($message['decrypted_message']['in_seq_no'])) {
|
||||||
if (($message['decrypted_message']['in_seq_no'] - $this->secret_chats[$chat_id]['out_seq_no_x']) / 2 < $last) {
|
if (($message['decrypted_message']['in_seq_no'] - $this->secret_chats[$chat_id]['out_seq_no_x']) / 2 < $last) {
|
||||||
yield $this->discardSecretChat($chat_id);
|
yield $this->discardSecretChat($chat_id);
|
||||||
|
|
||||||
throw new \danog\MadelineProto\SecurityException('in_seq_no is not increasing');
|
throw new \danog\MadelineProto\SecurityException('in_seq_no is not increasing');
|
||||||
}
|
}
|
||||||
$last = ($message['decrypted_message']['in_seq_no'] - $this->secret_chats[$chat_id]['out_seq_no_x']) / 2;
|
$last = ($message['decrypted_message']['in_seq_no'] - $this->secret_chats[$chat_id]['out_seq_no_x']) / 2;
|
||||||
@ -40,14 +39,11 @@ trait SeqNoHandler
|
|||||||
}
|
}
|
||||||
if ($seqno > $this->secret_chats[$chat_id]['out_seq_no'] + 1) {
|
if ($seqno > $this->secret_chats[$chat_id]['out_seq_no'] + 1) {
|
||||||
yield $this->discardSecretChat($chat_id);
|
yield $this->discardSecretChat($chat_id);
|
||||||
|
|
||||||
throw new \danog\MadelineProto\SecurityException('in_seq_no is too big');
|
throw new \danog\MadelineProto\SecurityException('in_seq_no is too big');
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
private function checkSecretOutSeqNo($chat_id, $seqno): \Generator
|
||||||
private function checkSecretOutSeqNo($chat_id, $seqno)
|
|
||||||
{
|
{
|
||||||
$seqno = ($seqno - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2;
|
$seqno = ($seqno - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2;
|
||||||
$C = 0;
|
$C = 0;
|
||||||
@ -55,8 +51,7 @@ trait SeqNoHandler
|
|||||||
if (isset($message['decrypted_message']['out_seq_no']) && $C < $this->secret_chats[$chat_id]['in_seq_no']) {
|
if (isset($message['decrypted_message']['out_seq_no']) && $C < $this->secret_chats[$chat_id]['in_seq_no']) {
|
||||||
if (($message['decrypted_message']['out_seq_no'] - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2 !== $C) {
|
if (($message['decrypted_message']['out_seq_no'] - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2 !== $C) {
|
||||||
yield $this->discardSecretChat($chat_id);
|
yield $this->discardSecretChat($chat_id);
|
||||||
|
throw new \danog\MadelineProto\SecurityException('out_seq_no hole: should be ' . $C . ', is ' . ($message['decrypted_message']['out_seq_no'] - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2);
|
||||||
throw new \danog\MadelineProto\SecurityException('out_seq_no hole: should be '.$C.', is '.($message['decrypted_message']['out_seq_no'] - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2);
|
|
||||||
}
|
}
|
||||||
$C++;
|
$C++;
|
||||||
}
|
}
|
||||||
@ -64,25 +59,20 @@ trait SeqNoHandler
|
|||||||
//$this->logger->logger($C, $seqno);
|
//$this->logger->logger($C, $seqno);
|
||||||
if ($seqno < $C) {
|
if ($seqno < $C) {
|
||||||
// <= C
|
// <= C
|
||||||
$this->logger->logger('WARNING: dropping repeated message with seqno '.$seqno);
|
$this->logger->logger('WARNING: dropping repeated message with seqno ' . $seqno);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ($seqno > $C) {
|
if ($seqno > $C) {
|
||||||
// > C+1
|
// > C+1
|
||||||
yield $this->discardSecretChat($chat_id);
|
yield $this->discardSecretChat($chat_id);
|
||||||
|
throw new \danog\MadelineProto\SecurityException('WARNING: out_seq_no gap detected (' . $seqno . ' > ' . $C . ')!');
|
||||||
throw new \danog\MadelineProto\SecurityException('WARNING: out_seq_no gap detected ('.$seqno.' > '.$C.')!');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function generateSecretInSeqNo($chat)
|
private function generateSecretInSeqNo($chat)
|
||||||
{
|
{
|
||||||
return $this->secret_chats[$chat]['layer'] > 8 ? $this->secret_chats[$chat]['in_seq_no'] * 2 + $this->secret_chats[$chat]['in_seq_no_x'] : -1;
|
return $this->secret_chats[$chat]['layer'] > 8 ? $this->secret_chats[$chat]['in_seq_no'] * 2 + $this->secret_chats[$chat]['in_seq_no_x'] : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function generateSecretOutSeqNo($chat)
|
private function generateSecretOutSeqNo($chat)
|
||||||
{
|
{
|
||||||
return $this->secret_chats[$chat]['layer'] > 8 ? $this->secret_chats[$chat]['out_seq_no'] * 2 + $this->secret_chats[$chat]['out_seq_no_x'] : -1;
|
return $this->secret_chats[$chat]['layer'] > 8 ? $this->secret_chats[$chat]['out_seq_no'] * 2 + $this->secret_chats[$chat]['out_seq_no_x'] : -1;
|
||||||
|
@ -27,7 +27,6 @@ class Serialization
|
|||||||
public static function realpaths($file)
|
public static function realpaths($file)
|
||||||
{
|
{
|
||||||
$file = Absolute::absolute($file);
|
$file = Absolute::absolute($file);
|
||||||
|
return ['file' => $file, 'lockfile' => $file . '.lock', 'tempfile' => $file . '.temp.session'];
|
||||||
return ['file' => $file, 'lockfile' => $file.'.lock', 'tempfile' => $file.'.temp.session'];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,41 +27,34 @@ class Server
|
|||||||
private $settings;
|
private $settings;
|
||||||
private $pids = [];
|
private $pids = [];
|
||||||
private $mypid;
|
private $mypid;
|
||||||
|
|
||||||
public function __construct($settings)
|
public function __construct($settings)
|
||||||
{
|
{
|
||||||
\set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
|
\set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
|
||||||
\danog\MadelineProto\Logger::constructor(3);
|
\danog\MadelineProto\Logger::constructor(3);
|
||||||
|
|
||||||
if (!\extension_loaded('sockets')) {
|
if (!\extension_loaded('sockets')) {
|
||||||
throw new Exception(['extension', 'sockets']);
|
throw new Exception(['extension', 'sockets']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!\extension_loaded('pcntl')) {
|
if (!\extension_loaded('pcntl')) {
|
||||||
throw new Exception(['extension', 'pcntl']);
|
throw new Exception(['extension', 'pcntl']);
|
||||||
}
|
}
|
||||||
$this->settings = $settings;
|
$this->settings = $settings;
|
||||||
$this->mypid = \getmypid();
|
$this->mypid = \getmypid();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function start()
|
public function start()
|
||||||
{
|
{
|
||||||
\pcntl_signal(SIGTERM, [$this, 'sigHandler']);
|
\pcntl_signal(SIGTERM, [$this, 'sigHandler']);
|
||||||
\pcntl_signal(SIGINT, [$this, 'sigHandler']);
|
\pcntl_signal(SIGINT, [$this, 'sigHandler']);
|
||||||
\pcntl_signal(SIGCHLD, [$this, 'sigHandler']);
|
\pcntl_signal(SIGCHLD, [$this, 'sigHandler']);
|
||||||
|
|
||||||
$this->sock = new \Socket($this->settings['type'], SOCK_STREAM, $this->settings['protocol']);
|
$this->sock = new \Socket($this->settings['type'], SOCK_STREAM, $this->settings['protocol']);
|
||||||
$this->sock->bind($this->settings['address'], $this->settings['port']);
|
$this->sock->bind($this->settings['address'], $this->settings['port']);
|
||||||
$this->sock->listen();
|
$this->sock->listen();
|
||||||
$this->sock->setBlocking(true);
|
$this->sock->setBlocking(true);
|
||||||
|
|
||||||
$timeout = 2;
|
$timeout = 2;
|
||||||
$this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout);
|
$this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout);
|
||||||
$this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
|
$this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
|
||||||
\danog\MadelineProto\Logger::log('Server started! Listening on '.$this->settings['address'].':'.$this->settings['port']);
|
\danog\MadelineProto\Logger::log('Server started! Listening on ' . $this->settings['address'] . ':' . $this->settings['port']);
|
||||||
while (true) {
|
while (true) {
|
||||||
\pcntl_signal_dispatch();
|
\pcntl_signal_dispatch();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ($sock = $this->sock->accept()) {
|
if ($sock = $this->sock->accept()) {
|
||||||
$this->handle($sock);
|
$this->handle($sock);
|
||||||
@ -70,7 +63,6 @@ class Server
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function handle($socket)
|
private function handle($socket)
|
||||||
{
|
{
|
||||||
$pid = \pcntl_fork();
|
$pid = \pcntl_fork();
|
||||||
@ -83,29 +75,25 @@ class Server
|
|||||||
$handler->loop();
|
$handler->loop();
|
||||||
die;
|
die;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __destruct()
|
public function __destruct()
|
||||||
{
|
{
|
||||||
if ($this->mypid === \getmypid()) {
|
if ($this->mypid === \getmypid()) {
|
||||||
\danog\MadelineProto\Logger::log('Shutting main process '.$this->mypid.' down');
|
\danog\MadelineProto\Logger::log('Shutting main process ' . $this->mypid . ' down');
|
||||||
unset($this->sock);
|
unset($this->sock);
|
||||||
foreach ($this->pids as $pid) {
|
foreach ($this->pids as $pid) {
|
||||||
\danog\MadelineProto\Logger::log("Waiting for $pid");
|
\danog\MadelineProto\Logger::log("Waiting for {$pid}");
|
||||||
\pcntl_wait($pid);
|
\pcntl_wait($pid);
|
||||||
}
|
}
|
||||||
\danog\MadelineProto\Logger::log('Done, closing main process');
|
\danog\MadelineProto\Logger::log('Done, closing main process');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function sigHandler($sig)
|
public function sigHandler($sig)
|
||||||
{
|
{
|
||||||
switch ($sig) {
|
switch ($sig) {
|
||||||
case SIGTERM:
|
case SIGTERM:
|
||||||
case SIGINT:
|
case SIGINT:
|
||||||
exit();
|
exit;
|
||||||
|
|
||||||
case SIGCHLD:
|
case SIGCHLD:
|
||||||
\pcntl_waitpid(-1, $status);
|
\pcntl_waitpid(-1, $status);
|
||||||
break;
|
break;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shutdown module.
|
* Shutdown module.
|
||||||
*
|
*
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ADNL stream wrapper.
|
* ADNL stream wrapper.
|
||||||
*
|
*
|
||||||
@ -24,7 +25,6 @@ use danog\MadelineProto\Stream\Async\BufferedStream;
|
|||||||
use danog\MadelineProto\Stream\BufferedStreamInterface;
|
use danog\MadelineProto\Stream\BufferedStreamInterface;
|
||||||
use danog\MadelineProto\Stream\ConnectionContext;
|
use danog\MadelineProto\Stream\ConnectionContext;
|
||||||
use danog\MadelineProto\Stream\MTProtoBufferInterface;
|
use danog\MadelineProto\Stream\MTProtoBufferInterface;
|
||||||
|
|
||||||
use danog\MadelineProto\Stream\RawStreamInterface;
|
use danog\MadelineProto\Stream\RawStreamInterface;
|
||||||
use danog\MadelineProto\Tools;
|
use danog\MadelineProto\Tools;
|
||||||
|
|
||||||
@ -39,7 +39,6 @@ class ADNLStream implements BufferedStreamInterface, MTProtoBufferInterface
|
|||||||
{
|
{
|
||||||
use BufferedStream;
|
use BufferedStream;
|
||||||
private $stream;
|
private $stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to stream.
|
* Connect to stream.
|
||||||
*
|
*
|
||||||
@ -51,7 +50,6 @@ class ADNLStream implements BufferedStreamInterface, MTProtoBufferInterface
|
|||||||
{
|
{
|
||||||
$this->stream = yield $ctx->getStream($header);
|
$this->stream = yield $ctx->getStream($header);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Async close.
|
* Async close.
|
||||||
*
|
*
|
||||||
@ -61,7 +59,6 @@ class ADNLStream implements BufferedStreamInterface, MTProtoBufferInterface
|
|||||||
{
|
{
|
||||||
return $this->stream->disconnect();
|
return $this->stream->disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get write buffer asynchronously.
|
* Get write buffer asynchronously.
|
||||||
*
|
*
|
||||||
@ -77,10 +74,8 @@ class ADNLStream implements BufferedStreamInterface, MTProtoBufferInterface
|
|||||||
$this->stream->startWriteHash();
|
$this->stream->startWriteHash();
|
||||||
$this->stream->checkWriteHash($length - 32);
|
$this->stream->checkWriteHash($length - 32);
|
||||||
yield $buffer->bufferWrite(Tools::random(32));
|
yield $buffer->bufferWrite(Tools::random(32));
|
||||||
|
|
||||||
return $buffer;
|
return $buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get read buffer asynchronously.
|
* Get read buffer asynchronously.
|
||||||
*
|
*
|
||||||
@ -96,10 +91,8 @@ class ADNLStream implements BufferedStreamInterface, MTProtoBufferInterface
|
|||||||
$this->stream->checkReadHash($length);
|
$this->stream->checkReadHash($length);
|
||||||
yield $buffer->bufferRead(32);
|
yield $buffer->bufferRead(32);
|
||||||
$length -= 32;
|
$length -= 32;
|
||||||
|
|
||||||
return $buffer;
|
return $buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*
|
*
|
||||||
@ -118,8 +111,6 @@ class ADNLStream implements BufferedStreamInterface, MTProtoBufferInterface
|
|||||||
{
|
{
|
||||||
return $this->stream;
|
return $this->stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static function getName(): string
|
public static function getName(): string
|
||||||
{
|
{
|
||||||
return __CLASS__;
|
return __CLASS__;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Buffer helper trait.
|
* Buffer helper trait.
|
||||||
*
|
*
|
||||||
@ -33,7 +34,6 @@ trait Buffer
|
|||||||
{
|
{
|
||||||
return \danog\MadelineProto\Tools::call($this->bufferReadGenerator($length));
|
return \danog\MadelineProto\Tools::call($this->bufferReadGenerator($length));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function bufferWrite(string $data): Promise
|
public function bufferWrite(string $data): Promise
|
||||||
{
|
{
|
||||||
return \danog\MadelineProto\Tools::call($this->bufferWriteGenerator($data));
|
return \danog\MadelineProto\Tools::call($this->bufferWriteGenerator($data));
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Buffered stream helper trait.
|
* Buffered stream helper trait.
|
||||||
*
|
*
|
||||||
@ -30,7 +31,6 @@ use Amp\Promise;
|
|||||||
trait BufferedStream
|
trait BufferedStream
|
||||||
{
|
{
|
||||||
use Stream;
|
use Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get read buffer asynchronously.
|
* Get read buffer asynchronously.
|
||||||
*
|
*
|
||||||
@ -42,7 +42,6 @@ trait BufferedStream
|
|||||||
{
|
{
|
||||||
return \danog\MadelineProto\Tools::call($this->getReadBufferGenerator($length));
|
return \danog\MadelineProto\Tools::call($this->getReadBufferGenerator($length));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get write buffer asynchronously.
|
* Get write buffer asynchronously.
|
||||||
*
|
*
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Raw stream helper trait.
|
* Raw stream helper trait.
|
||||||
*
|
*
|
||||||
@ -30,17 +31,14 @@ use Amp\Promise;
|
|||||||
trait RawStream
|
trait RawStream
|
||||||
{
|
{
|
||||||
use Stream;
|
use Stream;
|
||||||
|
|
||||||
public function read(): Promise
|
public function read(): Promise
|
||||||
{
|
{
|
||||||
return \danog\MadelineProto\Tools::call($this->readGenerator());
|
return \danog\MadelineProto\Tools::call($this->readGenerator());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function write(string $data): Promise
|
public function write(string $data): Promise
|
||||||
{
|
{
|
||||||
return \danog\MadelineProto\Tools::call($this->writeGenerator($data));
|
return \danog\MadelineProto\Tools::call($this->writeGenerator($data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function end(string $finalData = ''): Promise
|
public function end(string $finalData = ''): Promise
|
||||||
{
|
{
|
||||||
return \danog\MadelineProto\Tools::call($this->endGenerator($finalData));
|
return \danog\MadelineProto\Tools::call($this->endGenerator($finalData));
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic stream helper trait.
|
* Generic stream helper trait.
|
||||||
*
|
*
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Buffer interface.
|
* Buffer interface.
|
||||||
*
|
*
|
||||||
@ -35,7 +36,6 @@ interface BufferInterface
|
|||||||
* @return Promise
|
* @return Promise
|
||||||
*/
|
*/
|
||||||
public function bufferRead(int $length): Promise;
|
public function bufferRead(int $length): Promise;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write data asynchronously.
|
* Write data asynchronously.
|
||||||
*
|
*
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Buffered proxy stream interface.
|
* Buffered proxy stream interface.
|
||||||
*
|
*
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Buffered stream interface.
|
* Buffered stream interface.
|
||||||
*
|
*
|
||||||
@ -35,7 +36,6 @@ interface BufferedStreamInterface extends StreamInterface
|
|||||||
* @return Promise
|
* @return Promise
|
||||||
*/
|
*/
|
||||||
public function getReadBuffer(&$length): Promise;
|
public function getReadBuffer(&$length): Promise;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get write buffer asynchronously.
|
* Get write buffer asynchronously.
|
||||||
*
|
*
|
||||||
@ -44,7 +44,6 @@ interface BufferedStreamInterface extends StreamInterface
|
|||||||
* @return Promise
|
* @return Promise
|
||||||
*/
|
*/
|
||||||
public function getWriteBuffer(int $length, string $append = ''): Promise;
|
public function getWriteBuffer(int $length, string $append = ''): Promise;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get stream name.
|
* Get stream name.
|
||||||
*
|
*
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Buffered raw stream.
|
* Buffered raw stream.
|
||||||
*
|
*
|
||||||
@ -36,14 +37,11 @@ use danog\MadelineProto\Stream\RawStreamInterface;
|
|||||||
class BufferedRawStream implements BufferedStreamInterface, BufferInterface, RawStreamInterface
|
class BufferedRawStream implements BufferedStreamInterface, BufferInterface, RawStreamInterface
|
||||||
{
|
{
|
||||||
use RawStream;
|
use RawStream;
|
||||||
|
|
||||||
const MAX_SIZE = 10 * 1024 * 1024;
|
const MAX_SIZE = 10 * 1024 * 1024;
|
||||||
|
|
||||||
protected $stream;
|
protected $stream;
|
||||||
protected $memory_stream;
|
protected $memory_stream;
|
||||||
private $append = '';
|
private $append = '';
|
||||||
private $append_after = 0;
|
private $append_after = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asynchronously connect to a TCP/TLS server.
|
* Asynchronously connect to a TCP/TLS server.
|
||||||
*
|
*
|
||||||
@ -55,10 +53,8 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw
|
|||||||
{
|
{
|
||||||
$this->stream = yield $ctx->getStream($header);
|
$this->stream = yield $ctx->getStream($header);
|
||||||
$this->memory_stream = \fopen('php://memory', 'r+');
|
$this->memory_stream = \fopen('php://memory', 'r+');
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Async chunked read.
|
* Async chunked read.
|
||||||
*
|
*
|
||||||
@ -71,7 +67,6 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw
|
|||||||
}
|
}
|
||||||
return $this->stream->read();
|
return $this->stream->read();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Async write.
|
* Async write.
|
||||||
*
|
*
|
||||||
@ -86,7 +81,6 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw
|
|||||||
}
|
}
|
||||||
return $this->stream->write($data);
|
return $this->stream->write($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Async close.
|
* Async close.
|
||||||
*
|
*
|
||||||
@ -103,7 +97,6 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw
|
|||||||
$this->stream = null;
|
$this->stream = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get read buffer asynchronously.
|
* Get read buffer asynchronously.
|
||||||
*
|
*
|
||||||
@ -128,10 +121,8 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw
|
|||||||
\fclose($this->memory_stream);
|
\fclose($this->memory_stream);
|
||||||
$this->memory_stream = $new_memory_stream;
|
$this->memory_stream = $new_memory_stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new \Amp\Success($this);
|
return new \Amp\Success($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get write buffer asynchronously.
|
* Get write buffer asynchronously.
|
||||||
*
|
*
|
||||||
@ -145,10 +136,8 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw
|
|||||||
$this->append = $append;
|
$this->append = $append;
|
||||||
$this->append_after = $length - \strlen($append);
|
$this->append_after = $length - \strlen($append);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new \Amp\Success($this);
|
return new \Amp\Success($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read data asynchronously.
|
* Read data asynchronously.
|
||||||
*
|
*
|
||||||
@ -169,7 +158,6 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw
|
|||||||
}
|
}
|
||||||
return \danog\MadelineProto\Tools::call($this->bufferReadGenerator($length));
|
return \danog\MadelineProto\Tools::call($this->bufferReadGenerator($length));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read data asynchronously.
|
* Read data asynchronously.
|
||||||
*
|
*
|
||||||
@ -185,22 +173,18 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw
|
|||||||
if ($buffer_length < $length && $buffer_length) {
|
if ($buffer_length < $length && $buffer_length) {
|
||||||
\fseek($this->memory_stream, $offset + $buffer_length);
|
\fseek($this->memory_stream, $offset + $buffer_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
while ($buffer_length < $length) {
|
while ($buffer_length < $length) {
|
||||||
$chunk = yield $this->read();
|
$chunk = yield $this->read();
|
||||||
if ($chunk === null) {
|
if ($chunk === null) {
|
||||||
$this->disconnect();
|
$this->disconnect();
|
||||||
|
|
||||||
throw new \danog\MadelineProto\NothingInTheSocketException();
|
throw new \danog\MadelineProto\NothingInTheSocketException();
|
||||||
}
|
}
|
||||||
\fwrite($this->memory_stream, $chunk);
|
\fwrite($this->memory_stream, $chunk);
|
||||||
$buffer_length += \strlen($chunk);
|
$buffer_length += \strlen($chunk);
|
||||||
}
|
}
|
||||||
\fseek($this->memory_stream, $offset);
|
\fseek($this->memory_stream, $offset);
|
||||||
|
|
||||||
return \fread($this->memory_stream, $length);
|
return \fread($this->memory_stream, $length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Async write.
|
* Async write.
|
||||||
*
|
*
|
||||||
@ -218,14 +202,11 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw
|
|||||||
} elseif ($this->append_after < 0) {
|
} elseif ($this->append_after < 0) {
|
||||||
$this->append_after = 0;
|
$this->append_after = 0;
|
||||||
$this->append = '';
|
$this->append = '';
|
||||||
|
|
||||||
throw new Exception('Tried to send too much out of frame data, cannot append');
|
throw new Exception('Tried to send too much out of frame data, cannot append');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->write($data);
|
return $this->write($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*
|
*
|
||||||
@ -244,7 +225,6 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw
|
|||||||
{
|
{
|
||||||
return $this->stream;
|
return $this->stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get class name.
|
* Get class name.
|
||||||
*
|
*
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AES CTR stream wrapper.
|
* AES CTR stream wrapper.
|
||||||
*
|
*
|
||||||
@ -26,7 +27,6 @@ use danog\MadelineProto\Stream\BufferedProxyStreamInterface;
|
|||||||
use danog\MadelineProto\Stream\BufferInterface;
|
use danog\MadelineProto\Stream\BufferInterface;
|
||||||
use danog\MadelineProto\Stream\ConnectionContext;
|
use danog\MadelineProto\Stream\ConnectionContext;
|
||||||
use danog\MadelineProto\Stream\RawStreamInterface;
|
use danog\MadelineProto\Stream\RawStreamInterface;
|
||||||
|
|
||||||
use tgseclib\Crypt\AES;
|
use tgseclib\Crypt\AES;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -48,7 +48,6 @@ class CtrStream implements BufferedProxyStreamInterface, BufferInterface
|
|||||||
private $extra;
|
private $extra;
|
||||||
private $append = '';
|
private $append = '';
|
||||||
private $append_after = 0;
|
private $append_after = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to stream.
|
* Connect to stream.
|
||||||
*
|
*
|
||||||
@ -62,15 +61,12 @@ class CtrStream implements BufferedProxyStreamInterface, BufferInterface
|
|||||||
$this->encrypt->enableContinuousBuffer();
|
$this->encrypt->enableContinuousBuffer();
|
||||||
$this->encrypt->setKey($this->extra['encrypt']['key']);
|
$this->encrypt->setKey($this->extra['encrypt']['key']);
|
||||||
$this->encrypt->setIV($this->extra['encrypt']['iv']);
|
$this->encrypt->setIV($this->extra['encrypt']['iv']);
|
||||||
|
|
||||||
$this->decrypt = new \tgseclib\Crypt\AES('ctr');
|
$this->decrypt = new \tgseclib\Crypt\AES('ctr');
|
||||||
$this->decrypt->enableContinuousBuffer();
|
$this->decrypt->enableContinuousBuffer();
|
||||||
$this->decrypt->setKey($this->extra['decrypt']['key']);
|
$this->decrypt->setKey($this->extra['decrypt']['key']);
|
||||||
$this->decrypt->setIV($this->extra['decrypt']['iv']);
|
$this->decrypt->setIV($this->extra['decrypt']['iv']);
|
||||||
|
|
||||||
$this->stream = yield $ctx->getStream($header);
|
$this->stream = yield $ctx->getStream($header);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Async close.
|
* Async close.
|
||||||
*
|
*
|
||||||
@ -80,7 +76,6 @@ class CtrStream implements BufferedProxyStreamInterface, BufferInterface
|
|||||||
{
|
{
|
||||||
return $this->stream->disconnect();
|
return $this->stream->disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get write buffer asynchronously.
|
* Get write buffer asynchronously.
|
||||||
*
|
*
|
||||||
@ -95,10 +90,8 @@ class CtrStream implements BufferedProxyStreamInterface, BufferInterface
|
|||||||
$this->append = $append;
|
$this->append = $append;
|
||||||
$this->append_after = $length - \strlen($append);
|
$this->append_after = $length - \strlen($append);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get read buffer asynchronously.
|
* Get read buffer asynchronously.
|
||||||
*
|
*
|
||||||
@ -109,10 +102,8 @@ class CtrStream implements BufferedProxyStreamInterface, BufferInterface
|
|||||||
public function getReadBufferGenerator(&$length): \Generator
|
public function getReadBufferGenerator(&$length): \Generator
|
||||||
{
|
{
|
||||||
$this->read_buffer = yield $this->stream->getReadBuffer($length);
|
$this->read_buffer = yield $this->stream->getReadBuffer($length);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrypts read data asynchronously.
|
* Decrypts read data asynchronously.
|
||||||
*
|
*
|
||||||
@ -126,7 +117,6 @@ class CtrStream implements BufferedProxyStreamInterface, BufferInterface
|
|||||||
{
|
{
|
||||||
return @$this->decrypt->encrypt(yield $this->read_buffer->bufferRead($length));
|
return @$this->decrypt->encrypt(yield $this->read_buffer->bufferRead($length));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes data to the stream.
|
* Writes data to the stream.
|
||||||
*
|
*
|
||||||
@ -146,14 +136,11 @@ class CtrStream implements BufferedProxyStreamInterface, BufferInterface
|
|||||||
} elseif ($this->append_after < 0) {
|
} elseif ($this->append_after < 0) {
|
||||||
$this->append_after = 0;
|
$this->append_after = 0;
|
||||||
$this->append = '';
|
$this->append = '';
|
||||||
|
|
||||||
throw new \danog\MadelineProto\Exception('Tried to send too much out of frame data, cannot append');
|
throw new \danog\MadelineProto\Exception('Tried to send too much out of frame data, cannot append');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->write_buffer->bufferWrite(@$this->encrypt->encrypt($data));
|
return $this->write_buffer->bufferWrite(@$this->encrypt->encrypt($data));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set obfuscation keys/IVs.
|
* Set obfuscation keys/IVs.
|
||||||
*
|
*
|
||||||
@ -165,7 +152,6 @@ class CtrStream implements BufferedProxyStreamInterface, BufferInterface
|
|||||||
{
|
{
|
||||||
$this->extra = $data;
|
$this->extra = $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*
|
*
|
||||||
@ -175,7 +161,6 @@ class CtrStream implements BufferedProxyStreamInterface, BufferInterface
|
|||||||
{
|
{
|
||||||
return $this->stream->getSocket();
|
return $this->stream->getSocket();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
@ -193,7 +178,6 @@ class CtrStream implements BufferedProxyStreamInterface, BufferInterface
|
|||||||
{
|
{
|
||||||
return $this->decrypt;
|
return $this->decrypt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getName(): string
|
public static function getName(): string
|
||||||
{
|
{
|
||||||
return __CLASS__;
|
return __CLASS__;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hash stream wrapper.
|
* Hash stream wrapper.
|
||||||
*
|
*
|
||||||
@ -23,7 +24,6 @@ use danog\MadelineProto\Stream\Async\BufferedStream;
|
|||||||
use danog\MadelineProto\Stream\BufferedProxyStreamInterface;
|
use danog\MadelineProto\Stream\BufferedProxyStreamInterface;
|
||||||
use danog\MadelineProto\Stream\BufferInterface;
|
use danog\MadelineProto\Stream\BufferInterface;
|
||||||
use danog\MadelineProto\Stream\ConnectionContext;
|
use danog\MadelineProto\Stream\ConnectionContext;
|
||||||
|
|
||||||
use danog\MadelineProto\Stream\RawStreamInterface;
|
use danog\MadelineProto\Stream\RawStreamInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -45,7 +45,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
private $read_check_pos = 0;
|
private $read_check_pos = 0;
|
||||||
private $stream;
|
private $stream;
|
||||||
private $rev = false;
|
private $rev = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable read hashing.
|
* Enable read hashing.
|
||||||
*
|
*
|
||||||
@ -55,7 +54,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
{
|
{
|
||||||
$this->read_hash = \hash_init($this->hash_name);
|
$this->read_hash = \hash_init($this->hash_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check the read hash after N bytes are read.
|
* Check the read hash after N bytes are read.
|
||||||
*
|
*
|
||||||
@ -67,7 +65,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
{
|
{
|
||||||
$this->read_check_after = $after;
|
$this->read_check_after = $after;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop read hashing and get final hash.
|
* Stop read hashing and get final hash.
|
||||||
*
|
*
|
||||||
@ -82,10 +79,8 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
$this->read_hash = null;
|
$this->read_hash = null;
|
||||||
$this->read_check_after = 0;
|
$this->read_check_after = 0;
|
||||||
$this->read_check_pos = 0;
|
$this->read_check_pos = 0;
|
||||||
|
|
||||||
return $hash;
|
return $hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if we are read hashing.
|
* Check if we are read hashing.
|
||||||
*
|
*
|
||||||
@ -95,7 +90,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
{
|
{
|
||||||
return $this->read_hash !== null;
|
return $this->read_hash !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable write hashing.
|
* Enable write hashing.
|
||||||
*
|
*
|
||||||
@ -105,7 +99,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
{
|
{
|
||||||
$this->write_hash = \hash_init($this->hash_name);
|
$this->write_hash = \hash_init($this->hash_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write the write hash after N bytes are read.
|
* Write the write hash after N bytes are read.
|
||||||
*
|
*
|
||||||
@ -117,7 +110,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
{
|
{
|
||||||
$this->write_check_after = $after;
|
$this->write_check_after = $after;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop write hashing and get final hash.
|
* Stop write hashing and get final hash.
|
||||||
*
|
*
|
||||||
@ -132,10 +124,8 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
$this->write_hash = null;
|
$this->write_hash = null;
|
||||||
$this->write_check_after = 0;
|
$this->write_check_after = 0;
|
||||||
$this->write_check_pos = 0;
|
$this->write_check_pos = 0;
|
||||||
|
|
||||||
return $hash;
|
return $hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if we are write hashing.
|
* Check if we are write hashing.
|
||||||
*
|
*
|
||||||
@ -145,7 +135,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
{
|
{
|
||||||
return $this->write_hash !== null;
|
return $this->write_hash !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hashes read data asynchronously.
|
* Hashes read data asynchronously.
|
||||||
*
|
*
|
||||||
@ -167,7 +156,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
if ($hash !== yield $this->read_buffer->bufferRead(\strlen($hash))) {
|
if ($hash !== yield $this->read_buffer->bufferRead(\strlen($hash))) {
|
||||||
throw new \danog\MadelineProto\Exception('Hash mismatch');
|
throw new \danog\MadelineProto\Exception('Hash mismatch');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
$data = yield $this->read_buffer->bufferRead($length);
|
$data = yield $this->read_buffer->bufferRead($length);
|
||||||
@ -175,10 +163,8 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
if ($this->read_check_after) {
|
if ($this->read_check_after) {
|
||||||
$this->read_check_pos += $length;
|
$this->read_check_pos += $length;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the hash algorithm.
|
* Set the hash algorithm.
|
||||||
*
|
*
|
||||||
@ -196,7 +182,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
}
|
}
|
||||||
$this->hash_name = $hash;
|
$this->hash_name = $hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to stream.
|
* Connect to stream.
|
||||||
*
|
*
|
||||||
@ -212,10 +197,8 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
$this->read_hash = null;
|
$this->read_hash = null;
|
||||||
$this->read_check_after = 0;
|
$this->read_check_after = 0;
|
||||||
$this->read_check_pos = 0;
|
$this->read_check_pos = 0;
|
||||||
|
|
||||||
$this->stream = yield $ctx->getStream($header);
|
$this->stream = yield $ctx->getStream($header);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Async close.
|
* Async close.
|
||||||
*
|
*
|
||||||
@ -225,7 +208,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
{
|
{
|
||||||
return $this->stream->disconnect();
|
return $this->stream->disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get read buffer asynchronously.
|
* Get read buffer asynchronously.
|
||||||
*
|
*
|
||||||
@ -237,13 +219,10 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
{
|
{
|
||||||
//if ($this->read_hash) {
|
//if ($this->read_hash) {
|
||||||
$this->read_buffer = yield $this->stream->getReadBuffer($length);
|
$this->read_buffer = yield $this->stream->getReadBuffer($length);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//return yield $this->stream->getReadBuffer($length);
|
//return yield $this->stream->getReadBuffer($length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get write buffer asynchronously.
|
* Get write buffer asynchronously.
|
||||||
*
|
*
|
||||||
@ -255,13 +234,10 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
{
|
{
|
||||||
//if ($this->write_hash) {
|
//if ($this->write_hash) {
|
||||||
$this->write_buffer = yield $this->stream->getWriteBuffer($length, $append);
|
$this->write_buffer = yield $this->stream->getWriteBuffer($length, $append);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//return yield $this->stream->getWriteBuffer($length, $append);
|
//return yield $this->stream->getWriteBuffer($length, $append);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads data from the stream.
|
* Reads data from the stream.
|
||||||
*
|
*
|
||||||
@ -274,10 +250,8 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
if ($this->read_hash === null) {
|
if ($this->read_hash === null) {
|
||||||
return $this->read_buffer->bufferRead($length);
|
return $this->read_buffer->bufferRead($length);
|
||||||
}
|
}
|
||||||
|
|
||||||
return \danog\MadelineProto\Tools::call($this->bufferReadGenerator($length));
|
return \danog\MadelineProto\Tools::call($this->bufferReadGenerator($length));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes data to the stream.
|
* Writes data to the stream.
|
||||||
*
|
*
|
||||||
@ -292,15 +266,13 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
if ($this->write_hash === null) {
|
if ($this->write_hash === null) {
|
||||||
return $this->write_buffer->bufferWrite($data);
|
return $this->write_buffer->bufferWrite($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
$length = \strlen($data);
|
$length = \strlen($data);
|
||||||
if ($this->write_check_after && $length + $this->write_check_pos >= $this->write_check_after) {
|
if ($this->write_check_after && $length + $this->write_check_pos >= $this->write_check_after) {
|
||||||
if ($length + $this->write_check_pos > $this->write_check_after) {
|
if ($length + $this->write_check_pos > $this->write_check_after) {
|
||||||
throw new \danog\MadelineProto\Exception('Too much out of frame data was sent, cannot check hash');
|
throw new \danog\MadelineProto\Exception('Too much out of frame data was sent, cannot check hash');
|
||||||
}
|
}
|
||||||
\hash_update($this->write_hash, $data);
|
\hash_update($this->write_hash, $data);
|
||||||
|
return $this->write_buffer->bufferWrite($data . $this->getWriteHash());
|
||||||
return $this->write_buffer->bufferWrite($data.$this->getWriteHash());
|
|
||||||
}
|
}
|
||||||
if ($this->write_check_after) {
|
if ($this->write_check_after) {
|
||||||
$this->write_check_pos += $length;
|
$this->write_check_pos += $length;
|
||||||
@ -308,10 +280,8 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
if ($this->write_hash) {
|
if ($this->write_hash) {
|
||||||
\hash_update($this->write_hash, $data);
|
\hash_update($this->write_hash, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->write_buffer->bufferWrite($data);
|
return $this->write_buffer->bufferWrite($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*
|
*
|
||||||
@ -321,7 +291,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
{
|
{
|
||||||
return $this->stream->getSocket();
|
return $this->stream->getSocket();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Buffered raw stream.
|
* Buffered raw stream.
|
||||||
*
|
*
|
||||||
@ -44,7 +45,6 @@ class SimpleBufferedRawStream extends BufferedRawStream implements BufferedStrea
|
|||||||
if ($buffer_length < $length && $buffer_length) {
|
if ($buffer_length < $length && $buffer_length) {
|
||||||
\fseek($this->memory_stream, $offset + $buffer_length);
|
\fseek($this->memory_stream, $offset + $buffer_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
while ($buffer_length < $length) {
|
while ($buffer_length < $length) {
|
||||||
$chunk = yield $this->read();
|
$chunk = yield $this->read();
|
||||||
if ($chunk === null) {
|
if ($chunk === null) {
|
||||||
@ -55,7 +55,6 @@ class SimpleBufferedRawStream extends BufferedRawStream implements BufferedStrea
|
|||||||
$buffer_length += \strlen($chunk);
|
$buffer_length += \strlen($chunk);
|
||||||
}
|
}
|
||||||
\fseek($this->memory_stream, $offset);
|
\fseek($this->memory_stream, $offset);
|
||||||
|
|
||||||
return \fread($this->memory_stream, $length);
|
return \fread($this->memory_stream, $length);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -67,7 +66,6 @@ class SimpleBufferedRawStream extends BufferedRawStream implements BufferedStrea
|
|||||||
{
|
{
|
||||||
return $this->stream;
|
return $this->stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get class name.
|
* Get class name.
|
||||||
*
|
*
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connection context.
|
* Connection context.
|
||||||
*
|
*
|
||||||
@ -107,14 +108,12 @@ class ConnectionContext
|
|||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
private $key = 0;
|
private $key = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read callback.
|
* Read callback.
|
||||||
*
|
*
|
||||||
* @var callable
|
* @var callable
|
||||||
*/
|
*/
|
||||||
private $readCallback;
|
private $readCallback;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the socket context.
|
* Set the socket context.
|
||||||
*
|
*
|
||||||
@ -125,10 +124,8 @@ class ConnectionContext
|
|||||||
public function setSocketContext(ConnectContext $socketContext): self
|
public function setSocketContext(ConnectContext $socketContext): self
|
||||||
{
|
{
|
||||||
$this->socketContext = $socketContext;
|
$this->socketContext = $socketContext;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the socket context.
|
* Get the socket context.
|
||||||
*
|
*
|
||||||
@ -138,7 +135,6 @@ class ConnectionContext
|
|||||||
{
|
{
|
||||||
return $this->socketContext;
|
return $this->socketContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the connection URI.
|
* Set the connection URI.
|
||||||
*
|
*
|
||||||
@ -149,10 +145,8 @@ class ConnectionContext
|
|||||||
public function setUri($uri): self
|
public function setUri($uri): self
|
||||||
{
|
{
|
||||||
$this->uri = $uri instanceof Uri ? $uri : new Uri($uri);
|
$this->uri = $uri instanceof Uri ? $uri : new Uri($uri);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the URI as a string.
|
* Get the URI as a string.
|
||||||
*
|
*
|
||||||
@ -162,7 +156,6 @@ class ConnectionContext
|
|||||||
{
|
{
|
||||||
return (string) $this->uri;
|
return (string) $this->uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the URI.
|
* Get the URI.
|
||||||
*
|
*
|
||||||
@ -172,7 +165,6 @@ class ConnectionContext
|
|||||||
{
|
{
|
||||||
return $this->uri;
|
return $this->uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the cancellation token.
|
* Set the cancellation token.
|
||||||
*
|
*
|
||||||
@ -183,10 +175,8 @@ class ConnectionContext
|
|||||||
public function setCancellationToken($cancellationToken): self
|
public function setCancellationToken($cancellationToken): self
|
||||||
{
|
{
|
||||||
$this->cancellationToken = $cancellationToken;
|
$this->cancellationToken = $cancellationToken;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the cancellation token.
|
* Get the cancellation token.
|
||||||
*
|
*
|
||||||
@ -215,10 +205,8 @@ class ConnectionContext
|
|||||||
public function setTest(bool $test): self
|
public function setTest(bool $test): self
|
||||||
{
|
{
|
||||||
$this->test = $test;
|
$this->test = $test;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this is a test connection.
|
* Whether this is a test connection.
|
||||||
*
|
*
|
||||||
@ -237,7 +225,6 @@ class ConnectionContext
|
|||||||
{
|
{
|
||||||
return $this->media;
|
return $this->media;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this is a CDN connection.
|
* Whether this is a CDN connection.
|
||||||
*
|
*
|
||||||
@ -247,7 +234,6 @@ class ConnectionContext
|
|||||||
{
|
{
|
||||||
return $this->cdn;
|
return $this->cdn;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this connection context will only be used by the DNS client.
|
* Whether this connection context will only be used by the DNS client.
|
||||||
*
|
*
|
||||||
@ -257,7 +243,6 @@ class ConnectionContext
|
|||||||
{
|
{
|
||||||
return $this->isDns;
|
return $this->isDns;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this connection context will only be used by the DNS client.
|
* Whether this connection context will only be used by the DNS client.
|
||||||
*
|
*
|
||||||
@ -279,10 +264,8 @@ class ConnectionContext
|
|||||||
public function secure(bool $secure): self
|
public function secure(bool $secure): self
|
||||||
{
|
{
|
||||||
$this->secure = $secure;
|
$this->secure = $secure;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to use TLS with socket connections.
|
* Whether to use TLS with socket connections.
|
||||||
*
|
*
|
||||||
@ -292,7 +275,6 @@ class ConnectionContext
|
|||||||
{
|
{
|
||||||
return $this->secure;
|
return $this->secure;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the DC ID.
|
* Set the DC ID.
|
||||||
*
|
*
|
||||||
@ -304,15 +286,13 @@ class ConnectionContext
|
|||||||
{
|
{
|
||||||
$int = \intval($dc);
|
$int = \intval($dc);
|
||||||
if (!(1 <= $int && $int <= 1000)) {
|
if (!(1 <= $int && $int <= 1000)) {
|
||||||
throw new Exception("Invalid DC id provided: $dc");
|
throw new Exception("Invalid DC id provided: {$dc}");
|
||||||
}
|
}
|
||||||
$this->dc = $dc;
|
$this->dc = $dc;
|
||||||
$this->media = \strpos($dc, '_media') !== false;
|
$this->media = \strpos($dc, '_media') !== false;
|
||||||
$this->cdn = \strpos($dc, '_cdn') !== false;
|
$this->cdn = \strpos($dc, '_cdn') !== false;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the DC ID.
|
* Get the DC ID.
|
||||||
*
|
*
|
||||||
@ -322,7 +302,6 @@ class ConnectionContext
|
|||||||
{
|
{
|
||||||
return $this->dc;
|
return $this->dc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the int DC ID.
|
* Get the int DC ID.
|
||||||
*
|
*
|
||||||
@ -337,10 +316,8 @@ class ConnectionContext
|
|||||||
if ($this->media) {
|
if ($this->media) {
|
||||||
$dc = -$dc;
|
$dc = -$dc;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $dc;
|
return $dc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to use ipv6.
|
* Whether to use ipv6.
|
||||||
*
|
*
|
||||||
@ -351,10 +328,8 @@ class ConnectionContext
|
|||||||
public function setIpv6(bool $ipv6): self
|
public function setIpv6(bool $ipv6): self
|
||||||
{
|
{
|
||||||
$this->ipv6 = $ipv6;
|
$this->ipv6 = $ipv6;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to use ipv6.
|
* Whether to use ipv6.
|
||||||
*
|
*
|
||||||
@ -364,7 +339,6 @@ class ConnectionContext
|
|||||||
{
|
{
|
||||||
return $this->ipv6;
|
return $this->ipv6;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a stream to the stream chain.
|
* Add a stream to the stream chain.
|
||||||
*
|
*
|
||||||
@ -377,10 +351,8 @@ class ConnectionContext
|
|||||||
{
|
{
|
||||||
$this->nextStreams[] = [$streamName, $extra];
|
$this->nextStreams[] = [$streamName, $extra];
|
||||||
$this->key = \count($this->nextStreams) - 1;
|
$this->key = \count($this->nextStreams) - 1;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set read callback, called every time the socket reads at least a byte.
|
* Set read callback, called every time the socket reads at least a byte.
|
||||||
*
|
*
|
||||||
@ -392,7 +364,6 @@ class ConnectionContext
|
|||||||
{
|
{
|
||||||
$this->readCallback = $callable;
|
$this->readCallback = $callable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a read callback is present.
|
* Check if a read callback is present.
|
||||||
*
|
*
|
||||||
@ -402,7 +373,6 @@ class ConnectionContext
|
|||||||
{
|
{
|
||||||
return $this->readCallback !== null;
|
return $this->readCallback !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get read callback.
|
* Get read callback.
|
||||||
*
|
*
|
||||||
@ -412,7 +382,6 @@ class ConnectionContext
|
|||||||
{
|
{
|
||||||
return $this->readCallback;
|
return $this->readCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current stream name from the stream chain.
|
* Get the current stream name from the stream chain.
|
||||||
*
|
*
|
||||||
@ -422,7 +391,6 @@ class ConnectionContext
|
|||||||
{
|
{
|
||||||
return $this->nextStreams[$this->key][0];
|
return $this->nextStreams[$this->key][0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if has stream within stream chain.
|
* Check if has stream within stream chain.
|
||||||
*
|
*
|
||||||
@ -439,7 +407,6 @@ class ConnectionContext
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a stream from the stream chain.
|
* Get a stream from the stream chain.
|
||||||
*
|
*
|
||||||
@ -455,11 +422,8 @@ class ConnectionContext
|
|||||||
$obj->setExtra($extra);
|
$obj->setExtra($extra);
|
||||||
}
|
}
|
||||||
yield $obj->connect($this, $buffer);
|
yield $obj->connect($this, $buffer);
|
||||||
|
|
||||||
return $obj;
|
return $obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the inputClientProxy proxy MTProto object.
|
* Get the inputClientProxy proxy MTProto object.
|
||||||
*
|
*
|
||||||
@ -499,13 +463,11 @@ class ConnectionContext
|
|||||||
}
|
}
|
||||||
$string .= \preg_replace('/.*\\\\/', '', $stream[0]);
|
$string .= \preg_replace('/.*\\\\/', '', $stream[0]);
|
||||||
if ($stream[1] && $stream[0] !== DefaultStream::getName()) {
|
if ($stream[1] && $stream[0] !== DefaultStream::getName()) {
|
||||||
$string .= ' ('.\json_encode($stream[1]).')';
|
$string .= ' (' . \json_encode($stream[1]) . ')';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $string;
|
return $string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a representation of the context.
|
* Returns a representation of the context.
|
||||||
*
|
*
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MTProto buffer interface.
|
* MTProto buffer interface.
|
||||||
*
|
*
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abridged stream wrapper.
|
* Abridged stream wrapper.
|
||||||
*
|
*
|
||||||
@ -34,9 +35,7 @@ use danog\MadelineProto\Stream\RawStreamInterface;
|
|||||||
class AbridgedStream implements BufferedStreamInterface, MTProtoBufferInterface
|
class AbridgedStream implements BufferedStreamInterface, MTProtoBufferInterface
|
||||||
{
|
{
|
||||||
use BufferedStream;
|
use BufferedStream;
|
||||||
|
|
||||||
private $stream;
|
private $stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to stream.
|
* Connect to stream.
|
||||||
*
|
*
|
||||||
@ -46,9 +45,8 @@ class AbridgedStream implements BufferedStreamInterface, MTProtoBufferInterface
|
|||||||
*/
|
*/
|
||||||
public function connectGenerator(ConnectionContext $ctx, string $header = ''): \Generator
|
public function connectGenerator(ConnectionContext $ctx, string $header = ''): \Generator
|
||||||
{
|
{
|
||||||
$this->stream = yield $ctx->getStream(\chr(239).$header);
|
$this->stream = yield $ctx->getStream(\chr(239) . $header);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Async close.
|
* Async close.
|
||||||
*
|
*
|
||||||
@ -58,7 +56,6 @@ class AbridgedStream implements BufferedStreamInterface, MTProtoBufferInterface
|
|||||||
{
|
{
|
||||||
return $this->stream->disconnect();
|
return $this->stream->disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get write buffer asynchronously.
|
* Get write buffer asynchronously.
|
||||||
*
|
*
|
||||||
@ -72,14 +69,12 @@ class AbridgedStream implements BufferedStreamInterface, MTProtoBufferInterface
|
|||||||
if ($length < 127) {
|
if ($length < 127) {
|
||||||
$message = \chr($length);
|
$message = \chr($length);
|
||||||
} else {
|
} else {
|
||||||
$message = \chr(127).\substr(\pack('V', $length), 0, 3);
|
$message = \chr(127) . \substr(\pack('V', $length), 0, 3);
|
||||||
}
|
}
|
||||||
$buffer = yield $this->stream->getWriteBuffer(\strlen($message) + $length, $append);
|
$buffer = yield $this->stream->getWriteBuffer(\strlen($message) + $length, $append);
|
||||||
yield $buffer->bufferWrite($message);
|
yield $buffer->bufferWrite($message);
|
||||||
|
|
||||||
return $buffer;
|
return $buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get read buffer asynchronously.
|
* Get read buffer asynchronously.
|
||||||
*
|
*
|
||||||
@ -92,13 +87,11 @@ class AbridgedStream implements BufferedStreamInterface, MTProtoBufferInterface
|
|||||||
$buffer = yield $this->stream->getReadBuffer($l);
|
$buffer = yield $this->stream->getReadBuffer($l);
|
||||||
$length = \ord(yield $buffer->bufferRead(1));
|
$length = \ord(yield $buffer->bufferRead(1));
|
||||||
if ($length >= 127) {
|
if ($length >= 127) {
|
||||||
$length = \unpack('V', (yield $buffer->bufferRead(3))."\0")[1];
|
$length = \unpack('V', yield $buffer->bufferRead(3) . "\0")[1];
|
||||||
}
|
}
|
||||||
$length <<= 2;
|
$length <<= 2;
|
||||||
|
|
||||||
return $buffer;
|
return $buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*
|
*
|
||||||
@ -108,7 +101,6 @@ class AbridgedStream implements BufferedStreamInterface, MTProtoBufferInterface
|
|||||||
{
|
{
|
||||||
return $this->stream->getSocket();
|
return $this->stream->getSocket();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TCP full stream wrapper.
|
* TCP full stream wrapper.
|
||||||
*
|
*
|
||||||
@ -40,7 +41,6 @@ class FullStream implements BufferedStreamInterface, MTProtoBufferInterface
|
|||||||
private $stream;
|
private $stream;
|
||||||
private $in_seq_no = -1;
|
private $in_seq_no = -1;
|
||||||
private $out_seq_no = -1;
|
private $out_seq_no = -1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stream to use as data source.
|
* Stream to use as data source.
|
||||||
*
|
*
|
||||||
@ -54,10 +54,8 @@ class FullStream implements BufferedStreamInterface, MTProtoBufferInterface
|
|||||||
$this->out_seq_no = -1;
|
$this->out_seq_no = -1;
|
||||||
$this->stream = new HashedBufferedStream();
|
$this->stream = new HashedBufferedStream();
|
||||||
$this->stream->setExtra('crc32b_rev');
|
$this->stream->setExtra('crc32b_rev');
|
||||||
|
|
||||||
return $this->stream->connect($ctx, $header);
|
return $this->stream->connect($ctx, $header);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Async close.
|
* Async close.
|
||||||
*
|
*
|
||||||
@ -67,7 +65,6 @@ class FullStream implements BufferedStreamInterface, MTProtoBufferInterface
|
|||||||
{
|
{
|
||||||
return $this->stream->disconnect();
|
return $this->stream->disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get write buffer asynchronously.
|
* Get write buffer asynchronously.
|
||||||
*
|
*
|
||||||
@ -82,10 +79,8 @@ class FullStream implements BufferedStreamInterface, MTProtoBufferInterface
|
|||||||
$buffer = yield $this->stream->getWriteBuffer($length + 12, $append);
|
$buffer = yield $this->stream->getWriteBuffer($length + 12, $append);
|
||||||
$this->out_seq_no++;
|
$this->out_seq_no++;
|
||||||
$buffer->bufferWrite(\pack('VV', $length + 12, $this->out_seq_no));
|
$buffer->bufferWrite(\pack('VV', $length + 12, $this->out_seq_no));
|
||||||
|
|
||||||
return $buffer;
|
return $buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get read buffer asynchronously.
|
* Get read buffer asynchronously.
|
||||||
*
|
*
|
||||||
@ -105,10 +100,8 @@ class FullStream implements BufferedStreamInterface, MTProtoBufferInterface
|
|||||||
if ($in_seq_no != $this->in_seq_no) {
|
if ($in_seq_no != $this->in_seq_no) {
|
||||||
throw new \danog\MadelineProto\Exception('Incoming seq_no mismatch');
|
throw new \danog\MadelineProto\Exception('Incoming seq_no mismatch');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $buffer;
|
return $buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*
|
*
|
||||||
@ -118,7 +111,6 @@ class FullStream implements BufferedStreamInterface, MTProtoBufferInterface
|
|||||||
{
|
{
|
||||||
return $this->stream->getSocket();
|
return $this->stream->getSocket();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP stream wrapper.
|
* HTTP stream wrapper.
|
||||||
*
|
*
|
||||||
@ -45,7 +46,6 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface
|
|||||||
* @var \Amp\Uri\Uri
|
* @var \Amp\Uri\Uri
|
||||||
*/
|
*/
|
||||||
private $uri;
|
private $uri;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to stream.
|
* Connect to stream.
|
||||||
*
|
*
|
||||||
@ -59,7 +59,6 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface
|
|||||||
$this->stream = yield $ctx->getStream($header);
|
$this->stream = yield $ctx->getStream($header);
|
||||||
$this->uri = $ctx->getUri();
|
$this->uri = $ctx->getUri();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set proxy data.
|
* Set proxy data.
|
||||||
*
|
*
|
||||||
@ -70,10 +69,9 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface
|
|||||||
public function setExtra($extra)
|
public function setExtra($extra)
|
||||||
{
|
{
|
||||||
if (isset($extra['user']) && isset($extra['password'])) {
|
if (isset($extra['user']) && isset($extra['password'])) {
|
||||||
$this->header = \base64_encode($extra['user'].':'.$extra['password'])."\r\n";
|
$this->header = \base64_encode($extra['user'] . ':' . $extra['password']) . "\r\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Async close.
|
* Async close.
|
||||||
*
|
*
|
||||||
@ -83,7 +81,6 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface
|
|||||||
{
|
{
|
||||||
return $this->stream->disconnect();
|
return $this->stream->disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get write buffer asynchronously.
|
* Get write buffer asynchronously.
|
||||||
*
|
*
|
||||||
@ -93,13 +90,11 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface
|
|||||||
*/
|
*/
|
||||||
public function getWriteBufferGenerator(int $length, string $append = ''): \Generator
|
public function getWriteBufferGenerator(int $length, string $append = ''): \Generator
|
||||||
{
|
{
|
||||||
$headers = 'POST '.$this->uri->getPath()." HTTP/1.1\r\nHost: ".$this->uri->getHost().':'.$this->uri->getPort()."\r\n"."Content-Type: application/x-www-form-urlencoded\r\nConnection: keep-alive\r\nKeep-Alive: timeout=100000, max=10000000\r\nContent-Length: ".$length.$this->header."\r\n\r\n";
|
$headers = 'POST ' . $this->uri->getPath() . " HTTP/1.1\r\nHost: " . $this->uri->getHost() . ':' . $this->uri->getPort() . "\r\n" . "Content-Type: application/x-www-form-urlencoded\r\nConnection: keep-alive\r\nKeep-Alive: timeout=100000, max=10000000\r\nContent-Length: " . $length . $this->header . "\r\n\r\n";
|
||||||
$buffer = yield $this->stream->getWriteBuffer(\strlen($headers) + $length, $append);
|
$buffer = yield $this->stream->getWriteBuffer(\strlen($headers) + $length, $append);
|
||||||
yield $buffer->bufferWrite($headers);
|
yield $buffer->bufferWrite($headers);
|
||||||
|
|
||||||
return $buffer;
|
return $buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get read buffer asynchronously.
|
* Get read buffer asynchronously.
|
||||||
*
|
*
|
||||||
@ -115,7 +110,8 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface
|
|||||||
while (true) {
|
while (true) {
|
||||||
$piece = yield $buffer->bufferRead(2);
|
$piece = yield $buffer->bufferRead(2);
|
||||||
$headers .= $piece;
|
$headers .= $piece;
|
||||||
if ($piece === "\n\r") { // Assume end of headers with \r\n\r\n
|
if ($piece === "\n\r") {
|
||||||
|
// Assume end of headers with \r\n\r\n
|
||||||
$headers .= yield $buffer->bufferRead(1);
|
$headers .= yield $buffer->bufferRead(1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -125,7 +121,6 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface
|
|||||||
$was_crlf = $piece === "\r\n";
|
$was_crlf = $piece === "\r\n";
|
||||||
}
|
}
|
||||||
$headers = \explode("\r\n", $headers);
|
$headers = \explode("\r\n", $headers);
|
||||||
|
|
||||||
list($protocol, $code, $description) = \explode(' ', $headers[0], 3);
|
list($protocol, $code, $description) = \explode(' ', $headers[0], 3);
|
||||||
list($protocol, $protocol_version) = \explode('/', $protocol);
|
list($protocol, $protocol_version) = \explode('/', $protocol);
|
||||||
if ($protocol !== 'HTTP') {
|
if ($protocol !== 'HTTP') {
|
||||||
@ -133,7 +128,7 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface
|
|||||||
}
|
}
|
||||||
$code = (int) $code;
|
$code = (int) $code;
|
||||||
unset($headers[0]);
|
unset($headers[0]);
|
||||||
if (\array_pop($headers).\array_pop($headers) !== '') {
|
if (\array_pop($headers) . \array_pop($headers) !== '') {
|
||||||
throw new \danog\MadelineProto\Exception('Wrong last header');
|
throw new \danog\MadelineProto\Exception('Wrong last header');
|
||||||
}
|
}
|
||||||
foreach ($headers as $key => $current_header) {
|
foreach ($headers as $key => $current_header) {
|
||||||
@ -141,31 +136,24 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface
|
|||||||
$current_header = \explode(':', $current_header, 2);
|
$current_header = \explode(':', $current_header, 2);
|
||||||
$headers[\strtolower($current_header[0])] = \trim($current_header[1]);
|
$headers[\strtolower($current_header[0])] = \trim($current_header[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$close = $protocol === 'HTTP/1.0';
|
$close = $protocol === 'HTTP/1.0';
|
||||||
if (isset($headers['connection'])) {
|
if (isset($headers['connection'])) {
|
||||||
$close = \strtolower($headers['connection']) === 'close';
|
$close = \strtolower($headers['connection']) === 'close';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($code !== 200) {
|
if ($code !== 200) {
|
||||||
$read = '';
|
$read = '';
|
||||||
if (isset($headers['content-length'])) {
|
if (isset($headers['content-length'])) {
|
||||||
$read = yield $buffer->bufferRead((int) $headers['content-length']);
|
$read = yield $buffer->bufferRead((int) $headers['content-length']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($close) {
|
if ($close) {
|
||||||
$this->disconnect();
|
$this->disconnect();
|
||||||
yield $this->connect($this->ctx);
|
yield $this->connect($this->ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
\danog\MadelineProto\Logger::log($read);
|
\danog\MadelineProto\Logger::log($read);
|
||||||
|
|
||||||
$this->code = \danog\MadelineProto\Tools::packSignedInt(-$code);
|
$this->code = \danog\MadelineProto\Tools::packSignedInt(-$code);
|
||||||
$length = 4;
|
$length = 4;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($close) {
|
if ($close) {
|
||||||
$this->stream->disconnect();
|
$this->stream->disconnect();
|
||||||
yield $this->stream->connect($this->ctx);
|
yield $this->stream->connect($this->ctx);
|
||||||
@ -173,15 +161,12 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface
|
|||||||
if (isset($headers['content-length'])) {
|
if (isset($headers['content-length'])) {
|
||||||
$length = (int) $headers['content-length'];
|
$length = (int) $headers['content-length'];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $buffer;
|
return $buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function bufferRead(int $length): Promise
|
public function bufferRead(int $length): Promise
|
||||||
{
|
{
|
||||||
return new Success($this->code);
|
return new Success($this->code);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*
|
*
|
||||||
@ -200,7 +185,6 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface
|
|||||||
{
|
{
|
||||||
return $this->stream;
|
return $this->stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getName(): string
|
public static function getName(): string
|
||||||
{
|
{
|
||||||
return __CLASS__;
|
return __CLASS__;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTPS stream wrapper.
|
* HTTPS stream wrapper.
|
||||||
*
|
*
|
||||||
@ -20,7 +21,6 @@ namespace danog\MadelineProto\Stream\MTProtoTransport;
|
|||||||
|
|
||||||
use danog\MadelineProto\Stream\ConnectionContext;
|
use danog\MadelineProto\Stream\ConnectionContext;
|
||||||
use danog\MadelineProto\Stream\MTProtoBufferInterface;
|
use danog\MadelineProto\Stream\MTProtoBufferInterface;
|
||||||
|
|
||||||
use danog\MadelineProto\Stream\RawStreamInterface;
|
use danog\MadelineProto\Stream\RawStreamInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,7 +41,6 @@ class HttpsStream extends HttpStream implements MTProtoBufferInterface
|
|||||||
{
|
{
|
||||||
return parent::connectGenerator($ctx->getCtx()->secure(true), $header);
|
return parent::connectGenerator($ctx->getCtx()->secure(true), $header);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TCP Intermediate stream wrapper.
|
* TCP Intermediate stream wrapper.
|
||||||
*
|
*
|
||||||
@ -24,7 +25,6 @@ use danog\MadelineProto\Stream\Async\BufferedStream;
|
|||||||
use danog\MadelineProto\Stream\BufferedStreamInterface;
|
use danog\MadelineProto\Stream\BufferedStreamInterface;
|
||||||
use danog\MadelineProto\Stream\ConnectionContext;
|
use danog\MadelineProto\Stream\ConnectionContext;
|
||||||
use danog\MadelineProto\Stream\MTProtoBufferInterface;
|
use danog\MadelineProto\Stream\MTProtoBufferInterface;
|
||||||
|
|
||||||
use danog\MadelineProto\Stream\RawStreamInterface;
|
use danog\MadelineProto\Stream\RawStreamInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,7 +38,6 @@ class IntermediatePaddedStream implements BufferedStreamInterface, MTProtoBuffer
|
|||||||
{
|
{
|
||||||
use BufferedStream;
|
use BufferedStream;
|
||||||
private $stream;
|
private $stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to stream.
|
* Connect to stream.
|
||||||
*
|
*
|
||||||
@ -48,9 +47,8 @@ class IntermediatePaddedStream implements BufferedStreamInterface, MTProtoBuffer
|
|||||||
*/
|
*/
|
||||||
public function connectGenerator(ConnectionContext $ctx, string $header = ''): \Generator
|
public function connectGenerator(ConnectionContext $ctx, string $header = ''): \Generator
|
||||||
{
|
{
|
||||||
$this->stream = yield $ctx->getStream(\str_repeat(\chr(221), 4).$header);
|
$this->stream = yield $ctx->getStream(\str_repeat(\chr(221), 4) . $header);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Async close.
|
* Async close.
|
||||||
*
|
*
|
||||||
@ -60,7 +58,6 @@ class IntermediatePaddedStream implements BufferedStreamInterface, MTProtoBuffer
|
|||||||
{
|
{
|
||||||
return $this->stream->disconnect();
|
return $this->stream->disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get write buffer asynchronously.
|
* Get write buffer asynchronously.
|
||||||
*
|
*
|
||||||
@ -71,12 +68,10 @@ class IntermediatePaddedStream implements BufferedStreamInterface, MTProtoBuffer
|
|||||||
public function getWriteBufferGenerator(int $length, string $append = ''): \Generator
|
public function getWriteBufferGenerator(int $length, string $append = ''): \Generator
|
||||||
{
|
{
|
||||||
$padding_length = \danog\MadelineProto\Tools::randomInt($modulus = 16);
|
$padding_length = \danog\MadelineProto\Tools::randomInt($modulus = 16);
|
||||||
$buffer = yield $this->stream->getWriteBuffer(4 + $length + $padding_length, $append.\danog\MadelineProto\Tools::random($padding_length));
|
$buffer = yield $this->stream->getWriteBuffer(4 + $length + $padding_length, $append . \danog\MadelineProto\Tools::random($padding_length));
|
||||||
yield $buffer->bufferWrite(\pack('V', $padding_length + $length));
|
yield $buffer->bufferWrite(\pack('V', $padding_length + $length));
|
||||||
|
|
||||||
return $buffer;
|
return $buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get read buffer asynchronously.
|
* Get read buffer asynchronously.
|
||||||
*
|
*
|
||||||
@ -88,10 +83,8 @@ class IntermediatePaddedStream implements BufferedStreamInterface, MTProtoBuffer
|
|||||||
{
|
{
|
||||||
$buffer = yield $this->stream->getReadBuffer($l);
|
$buffer = yield $this->stream->getReadBuffer($l);
|
||||||
$length = \unpack('V', yield $buffer->bufferRead(4))[1];
|
$length = \unpack('V', yield $buffer->bufferRead(4))[1];
|
||||||
|
|
||||||
return $buffer;
|
return $buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*
|
*
|
||||||
@ -110,7 +103,6 @@ class IntermediatePaddedStream implements BufferedStreamInterface, MTProtoBuffer
|
|||||||
{
|
{
|
||||||
return $this->stream;
|
return $this->stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getName(): string
|
public static function getName(): string
|
||||||
{
|
{
|
||||||
return __CLASS__;
|
return __CLASS__;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TCP Intermediate stream wrapper.
|
* TCP Intermediate stream wrapper.
|
||||||
*
|
*
|
||||||
@ -24,7 +25,6 @@ use danog\MadelineProto\Stream\Async\BufferedStream;
|
|||||||
use danog\MadelineProto\Stream\BufferedStreamInterface;
|
use danog\MadelineProto\Stream\BufferedStreamInterface;
|
||||||
use danog\MadelineProto\Stream\ConnectionContext;
|
use danog\MadelineProto\Stream\ConnectionContext;
|
||||||
use danog\MadelineProto\Stream\MTProtoBufferInterface;
|
use danog\MadelineProto\Stream\MTProtoBufferInterface;
|
||||||
|
|
||||||
use danog\MadelineProto\Stream\RawStreamInterface;
|
use danog\MadelineProto\Stream\RawStreamInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,7 +38,6 @@ class IntermediateStream implements BufferedStreamInterface, MTProtoBufferInterf
|
|||||||
{
|
{
|
||||||
use BufferedStream;
|
use BufferedStream;
|
||||||
private $stream;
|
private $stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to stream.
|
* Connect to stream.
|
||||||
*
|
*
|
||||||
@ -48,9 +47,8 @@ class IntermediateStream implements BufferedStreamInterface, MTProtoBufferInterf
|
|||||||
*/
|
*/
|
||||||
public function connectGenerator(ConnectionContext $ctx, string $header = ''): \Generator
|
public function connectGenerator(ConnectionContext $ctx, string $header = ''): \Generator
|
||||||
{
|
{
|
||||||
$this->stream = yield $ctx->getStream(\str_repeat(\chr(238), 4).$header);
|
$this->stream = yield $ctx->getStream(\str_repeat(\chr(238), 4) . $header);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Async close.
|
* Async close.
|
||||||
*
|
*
|
||||||
@ -60,7 +58,6 @@ class IntermediateStream implements BufferedStreamInterface, MTProtoBufferInterf
|
|||||||
{
|
{
|
||||||
return $this->stream->disconnect();
|
return $this->stream->disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get write buffer asynchronously.
|
* Get write buffer asynchronously.
|
||||||
*
|
*
|
||||||
@ -72,10 +69,8 @@ class IntermediateStream implements BufferedStreamInterface, MTProtoBufferInterf
|
|||||||
{
|
{
|
||||||
$buffer = yield $this->stream->getWriteBuffer($length + 4, $append);
|
$buffer = yield $this->stream->getWriteBuffer($length + 4, $append);
|
||||||
yield $buffer->bufferWrite(\pack('V', $length));
|
yield $buffer->bufferWrite(\pack('V', $length));
|
||||||
|
|
||||||
return $buffer;
|
return $buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get read buffer asynchronously.
|
* Get read buffer asynchronously.
|
||||||
*
|
*
|
||||||
@ -87,10 +82,8 @@ class IntermediateStream implements BufferedStreamInterface, MTProtoBufferInterf
|
|||||||
{
|
{
|
||||||
$buffer = yield $this->stream->getReadBuffer($l);
|
$buffer = yield $this->stream->getReadBuffer($l);
|
||||||
$length = \unpack('V', yield $buffer->bufferRead(4))[1];
|
$length = \unpack('V', yield $buffer->bufferRead(4))[1];
|
||||||
|
|
||||||
return $buffer;
|
return $buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*
|
*
|
||||||
@ -109,8 +102,6 @@ class IntermediateStream implements BufferedStreamInterface, MTProtoBufferInterf
|
|||||||
{
|
{
|
||||||
return $this->stream;
|
return $this->stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static function getName(): string
|
public static function getName(): string
|
||||||
{
|
{
|
||||||
return __CLASS__;
|
return __CLASS__;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obfuscated2 stream wrapper.
|
* Obfuscated2 stream wrapper.
|
||||||
*
|
*
|
||||||
@ -33,10 +34,8 @@ use danog\MadelineProto\Stream\ConnectionContext;
|
|||||||
class ObfuscatedStream extends CtrStream implements BufferedProxyStreamInterface
|
class ObfuscatedStream extends CtrStream implements BufferedProxyStreamInterface
|
||||||
{
|
{
|
||||||
use Stream;
|
use Stream;
|
||||||
|
|
||||||
private $stream;
|
private $stream;
|
||||||
private $extra;
|
private $extra;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to stream.
|
* Connect to stream.
|
||||||
*
|
*
|
||||||
@ -48,52 +47,30 @@ class ObfuscatedStream extends CtrStream implements BufferedProxyStreamInterface
|
|||||||
{
|
{
|
||||||
if (isset($this->extra['address'])) {
|
if (isset($this->extra['address'])) {
|
||||||
$ctx = $ctx->getCtx();
|
$ctx = $ctx->getCtx();
|
||||||
$ctx->setUri('tcp://'.$this->extra['address'].':'.$this->extra['port']);
|
$ctx->setUri('tcp://' . $this->extra['address'] . ':' . $this->extra['port']);
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
$random = \danog\MadelineProto\Tools::random(64);
|
$random = \danog\MadelineProto\Tools::random(64);
|
||||||
} while (\in_array(\substr($random, 0, 4), ['PVrG', 'GET ', 'POST', 'HEAD', \str_repeat(\chr(238), 4), \str_repeat(\chr(221), 4)]) || $random[0] === \chr(0xef) || \substr($random, 4, 4) === "\0\0\0\0");
|
} while (\in_array(\substr($random, 0, 4), ['PVrG', 'GET ', 'POST', 'HEAD', \str_repeat(\chr(238), 4), \str_repeat(\chr(221), 4)]) || $random[0] === \chr(0xef) || \substr($random, 4, 4) === "\0\0\0\0");
|
||||||
|
|
||||||
if (\strlen($header) === 1) {
|
if (\strlen($header) === 1) {
|
||||||
$header = \str_repeat($header, 4);
|
$header = \str_repeat($header, 4);
|
||||||
}
|
}
|
||||||
$random = \substr_replace($random, $header.\substr($random, 56 + \strlen($header)), 56);
|
$random = \substr_replace($random, $header . \substr($random, 56 + \strlen($header)), 56);
|
||||||
$random = \substr_replace($random, \pack('s', $ctx->getIntDc()).\substr($random, 60 + 2), 60);
|
$random = \substr_replace($random, \pack('s', $ctx->getIntDc()) . \substr($random, 60 + 2), 60);
|
||||||
|
|
||||||
$reversed = \strrev($random);
|
$reversed = \strrev($random);
|
||||||
|
|
||||||
$key = \substr($random, 8, 32);
|
$key = \substr($random, 8, 32);
|
||||||
$keyRev = \substr($reversed, 8, 32);
|
$keyRev = \substr($reversed, 8, 32);
|
||||||
|
|
||||||
if (isset($this->extra['secret'])) {
|
if (isset($this->extra['secret'])) {
|
||||||
$key = \hash('sha256', $key.$this->extra['secret'], true);
|
$key = \hash('sha256', $key . $this->extra['secret'], true);
|
||||||
$keyRev = \hash('sha256', $keyRev.$this->extra['secret'], true);
|
$keyRev = \hash('sha256', $keyRev . $this->extra['secret'], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$iv = \substr($random, 40, 16);
|
$iv = \substr($random, 40, 16);
|
||||||
$ivRev = \substr($reversed, 40, 16);
|
$ivRev = \substr($reversed, 40, 16);
|
||||||
|
parent::setExtra(['encrypt' => ['key' => $key, 'iv' => $iv], 'decrypt' => ['key' => $keyRev, 'iv' => $ivRev]]);
|
||||||
parent::setExtra(
|
|
||||||
[
|
|
||||||
'encrypt' => [
|
|
||||||
'key' => $key,
|
|
||||||
'iv' => $iv
|
|
||||||
],
|
|
||||||
'decrypt' => [
|
|
||||||
'key' => $keyRev,
|
|
||||||
'iv' => $ivRev
|
|
||||||
]
|
|
||||||
]
|
|
||||||
);
|
|
||||||
yield from parent::connectGenerator($ctx);
|
yield from parent::connectGenerator($ctx);
|
||||||
|
|
||||||
$random = \substr_replace($random, \substr(@$this->getEncryptor()->encrypt($random), 56, 8), 56, 8);
|
$random = \substr_replace($random, \substr(@$this->getEncryptor()->encrypt($random), 56, 8), 56, 8);
|
||||||
|
|
||||||
yield $this->getStream()->write($random);
|
yield $this->getStream()->write($random);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does nothing.
|
* Does nothing.
|
||||||
*
|
*
|
||||||
@ -111,7 +88,6 @@ class ObfuscatedStream extends CtrStream implements BufferedProxyStreamInterface
|
|||||||
$extra['secret'] = \substr($extra['secret'], 1, 16);
|
$extra['secret'] = \substr($extra['secret'], 1, 16);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->extra = $extra;
|
$this->extra = $extra;
|
||||||
}
|
}
|
||||||
public static function getName(): string
|
public static function getName(): string
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP proxy stream wrapper.
|
* HTTP proxy stream wrapper.
|
||||||
*
|
*
|
||||||
@ -25,7 +26,6 @@ use danog\MadelineProto\Stream\Async\RawStream;
|
|||||||
use danog\MadelineProto\Stream\BufferedProxyStreamInterface;
|
use danog\MadelineProto\Stream\BufferedProxyStreamInterface;
|
||||||
use danog\MadelineProto\Stream\ConnectionContext;
|
use danog\MadelineProto\Stream\ConnectionContext;
|
||||||
use danog\MadelineProto\Stream\RawProxyStreamInterface;
|
use danog\MadelineProto\Stream\RawProxyStreamInterface;
|
||||||
|
|
||||||
use danog\MadelineProto\Stream\RawStreamInterface;
|
use danog\MadelineProto\Stream\RawStreamInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,7 +37,6 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface
|
|||||||
{
|
{
|
||||||
use RawStream;
|
use RawStream;
|
||||||
private $extra;
|
private $extra;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to stream.
|
* Connect to stream.
|
||||||
*
|
*
|
||||||
@ -50,33 +49,28 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface
|
|||||||
$ctx = $ctx->getCtx();
|
$ctx = $ctx->getCtx();
|
||||||
$uri = $ctx->getUri();
|
$uri = $ctx->getUri();
|
||||||
$secure = $ctx->isSecure();
|
$secure = $ctx->isSecure();
|
||||||
|
|
||||||
if ($secure) {
|
if ($secure) {
|
||||||
$ctx->setSocketContext($ctx->getSocketContext()->withTlsContext(new ClientTlsContext($uri->getHost())));
|
$ctx->setSocketContext($ctx->getSocketContext()->withTlsContext(new ClientTlsContext($uri->getHost())));
|
||||||
}
|
}
|
||||||
|
$ctx->setUri('tcp://' . $this->extra['address'] . ':' . $this->extra['port'])->secure(false);
|
||||||
$ctx->setUri('tcp://'.$this->extra['address'].':'.$this->extra['port'])->secure(false);
|
|
||||||
|
|
||||||
$this->stream = yield $ctx->getStream();
|
$this->stream = yield $ctx->getStream();
|
||||||
$address = $uri->getHost();
|
$address = $uri->getHost();
|
||||||
$port = $uri->getPort();
|
$port = $uri->getPort();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (\strlen(\inet_pton($address) === 16)) {
|
if (\strlen(\inet_pton($address) === 16)) {
|
||||||
$address = '['.$address.']';
|
$address = '[' . $address . ']';
|
||||||
}
|
}
|
||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
}
|
}
|
||||||
|
yield $this->stream->write("CONNECT {$address}:{$port} HTTP/1.1\r\nHost: {$address}:{$port}\r\nAccept: */*\r\n" . $this->getProxyAuthHeader() . "Connection: keep-Alive\r\n\r\n");
|
||||||
yield $this->stream->write("CONNECT $address:$port HTTP/1.1\r\nHost: $address:$port\r\nAccept: */*\r\n".$this->getProxyAuthHeader()."Connection: keep-Alive\r\n\r\n");
|
|
||||||
|
|
||||||
$buffer = yield $this->stream->getReadBuffer($l);
|
$buffer = yield $this->stream->getReadBuffer($l);
|
||||||
$headers = '';
|
$headers = '';
|
||||||
$was_crlf = false;
|
$was_crlf = false;
|
||||||
while (true) {
|
while (true) {
|
||||||
$piece = yield $buffer->bufferRead(2);
|
$piece = yield $buffer->bufferRead(2);
|
||||||
$headers .= $piece;
|
$headers .= $piece;
|
||||||
if ($piece === "\n\r") { // Assume end of headers with \r\n\r\n
|
if ($piece === "\n\r") {
|
||||||
|
// Assume end of headers with \r\n\r\n
|
||||||
$headers .= yield $buffer->bufferRead(1);
|
$headers .= yield $buffer->bufferRead(1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -86,7 +80,6 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface
|
|||||||
$was_crlf = $piece === "\r\n";
|
$was_crlf = $piece === "\r\n";
|
||||||
}
|
}
|
||||||
$headers = \explode("\r\n", $headers);
|
$headers = \explode("\r\n", $headers);
|
||||||
|
|
||||||
list($protocol, $code, $description) = \explode(' ', $headers[0], 3);
|
list($protocol, $code, $description) = \explode(' ', $headers[0], 3);
|
||||||
list($protocol, $protocol_version) = \explode('/', $protocol);
|
list($protocol, $protocol_version) = \explode('/', $protocol);
|
||||||
if ($protocol !== 'HTTP') {
|
if ($protocol !== 'HTTP') {
|
||||||
@ -94,7 +87,7 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface
|
|||||||
}
|
}
|
||||||
$code = (int) $code;
|
$code = (int) $code;
|
||||||
unset($headers[0]);
|
unset($headers[0]);
|
||||||
if (\array_pop($headers).\array_pop($headers) !== '') {
|
if (\array_pop($headers) . \array_pop($headers) !== '') {
|
||||||
throw new \danog\MadelineProto\Exception('Wrong last header');
|
throw new \danog\MadelineProto\Exception('Wrong last header');
|
||||||
}
|
}
|
||||||
foreach ($headers as $key => $current_header) {
|
foreach ($headers as $key => $current_header) {
|
||||||
@ -102,28 +95,22 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface
|
|||||||
$current_header = \explode(':', $current_header, 2);
|
$current_header = \explode(':', $current_header, 2);
|
||||||
$headers[\strtolower($current_header[0])] = \trim($current_header[1]);
|
$headers[\strtolower($current_header[0])] = \trim($current_header[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$close = $protocol === 'HTTP/1.0';
|
$close = $protocol === 'HTTP/1.0';
|
||||||
if (isset($headers['connection'])) {
|
if (isset($headers['connection'])) {
|
||||||
$close = \strtolower($headers['connection']) === 'close';
|
$close = \strtolower($headers['connection']) === 'close';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($code !== 200) {
|
if ($code !== 200) {
|
||||||
$read = '';
|
$read = '';
|
||||||
if (isset($headers['content-length'])) {
|
if (isset($headers['content-length'])) {
|
||||||
$read = yield $buffer->bufferRead((int) $headers['content-length']);
|
$read = yield $buffer->bufferRead((int) $headers['content-length']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($close) {
|
if ($close) {
|
||||||
$this->disconnect();
|
$this->disconnect();
|
||||||
yield $this->connect($ctx);
|
yield $this->connect($ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
\danog\MadelineProto\Logger::log(\trim($read));
|
\danog\MadelineProto\Logger::log(\trim($read));
|
||||||
|
|
||||||
throw new \danog\MadelineProto\Exception($description, $code);
|
throw new \danog\MadelineProto\Exception($description, $code);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($close) {
|
if ($close) {
|
||||||
yield $this->stream->disconnect();
|
yield $this->stream->disconnect();
|
||||||
yield $this->stream->connect($ctx);
|
yield $this->stream->connect($ctx);
|
||||||
@ -132,17 +119,14 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface
|
|||||||
$length = (int) $headers['content-length'];
|
$length = (int) $headers['content-length'];
|
||||||
$read = yield $buffer->bufferRead($length);
|
$read = yield $buffer->bufferRead($length);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($secure) {
|
if ($secure) {
|
||||||
yield $this->getSocket()->setupTls();
|
yield $this->getSocket()->setupTls();
|
||||||
}
|
}
|
||||||
\danog\MadelineProto\Logger::log('Connected to '.$address.':'.$port.' via http');
|
\danog\MadelineProto\Logger::log('Connected to ' . $address . ':' . $port . ' via http');
|
||||||
|
|
||||||
if (\strlen($header)) {
|
if (\strlen($header)) {
|
||||||
yield (yield $this->stream->getWriteBuffer(\strlen($header)))->bufferWrite($header);
|
yield (yield $this->stream->getWriteBuffer(\strlen($header)))->bufferWrite($header);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Async close.
|
* Async close.
|
||||||
*
|
*
|
||||||
@ -152,7 +136,6 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface
|
|||||||
{
|
{
|
||||||
return $this->stream->disconnect();
|
return $this->stream->disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get write buffer asynchronously.
|
* Get write buffer asynchronously.
|
||||||
*
|
*
|
||||||
@ -164,7 +147,6 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface
|
|||||||
{
|
{
|
||||||
return $this->stream->getWriteBuffer($length, $append);
|
return $this->stream->getWriteBuffer($length, $append);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get read buffer asynchronously.
|
* Get read buffer asynchronously.
|
||||||
*
|
*
|
||||||
@ -176,26 +158,21 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface
|
|||||||
{
|
{
|
||||||
return $this->stream->getReadBuffer($length);
|
return $this->stream->getReadBuffer($length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function read(): Promise
|
public function read(): Promise
|
||||||
{
|
{
|
||||||
return $this->stream->read();
|
return $this->stream->read();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function write(string $data): Promise
|
public function write(string $data): Promise
|
||||||
{
|
{
|
||||||
return $this->stream->write($data);
|
return $this->stream->write($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getProxyAuthHeader()
|
private function getProxyAuthHeader()
|
||||||
{
|
{
|
||||||
if (!isset($this->extra['username']) || !isset($this->extra['password'])) {
|
if (!isset($this->extra['username']) || !isset($this->extra['password'])) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
return 'Proxy-Authorization: Basic ' . \base64_encode($this->extra['username'] . ':' . $this->extra['password']) . "\r\n";
|
||||||
return 'Proxy-Authorization: Basic '.\base64_encode($this->extra['username'].':'.$this->extra['password'])."\r\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets proxy data.
|
* Sets proxy data.
|
||||||
*
|
*
|
||||||
@ -207,7 +184,6 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface
|
|||||||
{
|
{
|
||||||
$this->extra = $extra;
|
$this->extra = $extra;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*
|
*
|
||||||
@ -217,7 +193,6 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface
|
|||||||
{
|
{
|
||||||
return $this->stream->getSocket();
|
return $this->stream->getSocket();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user