Final fixes, and update to latest version of websocket lib

This commit is contained in:
Daniil Gentili 2020-10-04 16:27:22 +02:00
parent d49f59eec5
commit d31b798df9
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
36 changed files with 251 additions and 173 deletions

View File

@ -40,7 +40,8 @@
"danog/loop": "^0.1.0", "danog/loop": "^0.1.0",
"danog/tgseclib": "^3", "danog/tgseclib": "^3",
"amphp/redis": "^1.0", "amphp/redis": "^1.0",
"symfony/polyfill-php80": "^1.18" "symfony/polyfill-php80": "^1.18",
"amphp/websocket-client": "^1.0"
}, },
"require-dev": { "require-dev": {
"vlucas/phpdotenv": "^3", "vlucas/phpdotenv": "^3",
@ -51,8 +52,6 @@
"haydenpierce/class-finder": "^0.4", "haydenpierce/class-finder": "^0.4",
"amphp/http-server": "dev-master", "amphp/http-server": "dev-master",
"amphp/http": "^1.6", "amphp/http": "^1.6",
"amphp/websocket-client": "dev-master as 1",
"amphp/websocket": "dev-master as 1",
"ext-ctype": "*", "ext-ctype": "*",
"danog/7to70": "^1", "danog/7to70": "^1",
"danog/7to5": "^1", "danog/7to5": "^1",

View File

@ -1,65 +0,0 @@
<?php
/**
* Async parameters class.
*
* This file is part of MadelineProto.
* MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
* You should have received a copy of the GNU General Public License along with MadelineProto.
* If not, see <http://www.gnu.org/licenses/>.
*
* @author Daniil Gentili <daniil@daniil.it>
* @copyright 2016-2020 Daniil Gentili <daniil@daniil.it>
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
*
* @link https://docs.madelineproto.xyz MadelineProto documentation
*/
namespace danog\MadelineProto\Async;
/**
* Async parameters class.
*
* Manages asynchronous generation of method parameters
*
* @author Daniil Gentili <daniil@daniil.it>
*/
class AsyncParameters
{
/**
* Async callable.
*
* @var callable
*/
private $callable;
/**
* Create async parameters.
*
* @param callable $callable Async callable that will return parameters
*/
public function __construct(callable $callable)
{
$this->callable = $callable;
}
/**
* Create async parameters.
*
* @param callable $callable Async callable that will return parameters
*/
public function setCallable(callable $callable): void
{
$this->callable = $callable;
}
/**
* Get parameters asynchronously.
*
* @return \Generator<array>|\Amp\Promise<array>
*/
public function getParameters()
{
$callable = $this->callable;
return $callable();
}
}

View File

@ -393,7 +393,9 @@ class Connection
{ {
$deferred = new Deferred(); $deferred = new Deferred();
if (!isset($message['serialized_body'])) { if (!isset($message['serialized_body'])) {
$body = \is_object($message['body']) ? yield from $message['body'] : $message['body']; $body = $message['body'] instanceof \Generator
? yield from $message['body']
: $message['body'];
$refreshNext = $message['refreshReferences'] ?? false; $refreshNext = $message['refreshReferences'] ?? false;
if ($refreshNext) { if ($refreshNext) {
$this->API->referenceDatabase->refreshNext(true); $this->API->referenceDatabase->refreshNext(true);

View File

@ -122,7 +122,7 @@ class DataCenter
/** /**
* DoH connector. * DoH connector.
*/ */
private Rfc6455Connector $webSocketConnnector; private Rfc6455Connector $webSocketConnector;
public function __sleep() public function __sleep()
{ {
@ -238,7 +238,7 @@ class DataCenter
$this->dnsConnector = new DnsConnector(new Rfc1035StubResolver()); $this->dnsConnector = new DnsConnector(new Rfc1035StubResolver());
if (\class_exists(Rfc6455Connector::class)) { if (\class_exists(Rfc6455Connector::class)) {
$this->webSocketConnnector = new Rfc6455Connector($this->HTTPClient); $this->webSocketConnector = new Rfc6455Connector($this->HTTPClient);
} }
} }
$this->settings->applyChanges(); $this->settings->applyChanges();
@ -420,6 +420,7 @@ class DataCenter
if ($stream[0] === DefaultStream::class && $stream[1] === []) { if ($stream[0] === DefaultStream::class && $stream[1] === []) {
$stream[1] = $useDoH ? new DoHConnector($this, $ctx) : $this->dnsConnector; $stream[1] = $useDoH ? new DoHConnector($this, $ctx) : $this->dnsConnector;
} }
/** @var array{0: class-string, 1: mixed} $stream */
$ctx->addStream(...$stream); $ctx->addStream(...$stream);
} }
$ctxs[] = $ctx; $ctxs[] = $ctx;
@ -480,8 +481,9 @@ class DataCenter
if (!\class_exists(Handshake::class)) { if (!\class_exists(Handshake::class)) {
throw new Exception('Please install amphp/websocket-client by running "composer require amphp/websocket-client:dev-master"'); throw new Exception('Please install amphp/websocket-client by running "composer require amphp/websocket-client:dev-master"');
} }
$stream[1] = $this->webSocketConnnector; $stream[1] = $this->webSocketConnector;
} }
/** @var array{0: class-string, 1: mixed} $stream */
$ctx->addStream(...$stream); $ctx->addStream(...$stream);
} }
$ctxs[] = $ctx; $ctxs[] = $ctx;

View File

@ -7,8 +7,6 @@ use danog\MadelineProto\Logger;
/** /**
* Array caching trait. * Array caching trait.
*
* @property string $table
*/ */
trait ArrayCacheTrait trait ArrayCacheTrait
{ {
@ -94,8 +92,8 @@ trait ArrayCacheTrait
Logger::log( Logger::log(
\sprintf( \sprintf(
"cache for table:%s; keys left: %s; keys removed: %s", "cache for table: %s; keys left: %s; keys removed: %s",
$this->table, (string) $this,
\count($this->cache), \count($this->cache),
$oldCount $oldCount
), ),

View File

@ -8,8 +8,6 @@ use ReflectionClass;
/** /**
* Array caching trait. * Array caching trait.
*
* @property string $table
*/ */
abstract class DriverArray implements DbArray abstract class DriverArray implements DbArray
{ {
@ -20,6 +18,12 @@ abstract class DriverArray implements DbArray
$this->stopCacheCleanupLoop(); $this->stopCacheCleanupLoop();
} }
/**
* Get string representation of driver/table.
*
* @return string
*/
abstract public function __toString(): string;
public function __wakeup() public function __wakeup()
{ {
@ -62,7 +66,7 @@ abstract class DriverArray implements DbArray
$counter++; $counter++;
if ($counter % 500 === 0) { if ($counter % 500 === 0) {
yield $new->offsetSet($key, $item); yield $new->offsetSet($key, $item);
Logger::log("Loading data to table {$new->table}: $counter/$total", Logger::WARNING); Logger::log("Loading data to table {$new}: $counter/$total", Logger::WARNING);
} else { } else {
$new->offsetSet($key, $item); $new->offsetSet($key, $item);
} }

View File

@ -22,6 +22,20 @@ class MysqlArray extends SqlArray
// Legacy // Legacy
protected array $settings; protected array $settings;
/**
* Initialize on startup.
*
* @return \Generator
*/
public function initStartup(): \Generator
{
return $this->initConnection($this->dbSettings);
}
public function __toString(): string
{
return $this->table;
}
public function __sleep(): array public function __sleep(): array
{ {
return ['table', 'dbSettings']; return ['table', 'dbSettings'];

View File

@ -22,6 +22,19 @@ class PostgresArray extends SqlArray
// Legacy // Legacy
protected array $settings; protected array $settings;
/**
* Initialize on startup.
*
* @return \Generator
*/
public function initStartup(): \Generator
{
return $this->initConnection($this->dbSettings);
}
public function __toString(): string
{
return $this->table;
}
/** /**
* Initialize connection. * Initialize connection.
* *

View File

@ -15,13 +15,25 @@ use function Amp\call;
class RedisArray extends SqlArray class RedisArray extends SqlArray
{ {
protected string $table;
protected DatabaseRedis $dbSettings; protected DatabaseRedis $dbSettings;
private RedisRedis $db; private RedisRedis $db;
// Legacy // Legacy
protected array $settings; protected array $settings;
/**
* Initialize on startup.
*
* @return \Generator
*/
public function initStartup(): \Generator
{
return $this->initConnection($this->dbSettings);
}
public function __toString(): string
{
return $this->table;
}
/** /**
* @return Generator * @return Generator
* *

View File

@ -9,6 +9,8 @@ use function Amp\call;
abstract class SqlArray extends DriverArray abstract class SqlArray extends DriverArray
{ {
protected string $table;
/** /**
* Create table for property. * Create table for property.
* *
@ -20,15 +22,6 @@ abstract class SqlArray extends DriverArray
abstract protected function renameTable(string $from, string $to): \Generator; abstract protected function renameTable(string $from, string $to): \Generator;
/**
* Initialize on startup.
*
* @return \Generator
*/
public function initStartup(): \Generator
{
return $this->initConnection($this->dbSettings);
}
/** /**
* @param string $name * @param string $name
@ -37,7 +30,7 @@ abstract class SqlArray extends DriverArray
* @param DatabaseAbstract $settings * @param DatabaseAbstract $settings
* *
* @return Promise * @return Promise
* *
* @psalm-return Promise<static> * @psalm-return Promise<static>
*/ */
public static function getInstance(string $name, $value = null, string $tablePrefix = '', $settings): Promise public static function getInstance(string $name, $value = null, string $tablePrefix = '', $settings): Promise
@ -50,6 +43,7 @@ abstract class SqlArray extends DriverArray
$instance->table = $tableName; $instance->table = $tableName;
} }
/** @psalm-suppress UndefinedPropertyAssignment */
$instance->dbSettings = $settings; $instance->dbSettings = $settings;
$instance->ttl = $settings->getCacheTtl(); $instance->ttl = $settings->getCacheTtl();

View File

@ -117,13 +117,13 @@ class DoHConnector implements Connector
foreach ($uris as $builtUri) { foreach ($uris as $builtUri) {
try { try {
$streamContext = \stream_context_create($socketContext->withoutTlsContext()->toStreamContextArray()); $streamContext = \stream_context_create($socketContext->withoutTlsContext()->toStreamContextArray());
/** @psalm-ignore NullArgument */ /** @psalm-suppress NullArgument */
if (!($socket = @\stream_socket_client($builtUri, $errno, $errstr, null, $flags, $streamContext))) { if (!($socket = @\stream_socket_client($builtUri, $errno, $errstr, null, $flags, $streamContext))) {
throw new ConnectException(\sprintf('Connection to %s failed: [Error #%d] %s%s', $uri, $errno, $errstr, $failures ? '; previous attempts: '.\implode($failures) : ''), $errno); throw new ConnectException(\sprintf('Connection to %s failed: [Error #%d] %s%s', $uri, $errno, $errstr, $failures ? '; previous attempts: '.\implode($failures) : ''), $errno);
} }
\stream_set_blocking($socket, false); \stream_set_blocking($socket, false);
$deferred = new Deferred(); $deferred = new Deferred();
/** @psalm-ignore InvalidArgument */ /** @psalm-suppress InvalidArgument */
$watcher = Loop::onWritable($socket, [$deferred, 'resolve']); $watcher = Loop::onWritable($socket, [$deferred, 'resolve']);
$id = $token->subscribe([$deferred, 'fail']); $id = $token->subscribe([$deferred, 'fail']);
try { try {

View File

@ -33,9 +33,9 @@ interface FileCallbackInterface
/** /**
* Invoke callback. * Invoke callback.
* *
* @param int $percent Percent * @param float $percent Percent
* @param int $speed Speed in mbps * @param float $speed Speed in mbps
* @param int $time Time * @param float $time Time
* *
* @return mixed * @return mixed
*/ */

View File

@ -5172,7 +5172,7 @@ class InternalDoc extends APIFactory
*/ */
public function getExtensionFromLocation($location, string $default): string public function getExtensionFromLocation($location, string $default): string
{ {
return \danog\MadelineProto\MTProto::getExtensionFromLocation($location, $default); return \danog\MadelineProto\TL\Conversion\Extension::getExtensionFromLocation($location, $default);
} }
/** /**
* Get extension from mime type. * Get extension from mime type.
@ -5183,7 +5183,7 @@ class InternalDoc extends APIFactory
*/ */
public function getExtensionFromMime(string $mime): string public function getExtensionFromMime(string $mime): string
{ {
return \danog\MadelineProto\MTProto::getExtensionFromMime($mime); return \danog\MadelineProto\TL\Conversion\Extension::getExtensionFromMime($mime);
} }
/** /**
* Get info about file. * Get info about file.
@ -5272,7 +5272,21 @@ class InternalDoc extends APIFactory
* *
* @return \Amp\Promise Info object * @return \Amp\Promise Info object
* *
* @psalm-return \Amp\Promise<array|mixed> * @psalm-return \Generator<int|mixed, \Amp\Promise|\Amp\Promise<string>|array, mixed, array{
* InputPeer: array{_: string, user_id?: mixed, access_hash?: mixed, min?: mixed, chat_id?: mixed, channel_id?: mixed},
* Peer: array{_: string, user_id?: mixed, chat_id?: mixed, channel_id?: mixed},
* DialogPeer: array{_: string, peer: array{_: string, user_id?: mixed, chat_id?: mixed, channel_id?: mixed}},
* NotifyPeer: array{_: string, peer: array{_: string, user_id?: mixed, chat_id?: mixed, channel_id?: mixed}},
* InputDialogPeer: array{_: string, peer: array{_: string, user_id?: mixed, access_hash?: mixed, min?: mixed, chat_id?: mixed, channel_id?: mixed}},
* InputNotifyPeer: array{_: string, peer: array{_: string, user_id?: mixed, access_hash?: mixed, min?: mixed, chat_id?: mixed, channel_id?: mixed}},
* bot_api_id: int|string,
* user_id?: int,
* chat_id?: int,
* channel_id?: int,
* InputUser?: {_: string, user_id?: int, access_hash?: mixed, min?: bool},
* InputChannel?: {_: string, channel_id: int, access_hash: mixed, min: bool},
* type: string
* }>
*/ */
public function getInfo($id, $recursive = true, array $extra = []) public function getInfo($id, $recursive = true, array $extra = [])
{ {
@ -5312,7 +5326,7 @@ class InternalDoc extends APIFactory
*/ */
public function getMimeFromBuffer(string $buffer): string public function getMimeFromBuffer(string $buffer): string
{ {
return \danog\MadelineProto\MTProto::getMimeFromBuffer($buffer); return \danog\MadelineProto\TL\Conversion\Extension::getMimeFromBuffer($buffer);
} }
/** /**
* Get mime type from file extension. * Get mime type from file extension.
@ -5324,7 +5338,7 @@ class InternalDoc extends APIFactory
*/ */
public function getMimeFromExtension(string $extension, string $default): string public function getMimeFromExtension(string $extension, string $default): string
{ {
return \danog\MadelineProto\MTProto::getMimeFromExtension($extension, $default); return \danog\MadelineProto\TL\Conversion\Extension::getMimeFromExtension($extension, $default);
} }
/** /**
* Get mime type of file. * Get mime type of file.
@ -5335,7 +5349,7 @@ class InternalDoc extends APIFactory
*/ */
public function getMimeFromFile(string $file): string public function getMimeFromFile(string $file): string
{ {
return \danog\MadelineProto\MTProto::getMimeFromFile($file); return \danog\MadelineProto\TL\Conversion\Extension::getMimeFromFile($file);
} }
/** /**
* Get download info of the propic of a user * Get download info of the propic of a user
@ -5670,9 +5684,11 @@ class InternalDoc extends APIFactory
* *
* If the $aargs['noResponse'] is true, will not wait for a response. * If the $aargs['noResponse'] is true, will not wait for a response.
* *
* @param string $method Method name * @param string $method Method name
* @param array $args Arguments * @param array|\Generator $args Arguments
* @param array $aargs Additional arguments * @param array $aargs Additional arguments
*
* @psalm-param array|\Generator<mixed, mixed, mixed, array> $args
* *
* @return \Amp\Promise * @return \Amp\Promise
*/ */
@ -5686,9 +5702,11 @@ class InternalDoc extends APIFactory
/** /**
* Call method and make sure it is asynchronously sent. * Call method and make sure it is asynchronously sent.
* *
* @param string $method Method name * @param string $method Method name
* @param array $args Arguments * @param array|\Generator $args Arguments
* @param array $aargs Additional arguments * @param array $aargs Additional arguments
*
* @psalm-param array|\Generator<mixed, mixed, mixed, array> $args
* *
* @return \Amp\Promise * @return \Amp\Promise
*/ */

View File

@ -18,14 +18,16 @@ class FileCallback extends Obj implements FileCallbackInterface
/** /**
* Invoke callback. * Invoke callback.
* *
* @param int $percent Percent * @param float $percent Percent
* @param int $speed Speed in mbps * @param float $speed Speed in mbps
* @param int $time Time * @param float $time Time
*
* @psalm-suppress MethodSignatureMismatch
* *
* @return mixed * @return mixed
*/ */
public function __invoke(...$args) public function __invoke($percent, $speed, $time)
{ {
return $this->__call('__invoke', $args); return $this->__call('__invoke', [$percent, $speed, $time]);
} }
} }

View File

@ -21,6 +21,7 @@ namespace danog\MadelineProto\Loop\Update;
use danog\Loop\ResumableSignalLoop; use danog\Loop\ResumableSignalLoop;
use danog\MadelineProto\Loop\InternalLoop; use danog\MadelineProto\Loop\InternalLoop;
use danog\MadelineProto\MTProtoTools\UpdatesState;
/** /**
* update feed loop. * update feed loop.
@ -42,6 +43,10 @@ class SeqLoop extends ResumableSignalLoop
* Pending updates. * Pending updates.
*/ */
private array $pendingWakeups = []; private array $pendingWakeups = [];
/**
* State.
*/
private ?UpdatesState $state = null;
/** /**
* Main loop. * Main loop.
* *

File diff suppressed because one or more lines are too long

View File

@ -20,7 +20,6 @@
namespace danog\MadelineProto\MTProtoSession; namespace danog\MadelineProto\MTProtoSession;
use Amp\Deferred; use Amp\Deferred;
use danog\MadelineProto\Async\AsyncParameters;
use danog\MadelineProto\TL\Exception; use danog\MadelineProto\TL\Exception;
use danog\MadelineProto\Tools; use danog\MadelineProto\Tools;
@ -79,9 +78,11 @@ trait CallHandler
* *
* If the $aargs['noResponse'] is true, will not wait for a response. * If the $aargs['noResponse'] is true, will not wait for a response.
* *
* @param string $method Method name * @param string $method Method name
* @param array $args Arguments * @param array|\Generator $args Arguments
* @param array $aargs Additional arguments * @param array $aargs Additional arguments
*
* @psalm-param array|\Generator<mixed, mixed, mixed, array> $args
* *
* @return \Generator * @return \Generator
*/ */
@ -100,9 +101,11 @@ trait CallHandler
/** /**
* Call method and make sure it is asynchronously sent (generator). * Call method and make sure it is asynchronously sent (generator).
* *
* @param string $method Method name * @param string $method Method name
* @param array $args Arguments * @param array|\Generator $args Arguments
* @param array $aargs Additional arguments * @param array $aargs Additional arguments
*
* @psalm-param array|\Generator<mixed, mixed, mixed, array> $args
* *
* @return \Generator * @return \Generator
*/ */
@ -160,6 +163,7 @@ trait CallHandler
$aargs, $aargs,
[ [
'_' => $method, '_' => $method,
'body' => $args,
'type' => $methodInfo['type'], 'type' => $methodInfo['type'],
'contentRelated' => $this->contentRelated($method), 'contentRelated' => $this->contentRelated($method),
'promise' => $deferred, 'promise' => $deferred,
@ -167,16 +171,11 @@ trait CallHandler
'unencrypted' => !$this->shared->hasTempAuthKey() && \strpos($method, '.') === false 'unencrypted' => !$this->shared->hasTempAuthKey() && \strpos($method, '.') === false
] ]
); );
if (\is_object($args) && $args instanceof AsyncParameters) {
$message['body'] = yield $args->fetchParameters();
} else {
$message['body'] = $args;
}
if ($method === 'users.getUsers' && $args === ['id' => [['_' => 'inputUserSelf']]] || $method === 'auth.exportAuthorization' || $method === 'updates.getDifference') { if ($method === 'users.getUsers' && $args === ['id' => [['_' => 'inputUserSelf']]] || $method === 'auth.exportAuthorization' || $method === 'updates.getDifference') {
$message['user_related'] = true; $message['user_related'] = true;
} }
$aargs['postpone'] = $aargs['postpone'] ?? false; $aargs['postpone'] = $aargs['postpone'] ?? false;
$deferred = (yield from $this->sendMessage($message, !$aargs['postpone'])); $deferred = yield from $this->sendMessage($message, !$aargs['postpone']);
$this->checker->resume(); $this->checker->resume();
return $deferred; return $deferred;
} }

View File

@ -229,6 +229,7 @@ trait AuthKeyHandler
* Separate answer and hash * Separate answer and hash
*/ */
$answer_hash = \substr($answer_with_hash, 0, 20); $answer_hash = \substr($answer_with_hash, 0, 20);
/** @var string */
$answer = \substr($answer_with_hash, 20); $answer = \substr($answer_with_hash, 20);
/* /*
* *********************************************************************** * ***********************************************************************
@ -553,6 +554,7 @@ trait AuthKeyHandler
foreach ($dcs as $id => &$dc) { foreach ($dcs as $id => &$dc) {
$dc = $dc(); $dc = $dc();
} }
/** @var \Generator[] $dcs */
yield \danog\MadelineProto\Tools::all($dcs); yield \danog\MadelineProto\Tools::all($dcs);
foreach ($postpone as $id => $socket) { foreach ($postpone as $id => $socket) {
yield from $this->initAuthorizationSocket($id, $socket); yield from $this->initAuthorizationSocket($id, $socket);

View File

@ -31,9 +31,11 @@ trait CallHandler
/** /**
* Synchronous wrapper for methodCall. * Synchronous wrapper for methodCall.
* *
* @param string $method Method name * @param string $method Method name
* @param array $args Arguments * @param array|\Generator $args Arguments
* @param array $aargs Additional arguments * @param array $aargs Additional arguments
*
* @psalm-param array|\Generator<mixed, mixed, mixed, array> $args
* *
* @return mixed * @return mixed
*/ */
@ -46,9 +48,11 @@ trait CallHandler
* *
* If the $aargs['noResponse'] is true, will not wait for a response. * If the $aargs['noResponse'] is true, will not wait for a response.
* *
* @param string $method Method name * @param string $method Method name
* @param array $args Arguments * @param array|\Generator $args Arguments
* @param array $aargs Additional arguments * @param array $aargs Additional arguments
*
* @psalm-param array|\Generator<mixed, mixed, mixed, array> $args
* *
* @return \Generator * @return \Generator
*/ */
@ -59,9 +63,11 @@ trait CallHandler
/** /**
* Call method and make sure it is asynchronously sent. * Call method and make sure it is asynchronously sent.
* *
* @param string $method Method name * @param string $method Method name
* @param array $args Arguments * @param array|\Generator $args Arguments
* @param array $aargs Additional arguments * @param array $aargs Additional arguments
*
* @psalm-param array|\Generator<mixed, mixed, mixed, array> $args
* *
* @return \Generator * @return \Generator
*/ */

View File

@ -172,7 +172,9 @@ trait Files
$exception = null; $exception = null;
$start = \microtime(true); $start = \microtime(true);
while ($part_num < $part_total_num) { while ($part_num < $part_total_num) {
$writePromise = Tools::call($this->methodCallAsyncWrite($method, $callable($part_num), ['heavy' => true, 'file' => true, 'datacenter' => &$datacenter])); $resa = $callable($part_num);
\var_dump($resa);
$writePromise = Tools::call($this->methodCallAsyncWrite($method, $resa, ['heavy' => true, 'file' => true, 'datacenter' => &$datacenter]));
if (!$seekable) { if (!$seekable) {
yield $writePromise; yield $writePromise;
} }
@ -622,10 +624,10 @@ trait Files
} }
} }
if (!isset($res['ext']) || $res['ext'] === '') { if (!isset($res['ext']) || $res['ext'] === '') {
$res['ext'] = $this->getExtensionFromLocation($res['InputFileLocation'], $this->getExtensionFromMime($res['mime'] ?? 'image/jpeg')); $res['ext'] = Tools::getExtensionFromLocation($res['InputFileLocation'], Tools::getExtensionFromMime($res['mime'] ?? 'image/jpeg'));
} }
if (!isset($res['mime']) || $res['mime'] === '') { if (!isset($res['mime']) || $res['mime'] === '') {
$res['mime'] = $this->getMimeFromExtension($res['ext'], 'image/jpeg'); $res['mime'] = Tools::getMimeFromExtension($res['ext'], 'image/jpeg');
} }
if (!isset($res['name']) || $res['name'] === '') { if (!isset($res['name']) || $res['name'] === '') {
$res['name'] = Tools::unpackSignedLongString($messageMedia['file']['access_hash']); $res['name'] = Tools::unpackSignedLongString($messageMedia['file']['access_hash']);
@ -680,8 +682,8 @@ trait Files
$res['thumb_size'] = $messageMedia['type']; $res['thumb_size'] = $messageMedia['type'];
if ($messageMedia['location']['_'] === 'fileLocationUnavailable') { if ($messageMedia['location']['_'] === 'fileLocationUnavailable') {
$res['name'] = Tools::unpackSignedLongString($messageMedia['volume_id']).'_'.$messageMedia['local_id']; $res['name'] = Tools::unpackSignedLongString($messageMedia['volume_id']).'_'.$messageMedia['local_id'];
$res['mime'] = $this->getMimeFromBuffer($res['data']); $res['mime'] = Tools::getMimeFromBuffer($res['data']);
$res['ext'] = $this->getExtensionFromMime($res['mime']); $res['ext'] = TOols::getExtensionFromMime($res['mime']);
} else { } else {
$res = \array_merge($res, yield from $this->getDownloadInfo($messageMedia['location'])); $res = \array_merge($res, yield from $this->getDownloadInfo($messageMedia['location']));
} }
@ -699,13 +701,13 @@ trait Files
case 'fileLocation': case 'fileLocation':
$res['name'] = Tools::unpackSignedLongString($messageMedia['volume_id']).'_'.$messageMedia['local_id']; $res['name'] = Tools::unpackSignedLongString($messageMedia['volume_id']).'_'.$messageMedia['local_id'];
$res['InputFileLocation'] = ['_' => 'inputFileLocation', 'volume_id' => $messageMedia['volume_id'], 'local_id' => $messageMedia['local_id'], 'secret' => $messageMedia['secret'], 'dc_id' => $messageMedia['dc_id'], 'file_reference' => yield from $this->referenceDatabase->getReference(ReferenceDatabase::PHOTO_LOCATION_LOCATION, $messageMedia)]; $res['InputFileLocation'] = ['_' => 'inputFileLocation', 'volume_id' => $messageMedia['volume_id'], 'local_id' => $messageMedia['local_id'], 'secret' => $messageMedia['secret'], 'dc_id' => $messageMedia['dc_id'], 'file_reference' => yield from $this->referenceDatabase->getReference(ReferenceDatabase::PHOTO_LOCATION_LOCATION, $messageMedia)];
$res['ext'] = $this->getExtensionFromLocation($res['InputFileLocation'], '.jpg'); $res['ext'] = Tools::getExtensionFromLocation($res['InputFileLocation'], '.jpg');
$res['mime'] = $this->getMimeFromExtension($res['ext'], 'image/jpeg'); $res['mime'] = Tools::getMimeFromExtension($res['ext'], 'image/jpeg');
return $res; return $res;
case 'fileLocationToBeDeprecated': case 'fileLocationToBeDeprecated':
$res['name'] = Tools::unpackSignedLongString($messageMedia['volume_id']).'_'.$messageMedia['local_id']; $res['name'] = Tools::unpackSignedLongString($messageMedia['volume_id']).'_'.$messageMedia['local_id'];
$res['ext'] = '.jpg'; $res['ext'] = '.jpg';
$res['mime'] = $this->getMimeFromExtension($res['ext'], 'image/jpeg'); $res['mime'] = Tools::getMimeFromExtension($res['ext'], 'image/jpeg');
$res['InputFileLocation'] = [ $res['InputFileLocation'] = [
'_' => 'inputFileLocationTemp', '_' => 'inputFileLocationTemp',
// Will be overwritten // Will be overwritten
@ -742,7 +744,7 @@ trait Files
} }
$res['InputFileLocation'] = ['_' => 'inputDocumentFileLocation', 'id' => $messageMedia['document']['id'], 'access_hash' => $messageMedia['document']['access_hash'], 'version' => isset($messageMedia['document']['version']) ? $messageMedia['document']['version'] : 0, 'dc_id' => $messageMedia['document']['dc_id'], 'file_reference' => yield from $this->referenceDatabase->getReference(ReferenceDatabase::DOCUMENT_LOCATION, $messageMedia['document'])]; $res['InputFileLocation'] = ['_' => 'inputDocumentFileLocation', 'id' => $messageMedia['document']['id'], 'access_hash' => $messageMedia['document']['access_hash'], 'version' => isset($messageMedia['document']['version']) ? $messageMedia['document']['version'] : 0, 'dc_id' => $messageMedia['document']['dc_id'], 'file_reference' => yield from $this->referenceDatabase->getReference(ReferenceDatabase::DOCUMENT_LOCATION, $messageMedia['document'])];
if (!isset($res['ext']) || $res['ext'] === '') { if (!isset($res['ext']) || $res['ext'] === '') {
$res['ext'] = $this->getExtensionFromLocation($res['InputFileLocation'], $this->getExtensionFromMime($messageMedia['document']['mime_type'])); $res['ext'] = Tools::getExtensionFromLocation($res['InputFileLocation'], Tools::getExtensionFromMime($messageMedia['document']['mime_type']));
} }
if (!isset($res['name']) || $res['name'] === '') { if (!isset($res['name']) || $res['name'] === '') {
$res['name'] = Tools::unpackSignedLongString($messageMedia['document']['access_hash']); $res['name'] = Tools::unpackSignedLongString($messageMedia['document']['access_hash']);
@ -962,7 +964,7 @@ trait Files
* @param array $messageMedia File object * @param array $messageMedia File object
* @param bool $cdn Whether this is a CDN file * @param bool $cdn Whether this is a CDN file
* @param string $datacenter DC ID * @param string $datacenter DC ID
* @param string $old_dc Previous DC ID * @param ?string $old_dc Previous DC ID
* @param AES $ige IGE decryptor instance * @param AES $ige IGE decryptor instance
* @param callable $cb Status callback * @param callable $cb Status callback
* @param array $offset Offset * @param array $offset Offset

View File

@ -25,6 +25,7 @@ use danog\MadelineProto\Stream\Common\BufferedRawStream;
use danog\MadelineProto\Stream\Common\SimpleBufferedRawStream; use danog\MadelineProto\Stream\Common\SimpleBufferedRawStream;
use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\ConnectionContext;
use danog\MadelineProto\Stream\Transport\PremadeStream; use danog\MadelineProto\Stream\Transport\PremadeStream;
use danog\MadelineProto\TL\Conversion\Extension;
use danog\MadelineProto\Tools; use danog\MadelineProto\Tools;
@ -245,7 +246,7 @@ trait FilesLogic
throw new \danog\MadelineProto\Exception('Given file is too big!'); throw new \danog\MadelineProto\Exception('Given file is too big!');
} }
$stream = yield open($file, 'rb'); $stream = yield open($file, 'rb');
$mime = $this->getMimeFromFile($file); $mime = Extension::getMimeFromFile($file);
try { try {
return yield from $this->uploadFromStream($stream, $size, $mime, $fileName, $cb, $encrypted); return yield from $this->uploadFromStream($stream, $size, $mime, $fileName, $cb, $encrypted);
} finally { } finally {

View File

@ -432,7 +432,7 @@ trait PeerHandler
case 'contact': case 'contact':
return $id['user_id']; return $id['user_id'];
case 'updatePhoneCall': case 'updatePhoneCall':
return $id->getOtherID(); return $id['phone_call']->getOtherID();
case 'updateReadHistoryInbox': case 'updateReadHistoryInbox':
case 'updateReadHistoryOutbox': case 'updateReadHistoryOutbox':
return $this->getId($id['peer']); return $this->getId($id['peer']);

View File

@ -155,7 +155,7 @@ trait UpdateHandler
* *
* @internal * @internal
* *
* @return \Generator * @return \Generator<mixed, mixed, mixed, UpdatesState>
*/ */
public function loadUpdateState(): \Generator public function loadUpdateState(): \Generator
{ {

View File

@ -104,11 +104,17 @@ class MyTelegramOrgWrapper
$this->settings = new Settings; $this->settings = new Settings;
} elseif (\is_array($this->settings)) { } elseif (\is_array($this->settings)) {
$this->settings = Settings::parseFromLegacy($this->settings); $this->settings = Settings::parseFromLegacy($this->settings);
if (!$this->settings instanceof Settings) {
$settings = new Settings;
$settings->merge($this->settings);
$this->settings = $settings;
}
} }
if (!$this->jar || !$this->jar instanceof InMemoryCookieJar) { if (!$this->jar || !$this->jar instanceof InMemoryCookieJar) {
$this->jar = new InMemoryCookieJar(); $this->jar = new InMemoryCookieJar();
} }
$this->datacenter = new DataCenter(new class(new Logger($this->settings->getLogger())) { $this->datacenter = new DataCenter(new class(new Logger($this->settings->getLogger())) {
public Logger $logger;
public function __construct(Logger $logger) public function __construct(Logger $logger)
{ {
$this->logger = $logger; $this->logger = $logger;
@ -347,7 +353,7 @@ class MyTelegramOrgWrapper
* @param string $name Function name * @param string $name Function name
* @param array $arguments Arguments * @param array $arguments Arguments
* *
* @return void * @return mixed
*/ */
public function __call(string $name, array $arguments) public function __call(string $name, array $arguments)
{ {

View File

@ -106,7 +106,7 @@ class SessionPaths
* @param string $path Object path, defaults to session path * @param string $path Object path, defaults to session path
* *
* @return \Generator * @return \Generator
* *
* @psalm-return \Generator<mixed, mixed, mixed, object> * @psalm-return \Generator<mixed, mixed, mixed, object>
*/ */
public function unserialize(string $path = ''): \Generator public function unserialize(string $path = ''): \Generator

View File

@ -19,10 +19,12 @@
namespace danog\MadelineProto; namespace danog\MadelineProto;
use danog\MadelineProto\TL\Conversion\Extension;
/** /**
* Some tools. * Some tools.
*/ */
abstract class StrTools abstract class StrTools extends Extension
{ {
/** /**
* Convert to camelCase. * Convert to camelCase.

View File

@ -42,7 +42,6 @@ use danog\MadelineProto\Stream\WriteBufferInterface;
class UdpBufferedStream extends DefaultStream implements BufferedStreamInterface, MTProtoBufferInterface class UdpBufferedStream extends DefaultStream implements BufferedStreamInterface, MTProtoBufferInterface
{ {
use BufferedStream; use BufferedStream;
private RawStreamInterface $stream;
/** /**
* Connect to stream. * Connect to stream.
* *
@ -72,7 +71,7 @@ class UdpBufferedStream extends DefaultStream implements BufferedStreamInterface
* *
* @psalm-return \Generator<int, Promise, mixed, Failure<mixed>|Success<object>> * @psalm-return \Generator<int, Promise, mixed, Failure<mixed>|Success<object>>
*/ */
public function getReadBuffer(&$length): \Generator public function getReadBufferGenerator(&$length): \Generator
{ {
if (!$this->stream) { if (!$this->stream) {
return new Failure(new ClosedException("MadelineProto stream was disconnected")); return new Failure(new ClosedException("MadelineProto stream was disconnected"));
@ -185,7 +184,7 @@ class UdpBufferedStream extends DefaultStream implements BufferedStreamInterface
*/ */
public function getSocket(): EncryptableSocket public function getSocket(): EncryptableSocket
{ {
return $this->stream->getSocket(); return $this->getSocket();
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
@ -194,7 +193,7 @@ class UdpBufferedStream extends DefaultStream implements BufferedStreamInterface
*/ */
public function getStream(): RawStreamInterface public function getStream(): RawStreamInterface
{ {
return $this->stream; return $this;
} }
public static function getName(): string public static function getName(): string
{ {

View File

@ -100,7 +100,7 @@ class ConnectionContext
/** /**
* An array of arrays containing an array with the stream name and the extra parameter to pass to it. * An array of arrays containing an array with the stream name and the extra parameter to pass to it.
* *
* @var array<array<string, mixed>> * @var array<0: class-string, 1: mixed>[]
*/ */
private $nextStreams = []; private $nextStreams = [];
/** /**
@ -344,7 +344,9 @@ class ConnectionContext
* Add a stream to the stream chain. * Add a stream to the stream chain.
* *
* @param string $streamName * @param string $streamName
* @param mixed $extra * @param mixed $extra
*
* @psalm-param class-string $streamName
* *
* @return self * @return self
*/ */

View File

@ -38,7 +38,7 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface
{ {
use BufferedStream; use BufferedStream;
/** /**
* Stream * Stream.
* *
* @var RawStreamInterface * @var RawStreamInterface
*/ */

View File

@ -19,11 +19,14 @@
namespace danog\MadelineProto\Stream\Transport; namespace danog\MadelineProto\Stream\Transport;
use Amp\Http\Client\HttpClientBuilder;
use Amp\Promise; use Amp\Promise;
use Amp\Socket\EncryptableSocket; use Amp\Socket\EncryptableSocket;
use Amp\Websocket\Client\Connection; use Amp\Websocket\Client\Connection;
use Amp\Websocket\Client\Connector; use Amp\Websocket\Client\Connector;
use Amp\Websocket\Client\Handshake; use Amp\Websocket\Client\Handshake;
use Amp\Websocket\Client\Rfc6455Connector;
use Amp\Websocket\ClosedException;
use Amp\Websocket\Message; use Amp\Websocket\Message;
use danog\MadelineProto\Stream\Async\RawStream; use danog\MadelineProto\Stream\Async\RawStream;
use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\ConnectionContext;
@ -73,7 +76,7 @@ class WsStream implements RawStreamInterface, ProxyStreamInterface
$uri = $ctx->getStringUri(); $uri = $ctx->getStringUri();
$uri = \str_replace('tcp://', $ctx->isSecure() ? 'wss://' : 'ws://', $uri); $uri = \str_replace('tcp://', $ctx->isSecure() ? 'wss://' : 'ws://', $uri);
$handshake = new Handshake($uri); $handshake = new Handshake($uri);
$this->stream = yield ($this->connector ?? connector())->connect($handshake, $ctx->getCancellationToken()); $this->stream = yield ($this->connector ?? new Rfc6455Connector(HttpClientBuilder::buildDefault()))->connect($handshake, $ctx->getCancellationToken());
if (\strlen($header)) { if (\strlen($header)) {
yield $this->write($header); yield $this->write($header);
} }
@ -100,7 +103,7 @@ class WsStream implements RawStreamInterface, ProxyStreamInterface
$this->message = null; $this->message = null;
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
if ($e instanceof Amp\Websocket\ClosedException && $e->getReason() !== 'Client closed the underlying TCP connection') { if ($e instanceof ClosedException && $e->getReason() !== 'Client closed the underlying TCP connection') {
throw $e; throw $e;
} }
return null; return null;

View File

@ -22,6 +22,7 @@ namespace danog\MadelineProto\TL\Conversion;
use danog\Decoder\FileId; use danog\Decoder\FileId;
use danog\MadelineProto\Logger; use danog\MadelineProto\Logger;
use danog\MadelineProto\MTProtoTools\PeerHandler; use danog\MadelineProto\MTProtoTools\PeerHandler;
use danog\MadelineProto\Tools;
use const danog\Decoder\TYPES_IDS; use const danog\Decoder\TYPES_IDS;
@ -387,7 +388,7 @@ trait BotAPI
$res['file_name'] .= $res['ext']; $res['file_name'] .= $res['ext'];
unset($res['ext']); unset($res['ext']);
} else { } else {
$res['file_name'] .= $this->getExtensionFromMime($data['document']['mime_type']); $res['file_name'] .= Tools::getExtensionFromMime($data['document']['mime_type']);
} }
$res['file_size'] = $data['document']['size']; $res['file_size'] = $data['document']['size'];
$res['mime_type'] = $data['document']['mime_type']; $res['mime_type'] = $data['document']['mime_type'];
@ -698,9 +699,8 @@ trait BotAPI
$delimOffset = 0; $delimOffset = 0;
foreach ($initialArray as $item) { foreach ($initialArray as $item) {
$delimOffset += $this->mbStrlen($item); $delimOffset += $this->mbStrlen($item);
//if ($this->mbStrlen($item) > 0) { /** @var int $delimOffset */
$finalArray[] = $item.($delimOffset < $this->mbStrlen($string) ? $string[$delimOffset] : ''); $finalArray[] = $item.($delimOffset < $this->mbStrlen($string) ? $string[$delimOffset] : '');
//}
$delimOffset++; $delimOffset++;
} }
return $finalArray; return $finalArray;

File diff suppressed because one or more lines are too long

View File

@ -787,8 +787,8 @@ class TL
/** /**
* Get length of TL payload. * Get length of TL payload.
* *
* @param resource $stream Stream * @param resource|string $stream Stream
* @param array $type Type identifier * @param array $type Type identifier
* *
* @return int * @return int
*/ */

View File

@ -26,6 +26,8 @@ class Button implements \JsonSerializable, \ArrayAccess
{ {
/** /**
* Button data. * Button data.
*
* @psalm-var non-empty-array<array-key, mixed>
*/ */
private array $button; private array $button;
/** /**
@ -139,7 +141,7 @@ class Button implements \JsonSerializable, \ArrayAccess
* *
* @param $name Field name * @param $name Field name
* *
* @return void * @return mixed
*/ */
public function offsetGet($name) public function offsetGet($name)
{ {

View File

@ -88,7 +88,7 @@ class APIFactory extends AbstractAPIFactory
* *
* @param string $name Method name * @param string $name Method name
* @param array $arguments Arguments * @param array $arguments Arguments
* * @psalm-suppress UndefinedThisPropertyFetch
* @return \Generator * @return \Generator
*/ */
public function __call_async(string $name, array $arguments): \Generator public function __call_async(string $name, array $arguments): \Generator

View File

@ -1105,6 +1105,29 @@ class InternalDoc extends APIFactory
{ {
return \danog\MadelineProto\Tools::genVectorHash($ints); return \danog\MadelineProto\Tools::genVectorHash($ints);
} }
/**
* Get extension from file location.
*
* @param mixed $location File location
* @param string $default Default extension
*
* @return string
*/
public function getExtensionFromLocation($location, string $default): string
{
return \danog\MadelineProto\TL\Conversion\Extension::getExtensionFromLocation($location, $default);
}
/**
* Get extension from mime type.
*
* @param string $mime MIME type
*
* @return string
*/
public function getExtensionFromMime(string $mime): string
{
return \danog\MadelineProto\TL\Conversion\Extension::getExtensionFromMime($mime);
}
/** /**
* Get TL method namespaces. * Get TL method namespaces.
* *
@ -1114,6 +1137,40 @@ class InternalDoc extends APIFactory
{ {
return $this->API->getMethodNamespaces(); return $this->API->getMethodNamespaces();
} }
/**
* Get mime type from buffer.
*
* @param string $buffer Buffer
*
* @return string
*/
public function getMimeFromBuffer(string $buffer): string
{
return \danog\MadelineProto\TL\Conversion\Extension::getMimeFromBuffer($buffer);
}
/**
* Get mime type from file extension.
*
* @param string $extension File extension
* @param string $default Default mime type
*
* @return string
*/
public function getMimeFromExtension(string $extension, string $default): string
{
return \danog\MadelineProto\TL\Conversion\Extension::getMimeFromExtension($extension, $default);
}
/**
* Get mime type of file.
*
* @param string $file File
*
* @return string
*/
public function getMimeFromFile(string $file): string
{
return \danog\MadelineProto\TL\Conversion\Extension::getMimeFromFile($file);
}
/** /**
* Accesses a private variable from an object. * Accesses a private variable from an object.
* *