1
0
mirror of https://github.com/danog/MadelineProto.git synced 2024-11-26 17:04:39 +01:00
This commit is contained in:
Daniil Gentili 2024-03-10 15:48:55 +01:00
parent 61b438a38e
commit 8721db3f31
8 changed files with 1163 additions and 1375 deletions

View File

@ -24,7 +24,8 @@ $config->getFinder()
->in(__DIR__ . '/tests') ->in(__DIR__ . '/tests')
->in(__DIR__ . '/examples') ->in(__DIR__ . '/examples')
->in(__DIR__ . '/tools') ->in(__DIR__ . '/tools')
->exclude('TLParser.php'); ->notName('TLParser.php')
->notName('SecretTLParser.php');
$cacheDir = getenv('TRAVIS') ? getenv('HOME') . '/.php-cs-fixer' : __DIR__; $cacheDir = getenv('TRAVIS') ? getenv('HOME') . '/.php-cs-fixer' : __DIR__;

View File

@ -17,6 +17,10 @@
</enableExtensions> </enableExtensions>
<projectFiles> <projectFiles>
<directory name="src" /> <directory name="src" />
<ignoreFiles>
<file name="src/TL/TLParser.php" />
<file name="src/TL/SecretTLParser.php" />
</ignoreFiles>
</projectFiles> </projectFiles>
<issueHandlers> <issueHandlers>
<!-- Should totally go in level 1... --> <!-- Should totally go in level 1... -->

View File

@ -903,6 +903,11 @@ abstract class InternalDoc
{ {
return $this->wrapper->getAPI()->getInfo($id, $type); return $this->wrapper->getAPI()->getInfo($id, $type);
} }
public function getInputDialogPeer(mixed $id): array
{
return $this->wrapper->getAPI()->getInputDialogPeer($id);
}
/** /**
* Get logger. * Get logger.
*/ */

View File

@ -675,7 +675,7 @@ final class MTProto implements TLCallback, LoggerGetter, SettingsGetter
if (empty($file)) { if (empty($file)) {
$file = basename(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php'); $file = basename(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php');
} }
($this->logger ?? Logger::$default)->logger($param, $level, $file); ($this->logger ?? Logger::$default)?->logger($param, $level, $file);
} }
/** /**
* Get TL namespaces. * Get TL namespaces.
@ -1814,18 +1814,28 @@ final class MTProto implements TLCallback, LoggerGetter, SettingsGetter
{ {
return []; return [];
} }
/**
* @internal
*/
public function populateSupportUser(array $support): void
{
$this->supportUser = $support['user']['id'];
}
/**
* @internal
*/
public function populateConfig(array $config): void
{
$this->config = $config;
}
/** /**
* @internal * @internal
*/ */
public function getConstructorAfterDeserializationCallbacks(): array public function getConstructorAfterDeserializationCallbacks(): array
{ {
return [ return [
'help.support' => [function (array $support): void { 'help.support' => [$this->populateSupportUser(...)],
$this->supportUser = $support['user']['id']; 'config' => [$this->populateConfig(...)],
}],
'config' => [function (array $config): void {
$this->config = $config;
}],
]; ];
} }
/** /**
@ -1866,11 +1876,20 @@ final class MTProto implements TLCallback, LoggerGetter, SettingsGetter
[ [
'InputFileLocation' => $this->getDownloadInfo(...), 'InputFileLocation' => $this->getDownloadInfo(...),
'InputPeer' => $this->getInputPeer(...), 'InputPeer' => $this->getInputPeer(...),
'InputDialogPeer' => fn (mixed $id): array => ['_' => 'inputDialogPeer', 'peer' => $this->getInputPeer($id)], 'InputDialogPeer' => $this->getInputDialogPeer(...),
'InputCheckPasswordSRP' => fn (string $password): array => (new PasswordCalculator($this->methodCallAsyncRead('account.getPassword', [], $this->authorized_dc)))->getCheckPassword($password), 'InputCheckPasswordSRP' => $this->getPasswordSRP(...),
], ],
); );
} }
public function getInputDialogPeer(mixed $id): array
{
return ['_' => 'inputDialogPeer', 'peer' => $this->getInputPeer($id)];
}
/** @internal */
public function getPasswordSRP(string $password): array
{
return (new PasswordCalculator($this->methodCallAsyncRead('account.getPassword', [], $this->authorized_dc)))->getCheckPassword($password);
}
/** /**
* Get debug information for var_dump. * Get debug information for var_dump.
*/ */

View File

