1
0
mirror of https://github.com/danog/MadelineProto.git synced 2024-11-30 09:58:59 +01:00

Async constructor

This commit is contained in:
Daniil Gentili 2019-05-02 21:30:50 +02:00
parent 2e4be09279
commit 406a2d8aad
7 changed files with 1420 additions and 37 deletions

2
docs

@ -1 +1 @@
Subproject commit 0fcff8e5a31af300511949c4dbafc7be6c0d4dd7
Subproject commit 6d9ffce34a50e6400dba4a516c78062e5dc2f346

View File

@ -62,14 +62,17 @@ class API extends APIFactory
class_exists('\\Volatile');
$tounserialize = str_replace('O:26:"danog\\MadelineProto\\Button":', 'O:35:"danog\\MadelineProto\\TL\\Types\\Button":', $tounserialize);
foreach (['RSA', 'TL\\TLMethod', 'TL\\TLConstructor', 'MTProto', 'API', 'DataCenter', 'Connection', 'TL\\Types\\Button', 'TL\\Types\\Bytes', 'APIFactory'] as $class) {
class_exists('\\danog\\MadelineProto\\'.$class);
class_exists('\\danog\\MadelineProto\\' . $class);
}
$unserialized = \danog\Serialization::unserialize($tounserialize);
} catch (\danog\MadelineProto\Exception $e) {
if ($e->getFile() === 'MadelineProto' && $e->getLine() === 1) {
throw $e;
}
class_exists('\\Volatile');
$tounserialize = str_replace('O:26:"danog\\MadelineProto\\Button":', 'O:35:"danog\\MadelineProto\\TL\\Types\\Button":', $tounserialize);
foreach (['RSA', 'TL\\TLMethod', 'TL\\TLConstructor', 'MTProto', 'API', 'DataCenter', 'Connection', 'TL\\Types\\Button', 'TL\\Types\\Bytes', 'APIFactory'] as $class) {
class_exists('\\danog\\MadelineProto\\'.$class);
class_exists('\\danog\\MadelineProto\\' . $class);
}
Logger::log((string) $e, Logger::ERROR);
if (strpos($e->getMessage(), "Erroneous data format for unserializing 'phpseclib\\Math\\BigInteger'") === 0) {
@ -89,6 +92,15 @@ class API extends APIFactory
if (isset($unserialized->API)) {
$this->API = $unserialized->API;
$promise = $this->call(function () {
yield $this->API->asyncInitPromise;
$this->API->asyncInitPromise = null;
$this->APIFactory();
\danog\MadelineProto\Logger::log('Ping...', Logger::ULTRA_VERBOSE);
$pong = $this->ping(['ping_id' => 3], ['async' => true]);
\danog\MadelineProto\Logger::log('Pong: ' . $pong['ping_id'], Logger::ULTRA_VERBOSE);
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['madelineproto_ready'], Logger::NOTICE);
});
$this->APIFactory();
return;
@ -103,11 +115,16 @@ class API extends APIFactory
}
$this->API = new MTProto($params);
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['apifactory_start'], Logger::VERBOSE);
$promise = $this->call(function () {
yield $this->API->asyncInitPromise;
$this->API->asyncInitPromise = null;
$this->APIFactory();
\danog\MadelineProto\Logger::log('Ping...', Logger::ULTRA_VERBOSE);
$pong = $this->ping(['ping_id' => 3]);
\danog\MadelineProto\Logger::log('Pong: '.$pong['ping_id'], Logger::ULTRA_VERBOSE);
$pong = $this->ping(['ping_id' => 3], ['async' => true]);
\danog\MadelineProto\Logger::log('Pong: ' . $pong['ping_id'], Logger::ULTRA_VERBOSE);
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['madelineproto_ready'], Logger::NOTICE);
});
$this->APIFactory();
}
public function async($async)
@ -156,6 +173,10 @@ class API extends APIFactory
public function __set($name, $value)
{
if ($name === 'settings') {
if ($this->API->phoneConfigWatcherId) {
$this->wait($this->API->phoneConfigWatcherId);
$this->API->phoneConfigWatcherId = null;
}
if (Magic::is_fork() && !Magic::$processed_fork) {
\danog\MadelineProto\Logger::log('Detected fork');
$this->API->reset_session();

View File

@ -124,7 +124,7 @@ class APIFactory
public function __construct($namespace, $API)
{
$this->namespace = $namespace.'.';
$this->namespace = $namespace . '.';
$this->API = $API;
}
@ -143,23 +143,24 @@ class APIFactory
$this->API->setdem = false;
$this->API->__construct($this->API->settings);
}
$this->API->get_config([], ['datacenter' => $this->API->datacenter->curdc]);
//$this->API->get_config([], ['datacenter' => $this->API->datacenter->curdc]);
if (isset($this->session) && !is_null($this->session) && time() - $this->serialized > $this->API->settings['serialization']['serialization_interval']) {
Logger::log("Didn't serialize in a while, doing that now...");
$this->serialize($this->session);
}
/*
if ($name !== 'accept_tos' && $name !== 'decline_tos') {
$this->API->check_tos();
}
}*/
$lower_name = strtolower($name);
if ($this->lua === false) {
return $this->namespace !== '' || !isset($this->methods[$lower_name]) ? $this->__mtproto_call($this->namespace.$name, $arguments) : $this->__api_call($lower_name, $arguments);
return $this->namespace !== '' || !isset($this->methods[$lower_name]) ? $this->__mtproto_call($this->namespace . $name, $arguments) : $this->__api_call($lower_name, $arguments);
}
try {
$deserialized = $this->namespace !== '' || !isset($this->methods[$lower_name]) ? $this->__mtproto_call($this->namespace.$name, $arguments) : $this->__api_call($lower_name, $arguments);
$deserialized = $this->namespace !== '' || !isset($this->methods[$lower_name]) ? $this->__mtproto_call($this->namespace . $name, $arguments) : $this->__api_call($lower_name, $arguments);
Lua::convert_objects($deserialized);
@ -183,10 +184,23 @@ class APIFactory
public function __api_call($name, $arguments)
{
if ($this->API->asyncInitPromise) {
$async = is_array(end($arguments)) && isset(end($arguments)['async']) ? end($arguments)['async'] : ($this->async && $name !== 'loop');
if ($async) {
return $this->call(function () use ($name, $arguments) {
yield $this->API->asyncInitPromise;
$this->API->asyncInitPromise = null;
return yield $this->methods[$name](...$arguments);
});
} else {
$this->wait($this->API->asyncInitPromise);
$this->API->asyncInitPromise = null;
}
}
$result = $this->methods[$name](...$arguments);
if (is_object($result) && ($result instanceof \Generator || $result instanceof Promise)) {
$async = is_array(end($arguments)) && isset(end($arguments)['async']) ? end($arguments)['async'] : $this->async;
if ($async && ($name !== 'loop' || isset(end($arguments)['async']))) {
$async = is_array(end($arguments)) && isset(end($arguments)['async']) ? end($arguments)['async'] : ($this->async && $name !== 'loop');
if ($async) {
return $result;
} else {
return $this->wait($result);
@ -204,6 +218,20 @@ class APIFactory
$args = isset($arguments[0]) && is_array($arguments[0]) ? $arguments[0] : [];
$async = isset(end($arguments)['async']) ? end($arguments)['async'] : $this->async;
if ($this->API->asyncInitPromise) {
if ($async) {
return $this->call(function () use ($name, $args, $aargs) {
yield $this->API->asyncInitPromise;
$this->API->asyncInitPromise = null;
return yield $this->API->method_call_async_read($name, $args, $aargs);
;
});
} else {
$this->wait($this->API->asyncInitPromise);
$this->API->asyncInitPromise = null;
}
}
$res = $this->API->method_call_async_read($name, $args, $aargs);
if ($async) {

View File

@ -137,7 +137,6 @@ class MTProto implements TLCallback
private $msg_ids = [];
private $v = 0;
private $dialog_params = ['_' => 'MadelineProto.dialogParams', 'limit' => 0, 'offset_date' => 0, 'offset_id' => 0, 'offset_peer' => ['_' => 'inputPeerEmpty'], 'count' => 0];
private $ipv6 = false;
public $run_workers = false;
public $setdem = false;
public $storage = [];
@ -148,7 +147,14 @@ class MTProto implements TLCallback
public $update_deferred;
public $phoneConfigWatcherId;
public $asyncInitPromise;
public function __magic_construct($settings = [])
{
$this->asyncInitPromise = $this->call($this->__async_construct($settings));
}
public function __async_construct($settings = [])
{
\danog\MadelineProto\Magic::class_exists();
// Parse settings
@ -185,11 +191,11 @@ class MTProto implements TLCallback
*/
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['TL_translation'], Logger::ULTRA_VERBOSE);
$this->construct_TL($this->settings['tl_schema']['src'], [$this, $this->referenceDatabase]);
$this->connect_to_all_dcs();
yield $this->connect_to_all_dcs_async();
$this->datacenter->curdc = 2;
if ((!isset($this->authorization['user']['bot']) || !$this->authorization['user']['bot']) && $this->datacenter->sockets[$this->datacenter->curdc]->temp_auth_key !== null) {
try {
$nearest_dc = $this->method_call('help.getNearestDc', [], ['datacenter' => $this->datacenter->curdc]);
$nearest_dc = yield $this->method_call_async_read('help.getNearestDc', [], ['datacenter' => $this->datacenter->curdc]);
$this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['nearest_dc'], $nearest_dc['country'], $nearest_dc['nearest_dc']), Logger::NOTICE);
if ($nearest_dc['nearest_dc'] != $nearest_dc['this_dc']) {
$this->settings['connection_settings']['default_dc'] = $this->datacenter->curdc = (int) $nearest_dc['nearest_dc'];
@ -200,10 +206,9 @@ class MTProto implements TLCallback
}
}
}
$this->get_config([], ['datacenter' => $this->datacenter->curdc]);
yield $this->get_config_async([], ['datacenter' => $this->datacenter->curdc]);
$this->v = self::V;
return $this->settings;
}
public function __sleep()
@ -222,6 +227,10 @@ class MTProto implements TLCallback
}
public function __wakeup()
{
$this->asyncInitPromise = $this->call($this->__async_wakeup());
}
public function __async_wakeup()
{
set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
set_exception_handler(['\\danog\\MadelineProto\\Serialization', 'serialize_all']);
@ -356,12 +365,12 @@ class MTProto implements TLCallback
$this->reset_session(true, true);
$this->config = ['expires' => -1];
$this->dh_config = ['version' => 0];
$this->__construct($settings);
yield $this->__async_construct($settings);
$force = true;
foreach ($this->secret_chats as $chat => $data) {
try {
if (isset($this->secret_chats[$chat]) && $this->secret_chats[$chat]['InputEncryptedChat'] !== null) {
$this->notify_layer($chat);
yield $this->notify_layer_async($chat);
}
} catch (\danog\MadelineProto\RPCErrorException $e) {
}
@ -372,7 +381,7 @@ class MTProto implements TLCallback
$this->channels_state = [];
$this->got_state = false;
}
$this->connect_to_all_dcs();
yield $this->connect_to_all_dcs_async();
foreach ($this->calls as $id => $controller) {
if (!is_object($controller)) {
unset($this->calls[$id]);
@ -383,15 +392,15 @@ class MTProto implements TLCallback
$controller->setMadeline($this);
}
}
if ($this->get_self()) {
if (yield $this->get_self_async()) {
$this->authorized = self::LOGGED_IN;
}
if ($this->authorized === self::LOGGED_IN) {
$this->get_cdn_config($this->datacenter->curdc);
yield $this->get_cdn_config_async($this->datacenter->curdc);
$this->setup_logger();
}
if ($this->authorized === self::LOGGED_IN && !$this->authorization['user']['bot'] && $this->settings['peer']['cache_all_peers_on_startup']) {
$this->get_dialogs($force);
yield $this->get_dialogs_async($force);
}
if ($this->authorized === self::LOGGED_IN && $this->settings['updates']['handle_updates'] && !$this->updates_state['sync_loading']) {
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['getupdates_deserialization'], Logger::NOTICE);
@ -709,7 +718,7 @@ class MTProto implements TLCallback
if (!is_array($settings)) {
$settings = [];
}
$settings = array_replace_recursive($this->array_cast_recursive($default_settings, true), $this->array_cast_recursive($settings, true));
$settings = array_replace_recursive($default_settings, $settings);
if (isset(Lang::$lang[$settings['app_info']['lang_code']])) {
Lang::$current_lang = &Lang::$lang[$settings['app_info']['lang_code']];
}
@ -816,11 +825,6 @@ class MTProto implements TLCallback
}
// Connects to all datacenters and if necessary creates authorization keys, binds them and writes client info
public function connect_to_all_dcs()
{
return $this->wait($this->connect_to_all_dcs_async());
}
public function connect_to_all_dcs_async(): \Generator
{
$this->datacenter->__construct($this, $this->settings['connection'], $this->settings['connection_settings']);
@ -836,7 +840,10 @@ class MTProto implements TLCallback
}
yield $dcs;
yield $this->init_authorization_async();
if (!$this->phoneConfigWatcherId) $this->phoneConfigWatcherId = Loop::repeat(24 * 3600 * 1000, [$this, 'get_phone_config_async']);
if (!$this->phoneConfigWatcherId) {
$this->phoneConfigWatcherId = Loop::repeat(24 * 3600 * 1000, [$this, 'get_phone_config_async']);
}
yield $this->get_phone_config_async();
$this->logger->logger("Started phone config fetcher");
}
@ -868,13 +875,17 @@ class MTProto implements TLCallback
}
public function get_cdn_config($datacenter)
{
return $this->wait($this->get_cdn_config_async($datacenter));
}
public function get_cdn_config_async($datacenter)
{
/*
* ***********************************************************************
* Fetch RSA keys for CDN datacenters
*/
try {
foreach ($this->method_call('help.getCdnConfig', [], ['datacenter' => $datacenter])['public_keys'] as $curkey) {
foreach ((yield $this->method_call_async_read('help.getCdnConfig', [], ['datacenter' => $datacenter]))['public_keys'] as $curkey) {
$tempkey = new \danog\MadelineProto\RSA($curkey['public_key']);
$this->rsa_keys[$tempkey->fp] = $tempkey;
}

View File

@ -110,7 +110,11 @@ trait AuthKeyHandler
public function notify_layer($chat)
{
$this->method_call('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionNotifyLayer', 'layer' => $this->encrypted_layer]]], ['datacenter' => $this->datacenter->curdc]);
return $this->wait($this->notify_layer_async($chat));
}
public function notify_layer_async($chat)
{
yield $this->method_call_async_read('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionNotifyLayer', 'layer' => $this->encrypted_layer]]], ['datacenter' => $this->datacenter->curdc]);
}
protected $temp_rekeyed_secret_chats = [];

File diff suppressed because it is too large Load Diff

View File

@ -62,7 +62,7 @@ trait Events
$this->settings['updates']['handle_updates'] = true;
$this->settings['updates']['run_callback'] = true;
if (isset($this->datacenter->sockets[$this->settings['connection_settings']['default_dc']]->updater)) {
if (isset($this->datacenter->sockets[$this->settings['connection_settings']['default_dc']]->updater) && !$this->asyncInitPromise) {
$this->datacenter->sockets[$this->settings['connection_settings']['default_dc']]->updater->start();
}
}