1
0
mirror of https://github.com/danog/MadelineProto.git synced 2024-11-26 21:14:43 +01:00

Allow using fopen on php://memory, improve stream upload logic, handle MSG_WAIT_FAILED errors, improve call queue, improve tests

This commit is contained in:
Daniil Gentili 2023-09-07 16:24:35 +02:00
parent c6299d2f5a
commit da252bb291
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
7 changed files with 56 additions and 14 deletions

2
docs

@ -1 +1 @@
Subproject commit 544e2a897f399efb7c3bcba84cd872a1ffa6d278
Subproject commit 61cdff1c445fd53456b63d33a6feac12e4023514

View File

@ -34,6 +34,7 @@ use danog\MadelineProto\RemoteUrl;
use danog\MadelineProto\SessionPaths;
use danog\MadelineProto\Wrappers\Start;
use Revolt\EventLoop;
use Symfony\Component\Process\InputStream;
use Throwable;
use function Amp\async;
@ -242,7 +243,10 @@ final class Client extends ClientAbstract
$method === 'messages.sendMedia' ||
$method === 'messages.editMessage') &&
isset($args['media']['file']) &&
$args['media']['file'] instanceof FileCallbackInterface
(
$args['media']['file'] instanceof FileCallbackInterface
|| $args['media']['file'] instanceof InputStream
)
) {
$params = [$method, &$args, $aargs];
$wrapper = Wrapper::create($params, $this->session, $this->logger);
@ -252,7 +256,12 @@ final class Client extends ClientAbstract
$params = [$method, &$args, $aargs];
$wrapper = Wrapper::create($params, $this->session, $this->logger);
foreach ($args['multi_media'] as &$media) {
if (isset($media['media']['file']) && $media['media']['file'] instanceof FileCallbackInterface) {
if (isset($media['media']['file']) &&
(
$media['media']['file'] instanceof FileCallbackInterface
|| $media['media']['file'] instanceof ReadableStream
)
) {
$wrapper->wrap($media['media']['file'], true);
}
}

View File

@ -115,9 +115,9 @@ final class Wrapper extends ClientAbstract
}
$class = null;
if ($callback instanceof ByteStreamReadableStream) {
$class = \method_exists($callback, 'seek') ? ReadableStream::class : SeekableReadableStream::class;
$class = \method_exists($callback, 'seek') ? SeekableReadableStream::class : ReadableStream::class;
} elseif ($callback instanceof ByteStreamWritableStream) {
$class = \method_exists($callback, 'seek') ? WritableStream::class : SeekableWritableStream::class;
$class = \method_exists($callback, 'seek') ? SeekableWritableStream::class : WritableStream::class;
} elseif ($callback instanceof FileCallbackInterface) {
$class = FileCallback::class;
} elseif ($callback instanceof Cancellation) {

View File

@ -130,7 +130,7 @@ trait CallHandler
if (isset($args['message']) && \is_string($args['message']) && \mb_strlen($args['message'], 'UTF-8') > ($this->API->getConfig())['message_length_max'] && \mb_strlen($this->API->parseMode($args)['message'], 'UTF-8') > ($this->API->getConfig())['message_length_max']) {
$args = $this->API->splitToChunks($args);
$promises = [];
$aargs['queue'] = $method;
$aargs['queue'] = $method.' '.time();
$aargs['multiple'] = true;
}
if (isset($aargs['multiple'])) {

View File

@ -312,6 +312,16 @@ trait ResponseHandler
}
EventLoop::queue(closure: $this->methodRecall(...), message_id: $request->getMsgId(), datacenter: $datacenter);
return null;
case 400:
if ($request->hasQueue() &&
($response['error_message'] === 'MSG_WAIT_FAILED'
|| $response['error_message'] === 'MSG_WAIT_TIMEOUT'
)
) {
EventLoop::queue(closure: $this->methodRecall(...), message_id: $request->getMsgId());
return null;
}
return fn () => new RPCErrorException($response['error_message'], $response['error_code'], $request->getConstructor());
case 401:
switch ($response['error_message']) {
case 'USER_DEACTIVATED':

View File

@ -754,6 +754,13 @@ abstract class Tools extends AsyncTools
$name = $call->name->toLowerString();
if (isset(self::BLOCKING_FUNCTIONS[$name])) {
if ($name === 'fopen' &&
isset($call->args[0]) &&
$call->args[0]->value instanceof String_ &&
str_starts_with($call->args[0]->value->value, 'php://memory')
) {
continue;
}
$explanation = self::BLOCKING_FUNCTIONS[$name];
$issues []= new EventHandlerIssue(
message: \sprintf(Lang::$current_lang['do_not_use_blocking_function'], $name, $explanation),

View File

@ -15,7 +15,9 @@ If not, see <http://www.gnu.org/licenses/>.
* Various ways to load MadelineProto.
*/
use Amp\ByteStream\ReadableBuffer;
use danog\MadelineProto\API;
use danog\MadelineProto\FileCallback;
use danog\MadelineProto\Logger;
use danog\MadelineProto\Settings;
use danog\MadelineProto\VoIP;
@ -260,7 +262,7 @@ $media = [];
$media['photo'] = ['_' => 'inputMediaUploadedPhoto', 'file' => __DIR__.'/faust.jpg'];
// Image by URL
$media['photo'] = ['_' => 'inputMediaPhotoExternal', 'url' => 'https://github.com/danog/MadelineProto/raw/v8/tests/faust.jpg'];
$media['photo_url'] = ['_' => 'inputMediaPhotoExternal', 'url' => 'https://github.com/danog/MadelineProto/raw/v8/tests/faust.jpg'];
// Sticker
$media['sticker'] = ['_' => 'inputMediaUploadedDocument', 'file' => __DIR__.'/lel.webp', 'attributes' => [['_' => 'documentAttributeSticker', 'alt' => 'LEL']]];
@ -278,7 +280,21 @@ $media['voice'] = ['_' => 'inputMediaUploadedDocument', 'file' => __DIR__.'/mosc
$media['document'] = ['_' => 'inputMediaUploadedDocument', 'file' => __DIR__.'/60', 'mime_type' => 'magic/magic', 'attributes' => [['_' => 'documentAttributeFilename', 'file_name' => 'magic.magic']]];
// Document by URL
$media['document'] = ['_' => 'inputMediaDocumentExternal', 'url' => 'https://github.com/danog/MadelineProto/raw/v8/tests/60'];
$media['document_url'] = ['_' => 'inputMediaDocumentExternal', 'url' => 'https://github.com/danog/MadelineProto/raw/v8/tests/60'];
foreach ($media as $key => $value) {
if (isset($value['file'])) {
$value['file'] = new ReadableBuffer(read($value['file']));
$media["stream_$key"] = $value;
}
}
foreach ($media as $key => $value) {
if (isset($value['file'])) {
$value['file'] = new FileCallback($value['file'], function () {});
$media["callback_$key"] = $value;
}
}
$message = 'yay '.PHP_VERSION_ID;
$mention = $MadelineProto->getInfo(getenv('TEST_USERNAME')); // Returns an array with all of the constructors that can be extracted from a username or an id
@ -311,8 +327,8 @@ foreach ($peers as $peer) {
$MadelineProto->logger("Downloading $type");
$file = $MadelineProto->downloadToDir($dl, '/tmp');
if ($type !== 'photo') {
Assert::eq(read($file), $fileOrig, "Not equal!");
if ($type !== 'photo' && $type !== 'photo_url') {
Assert::eq(read($file), $fileOrig, "Not equal $type!");
}
$MadelineProto->logger("Uploading $type");
@ -320,8 +336,8 @@ foreach ($peers as $peer) {
$MadelineProto->logger("Downloading $type");
$file = $MadelineProto->downloadToDir($media, '/tmp');
if ($type !== 'photo') {
Assert::eq(read($file), $fileOrig, "Not equal!");
if ($type !== 'photo' && $type !== 'photo_url') {
Assert::eq(read($file), $fileOrig, "Not equal $type!");
}
$MadelineProto->logger("Re-sending $type");
@ -331,8 +347,8 @@ foreach ($peers as $peer) {
$MadelineProto->logger("Re-downloading $type");
$file = $MadelineProto->downloadToDir($dl, '/tmp');
if ($type !== 'photo') {
Assert::eq(read($file), $fileOrig, "Not equal!");
if ($type !== 'photo' && $type !== 'photo_url') {
Assert::eq(read($file), $fileOrig, "Not equal $type!");
}
}
}