@ -145,7 +145,7 @@ final class MinDatabase implements TLCallback
$this->cache = []; $this->cache = [];
} }
} }
public function addPeer(array $location): bool public function addPeer(array|int $location): bool
{ {
$peers = []; $peers = [];
switch ($location['_']) { switch ($location['_']) {

File diff suppressed because it is too large Load Diff

View File

@ -24,24 +24,26 @@ use danog\MadelineProto\MTProtoTools\MinDatabase;
use danog\MadelineProto\MTProtoTools\PeerDatabase; use danog\MadelineProto\MTProtoTools\PeerDatabase;
use danog\MadelineProto\MTProtoTools\ReferenceDatabase; use danog\MadelineProto\MTProtoTools\ReferenceDatabase;
use danog\MadelineProto\Settings\TLSchema; use danog\MadelineProto\Settings\TLSchema;
use ReflectionClass;
use ReflectionFunction; use ReflectionFunction;
use Webmozart\Assert\Assert; use Webmozart\Assert\Assert;
/** /**
* @internal * @internal
*/ */
final class Builder class Builder
{ {
/** /**
* TL instance. * TL instance.
*/ */
private TL $TL; protected TL $TL;
private readonly array $byType; protected readonly array $byType;
private readonly array $idByPredicate; protected readonly array $idByPredicate;
private readonly array $typeByPredicate; protected readonly array $typeByPredicate;
private readonly array $constructorByPredicate; protected readonly array $constructorByPredicate;
private readonly array $methodVectorTypes; protected readonly array $methodVectorTypes;
private $output; protected readonly string $class;
protected $output;
public function __construct( public function __construct(
TLSchema $settings, TLSchema $settings,
/** /**
@ -51,12 +53,21 @@ final class Builder
/** /**
* Output namespace. * Output namespace.
*/ */
private string $namespace, protected string $namespace,
) { ) {
$this->output = fopen($output, 'w'); $this->output = fopen($output, 'w');
$this->TL = new TL(); $this->TL = new TL();
$this->TL->init($settings); $this->TL->init($settings);
$this->class = basename($output, '.php');
$callbacks = [];
$callbacks []= (new ReflectionClass(MTProto::class))->newInstanceWithoutConstructor();
$callbacks []= (new ReflectionClass(ReferenceDatabase::class))->newInstanceWithoutConstructor();
$callbacks []= (new ReflectionClass(MinDatabase::class))->newInstanceWithoutConstructor();
$callbacks []= (new ReflectionClass(PeerDatabase::class))->newInstanceWithoutConstructor();
$this->TL->updateCallbacks($callbacks);
$byType = []; $byType = [];
$idByPredicate = ['vector' => var_export(hex2bin('1cb5c415'), true)]; $idByPredicate = ['vector' => var_export(hex2bin('1cb5c415'), true)];
$constructorByPredicate = []; $constructorByPredicate = [];
@ -82,7 +93,10 @@ final class Builder
} }
if (isset($constructor['layer'])) { if (isset($constructor['layer'])) {
continue; $constructor['predicate'] .= '_'.$constructor['layer'];
if (!$this instanceof SecretBuilder) {
continue;
}
} }
$constructor['id'] = $id; $constructor['id'] = $id;
@ -121,15 +135,15 @@ final class Builder
$this->byType = $byType; $this->byType = $byType;
} }
private static function escapeConstructorName(array $constructor): string protected static function escapeConstructorName(array $constructor): string
{ {
return str_replace(['.', ' '], '___', $constructor['predicate']); return str_replace(['.', ' '], '___', $constructor['predicate']);
} }
private static function escapeTypeName(string $name): string protected static function escapeTypeName(string $name): string
{ {
return str_replace(['.', ' '], '___', $name); return str_replace(['.', ' '], '___', $name);
} }
private function needFullConstructor(string $predicate): bool protected function needFullConstructor(string $predicate): bool
{ {
if (isset($this->TL->beforeConstructorDeserialization[$predicate]) if (isset($this->TL->beforeConstructorDeserialization[$predicate])
|| isset($this->TL->afterConstructorDeserialization[$predicate])) { || isset($this->TL->afterConstructorDeserialization[$predicate])) {
@ -137,7 +151,7 @@ final class Builder
} }
return false; return false;
} }
private static function methodFromClosure(ReflectionFunction $closure): string protected static function methodFromClosure(\Closure $closure): string
{ {
$refl = new ReflectionFunction($closure); $refl = new ReflectionFunction($closure);
return match ($refl->getClosureThis()::class) { return match ($refl->getClosureThis()::class) {
@ -148,18 +162,18 @@ final class Builder
}."->".$refl->getName(); }."->".$refl->getName();
} }
private function buildTypes(array $constructors, string $type): string protected function buildTypes(array $constructors, string $type): string
{ {
$typeMethod = "_type_".self::escapeTypeName($type); $typeMethod = "_type_".self::escapeTypeName($type);
$result = "match (stream_get_contents(\$stream, 4)) {\n"; $result = "match (stream_get_contents(\$stream, 4)) {\n";
foreach ($constructors as ['predicate' => $predicate, 'id' => $id]) { foreach ($constructors as ['predicate' => $predicate]) {
if ($predicate === 'gzip_packed') { if ($predicate === 'gzip_packed') {
continue; continue;
} }
if ($predicate === 'jsonObjectValue') { if ($predicate === 'jsonObjectValue') {
throw new AssertionError("Impossible!"); throw new AssertionError("Impossible!");
} }
$result .= var_export($id, true)." => "; $result .= $this->idByPredicate[$predicate]." => ";
$result .= $this->buildConstructor($predicate); $result .= $this->buildConstructor($predicate);
$result .= ",\n"; $result .= ",\n";
} }
@ -182,7 +196,7 @@ final class Builder
$result .= "default => self::err(\$stream)\n"; $result .= "default => self::err(\$stream)\n";
return $result."}\n"; return $result."}\n";
} }
private array $createdConstructors = []; protected array $createdConstructors = [];
public function buildConstructor(string $predicate): string public function buildConstructor(string $predicate): string
{ {
$constructor = $this->constructorByPredicate[$predicate]; $constructor = $this->constructorByPredicate[$predicate];
@ -207,7 +221,6 @@ final class Builder
$callback($tmp); $callback($tmp);
} }
} }
return $tmp;
'; ';
} elseif ($flags) { } elseif ($flags) {
$result = $this->buildConstructorFull($predicate, $params, $flags); $result = $this->buildConstructorFull($predicate, $params, $flags);
@ -216,7 +229,7 @@ final class Builder
if (!$this->needFullConstructor($predicate)) { if (!$this->needFullConstructor($predicate)) {
return $result; return $result;
} }
$result = "\$tmp = $result"; $result = "\$tmp = $result;\n";
} }
$pre = ''; $pre = '';
@ -227,6 +240,7 @@ final class Builder
foreach ($this->TL->afterConstructorDeserialization[$predicate] ?? [] as $closure) { foreach ($this->TL->afterConstructorDeserialization[$predicate] ?? [] as $closure) {
$result .= self::methodFromClosure($closure)."(\$tmp);\n"; $result .= self::methodFromClosure($closure)."(\$tmp);\n";
} }
$result .= "return \$tmp;\n";
$nameEscaped = self::escapeConstructorName($constructor); $nameEscaped = self::escapeConstructorName($constructor);
if (!isset($this->createdConstructors[$predicate])) { if (!isset($this->createdConstructors[$predicate])) {
@ -236,7 +250,7 @@ final class Builder
return $this->methodCall("deserialize_$nameEscaped"); return $this->methodCall("deserialize_$nameEscaped");
} }
private function buildConstructorFull(string $predicate, array $params, array $flags): string protected function buildConstructorFull(string $predicate, array $params, array $flags): string
{ {
$result = "\$tmp = ['_' => '$predicate'];\n"; $result = "\$tmp = ['_' => '$predicate'];\n";
$flagNames = []; $flagNames = [];
@ -263,10 +277,10 @@ final class Builder
$code = $this->buildType($param['type']); $code = $this->buildType($param['type']);
$result .= "if ($flag) \$tmp['$name'] = $code;\n"; $result .= "if ($flag) \$tmp['$name'] = $code;\n";
} }
return "$result\nreturn \$tmp;"; return $result;
} }
private function buildConstructorShort(string $predicate, array $params = []): string protected function buildConstructorShort(string $predicate, array $params = []): string
{ {
if ($predicate === 'dataJSON') { if ($predicate === 'dataJSON') {
return 'json_decode('.$this->buildType('string').', true, 512, \\JSON_THROW_ON_ERROR)'; return 'json_decode('.$this->buildType('string').', true, 512, \\JSON_THROW_ON_ERROR)';
@ -277,23 +291,18 @@ final class Builder
$superBare = $this->typeByPredicate[$predicate] === 'JSONValue' $superBare = $this->typeByPredicate[$predicate] === 'JSONValue'
|| $this->typeByPredicate[$predicate] === 'Peer'; || $this->typeByPredicate[$predicate] === 'Peer';
$result = ''; if ($superBare) {
if (!$superBare) { $result = $this->buildType(end($params)['type']);
$result .= "[\n"; } else {
$result = "[\n";
$result .= "'_' => '$predicate',\n"; $result .= "'_' => '$predicate',\n";
} foreach ($params as $param) {
foreach ($params as $param) { $result .= var_export($param['name'], true).' => ';
$code = $this->buildType($param['type']); $result .= $this->buildType($param['type']).",\n";
if ($superBare) {
$result .= $code;
} else {
$result .= var_export($param['name'], true)." => $code,\n";
} }
}
if (!$superBare) {
$result .= ']'; $result .= ']';
} }
if ($predicate === 'peerChat') { if ($predicate === 'peerChat') {
$result = "-$result"; $result = "-$result";
} elseif ($predicate === 'peerChannel') { } elseif ($predicate === 'peerChannel') {
@ -302,8 +311,8 @@ final class Builder
return $result; return $result;
} }
private array $createdVectors = []; protected array $createdVectors = [];
private function buildVector(string $type, bool $bare, ?string $payload = null): string protected function buildVector(string $type, bool $bare, ?string $payload = null): string
{ {
if (!isset($this->createdVectors[$type])) { if (!isset($this->createdVectors[$type])) {
$this->createdVectors[$type] = true; $this->createdVectors[$type] = true;
@ -334,9 +343,9 @@ final class Builder
); );
} }
private array $createdTypes = ['Object' => true]; protected array $createdTypes = ['Object' => true];
private array $typeStack = []; protected array $typeStack = [];
private function buildType(string $type): string protected function buildType(string $type): string
{ {
if (str_starts_with($type, 'Vector<')) { if (str_starts_with($type, 'Vector<')) {
return $this->buildVector(str_replace(['Vector<', '>'], '', $type), false); return $this->buildVector(str_replace(['Vector<', '>'], '', $type), false);
@ -376,7 +385,7 @@ final class Builder
); );
} }
$had = array_search($type, $this->typeStack) !== false; $had = array_search($type, $this->typeStack, true) !== false;
$this->typeStack []= $type; $this->typeStack []= $type;
try { try {
if (!$had) { if (!$had) {
@ -388,8 +397,8 @@ final class Builder
} }
} }
private array $methodsCreated = []; protected array $methodsCreated = [];
private function methodCall(string $method, string $stream = '$stream'): string protected function methodCall(string $method, string $stream = '$stream'): string
{ {
return ($this->methodsCreated[$method] ?? true) return ($this->methodsCreated[$method] ?? true)
? "\$this->$method($stream)" ? "\$this->$method($stream)"
@ -407,13 +416,13 @@ final class Builder
$static = $static ? 'static' : ''; $static = $static ? 'static' : '';
$this->w(" $public $static function $methodName(mixed \$stream$extraArg): $returnType {\n{$body}\n }\n"); $this->w(" $public $static function $methodName(mixed \$stream$extraArg): $returnType {\n{$body}\n }\n");
} }
private function w(string $data): void protected function w(string $data): void
{ {
fwrite($this->output, $data); fwrite($this->output, $data);
} }
public function build(): void public function build(): void
{ {
$this->w("<?php namespace {$this->namespace};\n/** @internal Autogenerated using tools/TL/Builder.php */\nfinal class TLParser {\n"); $this->w("<?php namespace {$this->namespace};\n/** @internal Autogenerated using tools/TL/Builder.php */\nfinal class {$this->class} {\n");
$this->m('err', ' $this->m('err', '
fseek($stream, -4, SEEK_CUR); fseek($stream, -4, SEEK_CUR);
@ -500,6 +509,13 @@ final class Builder
$this->buildVector($type, false, '$result []= '.$this->buildType($type)); $this->buildVector($type, false, '$result []= '.$this->buildType($type));
} }
$this->buildMain();
$this->w("}\n");
}
protected function buildMain(): void
{
$initial_constructors = array_filter( $initial_constructors = array_filter(
$this->constructorByPredicate, $this->constructorByPredicate,
static fn (array $arr) => ( static fn (array $arr) => (
@ -513,7 +529,5 @@ final class Builder
); );
$this->m("deserialize_type_Object", "return {$this->buildTypes($initial_constructors, 'Object')};", 'mixed', true, static: false); $this->m("deserialize_type_Object", "return {$this->buildTypes($initial_constructors, 'Object')};", 'mixed', true, static: false);
$this->w("}\n");
} }
} }

View File

@ -2,6 +2,7 @@
use danog\MadelineProto\Settings\TLSchema; use danog\MadelineProto\Settings\TLSchema;
use danog\MadelineProto\TL\Builder; use danog\MadelineProto\TL\Builder;
use danog\MadelineProto\TL\SecretBuilder;
require __DIR__.'/../vendor/autoload.php'; require __DIR__.'/../vendor/autoload.php';
@ -9,3 +10,6 @@ require __DIR__.'/../vendor/autoload.php';
$builder = new Builder(new TLSchema, __DIR__.'/../src/TL/TLParser.php', 'danog\\MadelineProto\\TL'); $builder = new Builder(new TLSchema, __DIR__.'/../src/TL/TLParser.php', 'danog\\MadelineProto\\TL');
$builder->build(); $builder->build();
$builder = new SecretBuilder(new TLSchema, __DIR__.'/../src/TL/SecretTLParser.php', 'danog\\MadelineProto\\TL');
$builder->build();