diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index 2a2d3968f..3d06fc804 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -4131,6 +4131,12 @@
+
+
+
+
+
+
diff --git a/src/API.php b/src/API.php
index dda71b29a..d4307ecbf 100644
--- a/src/API.php
+++ b/src/API.php
@@ -51,7 +51,7 @@ final class API extends AbstractAPI
*
* @var string
*/
- public const RELEASE = '8.0.0-beta202';
+ public const RELEASE = '8.0.0-beta203';
/**
* We're not logged in.
*
diff --git a/src/InternalDoc.php b/src/InternalDoc.php
index 9976f197c..879de945f 100644
--- a/src/InternalDoc.php
+++ b/src/InternalDoc.php
@@ -1081,9 +1081,9 @@ abstract class InternalDoc
/**
* Provide a stream for a file, URL or amp stream.
*/
- final public function getStream(\danog\MadelineProto\EventHandler\Message|\danog\MadelineProto\EventHandler\Media|\danog\MadelineProto\LocalFile|\danog\MadelineProto\RemoteUrl|\danog\MadelineProto\BotApiFileId|\Amp\ByteStream\ReadableStream $stream, ?\Amp\Cancellation $cancellation = null): \Amp\ByteStream\ReadableStream
+ final public function getStream(\danog\MadelineProto\EventHandler\Message|\danog\MadelineProto\EventHandler\Media|\danog\MadelineProto\LocalFile|\danog\MadelineProto\RemoteUrl|\danog\MadelineProto\BotApiFileId|\Amp\ByteStream\ReadableStream $stream, ?\Amp\Cancellation $cancellation = null, ?int &$size = null): \Amp\ByteStream\ReadableStream
{
- return $this->wrapper->getAPI()->getStream($stream, $cancellation);
+ return $this->wrapper->getAPI()->getStream($stream, $cancellation, $size);
}
/**
* Obtains a pipe that can be used to upload a file from a stream.
diff --git a/src/MTProtoTools/FilesAbstraction.php b/src/MTProtoTools/FilesAbstraction.php
index 41ed3ff8c..20fed8b01 100644
--- a/src/MTProtoTools/FilesAbstraction.php
+++ b/src/MTProtoTools/FilesAbstraction.php
@@ -24,6 +24,8 @@ use Amp\ByteStream\Pipe;
use Amp\ByteStream\ReadableBuffer;
use Amp\ByteStream\ReadableStream;
use Amp\Cancellation;
+use Amp\Http\Client\HttpClient;
+use Amp\Http\Client\HttpClientBuilder;
use Amp\Http\Client\Request;
use Amp\Process\Process;
use AssertionError;
@@ -53,6 +55,7 @@ use Webmozart\Assert\Assert;
use function Amp\async;
use function Amp\ByteStream\buffer;
+use function Amp\File\getSize;
use function Amp\File\openFile;
use function Amp\Future\await;
@@ -65,21 +68,31 @@ use function Amp\Future\await;
*/
trait FilesAbstraction
{
+ private static ?HttpClient $client;
/**
* Provide a stream for a file, URL or amp stream.
*/
- public function getStream(Message|Media|LocalFile|RemoteUrl|BotApiFileId|ReadableStream $stream, ?Cancellation $cancellation = null): ReadableStream
+ public function getStream(Message|Media|LocalFile|RemoteUrl|BotApiFileId|ReadableStream $stream, ?Cancellation $cancellation = null, ?int &$size = null): ReadableStream
{
if ($stream instanceof LocalFile) {
+ $size = getSize($stream->file);
return openFile($stream->file, 'r');
}
if ($stream instanceof RemoteUrl) {
+ self::$client ??= HttpClientBuilder::buildDefault();
$request = new Request($stream->url);
$request->setTransferTimeout(INF);
- return $this->getHTTPClient()->request(
+ $request->setBodySizeLimit(512 * 1024 * 8000);
+ $response = self::$client->request(
$request,
$cancellation
- )->getBody();
+ );
+ if (($status = $response->getStatus()) !== 200) {
+ throw new Exception("Wrong status code: {$status} ".$response->getReason());
+ }
+ $size = (int) ($response->getHeader('content-length') ?? $size);
+ $stream = $response->getBody();
+ return $stream;
}
if ($stream instanceof Message) {
$stream = $stream->media;
@@ -88,9 +101,11 @@ trait FilesAbstraction
}
}
if ($stream instanceof Media) {
+ $size = $stream->size;
return $stream->getStream(cancellation: $cancellation);
}
if ($stream instanceof BotApiFileId) {
+ $size = $stream->size;
return $this->downloadToReturnedStream($stream, cancellation: $cancellation);
}
return $stream;
@@ -1127,9 +1142,18 @@ trait FilesAbstraction
private function extractMime(bool $secret, Message|Media|LocalFile|RemoteUrl|BotApiFileId|ReadableStream &$file, ?string $fileName, ?callable $callback, ?Cancellation $cancellation): string
{
- $file = $this->getStream($file, $cancellation);
+ $size = 0;
+ $file = $this->getStream($file, $cancellation, $size);
$p = new Pipe(1024*1024);
- $fileFuture = async(fn () => $this->upload(new StreamDuplicator($file, $p->getSink()), $fileName ?? '', $callback, $secret, $cancellation));
+ $fileFuture = async(fn () => $this->uploadFromStream(
+ new StreamDuplicator($file, $p->getSink()),
+ $size,
+ 'application/octet-stream',
+ $fileName ?? '',
+ $callback,
+ $secret,
+ $cancellation
+ ));
$buff = '';
while (\strlen($buff) < 1024*1024 && null !== $chunk = $p->getSource()->read($cancellation)) {
@@ -1140,7 +1164,7 @@ trait FilesAbstraction
unset($p);
$file = $fileFuture->await();
- return (new finfo())->buffer($buff, FILEINFO_MIME_TYPE);
+ return (new finfo())->buffer($buff, FILEINFO_MIME_TYPE);
}
private function extractAudioInfo(bool $secret, Message|Media|LocalFile|RemoteUrl|BotApiFileId|ReadableStream &$file, ?string $fileName, ?callable $callback, ?Cancellation $cancellation, ?string &$mimeType, array &$attributes, mixed &$thumb): void
{
@@ -1163,7 +1187,8 @@ trait FilesAbstraction
return;
}
- $file = $this->getStream($file, $cancellation);
+ $size = 0;
+ $file = $this->getStream($file, $cancellation, $size);
$process = Process::start('ffmpeg -i pipe: -f image2pipe -', cancellation: $cancellation);
$stdin = $process->getStdin();
$stdout = $process->getStdout();
@@ -1189,7 +1214,15 @@ trait FilesAbstraction
unset($p);
}
- $fileFuture = async(fn () => $this->upload(new StreamDuplicator($file, ...$streams), $fileName ?? '', $callback, $secret, $cancellation));
+ $fileFuture = async(fn () => $this->uploadFromStream(
+ new StreamDuplicator($file, ...$streams),
+ $size,
+ 'application/octet-stream',
+ $fileName ?? '',
+ $callback,
+ $secret,
+ $cancellation
+ ));
[$stdout, $stderr] = await($f);
$process->join($cancellation);
@@ -1236,7 +1269,8 @@ trait FilesAbstraction
return;
}
- $file = $this->getStream($file, $cancellation);
+ $size = 0;
+ $file = $this->getStream($file, $cancellation, $size);
$ffmpeg = 'ffmpeg -i pipe: -ss '.$thumbSeek.' -frames:v 1 -f image2pipe -';
$process = Process::start($ffmpeg, cancellation: $cancellation);
$stdin = $process->getStdin();
@@ -1261,7 +1295,15 @@ trait FilesAbstraction
unset($p);
}
- $fileFuture = async(fn () => $this->upload(new StreamDuplicator($file, ...$streams), $fileName ?? '', $callback, $secret, $cancellation));
+ $fileFuture = async(fn () => $this->uploadFromStream(
+ new StreamDuplicator($file, ...$streams),
+ $size,
+ 'application/octet-stream',
+ $fileName ?? '',
+ $callback,
+ $secret,
+ $cancellation
+ ));
[$stdout, $stderr] = await($f);
if ($stdout !== '') {
diff --git a/src/Tools.php b/src/Tools.php
index 071bb21be..5a160a3bd 100644
--- a/src/Tools.php
+++ b/src/Tools.php
@@ -66,7 +66,6 @@ use const PHP_SAPI;
use const STR_PAD_RIGHT;
use function Amp\File\openFile;
-use function Amp\File\read;
use function unpack;
/**
@@ -712,7 +711,7 @@ abstract class Tools extends AsyncTools
}
$plugin = is_subclass_of($class, PluginEventHandler::class);
$file = (new ReflectionClass($class))->getFileName();
- $code = read($file);
+ $code = file_get_contents($file);
$code = (new ParserFactory)->createForNewestSupportedVersion()->parse($code);
Assert::notNull($code);
$traverser = new NodeTraverser;
diff --git a/tests/testing.php b/tests/testing.php
index 1ba07af67..f07101ff6 100755
--- a/tests/testing.php
+++ b/tests/testing.php
@@ -124,21 +124,6 @@ if (!getenv('GITHUB_SHA') && stripos(($MadelineProto->readline('Do you want to m
*/
if (!getenv('GITHUB_SHA') && stripos(($MadelineProto->readline('Do you want to handle incoming calls? (y/n): ')) ?? '', 'y') !== false) {
$howmany = $MadelineProto->readline('How many calls would you like me to handle? ');
- $offset = 0;
- while ($howmany > 0) {
- $updates = $MadelineProto->getUpdates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
- foreach ($updates as $update) {
- $MadelineProto->logger($update);
- $offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id
- switch ($update['update']['_']) {
- case 'updatePhoneCall':
- if (is_object($update['update']['phone_call']) && $update['update']['phone_call']->getCallState() === VoIP::CALL_STATE_INCOMING) {
- $update['update']['phone_call']->accept()->play('input.raw')->then('input.raw')->playOnHold(['input.raw'])->setOutputFile('output.raw');
- $howmany--;
- }
- }
- }
- }
}
/*