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": { "scripts": {
"build": [
"@docs",
"@cs-fix"
],
"check": [ "check": [
"@cs", "@cs",
"@test" "@test"
], ],
"cs": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix -v --diff --dry-run", "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", "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" "test": "@php -dzend.assertions=1 -dassert.exception=1 ./vendor/bin/phpunit --coverage-text"
} }
} }

View File

@ -19,6 +19,8 @@
namespace danog\MadelineProto\DocsBuilder; namespace danog\MadelineProto\DocsBuilder;
use danog\MadelineProto\Tools;
trait Constructors trait Constructors
{ {
public function mkConstructors() public function mkConstructors()
@ -64,7 +66,7 @@ trait Constructors
$param['type'] = 'DecryptedMessage'; $param['type'] = 'DecryptedMessage';
} }
$type_or_subtype = isset($param['subtype']) ? 'subtype' : 'type'; $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]); $param[$type_or_subtype] = \str_replace(['.', 'true', 'false'], ['_', 'Bool', 'Bool'], $param[$type_or_subtype]);
if (\preg_match('/%/', $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']; $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); $param[$type_or_subtype] = \substr($param[$type_or_subtype], 0, -1);
} }
$params .= "'".$param['name']."' => "; $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]).', '; $params .= (isset($param['subtype']) ? '\\['.$param[$type_or_subtype].'\\]' : $param[$type_or_subtype]).', ';
} }
$md_constructor = \str_replace('_', '\\_', $constructor.$layer); $md_constructor = \str_replace('_', '\\_', $constructor.$layer);
@ -126,7 +128,7 @@ trait Constructors
if (\preg_match('/%/', $ptype)) { if (\preg_match('/%/', $ptype)) {
$ptype = $this->constructors->findByType(\str_replace('%', '', $ptype))['predicate']; $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) === '>') { if (\substr($ptype, -1) === '>') {
$ptype = \substr($ptype, 0, -1); $ptype = \substr($ptype, 0, -1);
} }

View File

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

View File

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

View File

