This commit is contained in:
Daniil Gentili 2019-10-31 15:06:25 +01:00
parent eab16c2ed7
commit 612ec4cbe7
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
16 changed files with 850 additions and 406 deletions

View File

@ -66,12 +66,17 @@
}
],
"scripts": {
"build": [
"@docs",
"@cs-fix"
],
"check": [
"@cs",
"@test"
],
"cs": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix -v --diff --dry-run",
"cs-fix": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix -v --diff",
"docs": "php tools/build_docs.php",
"test": "@php -dzend.assertions=1 -dassert.exception=1 ./vendor/bin/phpunit --coverage-text"
}
}

View File

@ -19,6 +19,8 @@
namespace danog\MadelineProto\DocsBuilder;
use danog\MadelineProto\Tools;
trait Constructors
{
public function mkConstructors()
@ -64,7 +66,7 @@ trait Constructors
$param['type'] = 'DecryptedMessage';
}
$type_or_subtype = isset($param['subtype']) ? 'subtype' : 'type';
$type_or_bare_type = \ctype_upper($this->end(\explode('.', $param[$type_or_subtype]))[0]) || \in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int53', 'int', 'long', 'int128', 'int256', 'int512']) ? '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', 'int53', 'int', 'long', 'int128', 'int256', 'int512']) ? 'types' : 'constructors';
$param[$type_or_subtype] = \str_replace(['.', 'true', 'false'], ['_', 'Bool', 'Bool'], $param[$type_or_subtype]);
if (\preg_match('/%/', $param[$type_or_subtype])) {
$param[$type_or_subtype] = $this->constructors->findByType(\str_replace('%', '', $param[$type_or_subtype]))['predicate'];
@ -73,7 +75,7 @@ trait Constructors
$param[$type_or_subtype] = \substr($param[$type_or_subtype], 0, -1);
}
$params .= "'".$param['name']."' => ";
$param[$type_or_subtype] = '['.$this->escape($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]).', ';
}
$md_constructor = \str_replace('_', '\\_', $constructor.$layer);
@ -126,7 +128,7 @@ trait Constructors
if (\preg_match('/%/', $ptype)) {
$ptype = $this->constructors->findByType(\str_replace('%', '', $ptype))['predicate'];
}
$type_or_bare_type = (\ctype_upper($this->end(\explode('_', $ptype))[0]) || \in_array($ptype, ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int53', 'int', 'long', 'int128', 'int256', 'int512'])) && $ptype !== 'MTmessage' ? 'types' : 'constructors';
$type_or_bare_type = (\ctype_upper(Tools::end(\explode('_', $ptype))[0]) || \in_array($ptype, ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int53', 'int', 'long', 'int128', 'int256', 'int512'])) && $ptype !== 'MTmessage' ? 'types' : 'constructors';
if (\substr($ptype, -1) === '>') {
$ptype = \substr($ptype, 0, -1);
}

View File

@ -19,6 +19,8 @@
namespace danog\MadelineProto\DocsBuilder;
use danog\MadelineProto\Tools;
trait Methods
{
public function mkMethods()
@ -76,9 +78,9 @@ trait Methods
$param['type'] = 'InputPeer';
}
$type_or_subtype = isset($param['subtype']) ? 'subtype' : 'type';
$type_or_bare_type = \ctype_upper($this->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] = '['.$this->escape($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]).', ';
}
if (!isset($this->td_descriptions['methods'][$data['method']])) {
@ -159,7 +161,7 @@ trait Methods
if (\in_array($ptype, ['InputEncryptedFile']) && !isset($this->settings['td'])) {
$human_ptype = 'File path or '.$ptype;
}
$type_or_bare_type = \ctype_upper($this->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']])) {
$this->addToLang('method_'.$data['method'].'_param_'.$param['name'].'_type_'.$param['type']);
if (isset($this->td_descriptions['methods'][$data['method']]['description'])) {

View File

@ -19,9 +19,17 @@
namespace danog\MadelineProto;
/**
* Event handler
*/
class EventHandler extends InternalDoc
{
public function __construct($MadelineProto)
/**
* Constructor
*
* @param API|null $MadelineProto MadelineProto instance
*/
public function __construct(?API $MadelineProto)
{
if (!$MadelineProto) {
return;

View File

@ -4018,40 +4018,57 @@ interface folders
class InternalDoc extends APIFactory
{
public function logger($param, $level = \danog\MadelineProto\Logger::NOTICE, $file = null, array $extra = [])
/**
* Cleanup memory and session file.
*
* @return void
*/
public function cleanup(array $extra = [])
{
return $this->__call(__FUNCTION__, [$extra]);
}
/**
* Logger.
*
* @param string $param Parameter
* @param int $level Logging level
* @param string $file File where the message originated
*
* @return void
*/
public function logger($param, int $level = \danog\MadelineProto\Logger::NOTICE, string $file = '', array $extra = [])
{
return $this->__call(__FUNCTION__, [$param, $level, $file, $extra]);
}
public function isAltervista(array $extra = [])
/**
* Get async HTTP client.
*
* @return \Amp\Artax\Client
*/
public function getHTTPClient(array $extra = []): Amp\Artax\Client
{
return $this->__call(__FUNCTION__, [$extra]);
}
public function isInitingAuthorization(array $extra = [])
/**
* Get async DNS client.
*
* @return \Amp\Dns\Resolver
*/
public function getDNSClient(array $extra = []): Amp\Dns\Resolver
{
return $this->__call(__FUNCTION__, [$extra]);
}
public function getHTTPClient(array $extra = [])
{
return $this->__call(__FUNCTION__, [$extra]);
}
public function getDNSClient(array $extra = [])
{
return $this->__call(__FUNCTION__, [$extra]);
}
public function fileGetContents($url, array $extra = [])
/**
* Get contents of remote file asynchronously.
*
* @param string $url URL
*
* @return \Generator<string>
*/
public function fileGetContents(string $url, array $extra = [])
{
return $this->__call(__FUNCTION__, [$url, $extra]);
}
public function testing(callable $a, ?string $b = null, $c = null, $d = 2, $e = \danog\MadelineProto\MTProto::METHOD_BEFORE_CALLBACK, array $extra = []): ?string
{
return $this->__call(__FUNCTION__, [$a, $b, $c, $d, $e, $extra]);
}
/**
* Get all datacenter connections.
*
@ -4062,32 +4079,39 @@ class InternalDoc extends APIFactory
return $this->__call(__FUNCTION__, [$extra]);
}
public function hasAllAuth(array $extra = [])
public function hasAllAuth(array $extra = []): bool
{
return $this->__call(__FUNCTION__, [$extra]);
}
public function startLoops(array $extra = [])
{
return $this->__call(__FUNCTION__, [$extra]);
}
public function stopLoops(array $extra = [])
{
return $this->__call(__FUNCTION__, [$extra]);
}
public function getSettings($settings, $previousSettings = [
], array $extra = [])
/**
* Get correct settings array for the latest version.
*
* @param array $settings Current settings array
* @param array $previousSettings Previous settings array
*
* @return array
*/
public function getSettings(array $settings, array $previousSettings = [
], array $extra = []): array
{
return $this->__call(__FUNCTION__, [$settings, $previousSettings, $extra]);
}
public function parseSettings($settings, array $extra = [])
/**
* Parse and store settings.
*
* @param array $settings Settings
*
* @return void
*/
public function parseSettings(array $settings, array $extra = [])
{
return $this->__call(__FUNCTION__, [$settings, $extra]);
}
/**
* Setup logger.
*
* @return void
*/
public function setupLogger(array $extra = [])
{
return $this->__call(__FUNCTION__, [$extra]);
@ -4111,63 +4135,105 @@ class InternalDoc extends APIFactory
*
* @return boolean
*/
public function isHttp(string $datacenter, array $extra = [])
public function isHttp(string $datacenter, array $extra = []): bool
{
return $this->__call(__FUNCTION__, [$datacenter, $extra]);
}
public function isInitingAuthorization(array $extra = [])
{
return $this->__call(__FUNCTION__, [$extra]);
}
/**
* Connects to all datacenters and if necessary creates authorization keys, binds them and writes client info.
*
* @param boolean $reconnectAll Whether to reconnect to all DCs
*
* @return \Generator
*/
public function connectToAllDcs(bool $reconnectAll = true, array $extra = [])
{
return $this->__call(__FUNCTION__, [$reconnectAll, $extra]);
}
/**
* Clean up MadelineProto session after logout.
*
* @return void
*/
public function resetSession(array $extra = [])
{
return $this->__call(__FUNCTION__, [$extra]);
}
/**
* Reset the update state and fetch all updates from the beginning.
*
* @return void
*/
public function resetUpdateState(array $extra = [])
{
return $this->__call(__FUNCTION__, [$extra]);
}
/**
* Start the update system.
*
* @param boolean $anyway Force start update system?
*
* @return void
*/
public function startUpdateSystem($anyway = false, array $extra = [])
{
return $this->__call(__FUNCTION__, [$anyway, $extra]);
}
/**
* Store shared phone config.
*
* @param mixed $watcherId Watcher ID
*
* @return void
*/
public function getPhoneConfig($watcherId = null, array $extra = [])
{
return $this->__call(__FUNCTION__, [$watcherId, $extra]);
}
public function getCdnConfig($datacenter, array $extra = [])
/**
* Store RSA keys for CDN datacenters.
*
* @param string $datacenter DC ID
*
* @return \Generator
*/
public function getCdnConfig(string $datacenter, array $extra = [])
{
return $this->__call(__FUNCTION__, [$datacenter, $extra]);
}
public function getCachedConfig(array $extra = [])
/**
* Get cached server-side config.
*
* @return array
*/
public function getCachedConfig(array $extra = []): array
{
return $this->__call(__FUNCTION__, [$extra]);
}
public function getConfig($config = [
], $options = [
/**
* Get cached (or eventually re-fetch) server-side config.
*
* @param array $config Current config
* @param array $options Options for method call
*
* @return \Generator
*/
public function getConfig(array $config = [
], array $options = [
], array $extra = [])
{
return $this->__call(__FUNCTION__, [$config, $options, $extra]);
}
public function parseConfig(array $extra = [])
{
return $this->__call(__FUNCTION__, [$extra]);
}
public function parseDcOptions($dc_options, array $extra = [])
{
return $this->__call(__FUNCTION__, [$dc_options, $extra]);
}
/**
* Get info about the logged-in user.
*
* @return \Generator<array>
*/
public function getSelf(array $extra = [])
{
return $this->__call(__FUNCTION__, [$extra]);
@ -4990,82 +5056,186 @@ class InternalDoc extends APIFactory
{
return $this->__call(__FUNCTION__, [$value, $extra]);
}
public function packSignedInt($value, array $extra = [])
/**
* Convert integer to base256 signed int.
*
* @param integer $value Value to convert
*
* @return string
*/
public function packSignedInt(int $value, array $extra = []): string
{
return $this->__call(__FUNCTION__, [$value, $extra]);
}
public function packSignedLong($value, array $extra = [])
/**
* Convert integer to base256 long.
*
* @param int $value Value to convert
*
* @return string
*/
public function packSignedLong(int $value, array $extra = []): string
{
return $this->__call(__FUNCTION__, [$value, $extra]);
}
public function packUnsignedInt($value, array $extra = [])
/**
* Convert value to unsigned base256 int.
*
* @param int $value Value
*
* @return string
*/
public function packUnsignedInt(int $value, array $extra = []): string
{
return $this->__call(__FUNCTION__, [$value, $extra]);
}
public function packDouble($value, array $extra = [])
/**
* Convert double to binary version.
*
* @param double $value Value to convert
*
* @return string
*/
public function packDouble(\danog\MadelineProto\double $value, array $extra = []): string
{
return $this->__call(__FUNCTION__, [$value, $extra]);
}
public function unpackDouble($value, array $extra = [])
/**
* Unpack binary double.
*
* @param string $value Value to unpack
*
* @return double
*/
public function unpackDouble(string $value, array $extra = []): danog\MadelineProto\double
{
return $this->__call(__FUNCTION__, [$value, $extra]);
}
/**
* Synchronously wait for a promise|generator.
*
* @param \Generator|Promise $promise The promise to wait for
* @param boolean $ignoreSignal Whether to ignore shutdown signals
*
* @return mixed
*/
public function wait($promise, $ignoreSignal = false, array $extra = [])
{
return $this->__call(__FUNCTION__, [$promise, $ignoreSignal, $extra]);
}
public function all($promises, array $extra = [])
/**
* Returns a promise that succeeds when all promises succeed, and fails if any promise fails.
* Returned promise succeeds with an array of values used to succeed each contained promise, with keys corresponding to the array of promises.
*
* @param array<\Generator|Promise> $promises Promises
*
* @return Promise
*/
public function all(array $promises, array $extra = [])
{
return $this->__call(__FUNCTION__, [$promises, $extra]);
}
public function any($promises, array $extra = [])
/**
* Returns a promise that is resolved when all promises are resolved. The returned promise will not fail.
*
* @param array<Promise|\Generator> $promises Promises
*
* @return Promise
*/
public function any(array $promises, array $extra = [])
{
return $this->__call(__FUNCTION__, [$promises, $extra]);
}
public function some($promises, array $extra = [])
/**
* Resolves with a two-item array delineating successful and failed Promise results.
* The returned promise will only fail if the given number of required promises fail.
*
* @param array<Promise|\Generator> $promises Promises
*
* @return Promise
*/
public function some(array $promises, array $extra = [])
{
return $this->__call(__FUNCTION__, [$promises, $extra]);
}
public function first($promises, array $extra = [])
/**
* Returns a promise that succeeds when the first promise succeeds, and fails only if all promises fail.
*
* @param array<Promise|\Generator> $promises Promises
*
* @return Promise
*/
public function first(array $promises, array $extra = [])
{
return $this->__call(__FUNCTION__, [$promises, $extra]);
}
public function timeout($promise, $timeout, array $extra = [])
/**
* Create an artificial timeout for any \Generator or Promise.
*
* @param \Generator|Promise $promise
* @param integer $timeout
*
* @return Promise
*/
public function timeout($promise, int $timeout, array $extra = [])
{
return $this->__call(__FUNCTION__, [$promise, $timeout, $extra]);
}
/**
* Convert generator, promise or any other value to a promise.
*
* @param \Generator|Promise|mixed $promise
*
* @return Promise
*/
public function call($promise, array $extra = [])
{
return $this->__call(__FUNCTION__, [$promise, $extra]);
}
/**
* Call promise in background.
*
* @param \Generator|Promise $promise Promise to resolve
* @param ?\Generator|Promise $actual Promise to resolve instead of $promise
* @param string $file File
*
* @return void
*/
public function callFork($promise, $actual = null, $file = '', array $extra = [])
{
return $this->__call(__FUNCTION__, [$promise, $actual, $file, $extra]);
}
/**
* Call promise in background, deferring execution.
*
* @param \Generator|Promise $promise Promise to resolve
*
* @return void
*/
public function callForkDefer($promise, array $extra = [])
{
return $this->__call(__FUNCTION__, [$promise, $extra]);
}
public function rethrow($e, $file = '', array $extra = [])
/**
* Rethrow error catched in strand.
*
* @param \Throwable $e Exception
* @param string $file File where the strand started
*
* @return void
*/
public function rethrow(\Throwable $e, $file = '', array $extra = [])
{
return $this->__call(__FUNCTION__, [$e, $file, $extra]);
}
/**
* Call promise $b after promise $a.
*
* @param \Generator|Promise $a Promise A
* @param \Generator|Promise $b Promise B
*
* @return Promise
*/
public function after($a, $b, array $extra = [])
{
return $this->__call(__FUNCTION__, [$a, $b, $extra]);
@ -5241,6 +5411,37 @@ class InternalDoc extends APIFactory
{
return $this->__call(__FUNCTION__, [$string, $extra]);
}
/**
* Get final element of array.
*
* @param array $what Array
*
* @return mixed
*/
public function end(array $what, array $extra = [])
{
return $this->__call(__FUNCTION__, [$what, $extra]);
}
/**
* Escape string for markdown.
*
* @param string $hwat String to escape
*
* @return void
*/
public function markdownEscape(string $hwat, array $extra = []): string
{
return $this->__call(__FUNCTION__, [$hwat, $extra]);
}
/**
* Whether this is altervista.
*
* @return boolean
*/
public function isAltervista(array $extra = []): bool
{
return $this->__call(__FUNCTION__, [$extra]);
}
public function requestCall($user, array $extra = [])
{

View File

@ -25,7 +25,7 @@ use function Amp\ByteStream\getStderr;
use function Amp\ByteStream\getStdout;
/**
* Logger class
* Logger class.
*/
class Logger
{
@ -37,50 +37,50 @@ class Logger
const RESET = ['all' => 0, 'bold' => 21, 'dim' => 22, 'underlined' => 24, 'blink' => 25, 'reverse' => 26, 'hidden' => 28];
/**
* Logging mode
* Logging mode.
*
* @var integer
*/
public $mode = 0;
/**
* Optional logger parameter
* Optional logger parameter.
*
* @var mixed
*/
public $optional = null;
/**
* Logger prefix
* Logger prefix.
*
* @var string
*/
public $prefix = '';
/**
* Logging level
* Logging level.
*
* @var integer
*/
public $level = self::NOTICE;
/**
* Logging colors
* Logging colors.
*
* @var array
*/
public $colors = [];
/**
* Newline
* Newline.
*
* @var string
*/
public $newline = "\n";
/**
* Default logger instance
* Default logger instance.
*
* @var self
*/
public static $default;
/**
* Whether the AGPL notice was printed
* Whether the AGPL notice was printed.
*
* @var boolean
*/
@ -103,7 +103,7 @@ class Logger
* Construct global static logger from MadelineProto settings.
*
* @param array $settings Settings array
*
*
* @return void
*/
public static function constructorFromSettings(array $settings)
@ -118,7 +118,7 @@ class Logger
*
* @param array $settings Settings array
* @param string $prefix Optional prefix for log messages
*
*
* @return self
*/
public static function getLoggerFromSettings(array $settings, string $prefix = ''): self
@ -159,11 +159,11 @@ class Logger
* Construct global logger.
*
* @param int $mode One of the logger constants
* @param mixed $optional Optional parameter for logger
* @param mixed $optional Optional parameter for logger
* @param string $prefix Prefix for log messages
* @param int $level Default logging level
* @param int $max_size Maximum size for logfile
*
*
* @return void
*/
public static function constructor(int $mode, $optional = null, string $prefix = '', int $level = self::NOTICE, int $max_size = 100 * 1024 * 1024)
@ -175,11 +175,11 @@ class Logger
* Construct global logger.
*
* @param int $mode One of the logger constants
* @param mixed $optional Optional parameter for logger
* @param mixed $optional Optional parameter for logger
* @param string $prefix Prefix for log messages
* @param int $level Default logging level
* @param int $max_size Maximum size for logfile
*
*
* @return void
*/
public function __construct(int $mode, $optional = null, string $prefix = '', int $level = self::NOTICE, int $max_size = 100 * 1024 * 1024)
@ -232,11 +232,11 @@ class Logger
}
/**
* Log a message
* Log a message.
*
* @param mixed $param Message
* @param int $level Logging level
*
*
* @return void
*/
public static function log($param, int $level = self::NOTICE)
@ -249,12 +249,12 @@ class Logger
}
/**
* Log a message
* Log a message.
*
* @param mixed $param Message to log
* @param int $level Logging level
* @param int $level Logging level
* @param string $file File that originated the message
*
*
* @return void
*/
public function logger($param, int $level = self::NOTICE, string $file = '')

View File

@ -244,7 +244,7 @@ class MTProto extends AsyncConstruct implements TLCallback
/**
* Authorization info (User).
*
* @var [type]
* @var array|null
*/
public $authorization = null;
/**
@ -413,7 +413,7 @@ class MTProto extends AsyncConstruct implements TLCallback
public $datacenter;
/**
* Logger instance
* Logger instance.
*
* @var Logger
*/
@ -440,32 +440,13 @@ class MTProto extends AsyncConstruct implements TLCallback
*/
public function __construct_async($settings = [])
{
\danog\MadelineProto\Magic::classExists();
// Parse settings
Magic::classExists();
// Parse and store settings
$this->parseSettings($settings);
// Connect to servers
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['inst_dc'], Logger::ULTRA_VERBOSE);
if (!($this->channels_state instanceof CombinedUpdatesState)) {
$this->channels_state = new CombinedUpdatesState($this->channels_state);
}
if (isset($this->updates_state)) {
if (!($this->updates_state instanceof UpdatesState)) {
$this->updates_state = new UpdatesState($this->updates_state);
}
$this->channels_state->__construct([false => $this->updates_state]);
unset($this->updates_state);
}
if (!isset($this->datacenter)) {
$this->datacenter = new DataCenter($this, $this->settings['connection'], $this->settings['connection_settings']);
}
if (!isset($this->referenceDatabase)) {
$this->referenceDatabase = new ReferenceDatabase($this);
}
if (!isset($this->minDatabase)) {
$this->minDatabase = new MinDatabase($this);
}
$this->logger->logger(Lang::$current_lang['inst_dc'], Logger::ULTRA_VERBOSE);
$this->cleanupProperties();
// Load rsa keys
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['load_rsa'], Logger::ULTRA_VERBOSE);
$this->logger->logger(Lang::$current_lang['load_rsa'], Logger::ULTRA_VERBOSE);
$this->rsa_keys = [];
foreach ($this->settings['authorization']['rsa_keys'] as $key) {
$key = yield (new RSA())->load($key);
@ -475,7 +456,7 @@ class MTProto extends AsyncConstruct implements TLCallback
* ***********************************************************************
* Define some needed numbers for BigInteger
*/
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['TL_translation'], Logger::ULTRA_VERBOSE);
$this->logger->logger(Lang::$current_lang['TL_translation'], Logger::ULTRA_VERBOSE);
$callbacks = [$this, $this->referenceDatabase];
if (!($this->authorization['user']['bot'] ?? false)) {
$callbacks []= $this->minDatabase;
@ -487,7 +468,7 @@ class MTProto extends AsyncConstruct implements TLCallback
if ((!isset($this->authorization['user']['bot']) || !$this->authorization['user']['bot']) && $this->datacenter->getDataCenterConnection($this->datacenter->curdc)->hasTempAuthKey()) {
try {
$nearest_dc = yield $this->methodCallAsyncRead('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);
$this->logger->logger(\sprintf(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'];
}
@ -503,7 +484,7 @@ class MTProto extends AsyncConstruct implements TLCallback
}
/**
* Sleep function
* Sleep function.
*
* @return array
*/
@ -512,7 +493,74 @@ class MTProto extends AsyncConstruct implements TLCallback
if ($this->settings['serialization']['cleanup_before_serialization']) {
$this->cleanup();
}
return ['supportUser', 'referenceDatabase', 'minDatabase', 'channel_participants', 'event_handler', 'event_handler_instance', 'loop_callback', 'web_template', 'encrypted_layer', 'settings', 'config', 'authorization', 'authorized', 'rsa_keys', 'dh_config', 'chats', 'last_stored', 'qres', 'got_state', 'channels_state', 'updates', 'updates_key', 'full_chats', 'msg_ids', 'dialog_params', 'datacenter', 'v', 'constructors', 'td_constructors', 'methods', 'td_methods', 'td_descriptions', 'tl_callbacks', 'temp_requested_secret_chats', 'temp_rekeyed_secret_chats', 'secret_chats', 'hook_url', 'storage', 'authorized_dc', 'tos'];
return [
// Databases
'chats',
'full_chats',
'referenceDatabase',
'minDatabase',
'channel_participants',
// Misc caching
'dialog_params',
'last_stored',
'qres',
'supportUser',
'tos',
// Event handler
'event_handler',
'event_handler_instance',
'loop_callback',
'updates',
'updates_key',
'hook_url',
// Web login template
'web_template',
// Settings
'settings',
'config',
// Authorization keys
'datacenter',
// Authorization state
'authorization',
'authorized',
'authorized_dc',
// Authorization cache
'rsa_keys',
'dh_config',
// Update state
'got_state',
'channels_state',
'msg_ids',
// Version
'v',
// TL (we don't need this)
'constructors',
'td_constructors',
'methods',
'td_methods',
'td_descriptions',
'tl_callbacks',
// Secret chats
'secret_chats',
'encrypted_layer',
'temp_requested_secret_chats',
'temp_rekeyed_secret_chats',
// Object storage
'storage',
];
}
@ -533,12 +581,12 @@ class MTProto extends AsyncConstruct implements TLCallback
}
/**
* Logger
* Logger.
*
* @param string $param Parameter
* @param int $level Logging level
* @param int $level Logging level
* @param string $file File where the message originated
*
*
* @return void
*/
public function logger($param, int $level = Logger::NOTICE, string $file = '')
@ -551,7 +599,7 @@ class MTProto extends AsyncConstruct implements TLCallback
}
/**
* Get async HTTP client
* Get async HTTP client.
*
* @return \Amp\Artax\Client
*/
@ -561,7 +609,7 @@ class MTProto extends AsyncConstruct implements TLCallback
}
/**
* Get async DNS client
* Get async DNS client.
*
* @return \Amp\Dns\Resolver
*/
@ -571,10 +619,10 @@ class MTProto extends AsyncConstruct implements TLCallback
}
/**
* Get contents of remote file asynchronously
* Get contents of remote file asynchronously.
*
* @param string $url URL
*
*
* @return \Generator<string>
*/
public function fileGetContents(string $url): \Generator
@ -592,22 +640,8 @@ class MTProto extends AsyncConstruct implements TLCallback
return $this->datacenter->getDataCenterConnections();
}
public function hasAllAuth(): bool
{
if ($this->isInitingAuthorization()) {
return false;
}
foreach ($this->datacenter->getDataCenterConnections() as $dc) {
if (!$dc->isAuthorized() || !$dc->hasTempAuthKey()) {
return false;
}
}
return true;
}
/**
* Prompt serialization of instance
* Prompt serialization of instance.
*
* @return void
*/
@ -619,7 +653,7 @@ class MTProto extends AsyncConstruct implements TLCallback
}
}
/**
* Start all internal loops
* Start all internal loops.
*
* @return void
*/
@ -648,7 +682,7 @@ class MTProto extends AsyncConstruct implements TLCallback
$this->checkTosLoop->start();
}
/**
* Stop all internal loops
* Stop all internal loops.
*
* @return void
*/
@ -677,63 +711,12 @@ class MTProto extends AsyncConstruct implements TLCallback
}
/**
* Wakeup function
*/
public function __wakeup()
{
$backtrace = \debug_backtrace(0, 3);
$this->asyncInitPromise = true;
$this->setInitPromise($this->__wakeup_async($backtrace));
}
/**
* Async wakeup function
* Clean up properties from previous versions of MadelineProto.
*
* @param array $backtrace Stack trace
*
* @return \Generator
* @return void
*/
public function __wakeup_async(array $backtrace): \Generator
private function cleanupProperties()
{
\set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
$this->setupLogger();
if (\danog\MadelineProto\Magic::$has_thread && \is_object(\Thread::getCurrentThread())) {
return;
}
Lang::$current_lang = &Lang::$lang['en'];
if (isset($this->settings['app_info']['lang_code']) && isset(Lang::$lang[$this->settings['app_info']['lang_code']])) {
Lang::$current_lang = &Lang::$lang[$this->settings['app_info']['lang_code']];
}
if (!isset($this->referenceDatabase)) {
$this->referenceDatabase = new ReferenceDatabase($this);
}
if (!isset($this->minDatabase)) {
$this->minDatabase = new MinDatabase($this);
}
$callbacks = [$this, $this->referenceDatabase];
if (!($this->authorization['user']['bot'] ?? false)) {
$callbacks []= $this->minDatabase;
}
$this->updateCallbacks($callbacks);
$this->settings['connection_settings']['all']['ipv6'] = \danog\MadelineProto\Magic::$ipv6;
/*if (isset($this->settings['pwr']['updateHandler']) && $this->settings['pwr']['updateHandler'] === $this->settings['updates']['callback']) {
unset($this->settings['pwr']['updateHandler']);
$this->updates = [];
}*/
/*$keys = array_keys((array) get_object_vars($this));
if (count($keys) !== count(array_unique($keys))) {
throw new Bug74586Exception();
}
if (isset($this->data)) {
foreach ($this->data as $k => $v) {
$this->{$k} = $v;
}
unset($this->data);
}*/
if ($this->authorized === true) {
$this->authorized = self::LOGGED_IN;
}
if (!($this->channels_state instanceof CombinedUpdatesState)) {
$this->channels_state = new CombinedUpdatesState($this->channels_state);
}
@ -744,9 +727,147 @@ class MTProto extends AsyncConstruct implements TLCallback
$this->channels_state->__construct([false => $this->updates_state]);
unset($this->updates_state);
}
if (!isset($this->datacenter)) {
$this->datacenter = new DataCenter($this, $this->settings['connection'], $this->settings['connection_settings']);
}
if (!isset($this->referenceDatabase)) {
$this->referenceDatabase = new ReferenceDatabase($this);
}
if (!isset($this->minDatabase)) {
$this->minDatabase = new MinDatabase($this);
}
}
/**
* Upgrade MadelineProto instance
*
* @return \Generator
*/
private function upgradeMadelineProto(): \Generator
{
$this->logger->logger(Lang::$current_lang['serialization_ofd'], Logger::WARNING);
foreach ($this->datacenter->getDataCenterConnections() as $dc_id => $socket) {
if ($this->authorized === self::LOGGED_IN && \strpos($dc_id, '_') === false && $socket->hasPermAuthKey() && $socket->hasTempAuthKey()) {
$socket->bind();
$socket->authorized(true);
}
}
$settings = $this->settings;
if (isset($settings['updates']['callback'][0]) && $settings['updates']['callback'][0] === $this) {
$settings['updates']['callback'] = 'getUpdatesUpdateHandler';
}
if (isset($settings['updates']['getdifference_interval']) && $settings['updates']['getdifference_interval'] === -1) {
unset($settings['updates']['getdifference_interval']);
}
unset($settings['tl_schema']);
if (isset($settings['authorization']['rsa_key'])) {
unset($settings['authorization']['rsa_key']);
}
if (!isset($this->full_chats)) {
$this->full_chats = [];
}
if (!isset($this->secret_chats)) {
$this->secret_chats = [];
}
if ($this->event_handler && \class_exists($this->event_handler) && \is_subclass_of($this->event_handler, '\danog\MadelineProto\EventHandler')) {
$this->setEventHandler($this->event_handler);
foreach ($this->full_chats as $id => $full) {
if (isset($full['full'], $full['last_update'])) {
$this->full_chats[$id] = ['full' => $full['full'], 'last_update' => $full['last_update']];
}
}
foreach ($this->secret_chats as $key => &$chat) {
if (!\is_array($chat)) {
unset($this->secret_chats[$key]);
continue;
}
if ($chat['layer'] >= 73) {
$chat['mtproto'] = 2;
} else {
$chat['mtproto'] = 1;
}
}
foreach ($settings['connection_settings'] as $key => &$connection) {
if (\in_array($key, ['default_dc', 'media_socket_count', 'robin_period'])) {
continue;
}
if (!\is_array($connection)) {
unset($settings['connection_settings'][$key]);
continue;
}
if (!isset($connection['proxy'])) {
$connection['proxy'] = '\\Socket';
}
if (!isset($connection['proxy_extra'])) {
$connection['proxy_extra'] = [];
}
if (!isset($connection['pfs'])) {
$connection['pfs'] = \extension_loaded('gmp');
}
if ($connection['protocol'] === 'obfuscated2') {
$connection['protocol'] = 'tcp_intermediate_padded';
$connection['obfuscated'] = true;
}
}
if ($settings['app_info']['api_id'] === 6) {
unset($settings['app_info']);
}
$this->resetMTProtoSession(true, true);
$this->config = ['expires' => -1];
$this->dh_config = ['version' => 0];
yield $this->__construct_async($settings);
foreach ($this->secret_chats as $chat => $data) {
try {
if (isset($this->secret_chats[$chat]) && $this->secret_chats[$chat]['InputEncryptedChat'] !== null) {
yield $this->notifyLayer($chat);
}
} catch (\danog\MadelineProto\RPCErrorException $e) {
}
}
}
/**
* Wakeup function.
*/
public function __wakeup()
{
$backtrace = \debug_backtrace(0, 3);
$this->asyncInitPromise = true;
$this->setInitPromise($this->__wakeup_async($backtrace));
}
/**
* Async wakeup function.
*
* @param array $backtrace Stack trace
*
* @return \Generator
*/
public function __wakeup_async(array $backtrace): \Generator
{
// Setup one-time stuffs
Magic::classExists();
// Setup logger
$this->setupLogger();
// We don't like threads
if (Magic::$has_thread && \is_object(\Thread::getCurrentThread())) {
return;
}
// Setup language
Lang::$current_lang = &Lang::$lang['en'];
if (Lang::$lang[$this->settings['app_info']['lang_code'] ?? 'en'] ?? false) {
Lang::$current_lang = &Lang::$lang[$this->settings['app_info']['lang_code']];
}
// Cleanup old properties, init new stuffs
$this->cleanupProperties();
// Update TL callbacks
$callbacks = [$this, $this->referenceDatabase];
if (!($this->authorization['user']['bot'] ?? false)) {
$callbacks []= $this->minDatabase;
}
$this->updateCallbacks($callbacks);
$this->settings['connection_settings']['all']['ipv6'] = Magic::$ipv6;
if ($this->authorized === true) {
$this->authorized = self::LOGGED_IN;
}
$force = false;
$this->resetMTProtoSession();
@ -756,97 +877,19 @@ class MTProto extends AsyncConstruct implements TLCallback
}
}
if (isset($this->settings['tl_schema']['src']['botAPI']) && $this->settings['tl_schema']['src']['botAPI'] !== __DIR__.'/TL_botAPI.tl') {
if ($this->event_handler && \class_exists($this->event_handler) && \is_subclass_of($this->event_handler, EventHandler::class)) {
$this->setEventHandler($this->event_handler);
}
if (($this->settings['tl_schema']['src']['botAPI'] ?? '') !== __DIR__.'/TL_botAPI.tl') {
unset($this->v);
}
if (!isset($this->v) || $this->v !== self::V) {
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['serialization_ofd'], Logger::WARNING);
foreach ($this->datacenter->getDataCenterConnections() as $dc_id => $socket) {
if ($this->authorized === self::LOGGED_IN && \strpos($dc_id, '_') === false && $socket->hasPermAuthKey() && $socket->hasTempAuthKey()) {
$socket->bind();
$socket->authorized(true);
}
}
$settings = $this->settings;
if (isset($settings['updates']['callback'][0]) && $settings['updates']['callback'][0] === $this) {
$settings['updates']['callback'] = 'getUpdatesUpdateHandler';
}
if (isset($settings['updates']['getdifference_interval']) && $settings['updates']['getdifference_interval'] === -1) {
unset($settings['updates']['getdifference_interval']);
}
unset($settings['tl_schema']);
if (isset($settings['authorization']['rsa_key'])) {
unset($settings['authorization']['rsa_key']);
}
if (!isset($this->full_chats)) {
$this->full_chats = [];
}
if (!isset($this->secret_chats)) {
$this->secret_chats = [];
}
foreach ($this->full_chats as $id => $full) {
if (isset($full['full'], $full['last_update'])) {
$this->full_chats[$id] = ['full' => $full['full'], 'last_update' => $full['last_update']];
}
}
foreach ($this->secret_chats as $key => &$chat) {
if (!\is_array($chat)) {
unset($this->secret_chats[$key]);
continue;
}
if ($chat['layer'] >= 73) {
$chat['mtproto'] = 2;
} else {
$chat['mtproto'] = 1;
}
}
foreach ($settings['connection_settings'] as $key => &$connection) {
if (\in_array($key, ['default_dc', 'media_socket_count', 'robin_period'])) {
continue;
}
if (!\is_array($connection)) {
unset($settings['connection_settings'][$key]);
continue;
}
if (!isset($connection['proxy'])) {
$connection['proxy'] = '\\Socket';
}
if (!isset($connection['proxy_extra'])) {
$connection['proxy_extra'] = [];
}
if (!isset($connection['pfs'])) {
$connection['pfs'] = \extension_loaded('gmp');
}
if ($connection['protocol'] === 'obfuscated2') {
$connection['protocol'] = 'tcp_intermediate_padded';
$connection['obfuscated'] = true;
}
}
if ($settings['app_info']['api_id'] === 6) {
unset($settings['app_info']);
}
$this->resetMTProtoSession(true, true);
$this->config = ['expires' => -1];
$this->dh_config = ['version' => 0];
yield $this->__construct_async($settings);
yield $this->upgradeMadelineProto();
$force = true;
foreach ($this->secret_chats as $chat => $data) {
try {
if (isset($this->secret_chats[$chat]) && $this->secret_chats[$chat]['InputEncryptedChat'] !== null) {
yield $this->notifyLayer($chat);
}
} catch (\danog\MadelineProto\RPCErrorException $e) {
}
}
}
/*if (!$this->settings['updates']['handle_old_updates']) {
$this->channels_state = new CombinedUpdatesState();
$this->msg_ids = [];
$this->got_state = false;
}*/
yield $this->connectToAllDcs();
foreach ($this->calls as $id => $controller) {
if (!\is_object($controller)) {
@ -872,14 +915,14 @@ class MTProto extends AsyncConstruct implements TLCallback
yield $this->getDialogs($force);
}
if ($this->authorized === self::LOGGED_IN && $this->settings['updates']['handle_updates']) {
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['getupdates_deserialization'], Logger::NOTICE);
$this->logger->logger(Lang::$current_lang['getupdates_deserialization'], Logger::NOTICE);
yield $this->updaters[false]->resume();
}
$this->updaters[false]->start();
}
/**
* Destructor
* Destructor.
*/
public function __destruct()
{
@ -907,11 +950,11 @@ class MTProto extends AsyncConstruct implements TLCallback
}
/**
* Get correct settings array for the latest version
* Get correct settings array for the latest version.
*
* @param array $settings Current settings array
* @param array $previousSettings Previous settings array
*
*
* @return array
*/
public static function getSettings(array $settings, array $previousSettings = []): array
@ -1097,7 +1140,7 @@ class MTProto extends AsyncConstruct implements TLCallback
// can be tcp_full, tcp_abridged, tcp_intermediate, http, https, obfuscated2, udp (unsupported)
'test_mode' => false,
// decides whether to connect to the main telegram servers or to the testing servers (deep telegram)
'ipv6' => \danog\MadelineProto\Magic::$ipv6,
'ipv6' => Magic::$ipv6,
// decides whether to use ipv6, ipv6 attribute of API attribute of API class contains autodetected boolean
'timeout' => 2,
// timeout for sockets
@ -1242,17 +1285,17 @@ class MTProto extends AsyncConstruct implements TLCallback
return $settings;
}
/**
* Parse and store settings
* Parse and store settings.
*
* @param array $settings Settings
*
*
* @return void
*/
public function parseSettings(array $settings)
{
$settings = self::getSettings($settings, $this->settings);
if ($settings['app_info'] === null) {
throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['api_not_set'], 0, null, 'MadelineProto', 1);
throw new \danog\MadelineProto\Exception(Lang::$current_lang['api_not_set'], 0, null, 'MadelineProto', 1);
}
$this->settings = $settings;
if (!$this->settings['updates']['handle_updates']) {
@ -1263,7 +1306,7 @@ class MTProto extends AsyncConstruct implements TLCallback
}
/**
* Setup logger
* Setup logger.
*
* @return void
*/
@ -1283,7 +1326,7 @@ class MTProto extends AsyncConstruct implements TLCallback
public function resetMTProtoSession(bool $de = true, bool $auth_key = false)
{
if (!\is_object($this->datacenter)) {
throw new Exception(\danog\MadelineProto\Lang::$current_lang['session_corrupted']);
throw new Exception(Lang::$current_lang['session_corrupted']);
}
foreach ($this->datacenter->getDataCenterConnections() as $id => $socket) {
if ($de) {
@ -1307,6 +1350,20 @@ class MTProto extends AsyncConstruct implements TLCallback
return $this->datacenter->isHttp($datacenter);
}
public function hasAllAuth(): bool
{
if ($this->isInitingAuthorization()) {
return false;
}
foreach ($this->datacenter->getDataCenterConnections() as $dc) {
if (!$dc->isAuthorized() || !$dc->hasTempAuthKey()) {
return false;
}
}
return true;
}
public function isInitingAuthorization()
{
@ -1314,10 +1371,10 @@ class MTProto extends AsyncConstruct implements TLCallback
}
/**
* Connects to all datacenters and if necessary creates authorization keys, binds them and writes client info
* Connects to all datacenters and if necessary creates authorization keys, binds them and writes client info.
*
* @param boolean $reconnectAll Whether to reconnect to all DCs
*
*
* @return \Generator
*/
public function connectToAllDcs(bool $reconnectAll = true): \Generator
@ -1355,7 +1412,7 @@ class MTProto extends AsyncConstruct implements TLCallback
yield $this->getPhoneConfig();
}
/**
* Clean up MadelineProto session after logout
* Clean up MadelineProto session after logout.
*
* @return void
*/
@ -1401,7 +1458,7 @@ class MTProto extends AsyncConstruct implements TLCallback
$this->full_chats = [];
}
/**
* Reset the update state and fetch all updates from the beginning
* Reset the update state and fetch all updates from the beginning.
*
* @return void
*/
@ -1433,10 +1490,10 @@ class MTProto extends AsyncConstruct implements TLCallback
}
/**
* Start the update system
* Start the update system.
*
* @param boolean $anyway Force start update system?
*
*
* @return void
*/
public function startUpdateSystem($anyway = false)
@ -1479,10 +1536,10 @@ class MTProto extends AsyncConstruct implements TLCallback
}
/**
* Store shared phone config
* Store shared phone config.
*
* @param mixed $watcherId Watcher ID
*
*
* @return void
*/
public function getPhoneConfig($watcherId = null)
@ -1496,10 +1553,10 @@ class MTProto extends AsyncConstruct implements TLCallback
}
/**
* Store RSA keys for CDN datacenters
* Store RSA keys for CDN datacenters.
*
* @param string $datacenter DC ID
*
*
* @return \Generator
*/
public function getCdnConfig(string $datacenter): \Generator
@ -1515,7 +1572,7 @@ class MTProto extends AsyncConstruct implements TLCallback
}
/**
* Get cached server-side config
* Get cached server-side config.
*
* @return array
*/
@ -1525,11 +1582,11 @@ class MTProto extends AsyncConstruct implements TLCallback
}
/**
* Get cached (or eventually re-fetch) server-side config
* Get cached (or eventually re-fetch) server-side config.
*
* @param array $config Current config
* @param array $options Options for method call
*
*
* @return \Generator
*/
public function getConfig(array $config = [], array $options = []): \Generator
@ -1544,7 +1601,7 @@ class MTProto extends AsyncConstruct implements TLCallback
}
/**
* Parse cached config
* Parse cached config.
*
* @return \Generator
*/
@ -1555,15 +1612,15 @@ class MTProto extends AsyncConstruct implements TLCallback
unset($this->config['dc_options']);
yield $this->parseDcOptions($options);
}
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['config_updated'], Logger::NOTICE);
$this->logger->logger(Lang::$current_lang['config_updated'], Logger::NOTICE);
$this->logger->logger($this->config, Logger::NOTICE);
}
/**
* Parse DC options from config
* Parse DC options from config.
*
* @param array $dc_options DC options
*
*
* @return \Generator
*/
private function parseDcOptions(array $dc_options): \Generator
@ -1596,7 +1653,7 @@ class MTProto extends AsyncConstruct implements TLCallback
}
/**
* Get info about the logged-in user
* Get info about the logged-in user.
*
* @return \Generator<array>
*/
@ -1653,7 +1710,7 @@ class MTProto extends AsyncConstruct implements TLCallback
/**
* Get debug information for var_dump
* Get debug information for var_dump.
*
* @return array
*/

