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:
parent
c6299d2f5a
commit
da252bb291
2
docs
2
docs
@ -1 +1 @@
|
||||
Subproject commit 544e2a897f399efb7c3bcba84cd872a1ffa6d278
|
||||
Subproject commit 61cdff1c445fd53456b63d33a6feac12e4023514
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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'])) {
|
||||
|
@ -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':
|
||||
|
@ -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),
|
||||
|
@ -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!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user