1
0
mirror of https://github.com/danog/MadelineProto.git synced 2024-12-11 17:00:00 +01:00
MadelineProto/src/API.php

457 lines
15 KiB
PHP
Raw Normal View History

2022-12-30 21:54:44 +01:00
<?php
declare(strict_types=1);
Merge alpha into master (async, huge bugfixes and more) (#546) * Implement async and lots of bugfixes * Implement more async * Implement async, implement bugfixes for the connection module, for the datacenter module, huge bugfixes, huge perfomance improvements, media DCs for https, advanced selecting, custom var_dump, totally rewritten IOLoop and response mechanism, promises, improvements to the TL parser, custom mb_substr * Apply fixes from StyleCI * Bugfixes * Apply fixes from StyleCI * Bugfixes, implement combined promises * Apply fixes from StyleCI * Support passing method arguments as callable * Starting to write async upload logic * Apply fixes from StyleCI * Start implementing async file upload * Apply fixes from StyleCI * bugfix * Apply fixes from StyleCI * Start rewriting connection module * Add PHP file docblocks for all classes * Start working on new async stream API * Finish writing stream API * More stream API fixes * Apply fixes from StyleCI * Rewrite DataCenter and Connection modules * Clean up stream API documentation * Fixes * Apply fixes from StyleCI * Add referenced parameter to get length of buffer to read in getReadBuffer API * Moved all MessageHandler code in the Connection module, added a PHP version warning in the phar * Start fixing reads * Fix all protocol stream wrappers * Apply fixes from StyleCI * Implement disconnection, and remove end function * Working async RPC * Implement async file upload * Bugfix * Method recall bugfixes * Bugfixes * Trait bugfixes * Fix FIFO buffer * Bugfixes and speedtests * Async logging * Implement websocket streams * Implement loop API, signal API, clean closing and start changing layer * Small magna, websocket and HTTP fixes * Clean up loop API * Improved stack traces, 2FA and async * Login fixes * Added instructions for manual verification * Small fixes * More app info improvements * More app info improvements * TL and 2FA fixes * Update to layer 89 * More bugfixes * Implement broken media reporting * Remove debug comments * PHP 7.2 backwards compatibility * Bugfixes * Async key generation * Some simplifications * Transport fixes * Cleanup * async API * Performance fixes * Fixes to async API * Bugfixes * Implement one-time async loop * Authorization and logging fixes * Update to layer 91 * 7to5 fix * Null coalesce conversion * Implement socks5 proxy * Implement HTTP proxy * Fixes to HTTP proxy * MTProxy and socks5 fixes * Disable PHP 5 conversion * Proxies have higher priority * Avoid error handling in vendor * Override composer dependencies * Fix travis build * Final composer fixes * Proxy logic fixes * Fix get_updates update handling * Do not use parallel file driver if not supported * Refactor loader and implement HTTP fixes * Suppress errors in loader * HTTP and authorization fixes * HTTP fixes * Improved peer management * Use HTTP protocol on altervista * Small bugfixes * Minor fixes * Docufix * Docufix * Legacy fixes * Fix message queue * Avoid updating if using MTProxy * Improve logs and examples * Trim final newlines while converting parse mode * Reimplement noResponse flag * Async combined event handler and APIFactory fixes * Actually return config * Case-insensitive methods * Bugfix * Apply fixes from StyleCI (#545) * MTProxy fixes * PHP 5 warning * Improved PHP 5 warning * Use <br> along with newlines in web logs * Update docs
2018-12-26 20:51:14 +01:00
/**
* API module.
*
* This file is part of MadelineProto.
* MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
* You should have received a copy of the GNU General Public License along with MadelineProto.
* If not, see <http://www.gnu.org/licenses/>.
*
* @author Daniil Gentili <daniil@daniil.it>
2023-01-04 12:43:01 +01:00
* @copyright 2016-2023 Daniil Gentili <daniil@daniil.it>
Merge alpha into master (async, huge bugfixes and more) (#546) * Implement async and lots of bugfixes * Implement more async * Implement async, implement bugfixes for the connection module, for the datacenter module, huge bugfixes, huge perfomance improvements, media DCs for https, advanced selecting, custom var_dump, totally rewritten IOLoop and response mechanism, promises, improvements to the TL parser, custom mb_substr * Apply fixes from StyleCI * Bugfixes * Apply fixes from StyleCI * Bugfixes, implement combined promises * Apply fixes from StyleCI * Support passing method arguments as callable * Starting to write async upload logic * Apply fixes from StyleCI * Start implementing async file upload * Apply fixes from StyleCI * bugfix * Apply fixes from StyleCI * Start rewriting connection module * Add PHP file docblocks for all classes * Start working on new async stream API * Finish writing stream API * More stream API fixes * Apply fixes from StyleCI * Rewrite DataCenter and Connection modules * Clean up stream API documentation * Fixes * Apply fixes from StyleCI * Add referenced parameter to get length of buffer to read in getReadBuffer API * Moved all MessageHandler code in the Connection module, added a PHP version warning in the phar * Start fixing reads * Fix all protocol stream wrappers * Apply fixes from StyleCI * Implement disconnection, and remove end function * Working async RPC * Implement async file upload * Bugfix * Method recall bugfixes * Bugfixes * Trait bugfixes * Fix FIFO buffer * Bugfixes and speedtests * Async logging * Implement websocket streams * Implement loop API, signal API, clean closing and start changing layer * Small magna, websocket and HTTP fixes * Clean up loop API * Improved stack traces, 2FA and async * Login fixes * Added instructions for manual verification * Small fixes * More app info improvements * More app info improvements * TL and 2FA fixes * Update to layer 89 * More bugfixes * Implement broken media reporting * Remove debug comments * PHP 7.2 backwards compatibility * Bugfixes * Async key generation * Some simplifications * Transport fixes * Cleanup * async API * Performance fixes * Fixes to async API * Bugfixes * Implement one-time async loop * Authorization and logging fixes * Update to layer 91 * 7to5 fix * Null coalesce conversion * Implement socks5 proxy * Implement HTTP proxy * Fixes to HTTP proxy * MTProxy and socks5 fixes * Disable PHP 5 conversion * Proxies have higher priority * Avoid error handling in vendor * Override composer dependencies * Fix travis build * Final composer fixes * Proxy logic fixes * Fix get_updates update handling * Do not use parallel file driver if not supported * Refactor loader and implement HTTP fixes * Suppress errors in loader * HTTP and authorization fixes * HTTP fixes * Improved peer management * Use HTTP protocol on altervista * Small bugfixes * Minor fixes * Docufix * Docufix * Legacy fixes * Fix message queue * Avoid updating if using MTProxy * Improve logs and examples * Trim final newlines while converting parse mode * Reimplement noResponse flag * Async combined event handler and APIFactory fixes * Actually return config * Case-insensitive methods * Bugfix * Apply fixes from StyleCI (#545) * MTProxy fixes * PHP 5 warning * Improved PHP 5 warning * Use <br> along with newlines in web logs * Update docs
2018-12-26 20:51:14 +01:00
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
2019-10-31 15:07:35 +01:00
* @link https://docs.madelineproto.xyz MadelineProto documentation
Merge alpha into master (async, huge bugfixes and more) (#546) * Implement async and lots of bugfixes * Implement more async * Implement async, implement bugfixes for the connection module, for the datacenter module, huge bugfixes, huge perfomance improvements, media DCs for https, advanced selecting, custom var_dump, totally rewritten IOLoop and response mechanism, promises, improvements to the TL parser, custom mb_substr * Apply fixes from StyleCI * Bugfixes * Apply fixes from StyleCI * Bugfixes, implement combined promises * Apply fixes from StyleCI * Support passing method arguments as callable * Starting to write async upload logic * Apply fixes from StyleCI * Start implementing async file upload * Apply fixes from StyleCI * bugfix * Apply fixes from StyleCI * Start rewriting connection module * Add PHP file docblocks for all classes * Start working on new async stream API * Finish writing stream API * More stream API fixes * Apply fixes from StyleCI * Rewrite DataCenter and Connection modules * Clean up stream API documentation * Fixes * Apply fixes from StyleCI * Add referenced parameter to get length of buffer to read in getReadBuffer API * Moved all MessageHandler code in the Connection module, added a PHP version warning in the phar * Start fixing reads * Fix all protocol stream wrappers * Apply fixes from StyleCI * Implement disconnection, and remove end function * Working async RPC * Implement async file upload * Bugfix * Method recall bugfixes * Bugfixes * Trait bugfixes * Fix FIFO buffer * Bugfixes and speedtests * Async logging * Implement websocket streams * Implement loop API, signal API, clean closing and start changing layer * Small magna, websocket and HTTP fixes * Clean up loop API * Improved stack traces, 2FA and async * Login fixes * Added instructions for manual verification * Small fixes * More app info improvements * More app info improvements * TL and 2FA fixes * Update to layer 89 * More bugfixes * Implement broken media reporting * Remove debug comments * PHP 7.2 backwards compatibility * Bugfixes * Async key generation * Some simplifications * Transport fixes * Cleanup * async API * Performance fixes * Fixes to async API * Bugfixes * Implement one-time async loop * Authorization and logging fixes * Update to layer 91 * 7to5 fix * Null coalesce conversion * Implement socks5 proxy * Implement HTTP proxy * Fixes to HTTP proxy * MTProxy and socks5 fixes * Disable PHP 5 conversion * Proxies have higher priority * Avoid error handling in vendor * Override composer dependencies * Fix travis build * Final composer fixes * Proxy logic fixes * Fix get_updates update handling * Do not use parallel file driver if not supported * Refactor loader and implement HTTP fixes * Suppress errors in loader * HTTP and authorization fixes * HTTP fixes * Improved peer management * Use HTTP protocol on altervista * Small bugfixes * Minor fixes * Docufix * Docufix * Legacy fixes * Fix message queue * Avoid updating if using MTProxy * Improve logs and examples * Trim final newlines while converting parse mode * Reimplement noResponse flag * Async combined event handler and APIFactory fixes * Actually return config * Case-insensitive methods * Bugfix * Apply fixes from StyleCI (#545) * MTProxy fixes * PHP 5 warning * Improved PHP 5 warning * Use <br> along with newlines in web logs * Update docs
2018-12-26 20:51:14 +01:00
*/
2018-02-25 17:50:03 +01:00
2016-08-07 23:23:10 +02:00
namespace danog\MadelineProto;
2016-08-08 18:10:28 +02:00
2023-01-11 18:47:27 +01:00
use Amp\CancelledException;
2022-12-30 20:24:13 +01:00
use Amp\DeferredFuture;
2023-01-15 16:12:12 +01:00
use Amp\Future;
use Amp\Future\UnhandledFutureError;
2020-09-22 23:10:56 +02:00
use Amp\Ipc\Sync\ChannelledSocket;
2023-01-15 16:12:12 +01:00
use Amp\SignalException;
2023-01-11 18:47:27 +01:00
use Amp\TimeoutException;
2022-12-30 19:21:36 +01:00
use danog\MadelineProto\ApiWrappers\Start;
2020-09-22 23:10:56 +02:00
use danog\MadelineProto\Ipc\Client;
use danog\MadelineProto\Ipc\Server;
2020-09-26 21:57:06 +02:00
use danog\MadelineProto\Settings\Ipc as SettingsIpc;
use danog\MadelineProto\Settings\Logger as SettingsLogger;
use Revolt\EventLoop;
2023-01-15 16:12:12 +01:00
use Revolt\EventLoop\UncaughtThrowable;
2022-12-30 19:21:36 +01:00
use Throwable;
use Webmozart\Assert\Assert;
2020-02-26 14:14:26 +01:00
2023-01-03 21:51:49 +01:00
use function Amp\async;
2023-01-11 18:47:27 +01:00
use function Amp\Future\await;
2023-02-12 14:09:36 +01:00
use function Amp\Future\awaitFirst;
2023-01-03 21:51:49 +01:00
2019-12-28 17:34:04 +01:00
/**
* Main API wrapper for MadelineProto.
*/
2023-01-27 14:20:47 +01:00
final class API extends AbstractAPI
2016-08-07 23:23:30 +02:00
{
2020-10-15 19:07:37 +02:00
/**
* Release version.
*
* @var string
*/
2024-06-13 17:15:41 +02:00
public const RELEASE = '8.1.1';
2020-10-15 19:07:37 +02:00
/**
2023-07-04 18:19:06 +02:00
* We're not logged in.
2020-10-15 19:07:37 +02:00
*
* @var int
*/
2023-07-04 18:19:06 +02:00
public const NOT_LOGGED_IN = 0;
2020-10-15 19:07:37 +02:00
/**
2023-07-04 18:19:06 +02:00
* We're waiting for the login code.
2020-10-15 19:07:37 +02:00
*
* @var int
*/
2023-07-04 18:19:06 +02:00
public const WAITING_CODE = 1;
2020-10-15 19:07:37 +02:00
/**
2023-07-04 18:19:06 +02:00
* We're waiting for parameters to sign up.
2020-10-15 19:07:37 +02:00
*
* @var int
*/
2023-07-04 18:19:06 +02:00
public const WAITING_SIGNUP = -1;
2020-10-15 19:07:37 +02:00
/**
2023-07-04 18:19:06 +02:00
* We're waiting for the 2FA password.
2020-10-15 19:07:37 +02:00
*
* @var int
*/
2023-07-04 18:19:06 +02:00
public const WAITING_PASSWORD = 2;
2020-10-15 19:07:37 +02:00
/**
2023-07-04 18:19:06 +02:00
* We're logged in.
2020-10-15 19:07:37 +02:00
*
* @var int
*/
2023-07-04 18:19:06 +02:00
public const LOGGED_IN = 3;
/**
* We're logged out, the session will be deleted ASAP.
*
* @var int
*/
public const LOGGED_OUT = 4;
2023-06-27 19:47:41 +02:00
/**
* This peer is a user.
*
* @var string
*/
2023-07-04 18:19:06 +02:00
public const PEER_TYPE_USER = 'user';
2023-06-27 19:47:41 +02:00
/**
* This peer is a bot.
*
* @var string
*/
2023-07-04 18:19:06 +02:00
public const PEER_TYPE_BOT = 'bot';
2023-06-27 19:47:41 +02:00
/**
* This peer is a normal group.
*
* @var string
*/
2023-07-04 18:19:06 +02:00
public const PEER_TYPE_GROUP = 'chat';
2023-06-27 19:47:41 +02:00
/**
* This peer is a supergroup.
*
* @var string
*/
2023-07-04 18:19:06 +02:00
public const PEER_TYPE_SUPERGROUP = 'supergroup';
2023-06-27 19:47:41 +02:00
/**
* This peer is a channel.
*
* @var string
*/
2023-07-04 18:19:06 +02:00
public const PEER_TYPE_CHANNEL = 'channel';
2023-07-01 18:22:27 +02:00
/**
* Whether to generate only peer information.
*/
2023-07-04 18:19:06 +02:00
public const INFO_TYPE_PEER = 0;
2023-07-01 18:22:27 +02:00
/**
* Whether to generate only constructor information.
*/
2023-07-04 18:19:06 +02:00
public const INFO_TYPE_CONSTRUCTOR = 1;
2023-07-01 18:22:27 +02:00
/**
* Whether to generate only ID information.
*/
2023-07-04 18:19:06 +02:00
public const INFO_TYPE_ID = 2;
2023-07-01 18:22:27 +02:00
/**
* Whether to generate all information.
*/
2023-07-04 18:19:06 +02:00
public const INFO_TYPE_ALL = 3;
2023-07-01 18:22:27 +02:00
/**
* Whether to generate all usernames.
*/
2023-07-04 18:19:06 +02:00
public const INFO_TYPE_USERNAMES = 4;
/**
* Whether to generate just type info.
*/
public const INFO_TYPE_TYPE = 5;
2023-07-01 18:22:27 +02:00
2022-12-30 19:21:36 +01:00
use Start;
/**
* Session paths.
*
* @internal
*/
2023-01-25 19:12:49 +01:00
private SessionPaths $session;
2020-09-24 20:49:34 +02:00
/**
* Unlock callback.
*
* @var ?callable
*/
private $unlock = null;
2023-06-13 21:30:02 +02:00
/**
* Obtain the API ID UI template.
*/
2023-01-25 19:12:49 +01:00
public function getWebAPITemplate(): string
{
return $this->wrapper->getWebApiTemplate();
}
2023-06-13 21:30:02 +02:00
/**
* Set the API ID UI template.
*/
2023-01-25 19:12:49 +01:00
public function setWebApiTemplate(string $template): void
{
$this->wrapper->setWebApiTemplate($template);
}
2019-12-28 17:34:04 +01:00
/**
2023-06-27 19:47:41 +02:00
* Constructor function.
2019-12-28 17:34:04 +01:00
*
2023-09-06 21:12:19 +02:00
* @param string $session Session name
2023-08-13 16:21:59 +02:00
* @param SettingsAbstract $settings Settings
2019-12-28 17:34:04 +01:00
*/
2023-08-13 16:21:59 +02:00
public function __construct(string $session, ?SettingsAbstract $settings = null)
2016-08-07 23:23:30 +02:00
{
2023-01-24 12:45:55 +01:00
Magic::start(light: true);
2023-08-13 16:21:59 +02:00
$settings ??= new SettingsEmpty;
$this->session = new SessionPaths($session);
2023-01-26 14:33:30 +01:00
$this->wrapper = new APIWrapper($this->session);
$this->exportNamespaces();
2023-01-03 22:07:58 +01:00
2020-09-24 11:45:20 +02:00
Logger::constructorFromSettings($settings instanceof Settings
? $settings->getLogger()
2020-09-26 21:57:06 +02:00
: ($settings instanceof SettingsLogger ? $settings : new SettingsLogger));
2020-09-24 11:45:20 +02:00
if ($this->connectToMadelineProto($settings)) {
if (!$settings instanceof SettingsEmpty) {
EventLoop::queue($this->updateSettings(...), $settings);
}
2020-09-24 11:45:20 +02:00
return; // OK
}
2021-05-12 20:43:55 +02:00
2020-09-24 11:45:20 +02:00
if (!$settings instanceof Settings) {
2020-09-26 21:57:06 +02:00
$newSettings = new Settings;
$newSettings->merge($settings);
$settings = $newSettings;
2020-09-24 11:45:20 +02:00
}
$appInfo = $settings->getAppInfo();
if (!$appInfo->hasApiInfo()) {
2023-05-27 18:35:31 +02:00
if (!$appInfo->getShowPrompt()) {
throw new Exception("No API ID or API hash was provided, please specify them in the settings!");
}
$app = $this->APIStart($settings);
2020-09-24 11:45:20 +02:00
if (!$app) {
die();
}
$appInfo->setApiId($app['api_id']);
$appInfo->setApiHash($app['api_hash']);
}
2023-01-25 19:12:49 +01:00
$this->wrapper->setAPI(new MTProto($settings, $this->wrapper));
2023-09-29 17:28:18 +02:00
$this->wrapper->logger('Prompting initial serialization...');
$this->wrapper->serialize();
$this->wrapper->logger('Done initial serialization!');
2023-01-25 19:12:49 +01:00
$this->wrapper->logger(Lang::$current_lang['madelineproto_ready'], Logger::NOTICE);
2020-09-24 11:45:20 +02:00
}
2020-09-24 23:25:54 +02:00
2020-09-24 20:49:34 +02:00
/**
* Reconnect to full instance.
*/
2023-01-27 14:20:47 +01:00
protected function reconnectFull(): bool
2020-09-24 20:49:34 +02:00
{
2023-01-25 19:12:49 +01:00
if ($this->wrapper->getAPI() instanceof Client) {
$this->wrapper->logger('Restarting to full instance...');
2021-04-07 19:28:42 +02:00
try {
if (!isset($_GET['MadelineSelfRestart']) && (($this->hasEventHandler()) || !($this->isIpcWorker()))) {
2023-01-25 19:12:49 +01:00
$this->wrapper->logger('Restarting to full instance: the bot is already running!');
2023-07-10 20:10:06 +02:00
Tools::closeConnection($this->getWebMessage(Lang::$current_lang['botAlreadyRunning']));
2021-04-07 20:20:46 +02:00
return false;
2021-04-07 19:28:42 +02:00
}
2023-01-25 19:12:49 +01:00
$this->wrapper->logger('Restarting to full instance: stopping IPC server...');
$this->wrapper->getAPI()->stopIpcServer();
2023-01-15 16:12:12 +01:00
} catch (SecurityException|SignalException $e) {
2021-12-03 18:15:56 +01:00
throw $e;
2022-12-30 19:21:36 +01:00
} catch (Throwable $e) {
2023-01-15 16:12:12 +01:00
if ($e instanceof UncaughtThrowable) {
$e = $e->getPrevious();
if ($e instanceof SecurityException || $e instanceof SignalException) {
throw $e;
}
}
2023-01-25 19:12:49 +01:00
$this->wrapper->logger("Restarting to full instance: error $e");
2021-04-07 17:28:34 +02:00
}
2023-01-25 19:12:49 +01:00
$this->wrapper->logger('Restarting to full instance: reconnecting...');
2022-12-30 20:24:13 +01:00
$cancel = new DeferredFuture;
2023-01-03 22:07:58 +01:00
$cb = function () use ($cancel, &$cb): void {
[$result] = Serialization::tryConnect($this->session->getIpcPath(), $cancel->getFuture());
2021-04-18 16:02:59 +02:00
if ($result instanceof ChannelledSocket) {
try {
2023-01-25 19:12:49 +01:00
if (!$this->wrapper->getAPI() instanceof Client) {
$this->wrapper->logger('Restarting to full instance (again): the bot is already running!');
$result->disconnect();
2021-05-03 23:51:11 +02:00
return;
}
2023-01-25 19:12:49 +01:00
$this->wrapper->logger('Restarting to full instance (again): sending shutdown signal!');
$result->send(Server::SHUTDOWN);
$result->disconnect();
2023-01-15 16:12:12 +01:00
} catch (SecurityException|SignalException $e) {
2021-12-03 18:15:56 +01:00
throw $e;
2022-12-30 19:21:36 +01:00
} catch (Throwable $e) {
2023-01-15 16:12:12 +01:00
if ($e instanceof UncaughtThrowable) {
$e = $e->getPrevious();
if ($e instanceof SecurityException || $e instanceof SignalException) {
throw $e;
}
}
2023-01-25 19:12:49 +01:00
$this->wrapper->logger("Restarting to full instance: error in stop loop $e");
2021-04-18 16:02:59 +02:00
}
EventLoop::queue($cb);
2021-04-18 16:02:59 +02:00
}
};
EventLoop::queue($cb);
$this->connectToMadelineProto(new SettingsEmpty, true);
2023-01-22 17:52:44 +01:00
$cancel->complete(new Exception('Connected!'));
2020-09-24 20:49:34 +02:00
}
2021-04-07 20:20:46 +02:00
return true;
2020-09-24 20:49:34 +02:00
}
2020-09-24 11:45:20 +02:00
/**
* Connect to MadelineProto.
*
2023-09-06 21:12:19 +02:00
* @param SettingsAbstract $settings Settings
* @param bool $forceFull Whether to force full initialization
2020-09-24 11:45:20 +02:00
*/
2023-01-11 18:47:27 +01:00
protected function connectToMadelineProto(SettingsAbstract $settings, bool $forceFull = false, bool $tryReconnect = true): bool
2020-09-24 11:45:20 +02:00
{
2020-09-26 21:57:06 +02:00
if ($settings instanceof SettingsIpc) {
2021-04-23 14:21:47 +02:00
$forceFull = $forceFull || $settings->getSlow();
2020-09-24 11:45:20 +02:00
} elseif ($settings instanceof Settings) {
2021-04-23 14:21:47 +02:00
$forceFull = $forceFull || $settings->getIpc()->getSlow();
2020-09-24 11:45:20 +02:00
}
2021-09-25 14:02:12 +02:00
$forceFull = $forceFull || isset($_GET['MadelineSelfRestart']) || Magic::$altervista;
2023-01-11 18:47:27 +01:00
try {
[$unserialized, $this->unlock] = async(
Serialization::unserialize(...),
$this->session,
$settings,
$forceFull
2023-07-25 19:12:54 +02:00
)->await(Tools::getTimeoutCancellation(30.0));
2023-01-11 18:47:27 +01:00
} catch (CancelledException $e) {
if (!$e->getPrevious() instanceof TimeoutException) {
throw $e;
}
[$unserialized, $this->unlock] = [0, null];
}
2020-10-04 14:55:05 +02:00
2020-09-24 11:45:20 +02:00
if ($unserialized === 0) {
// Timeout
throw new Exception(Lang::$current_lang['could_not_connect_to_MadelineProto']);
2022-12-30 19:21:36 +01:00
} elseif ($unserialized instanceof Throwable) {
// IPC server error
throw $unserialized;
2020-09-24 11:45:20 +02:00
} elseif ($unserialized instanceof ChannelledSocket) {
// Success, IPC client
2023-01-25 19:12:49 +01:00
$this->wrapper->setAPI(new Client($unserialized, $this->session, Logger::$default));
2020-09-24 11:45:20 +02:00
return true;
2020-09-22 23:10:56 +02:00
} elseif ($unserialized) {
2020-09-24 11:45:20 +02:00
// Success, full session
2023-01-26 14:33:30 +01:00
$this->wrapper->getAPI()?->unreference();
$this->wrapper = $unserialized;
$this->wrapper->setSession($this->session);
$this->exportNamespaces();
2023-01-25 19:12:49 +01:00
if ($this->wrapper->getAPI()) {
unset($unserialized);
2020-02-26 11:47:30 +01:00
2020-09-26 21:57:06 +02:00
if ($settings instanceof SettingsIpc) {
2020-09-24 11:45:20 +02:00
$settings = new SettingsEmpty;
}
2023-01-25 19:12:49 +01:00
$this->wrapper->getAPI()->wakeup($settings, $this->wrapper);
$this->wrapper->logger(Lang::$current_lang['madelineproto_ready'], Logger::NOTICE);
2020-09-24 11:45:20 +02:00
return true;
2017-11-08 13:04:40 +01:00
}
}
2020-09-24 11:45:20 +02:00
return false;
}
2020-03-07 21:45:50 +01:00
/**
* Wakeup function.
*/
public function __wakeup(): void
{
2023-05-26 21:42:02 +02:00
$this->__construct($this->session->getSessionDirectoryPath());
2020-03-07 21:45:50 +01:00
}
2023-04-03 12:07:27 +02:00
public function __sleep(): array
{
2023-05-26 21:42:02 +02:00
return ['session'];
2023-04-03 12:07:27 +02:00
}
2023-01-15 16:12:12 +01:00
/**
* @var array<Future<null>>
*/
private static array $destructors = [];
/**
* @internal
*/
public static function finalize(): void
{
2023-01-25 15:53:28 +01:00
if (self::$destructors) {
await(self::$destructors);
}
2023-01-15 16:12:12 +01:00
}
2019-12-28 17:34:04 +01:00
/**
* Destruct function.
*
* @internal
*/
2017-04-21 13:14:21 +02:00
public function __destruct()
{
2023-01-25 19:12:49 +01:00
$id = \count(self::$destructors);
self::$destructors[$id] = async(function () use ($id): void {
$this->wrapper->logger('Shutting down MadelineProto ('.static::class.')');
2023-01-26 19:57:50 +01:00
$this->wrapper->getAPI()?->unreference();
2023-01-25 19:12:49 +01:00
if (isset($this->wrapper)) {
$this->wrapper->logger('Prompting final serialization...');
$this->wrapper->serialize();
$this->wrapper->logger('Done final serialization!');
}
if ($this->unlock) {
($this->unlock)();
}
unset(self::$destructors[$id]);
});
2016-08-07 23:23:10 +02:00
}
2020-02-26 14:14:26 +01:00
/**
2020-02-26 15:15:37 +01:00
* Start multiple instances of MadelineProto and the event handlers (enables async).
2020-02-26 14:14:26 +01:00
*
2023-09-06 21:12:19 +02:00
* @param array<API> $instances Instances of madeline
* @param array<class-string<EventHandler>>|class-string<EventHandler> $eventHandler Event handler(s)
2020-02-26 14:14:26 +01:00
*/
2023-01-04 15:13:55 +01:00
public static function startAndLoopMulti(array $instances, array|string $eventHandler): void
2020-02-26 14:14:26 +01:00
{
2020-02-26 15:15:37 +01:00
if (\is_string($eventHandler)) {
Assert::classExists($eventHandler);
2023-07-16 23:25:18 +02:00
$eventHandler::cachePlugins($eventHandler);
2023-10-01 20:05:04 +02:00
$eventHandler = array_fill_keys(array_keys($instances), $eventHandler);
} else {
Assert::notEmpty($eventHandler);
Assert::allClassExists($eventHandler);
2023-07-18 15:44:09 +02:00
foreach ($eventHandler as $c) {
$c::cachePlugins($c);
}
2020-02-26 15:15:37 +01:00
}
$errors = [];
2023-10-01 20:05:04 +02:00
$started = array_fill_keys(array_keys($instances), false);
$instanceOne = array_values($instances)[0];
2023-01-26 14:33:30 +01:00
$prev = EventLoop::getErrorHandler();
EventLoop::setErrorHandler(
2023-11-11 16:55:29 +01:00
$cb = static function (Throwable $e) use ($instanceOne, &$errors, &$started, $eventHandler): void {
if ($e instanceof UnhandledFutureError) {
2023-01-15 16:12:12 +01:00
$e = $e->getPrevious();
}
if ($e instanceof SecurityException || $e instanceof SignalException) {
throw $e;
}
2023-10-01 20:05:04 +02:00
if (str_starts_with($e->getMessage(), 'Could not connect to DC ')) {
throw $e;
2023-01-15 16:12:12 +01:00
}
2023-10-01 20:05:04 +02:00
$t = time();
$errors = [$t => $errors[$t] ?? 0];
$errors[$t]++;
2023-10-01 20:05:04 +02:00
if ($errors[$t] > 10 && array_sum($started) !== \count($eventHandler)) {
2023-01-25 19:12:49 +01:00
$instanceOne->wrapper->logger('More than 10 errors in a second and not inited, exiting!', Logger::FATAL_ERROR);
return;
}
echo $e;
2023-01-25 19:12:49 +01:00
$instanceOne->wrapper->logger((string) $e, Logger::FATAL_ERROR);
2020-02-26 15:15:37 +01:00
$instanceOne->report("Surfaced: $e");
}
);
try {
$promises = [];
foreach ($instances as $k => $instance) {
$instance->start();
2023-11-11 16:55:29 +01:00
$promises []= async(static function () use ($k, $instance, $eventHandler, &$started): void {
$instance->startAndLoopLogic($eventHandler[$k], $started[$k]);
});
}
2023-02-12 14:09:36 +01:00
awaitFirst($promises);
} finally {
if (EventLoop::getErrorHandler() === $cb) {
EventLoop::setErrorHandler($prev);
}
2021-04-07 20:20:46 +02:00
}
2020-06-20 13:03:15 +02:00
}
2018-02-25 17:50:03 +01:00
}