View File

@ -20,12 +20,22 @@
namespace danog\MadelineProto\MTProtoTools;
/**
* Stores multiple states.
* Stores multiple update states.
*/
class CombinedUpdatesState
{
/**
* Update states.
*
* @var array<UpdatesState>
*/
private $states = [];
/**
* Constructor function.
*
* @param array $init Initial array of states
*/
public function __construct($init = [])
{
$this->states[false] = new UpdatesState();
@ -41,14 +51,14 @@ class CombinedUpdatesState
}
/**
* Update multiple parameters.
* Get or update multiple parameters.
*
* @param array|null $init
* @param int $channel
* @param int $channel Channel to get info about (optional, if not provided returns the entire info array)
* @param array $init Parameters to update
*
* @return UpdatesState
* @return UpdatesState|UpdatesState[]
*/
public function get($channel = null, $init = [])
public function get(int $channel = null, array $init = [])
{
if ($channel === null) {
return $this->states;
@ -63,11 +73,11 @@ class CombinedUpdatesState
/**
* Remove update state.
*
* @param int $channel
* @param int $channel Channel whose state should be removed
*
* @return void
*/
public function remove($channel)
public function remove(int $channel)
{
if (isset($this->states[$channel])) {
unset($this->states[$channel]);
@ -77,11 +87,11 @@ class CombinedUpdatesState
/**
* Check if update state is present.
*
* @param int $channel
* @param int $channel Channel ID
*
* @return void
* @return bool
*/
public function has($channel)
public function has(int $channel): bool
{
return isset($this->states[$channel]);
}
@ -89,12 +99,12 @@ class CombinedUpdatesState
/**
* Are we currently busy?
*
* @param int $channel
* @param bool|null $set
* @param int $channel Channel to get info about
* @param bool|null $set Busy flag to set before returning
*
* @return bool
*/
public function syncLoading($channel, $set = null)
public function syncLoading(int $channel, bool $set = null): bool
{
return $this->get($channel)->syncLoading($set);
}

View File

@ -90,7 +90,7 @@ class UpdatesState
*
* @return bool
*/
public function isChannel()
public function isChannel(): bool
{
return (bool) $this->channelId;
}
@ -108,11 +108,11 @@ class UpdatesState
/**
* Are we currently busy?
*
* @param bool|null $set
* @param bool|null $set Update the currently busy flag
*
* @return bool
*/
public function syncLoading($set = null)
public function syncLoading(bool $set = null): bool
{
if ($set !== null) {
$this->syncLoading = $set;
@ -124,11 +124,11 @@ class UpdatesState
/**
* Update multiple parameters.
*
* @param array $init
* @param array $init Parameters to update
*
* @return self
*/
public function update($init)
public function update(array $init): self
{
foreach ($this->channelId ? ['pts'] : ['pts', 'qts', 'seq', 'date'] as $param) {
if (isset($init[$param])) {
@ -142,11 +142,11 @@ class UpdatesState
/**
* Get/set PTS.
*
* @param int $set
* @param int $set PTS to set
*
* @return int
* @return int PTS
*/
public function pts($set = 0)
public function pts(int $set = 0): int
{
if ($set !== 0 && $set > $this->pts) {
$this->pts = $set;
@ -158,11 +158,11 @@ class UpdatesState
/**
* Get/set QTS.
*
* @param int $set
* @param int $set QTS to set
*
* @return int
* @return int QTS
*/
public function qts($set = 0)
public function qts(int $set = 0): int
{
if ($set !== 0 && $set > $this->qts) {
$this->qts = $set;
@ -174,11 +174,11 @@ class UpdatesState
/**
* Get/set seq.
*
* @param int $set
* @param int $set Seq to set
*
* @return int
* @return int seq
*/
public function seq($set = 0)
public function seq(int $set = 0): int
{
if ($set !== 0 && $set > $this->seq) {
$this->seq = $set;
@ -190,11 +190,11 @@ class UpdatesState
/**
* Get/set date.
*
* @param int $set
* @param int $set Date to set
*
* @return int
* @return int Date
*/
public function date($set = 0)
public function date(int $set = 0): int
{
if ($set !== 0 && $set > $this->date) {
$this->date = $set;
@ -206,11 +206,11 @@ class UpdatesState
/**
* Check validity of PTS contained in update.
*
* @param array $update
* @param array $update Update
*
* @return int -1 if it's too old, 0 if it's ok, 1 if it's too new
*/
public function checkPts($update)
public function checkPts(array $update): int
{
return $update['pts'] - ($this->pts + $update['pts_count']);
}
@ -218,11 +218,11 @@ class UpdatesState
/**
* Check validity of seq contained in update.
*
* @param int $seq
* @param int $seq Seq
*
* @return int -1 if it's too old, 0 if it's ok, 1 if it's too new
*/
public function checkSeq($seq)
public function checkSeq(int $seq): int
{
return $seq ? $seq - ($this->seq + 1) : $seq;
}

File diff suppressed because one or more lines are too long

View File

@ -18,52 +18,74 @@
namespace danog\MadelineProto;
/**
* RSA class
*/
class RSA
{
use \danog\MadelineProto\TL\TL;
use \danog\MadelineProto\Tools;
use \danog\Serializable;
/**
* Exponent
*
* @var \phpseclib\Math\BigInteger
*/
public $e;
/**
* Modulus
*
* @var \phpseclib\Math\BigInteger
*/
public $n;
/**
* Fingerprint
*
* @var string
*/
public $fp;
public function load($rsa_key)
/**
* Load RSA key
*
* @param string $rsa_key RSA key
*
* @return \Generator<self>
*/
public function load(string $rsa_key): \Generator
{
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['rsa_init'], Logger::ULTRA_VERBOSE);
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['loading_key'], Logger::ULTRA_VERBOSE);
$key = \phpseclib\Crypt\RSA::load($rsa_key);
$this->n = self::getVar($key, 'modulus');
$this->e = self::getVar($key, 'exponent');
$this->n = Tools::getVar($key, 'modulus');
$this->e = Tools::getVar($key, 'exponent');
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['computing_fingerprint'], Logger::ULTRA_VERBOSE);
$this->fp = \substr(\sha1((yield $this->serializeObject(['type' => 'bytes'], $this->n->toBytes(), 'key')).(yield $this->serializeObject(['type' => 'bytes'], $this->e->toBytes(), 'key')), true), -8);
return $this;
}
public function __sleep()
/**
* Sleep function
*
* @return array
*/
public function __sleep(): array
{
return ['e', 'n', 'fp'];
}
public function encrypt($data)
/**
* Encrypt data
*
* @param string $data Data to encrypt
*
* @return string
*/
public function encrypt($data): string
{
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['rsa_encrypting'], Logger::VERBOSE);
return (new \phpseclib\Math\BigInteger((string) $data, 256))->powMod($this->e, $this->n)->toBytes();
}
/**
* Accesses a private variable from an object.
*
* @param object $obj
* @param string $var
* @return mixed
* @access public
*/
public static function getVar($obj, $var)
{
$reflection = new \ReflectionClass(\get_class($obj));
$prop = $reflection->getProperty($var);
$prop->setAccessible(true);
return $prop->getValue($obj);
}
}

View File

@ -19,16 +19,66 @@
namespace danog\MadelineProto\TL;
use danog\MadelineProto\MTProto;
trait TL
{
/**
* Highest available secret chat layer version
*
* @var integer
*/
public $encrypted_layer = -1;
/**
* Constructors
*
* @var TLConstructor
*/
public $constructors;
/**
* Methods
*
* @var TLMethods
*/
public $methods;
/**
* TD Constructors
*
* @var TLConstructors
*/
public $td_constructors;
/**
* TD Methods
*
* @var TLMethods
*/
public $td_methods;
/**
* Descriptions
*
* @var array
*/
public $td_descriptions;
/**
* TL callbacks
*
* @var array
*/
public $tl_callbacks = [];
/**
* API instance
*
* @var \danog\MadelineProto\MTProto
*/
private $API;
/**
* Constructor function
*
* @param MTProto $API API instance
*/
public function __construct(MTProto $API) {
$this->API = $API;
}
public function constructTL($files, $objects = [])
{
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['TL_loading'], \danog\MadelineProto\Logger::VERBOSE);

View File

@ -819,4 +819,22 @@ trait Tools
{
return Magic::$altervista;
}
/**
* Accesses a private variable from an object.
*
* @param object $obj Object
* @param string $var Attribute name
*
* @return mixed
* @access public
*/
public static function getVar($obj, string $var)
{
$reflection = new \ReflectionClass(\get_class($obj));
$prop = $reflection->getProperty($var);
$prop->setAccessible(true);
return $prop->getValue($obj);
}
}

View File

@ -21,7 +21,14 @@ namespace danog\MadelineProto\Wrappers;
trait DialogHandler
{
public function getDialogs($force = true)
/**
* Get dialog peers
*
* @param boolean $force Whether to refetch all dialogs ignoring cache
*
* @return \Generator<array<Peer>>
*/
public function getDialogs($force = true): \Generator
{
if ($this->authorization['user']['bot']) {
$res = [];
@ -39,7 +46,14 @@ trait DialogHandler
return $res;
}
public function getFullDialogs($force = true)
/**
* Get full info of all dialogs
*
* @param boolean $force Whether to refetch all dialogs ignoring cache
*
* @return \Generator
*/
public function getFullDialogs($force = true): \Generator
{
if ($force || !isset($this->dialog_params['offset_date']) || \is_null($this->dialog_params['offset_date']) || !isset($this->dialog_params['offset_id']) || \is_null($this->dialog_params['offset_id']) || !isset($this->dialog_params['offset_peer']) || \is_null($this->dialog_params['offset_peer']) || !isset($this->dialog_params['count']) || \is_null($this->dialog_params['count'])) {
$this->dialog_params = ['limit' => 100, 'offset_date' => 0, 'offset_id' => 0, 'offset_peer' => ['_' => 'inputPeerEmpty'], 'count' => 0, 'hash' => 0];

View File

@ -19,15 +19,39 @@
namespace danog\MadelineProto\Wrappers;
use EventHandler;
/**
* Manages logging in and out.
* Event handler
*/
trait Events
{
/**
* Event handler class name
*
* @var string
*/
public $event_handler;
/**
* Event handler instance
*
* @var \danog\MadelineProto\EventHandler
*/
private $event_handler_instance;
/**
* Event handler method list
*
* @var array<string>
*/
private $event_handler_methods = [];
/**
* Set event handler
*
* @param string|EventHandler $event_handler Event handler
*
* @return void
*/
public function setEventHandler($event_handler)
{
if (!\class_exists($event_handler) || !\is_subclass_of($event_handler, '\danog\MadelineProto\EventHandler')) {
@ -66,12 +90,26 @@ trait Events
}
}
public function getEventHandler()
/**
* Get event handler
*
* @return EventHandler
*/
public function getEventHandler(): EventHandler
{
return $this->event_handler_instance;
}
public function eventUpdateHandler($update)
/**
* Event update handler
*
* @param array $update Update
*
* @return void
*
* @internal Internal event handler
*/
public function eventUpdateHandler(array $update)
{
if (isset($this->event_handler_methods[$update['_']])) {
return $this->event_handler_methods[$update['_']]($update);

View File

@ -24,7 +24,12 @@ namespace danog\MadelineProto\Wrappers;
*/
trait TOS
{
public function checkTos()
/**
* Check for terms of service update
*
* @return \Generator
*/
public function checkTos(): \Generator
{
if ($this->authorized === self::LOGGED_IN && !$this->authorization['user']['bot']) {
if ($this->tos['expires'] < \time()) {
@ -46,7 +51,12 @@ trait TOS
}
}
public function acceptTos()
/**
* Accept terms of service update
*
* @return \Generator
*/
public function acceptTos(): \Generator
{
$this->tos['accepted'] = yield $this->methodCallAsyncRead('help.acceptTermsOfService', ['id' => $this->tos['terms_of_service']['id']], ['datacenter' => $this->datacenter->curdc]);
if ($this->tos['accepted']) {
@ -56,7 +66,14 @@ trait TOS
}
}
public function declineTos()
/**
* Decline terms of service update
*
* THIS WILL DELETE YOUR ACCOUNT!
*
* @return \Generator
*/
public function declineTos(): \Generator
{
yield $this->methodCallAsyncRead('account.deleteAccount', ['reason' => 'Decline ToS update'], ['datacenter' => $this->datacenter->curdc]);
yield $this->logout();