@ -4018,40 +4018,57 @@ interface folders
class InternalDoc extends APIFactory 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]); 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]); 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]); return $this->__call(__FUNCTION__, [$extra]);
} }
/**
public function getHTTPClient(array $extra = []) * Get contents of remote file asynchronously.
{ *
return $this->__call(__FUNCTION__, [$extra]); * @param string $url URL
} *
* @return \Generator<string>
public function getDNSClient(array $extra = []) */
{ public function fileGetContents(string $url, array $extra = [])
return $this->__call(__FUNCTION__, [$extra]);
}
public function fileGetContents($url, array $extra = [])
{ {
return $this->__call(__FUNCTION__, [$url, $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. * Get all datacenter connections.
* *
@ -4062,32 +4079,39 @@ class InternalDoc extends APIFactory
return $this->__call(__FUNCTION__, [$extra]); return $this->__call(__FUNCTION__, [$extra]);
} }
public function hasAllAuth(array $extra = []) public function hasAllAuth(array $extra = []): bool
{ {
return $this->__call(__FUNCTION__, [$extra]); return $this->__call(__FUNCTION__, [$extra]);
} }
/**
public function startLoops(array $extra = []) * Get correct settings array for the latest version.
{ *
return $this->__call(__FUNCTION__, [$extra]); * @param array $settings Current settings array
} * @param array $previousSettings Previous settings array
*
public function stopLoops(array $extra = []) * @return array
{ */
return $this->__call(__FUNCTION__, [$extra]); public function getSettings(array $settings, array $previousSettings = [
} ], array $extra = []): array
public function getSettings($settings, $previousSettings = [
], array $extra = [])
{ {
return $this->__call(__FUNCTION__, [$settings, $previousSettings, $extra]); 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]); return $this->__call(__FUNCTION__, [$settings, $extra]);
} }
/**
* Setup logger.
*
* @return void
*/
public function setupLogger(array $extra = []) public function setupLogger(array $extra = [])
{ {
return $this->__call(__FUNCTION__, [$extra]); return $this->__call(__FUNCTION__, [$extra]);
@ -4111,63 +4135,105 @@ class InternalDoc extends APIFactory
* *
* @return boolean * @return boolean
*/ */
public function isHttp(string $datacenter, array $extra = []) public function isHttp(string $datacenter, array $extra = []): bool
{ {
return $this->__call(__FUNCTION__, [$datacenter, $extra]); 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 = []) public function connectToAllDcs(bool $reconnectAll = true, array $extra = [])
{ {
return $this->__call(__FUNCTION__, [$reconnectAll, $extra]); return $this->__call(__FUNCTION__, [$reconnectAll, $extra]);
} }
/**
* Clean up MadelineProto session after logout.
*
* @return void
*/
public function resetSession(array $extra = []) public function resetSession(array $extra = [])
{ {
return $this->__call(__FUNCTION__, [$extra]); return $this->__call(__FUNCTION__, [$extra]);
} }
/**
* Reset the update state and fetch all updates from the beginning.
*
* @return void
*/
public function resetUpdateState(array $extra = []) public function resetUpdateState(array $extra = [])
{ {
return $this->__call(__FUNCTION__, [$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 = []) public function startUpdateSystem($anyway = false, array $extra = [])
{ {
return $this->__call(__FUNCTION__, [$anyway, $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 = []) public function getPhoneConfig($watcherId = null, array $extra = [])
{ {
return $this->__call(__FUNCTION__, [$watcherId, $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]); 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]); return $this->__call(__FUNCTION__, [$extra]);
} }
/**
public function getConfig($config = [ * Get cached (or eventually re-fetch) server-side config.
], $options = [ *
* @param array $config Current config
* @param array $options Options for method call
*
* @return \Generator
*/
public function getConfig(array $config = [
], array $options = [
], array $extra = []) ], array $extra = [])
{ {
return $this->__call(__FUNCTION__, [$config, $options, $extra]); return $this->__call(__FUNCTION__, [$config, $options, $extra]);
} }
/**
public function parseConfig(array $extra = []) * Get info about the logged-in user.
{ *
return $this->__call(__FUNCTION__, [$extra]); * @return \Generator<array>
} */
public function parseDcOptions($dc_options, array $extra = [])
{
return $this->__call(__FUNCTION__, [$dc_options, $extra]);
}
public function getSelf(array $extra = []) public function getSelf(array $extra = [])
{ {
return $this->__call(__FUNCTION__, [$extra]); return $this->__call(__FUNCTION__, [$extra]);
@ -4990,82 +5056,186 @@ class InternalDoc extends APIFactory
{ {
return $this->__call(__FUNCTION__, [$value, $extra]); 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]); 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]); 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]); 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]); 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]); 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 = []) public function wait($promise, $ignoreSignal = false, array $extra = [])
{ {
return $this->__call(__FUNCTION__, [$promise, $ignoreSignal, $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]); 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]); 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]); 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]); 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]); 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 = []) public function call($promise, array $extra = [])
{ {
return $this->__call(__FUNCTION__, [$promise, $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 = []) public function callFork($promise, $actual = null, $file = '', array $extra = [])
{ {
return $this->__call(__FUNCTION__, [$promise, $actual, $file, $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 = []) public function callForkDefer($promise, array $extra = [])
{ {
return $this->__call(__FUNCTION__, [$promise, $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]); 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 = []) public function after($a, $b, array $extra = [])
{ {
return $this->__call(__FUNCTION__, [$a, $b, $extra]); return $this->__call(__FUNCTION__, [$a, $b, $extra]);
@ -5241,6 +5411,37 @@ class InternalDoc extends APIFactory
{ {
return $this->__call(__FUNCTION__, [$string, $extra]); 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 = []) public function requestCall($user, array $extra = [])
{ {

View File

@ -25,7 +25,7 @@ use function Amp\ByteStream\getStderr;
use function Amp\ByteStream\getStdout; use function Amp\ByteStream\getStdout;
/** /**
* Logger class * Logger class.
*/ */
class Logger class Logger
{ {
@ -37,50 +37,50 @@ class Logger
const RESET = ['all' => 0, 'bold' => 21, 'dim' => 22, 'underlined' => 24, 'blink' => 25, 'reverse' => 26, 'hidden' => 28]; const RESET = ['all' => 0, 'bold' => 21, 'dim' => 22, 'underlined' => 24, 'blink' => 25, 'reverse' => 26, 'hidden' => 28];
/** /**
* Logging mode * Logging mode.
* *
* @var integer * @var integer
*/ */
public $mode = 0; public $mode = 0;
/** /**
* Optional logger parameter * Optional logger parameter.
* *
* @var mixed * @var mixed
*/ */
public $optional = null; public $optional = null;
/** /**
* Logger prefix * Logger prefix.
* *
* @var string * @var string
*/ */
public $prefix = ''; public $prefix = '';
/** /**
* Logging level * Logging level.
* *
* @var integer * @var integer
*/ */
public $level = self::NOTICE; public $level = self::NOTICE;
/** /**
* Logging colors * Logging colors.
* *
* @var array * @var array
*/ */
public $colors = []; public $colors = [];
/** /**
* Newline * Newline.
* *
* @var string * @var string
*/ */
public $newline = "\n"; public $newline = "\n";
/** /**
* Default logger instance * Default logger instance.
* *
* @var self * @var self
*/ */
public static $default; public static $default;
/** /**
* Whether the AGPL notice was printed * Whether the AGPL notice was printed.
* *
* @var boolean * @var boolean
*/ */
@ -232,7 +232,7 @@ class Logger
} }
/** /**
* Log a message * Log a message.
* *
* @param mixed $param Message * @param mixed $param Message
* @param int $level Logging level * @param int $level Logging level
@ -249,7 +249,7 @@ class Logger
} }
/** /**
* Log a message * Log a message.
* *
* @param mixed $param Message to log * @param mixed $param Message to log
* @param int $level Logging level * @param int $level Logging level

View File

@ -244,7 +244,7 @@ class MTProto extends AsyncConstruct implements TLCallback
/** /**
* Authorization info (User). * Authorization info (User).
* *
* @var [type] * @var array|null
*/ */
public $authorization = null; public $authorization = null;
/** /**
@ -413,7 +413,7 @@ class MTProto extends AsyncConstruct implements TLCallback
public $datacenter; public $datacenter;
/** /**
* Logger instance * Logger instance.
* *
* @var Logger * @var Logger
*/ */
@ -440,32 +440,13 @@ class MTProto extends AsyncConstruct implements TLCallback
*/ */
public function __construct_async($settings = []) public function __construct_async($settings = [])
{ {
\danog\MadelineProto\Magic::classExists(); Magic::classExists();
// Parse settings // Parse and store settings
$this->parseSettings($settings); $this->parseSettings($settings);
// Connect to servers $this->logger->logger(Lang::$current_lang['inst_dc'], Logger::ULTRA_VERBOSE);
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['inst_dc'], Logger::ULTRA_VERBOSE); $this->cleanupProperties();
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);
}
// Load rsa keys // 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 = []; $this->rsa_keys = [];
foreach ($this->settings['authorization']['rsa_keys'] as $key) { foreach ($this->settings['authorization']['rsa_keys'] as $key) {
$key = yield (new RSA())->load($key); $key = yield (new RSA())->load($key);
@ -475,7 +456,7 @@ class MTProto extends AsyncConstruct implements TLCallback
* *********************************************************************** * ***********************************************************************
* Define some needed numbers for BigInteger * 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]; $callbacks = [$this, $this->referenceDatabase];
if (!($this->authorization['user']['bot'] ?? false)) { if (!($this->authorization['user']['bot'] ?? false)) {
$callbacks []= $this->minDatabase; $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()) { if ((!isset($this->authorization['user']['bot']) || !$this->authorization['user']['bot']) && $this->datacenter->getDataCenterConnection($this->datacenter->curdc)->hasTempAuthKey()) {
try { try {
$nearest_dc = yield $this->methodCallAsyncRead('help.getNearestDc', [], ['datacenter' => $this->datacenter->curdc]); $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']) { if ($nearest_dc['nearest_dc'] != $nearest_dc['this_dc']) {
$this->settings['connection_settings']['default_dc'] = $this->datacenter->curdc = (int) $nearest_dc['nearest_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 * @return array
*/ */
@ -512,7 +493,74 @@ class MTProto extends AsyncConstruct implements TLCallback
if ($this->settings['serialization']['cleanup_before_serialization']) { if ($this->settings['serialization']['cleanup_before_serialization']) {
$this->cleanup(); $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,7 +581,7 @@ class MTProto extends AsyncConstruct implements TLCallback
} }
/** /**
* Logger * Logger.
* *
* @param string $param Parameter * @param string $param Parameter
* @param int $level Logging level * @param int $level Logging level
@ -551,7 +599,7 @@ class MTProto extends AsyncConstruct implements TLCallback
} }
/** /**
* Get async HTTP client * Get async HTTP client.
* *
* @return \Amp\Artax\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 * @return \Amp\Dns\Resolver
*/ */
@ -571,7 +619,7 @@ class MTProto extends AsyncConstruct implements TLCallback
} }
/** /**
* Get contents of remote file asynchronously * Get contents of remote file asynchronously.
* *
* @param string $url URL * @param string $url URL
* *
@ -592,22 +640,8 @@ class MTProto extends AsyncConstruct implements TLCallback
return $this->datacenter->getDataCenterConnections(); 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 * @return void
*/ */
@ -619,7 +653,7 @@ class MTProto extends AsyncConstruct implements TLCallback
} }
} }
/** /**
* Start all internal loops * Start all internal loops.
* *
* @return void * @return void
*/ */
@ -648,7 +682,7 @@ class MTProto extends AsyncConstruct implements TLCallback
$this->checkTosLoop->start(); $this->checkTosLoop->start();
} }
/** /**
* Stop all internal loops * Stop all internal loops.
* *
* @return void * @return void
*/ */
@ -677,63 +711,12 @@ class MTProto extends AsyncConstruct implements TLCallback
} }
/** /**
* Wakeup function * Clean up properties from previous versions of MadelineProto.
*/
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 void
*
* @return \Generator
*/ */
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)) { if (!($this->channels_state instanceof CombinedUpdatesState)) {
$this->channels_state = new CombinedUpdatesState($this->channels_state); $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]); $this->channels_state->__construct([false => $this->updates_state]);
unset($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')) { foreach ($this->full_chats as $id => $full) {
$this->setEventHandler($this->event_handler); 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; $force = false;
$this->resetMTProtoSession(); $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); unset($this->v);
} }
if (!isset($this->v) || $this->v !== self::V) { if (!isset($this->v) || $this->v !== self::V) {
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['serialization_ofd'], Logger::WARNING); yield $this->upgradeMadelineProto();
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);
$force = true; $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(); yield $this->connectToAllDcs();
foreach ($this->calls as $id => $controller) { foreach ($this->calls as $id => $controller) {
if (!\is_object($controller)) { if (!\is_object($controller)) {
@ -872,14 +915,14 @@ class MTProto extends AsyncConstruct implements TLCallback
yield $this->getDialogs($force); yield $this->getDialogs($force);
} }
if ($this->authorized === self::LOGGED_IN && $this->settings['updates']['handle_updates']) { 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(); yield $this->updaters[false]->resume();
} }
$this->updaters[false]->start(); $this->updaters[false]->start();
} }
/** /**
* Destructor * Destructor.
*/ */
public function __destruct() public function __destruct()
{ {
@ -907,7 +950,7 @@ 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 $settings Current settings array
* @param array $previousSettings Previous settings array * @param array $previousSettings Previous settings array
@ -1097,7 +1140,7 @@ class MTProto extends AsyncConstruct implements TLCallback
// can be tcp_full, tcp_abridged, tcp_intermediate, http, https, obfuscated2, udp (unsupported) // can be tcp_full, tcp_abridged, tcp_intermediate, http, https, obfuscated2, udp (unsupported)
'test_mode' => false, 'test_mode' => false,
// decides whether to connect to the main telegram servers or to the testing servers (deep telegram) // 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 // decides whether to use ipv6, ipv6 attribute of API attribute of API class contains autodetected boolean
'timeout' => 2, 'timeout' => 2,
// timeout for sockets // timeout for sockets
@ -1242,7 +1285,7 @@ class MTProto extends AsyncConstruct implements TLCallback
return $settings; return $settings;
} }
/** /**
* Parse and store settings * Parse and store settings.
* *
* @param array $settings Settings * @param array $settings Settings
* *
@ -1252,7 +1295,7 @@ class MTProto extends AsyncConstruct implements TLCallback
{ {
$settings = self::getSettings($settings, $this->settings); $settings = self::getSettings($settings, $this->settings);
if ($settings['app_info'] === null) { 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; $this->settings = $settings;
if (!$this->settings['updates']['handle_updates']) { if (!$this->settings['updates']['handle_updates']) {
@ -1263,7 +1306,7 @@ class MTProto extends AsyncConstruct implements TLCallback
} }
/** /**
* Setup logger * Setup logger.
* *
* @return void * @return void
*/ */
@ -1283,7 +1326,7 @@ class MTProto extends AsyncConstruct implements TLCallback
public function resetMTProtoSession(bool $de = true, bool $auth_key = false) public function resetMTProtoSession(bool $de = true, bool $auth_key = false)
{ {
if (!\is_object($this->datacenter)) { 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) { foreach ($this->datacenter->getDataCenterConnections() as $id => $socket) {
if ($de) { if ($de) {
@ -1307,6 +1350,20 @@ class MTProto extends AsyncConstruct implements TLCallback
return $this->datacenter->isHttp($datacenter); 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() public function isInitingAuthorization()
{ {
@ -1314,7 +1371,7 @@ 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 * @param boolean $reconnectAll Whether to reconnect to all DCs
* *
@ -1355,7 +1412,7 @@ class MTProto extends AsyncConstruct implements TLCallback
yield $this->getPhoneConfig(); yield $this->getPhoneConfig();
} }
/** /**
* Clean up MadelineProto session after logout * Clean up MadelineProto session after logout.
* *
* @return void * @return void
*/ */
@ -1401,7 +1458,7 @@ class MTProto extends AsyncConstruct implements TLCallback
$this->full_chats = []; $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 * @return void
*/ */
@ -1433,7 +1490,7 @@ class MTProto extends AsyncConstruct implements TLCallback
} }
/** /**
* Start the update system * Start the update system.
* *
* @param boolean $anyway Force start update system? * @param boolean $anyway Force start update system?
* *
@ -1479,7 +1536,7 @@ class MTProto extends AsyncConstruct implements TLCallback
} }
/** /**
* Store shared phone config * Store shared phone config.
* *
* @param mixed $watcherId Watcher ID * @param mixed $watcherId Watcher ID
* *
@ -1496,7 +1553,7 @@ class MTProto extends AsyncConstruct implements TLCallback
} }
/** /**
* Store RSA keys for CDN datacenters * Store RSA keys for CDN datacenters.
* *
* @param string $datacenter DC ID * @param string $datacenter DC ID
* *
@ -1515,7 +1572,7 @@ class MTProto extends AsyncConstruct implements TLCallback
} }
/** /**
* Get cached server-side config * Get cached server-side config.
* *
* @return array * @return array
*/ */
@ -1525,7 +1582,7 @@ 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 $config Current config
* @param array $options Options for method call * @param array $options Options for method call
@ -1544,7 +1601,7 @@ class MTProto extends AsyncConstruct implements TLCallback
} }
/** /**
* Parse cached config * Parse cached config.
* *
* @return \Generator * @return \Generator
*/ */
@ -1555,12 +1612,12 @@ class MTProto extends AsyncConstruct implements TLCallback
unset($this->config['dc_options']); unset($this->config['dc_options']);
yield $this->parseDcOptions($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); $this->logger->logger($this->config, Logger::NOTICE);
} }
/** /**
* Parse DC options from config * Parse DC options from config.
* *
* @param array $dc_options DC options * @param array $dc_options DC options
* *
@ -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> * @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 * @return array
*/ */

View File

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

View File

@ -90,7 +90,7 @@ class UpdatesState
* *
* @return bool * @return bool
*/ */
public function isChannel() public function isChannel(): bool
{ {
return (bool) $this->channelId; return (bool) $this->channelId;
} }
@ -108,11 +108,11 @@ class UpdatesState
/** /**
* Are we currently busy? * Are we currently busy?
* *
* @param bool|null $set * @param bool|null $set Update the currently busy flag
* *
* @return bool * @return bool
*/ */
public function syncLoading($set = null) public function syncLoading(bool $set = null): bool
{ {
if ($set !== null) { if ($set !== null) {
$this->syncLoading = $set; $this->syncLoading = $set;
@ -124,11 +124,11 @@ class UpdatesState
/** /**
* Update multiple parameters. * Update multiple parameters.
* *
* @param array $init * @param array $init Parameters to update
* *
* @return self * @return self
*/ */
public function update($init) public function update(array $init): self
{ {
foreach ($this->channelId ? ['pts'] : ['pts', 'qts', 'seq', 'date'] as $param) { foreach ($this->channelId ? ['pts'] : ['pts', 'qts', 'seq', 'date'] as $param) {
if (isset($init[$param])) { if (isset($init[$param])) {
@ -142,11 +142,11 @@ class UpdatesState
/** /**
* Get/set PTS. * 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) { if ($set !== 0 && $set > $this->pts) {
$this->pts = $set; $this->pts = $set;
@ -158,11 +158,11 @@ class UpdatesState
/** /**
* Get/set QTS. * 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) { if ($set !== 0 && $set > $this->qts) {
$this->qts = $set; $this->qts = $set;
@ -174,11 +174,11 @@ class UpdatesState
/** /**
* Get/set seq. * 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) { if ($set !== 0 && $set > $this->seq) {
$this->seq = $set; $this->seq = $set;
@ -190,11 +190,11 @@ class UpdatesState
/** /**
* Get/set date. * 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) { if ($set !== 0 && $set > $this->date) {
$this->date = $set; $this->date = $set;
@ -206,11 +206,11 @@ class UpdatesState
/** /**
* Check validity of PTS contained in update. * 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 * @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']); return $update['pts'] - ($this->pts + $update['pts_count']);
} }
@ -218,11 +218,11 @@ class UpdatesState
/** /**
* Check validity of seq contained in update. * 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 * @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; 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; namespace danog\MadelineProto;
/**
* RSA class
*/
class RSA class RSA
{ {
use \danog\MadelineProto\TL\TL; use \danog\MadelineProto\TL\TL;
use \danog\MadelineProto\Tools; use \danog\MadelineProto\Tools;
use \danog\Serializable; use \danog\Serializable;
/**
* Exponent
*
* @var \phpseclib\Math\BigInteger
*/
public $e; public $e;
/**
* Modulus
*
* @var \phpseclib\Math\BigInteger
*/
public $n; public $n;
/**
* Fingerprint
*
* @var string
*/
public $fp; 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['rsa_init'], Logger::ULTRA_VERBOSE);
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['loading_key'], Logger::ULTRA_VERBOSE); \danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['loading_key'], Logger::ULTRA_VERBOSE);
$key = \phpseclib\Crypt\RSA::load($rsa_key); $key = \phpseclib\Crypt\RSA::load($rsa_key);
$this->n = self::getVar($key, 'modulus'); $this->n = Tools::getVar($key, 'modulus');
$this->e = self::getVar($key, 'exponent'); $this->e = Tools::getVar($key, 'exponent');
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['computing_fingerprint'], Logger::ULTRA_VERBOSE); \danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['computing_fingerprint'], Logger::ULTRA_VERBOSE);
$this->fp = \substr(\sha1((yield $this->serializeObject(['type' => 'bytes'], $this->n->toBytes(), 'key')).(yield $this->serializeObject(['type' => 'bytes'], $this->e->toBytes(), 'key')), true), -8); $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; return $this;
} }
public function __sleep() /**
* Sleep function
*
* @return array
*/
public function __sleep(): array
{ {
return ['e', 'n', 'fp']; 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); \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(); 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; namespace danog\MadelineProto\TL;
use danog\MadelineProto\MTProto;
trait TL trait TL
{ {
/**
* Highest available secret chat layer version
*
* @var integer
*/
public $encrypted_layer = -1; public $encrypted_layer = -1;
/**
* Constructors
*
* @var TLConstructor
*/
public $constructors; public $constructors;
/**
* Methods
*
* @var TLMethods
*/
public $methods; public $methods;
/**
* TD Constructors
*
* @var TLConstructors
*/
public $td_constructors; public $td_constructors;
/**
* TD Methods
*
* @var TLMethods
*/
public $td_methods; public $td_methods;
/**
* Descriptions
*
* @var array
*/
public $td_descriptions; public $td_descriptions;
/**
* TL callbacks
*
* @var array
*/
public $tl_callbacks = []; 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 = []) public function constructTL($files, $objects = [])
{ {
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['TL_loading'], \danog\MadelineProto\Logger::VERBOSE); $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; 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 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']) { if ($this->authorization['user']['bot']) {
$res = []; $res = [];
@ -39,7 +46,14 @@ trait DialogHandler
return $res; 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'])) { 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]; $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; namespace danog\MadelineProto\Wrappers;
use EventHandler;
/** /**
* Manages logging in and out. * Event handler
*/ */
trait Events trait Events
{ {
/**
* Event handler class name
*
* @var string
*/
public $event_handler; public $event_handler;
/**
* Event handler instance
*
* @var \danog\MadelineProto\EventHandler
*/
private $event_handler_instance; private $event_handler_instance;
/**
* Event handler method list
*
* @var array<string>
*/
private $event_handler_methods = []; private $event_handler_methods = [];
/**
* Set event handler
*
* @param string|EventHandler $event_handler Event handler
*
* @return void
*/
public function setEventHandler($event_handler) public function setEventHandler($event_handler)
{ {
if (!\class_exists($event_handler) || !\is_subclass_of($event_handler, '\danog\MadelineProto\EventHandler')) { 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; 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['_']])) { if (isset($this->event_handler_methods[$update['_']])) {
return $this->event_handler_methods[$update['_']]($update); return $this->event_handler_methods[$update['_']]($update);

View File

@ -24,7 +24,12 @@ namespace danog\MadelineProto\Wrappers;
*/ */
trait TOS 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->authorized === self::LOGGED_IN && !$this->authorization['user']['bot']) {
if ($this->tos['expires'] < \time()) { 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]); $this->tos['accepted'] = yield $this->methodCallAsyncRead('help.acceptTermsOfService', ['id' => $this->tos['terms_of_service']['id']], ['datacenter' => $this->datacenter->curdc]);
if ($this->tos['accepted']) { 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->methodCallAsyncRead('account.deleteAccount', ['reason' => 'Decline ToS update'], ['datacenter' => $this->datacenter->curdc]);
yield $this->logout(); yield $this->logout();