1
0
mirror of https://github.com/danog/MadelineProto.git synced 2024-11-30 07:18:57 +01:00

Cancellation support

This commit is contained in:
Daniil Gentili 2023-09-30 21:29:51 +02:00
parent 7b6a65a55f
commit 949758aeb5
9 changed files with 74 additions and 47 deletions

View File

@ -725,6 +725,7 @@ Want to add your own open-source project to this list? [Click here!](https://doc
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#posmod-int-a-int-b-int" name="posmod">Positive modulo: posmod</a>
* <a href="https://docs.madelineproto.xyz/API_docs/methods/messages.getBotCallbackAnswer.html" name="messages.getBotCallbackAnswer">Press an inline callback button and get a callback answer from the bot: messages.getBotCallbackAnswer</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#openbuffered-danog-madelineproto-localfile-danog-madelineproto-remoteurl-amp-bytestream-readablestream-stream-amp-cancellation-cancellation-null-callable" name="openBuffered">Provide a buffered reader for a file, URL or amp stream: openBuffered</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#getstream-danog-madelineproto-eventhandler-message-danog-madelineproto-eventhandler-media-danog-madelineproto-localfile-danog-madelineproto-remoteurl-danog-madelineproto-botapifileid-amp-bytestream-readablestream-stream-amp-bytestream-readablestream" name="getStream">Provide a stream for a file, URL or amp stream: getStream</a>
* <a href="https://docs.madelineproto.xyz/API_docs/methods/messages.getInlineBotResults.html" name="messages.getInlineBotResults">Query an inline bot: messages.getInlineBotResults</a>
* <a href="https://docs.madelineproto.xyz/API_docs/methods/phone.setCallRating.html" name="phone.setCallRating">Rate a call, returns info about the rating message sent to the official VoIP bot: phone.setCallRating</a>
* <a href="https://docs.madelineproto.xyz/API_docs/methods/messages.rateTranscribedAudio.html" name="messages.rateTranscribedAudio">Rate transcribed voice message: messages.rateTranscribedAudio</a>
@ -823,13 +824,13 @@ Want to add your own open-source project to this list? [Click here!](https://doc
* <a href="https://docs.madelineproto.xyz/API_docs/methods/account.acceptAuthorization.html" name="account.acceptAuthorization">Sends a Telegram Passport authorization form, effectively sharing data with the service: account.acceptAuthorization</a>
* <a href="https://docs.madelineproto.xyz/API_docs/methods/messages.setTyping.html" name="messages.setTyping">Sends a current user typing event (see SendMessageAction for all event types) to a conversation partner or group: messages.setTyping</a>
* <a href="https://docs.madelineproto.xyz/API_docs/methods/bots.sendCustomRequest.html" name="bots.sendCustomRequest">Sends a custom request; for bots only: bots.sendCustomRequest</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#senddocument-int-string-peer-danog-madelineproto-eventhandler-message-danog-madelineproto-eventhandler-media-localfile-remoteurl-botapifileid-amp-bytestream-readablestream-file-danog-madelineproto-eventhandler-message-danog-madelineproto-eventhandler-media-localfile-remoteurl-botapifileid-amp-bytestream-readablestream-null-thumb-null-string-caption-parsemode-parsemode-danog-madelineproto-parsemode-text-callable-callback-null-string-filename-null-string-mimetype-null-int-ttl-null-bool-spoiler-false-int-null-replytomsgid-null-int-null-topmsgid-null-array-null-replymarkup-null-int-null-sendas-null-int-null-scheduledate-null-bool-silent-false-bool-noforwards-false-bool-background-false-bool-cleardraft-false-bool-updatestickersetsorder-false-danog-madelineproto-eventhandler-message" name="sendDocument">Sends a document: sendDocument</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#senddocument-int-string-peer-danog-madelineproto-eventhandler-message-danog-madelineproto-eventhandler-media-localfile-remoteurl-botapifileid-amp-bytestream-readablestream-file-danog-madelineproto-eventhandler-message-danog-madelineproto-eventhandler-media-localfile-remoteurl-botapifileid-amp-bytestream-readablestream-null-thumb-null-string-caption-parsemode-parsemode-danog-madelineproto-parsemode-text-callable-callback-null-string-filename-null-string-mimetype-null-int-ttl-null-bool-spoiler-false-int-null-replytomsgid-null-int-null-topmsgid-null-array-null-replymarkup-null-int-null-sendas-null-int-null-scheduledate-null-bool-silent-false-bool-noforwards-false-bool-background-false-bool-cleardraft-false-bool-updatestickersetsorder-false-amp-cancellation-cancellation-null-danog-madelineproto-eventhandler-message" name="sendDocument">Sends a document: sendDocument</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#broadcastmessages-array-messages-danog-madelineproto-broadcast-filter-filter-null-bool-pin-false-int" name="broadcastMessages">Sends a list of messages to all peers (users, chats, channels) of the bot: broadcastMessages</a>
* <a href="https://docs.madelineproto.xyz/API_docs/methods/messages.sendMessage.html" name="messages.sendMessage">Sends a message to a chat: messages.sendMessage</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#sendmessagetoadmins-string-message-parsemode-parsemode-danog-madelineproto-parsemode-text-array-null-replymarkup-null-int-null-scheduledate-null-bool-silent-false-bool-noforwards-false-bool-background-false-bool-cleardraft-false-bool-nowebpage-false-list-danog-madelineproto-eventhandler-message" name="sendMessageToAdmins">Sends a message to all report peers (admins of the bot): sendMessageToAdmins</a>
* <a href="https://docs.madelineproto.xyz/API_docs/methods/messages.sendEncryptedFile.html" name="messages.sendEncryptedFile">Sends a message with a file attachment to a secret chat: messages.sendEncryptedFile</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#sendmessage-int-string-peer-string-message-parsemode-parsemode-danog-madelineproto-parsemode-text-int-null-replytomsgid-null-int-null-topmsgid-null-array-null-replymarkup-null-int-null-sendas-null-int-null-scheduledate-null-bool-silent-false-bool-noforwards-false-bool-background-false-bool-cleardraft-false-bool-nowebpage-false-bool-updatestickersetsorder-false-danog-madelineproto-eventhandler-message" name="sendMessage">Sends a message: sendMessage</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#sendphoto-int-string-peer-danog-madelineproto-eventhandler-message-danog-madelineproto-eventhandler-media-localfile-remoteurl-botapifileid-amp-bytestream-readablestream-file-string-caption-parsemode-parsemode-danog-madelineproto-parsemode-text-callable-callback-null-string-filename-null-int-ttl-null-bool-spoiler-false-int-null-replytomsgid-null-int-null-topmsgid-null-array-null-replymarkup-null-int-null-sendas-null-int-null-scheduledate-null-bool-silent-false-bool-noforwards-false-bool-background-false-bool-cleardraft-false-bool-updatestickersetsorder-false-danog-madelineproto-eventhandler-message" name="sendPhoto">Sends a photo: sendPhoto</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#sendphoto-int-string-peer-danog-madelineproto-eventhandler-message-danog-madelineproto-eventhandler-media-localfile-remoteurl-botapifileid-amp-bytestream-readablestream-file-string-caption-parsemode-parsemode-danog-madelineproto-parsemode-text-callable-callback-null-string-filename-null-int-ttl-null-bool-spoiler-false-int-null-replytomsgid-null-int-null-topmsgid-null-array-null-replymarkup-null-int-null-sendas-null-int-null-scheduledate-null-bool-silent-false-bool-noforwards-false-bool-background-false-bool-cleardraft-false-bool-updatestickersetsorder-false-amp-cancellation-cancellation-null-danog-madelineproto-eventhandler-message" name="sendPhoto">Sends a photo: sendPhoto</a>
* <a href="https://docs.madelineproto.xyz/API_docs/methods/messages.sendEncryptedService.html" name="messages.sendEncryptedService">Sends a service message to a secret chat: messages.sendEncryptedService</a>
* <a href="https://docs.madelineproto.xyz/API_docs/methods/messages.sendEncrypted.html" name="messages.sendEncrypted">Sends a text message to a secret chat: messages.sendEncrypted</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#sendcustomevent-mixed-payload-void" name="sendCustomEvent">Sends an updateCustomEvent update to the event handler: sendCustomEvent</a>
@ -903,7 +904,7 @@ Want to add your own open-source project to this list? [Click here!](https://doc
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#uploadfromurl-string-filecallbackinterface-url-int-size-0-string-filename-callable-cb-null-bool-encrypted-false-array-inputfile-constructor" name="uploadFromUrl">Upload file from URL: uploadFromUrl</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#uploadfromcallable-callable-callable-int-size-0-string-mime-application-octet-stream-string-filename-callable-cb-null-bool-seekable-true-bool-encrypted-false-array-inputfile-constructor" name="uploadFromCallable">Upload file from callable: uploadFromCallable</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#uploadfromstream-mixed-stream-int-size-0-string-mime-application-octet-stream-string-filename-callable-cb-null-bool-encrypted-false-array-inputfile-constructor" name="uploadFromStream">Upload file from stream: uploadFromStream</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#uploadencrypted-filecallbackinterface-string-array-file-string-filename-callable-cb-null-array-inputfile-constructor" name="uploadEncrypted">Upload file to secret chat: uploadEncrypted</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#uploadencrypted-filecallbackinterface-localfile-remoteurl-botapifileid-string-array-resource-file-string-filename-callable-cb-null-array-inputfile-constructor" name="uploadEncrypted">Upload file to secret chat: uploadEncrypted</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#upload-filecallbackinterface-localfile-remoteurl-botapifileid-string-array-resource-file-string-filename-callable-cb-null-bool-encrypted-false-array-inputfile-constructor" name="upload">Upload file: upload</a>
* <a href="https://docs.madelineproto.xyz/API_docs/methods/account.uploadRingtone.html" name="account.uploadRingtone">Upload notification sound, use account.saveRingtone to convert it and add it to the list of saved notification sounds: account.uploadRingtone</a>
* <a href="https://docs.madelineproto.xyz/API_docs/methods/account.uploadTheme.html" name="account.uploadTheme">Upload theme: account.uploadTheme</a>

2
docs

@ -1 +1 @@
Subproject commit 5da30efc5233a9ef6e6804dd48cdd89170e56209
Subproject commit 1cec0caca9f9642ee120c87f0ad378da35077925

View File

@ -17,6 +17,7 @@
namespace danog\MadelineProto\EventHandler;
use Amp\ByteStream\ReadableStream;
use Amp\Cancellation;
use danog\MadelineProto\Ipc\IpcCapable;
use danog\MadelineProto\MTProto;
use danog\MadelineProto\TL\Types\Bytes;
@ -138,9 +139,9 @@ abstract class Media extends IpcCapable implements JsonSerializable
*
* @param (callable(float, float, float): void)|null $cb Progress callback
*/
public function getStream(?callable $cb = null, int $offset = 0, int $end = -1): ReadableStream
public function getStream(?callable $cb = null, int $offset = 0, int $end = -1, ?Cancellation $cancellation = null): ReadableStream
{
return $this->getClient()->downloadToReturnedStream($this, $cb, $offset, $end);
return $this->getClient()->downloadToReturnedStream($this, $cb, $offset, $end, $cancellation);
}
/**
@ -149,10 +150,10 @@ abstract class Media extends IpcCapable implements JsonSerializable
* @param string $dir Directory where to download the file
* @param (callable(float, float, float): void)|null $cb Progress callback
*/
public function downloadToDir(?string $dir = null, ?callable $cb = null): string
public function downloadToDir(?string $dir = null, ?callable $cb = null, ?Cancellation $cancellation = null): string
{
$dir ??= \getcwd();
return $this->getClient()->downloadToDir($this, $dir, $cb);
return $this->getClient()->downloadToDir($this, $dir, $cb, $cancellation);
}
/**
* Download the media to file.
@ -160,9 +161,9 @@ abstract class Media extends IpcCapable implements JsonSerializable
* @param string $file Downloaded file path
* @param (callable(float, float, float): void)|null $cb Progress callback
*/
public function downloadToFile(string $file, ?callable $cb = null): string
public function downloadToFile(string $file, ?callable $cb = null, ?Cancellation $cancellation = null): string
{
return $this->getClient()->downloadToFile($this, $file, $cb);
return $this->getClient()->downloadToFile($this, $file, $cb, $cancellation);
}
/**

View File

@ -1644,11 +1644,13 @@ abstract class InternalDoc
* @param boolean $background Send this message as background message
* @param boolean $clearDraft Clears the draft field
* @param boolean $updateStickersetsOrder Whether to move used stickersets to top
* @param boolean $forceResend Whether to forcefully resend the file, even if its type and name are the same.
* @param Cancellation $cancellation Cancellation.
*
*/
public function sendDocument(string|int $peer, \danog\MadelineProto\EventHandler\Message|\danog\MadelineProto\EventHandler\Media|\danog\MadelineProto\LocalFile|\danog\MadelineProto\RemoteUrl|\danog\MadelineProto\BotApiFileId|\Amp\ByteStream\ReadableStream $file, \danog\MadelineProto\EventHandler\Message|\danog\MadelineProto\EventHandler\Media|\danog\MadelineProto\LocalFile|\danog\MadelineProto\RemoteUrl|\danog\MadelineProto\BotApiFileId|\Amp\ByteStream\ReadableStream|null $thumb = null, string $caption = '', \danog\MadelineProto\ParseMode $parseMode = \danog\MadelineProto\ParseMode::TEXT, ?callable $callback = null, ?string $fileName = null, ?string $mimeType = null, ?int $ttl = null, bool $spoiler = false, ?int $replyToMsgId = null, ?int $topMsgId = null, ?array $replyMarkup = null, string|int|null $sendAs = null, ?int $scheduleDate = null, bool $silent = false, bool $noForwards = false, bool $background = false, bool $clearDraft = false, bool $updateStickersetsOrder = false, ?\Amp\Cancellation $cancellation = null): \danog\MadelineProto\EventHandler\Message
public function sendDocument(string|int $peer, \danog\MadelineProto\EventHandler\Message|\danog\MadelineProto\EventHandler\Media|\danog\MadelineProto\LocalFile|\danog\MadelineProto\RemoteUrl|\danog\MadelineProto\BotApiFileId|\Amp\ByteStream\ReadableStream $file, \danog\MadelineProto\EventHandler\Message|\danog\MadelineProto\EventHandler\Media|\danog\MadelineProto\LocalFile|\danog\MadelineProto\RemoteUrl|\danog\MadelineProto\BotApiFileId|\Amp\ByteStream\ReadableStream|null $thumb, string $caption, \danog\MadelineProto\ParseMode $parseMode, ?callable $callback, ?string $fileName, ?string $mimeType, ?int $ttl, bool $spoiler, ?int $replyToMsgId, ?int $topMsgId, ?array $replyMarkup, string|int|null $sendAs, ?int $scheduleDate, bool $silent, bool $noForwards, bool $background, bool $clearDraft, bool $updateStickersetsOrder, bool $forceResend, ?\Amp\Cancellation $cancellation = null): \danog\MadelineProto\EventHandler\Message
{
return $this->wrapper->getAPI()->sendDocument($peer, $file, $thumb, $caption, $parseMode, $callback, $fileName, $mimeType, $ttl, $spoiler, $replyToMsgId, $topMsgId, $replyMarkup, $sendAs, $scheduleDate, $silent, $noForwards, $background, $clearDraft, $updateStickersetsOrder, $cancellation);
return $this->wrapper->getAPI()->sendDocument($peer, $file, $thumb, $caption, $parseMode, $callback, $fileName, $mimeType, $ttl, $spoiler, $replyToMsgId, $topMsgId, $replyMarkup, $sendAs, $scheduleDate, $silent, $noForwards, $background, $clearDraft, $updateStickersetsOrder, $forceResend, $cancellation);
}
/**
* Sends a message.
@ -1709,11 +1711,13 @@ abstract class InternalDoc
* @param boolean $background Send this message as background message
* @param boolean $clearDraft Clears the draft field
* @param boolean $updateStickersetsOrder Whether to move used stickersets to top
* @param boolean $forceResend Whether to forcefully resend the file, even if its type and name are the same.
* @param Cancellation $cancellation Cancellation.
*
*/
public function sendPhoto(string|int $peer, \danog\MadelineProto\EventHandler\Message|\danog\MadelineProto\EventHandler\Media|\danog\MadelineProto\LocalFile|\danog\MadelineProto\RemoteUrl|\danog\MadelineProto\BotApiFileId|\Amp\ByteStream\ReadableStream $file, string $caption = '', \danog\MadelineProto\ParseMode $parseMode = \danog\MadelineProto\ParseMode::TEXT, ?callable $callback = null, ?string $fileName = null, ?int $ttl = null, bool $spoiler = false, ?int $replyToMsgId = null, ?int $topMsgId = null, ?array $replyMarkup = null, string|int|null $sendAs = null, ?int $scheduleDate = null, bool $silent = false, bool $noForwards = false, bool $background = false, bool $clearDraft = false, bool $updateStickersetsOrder = false, ?\Amp\Cancellation $cancellation = null): \danog\MadelineProto\EventHandler\Message
public function sendPhoto(string|int $peer, \danog\MadelineProto\EventHandler\Message|\danog\MadelineProto\EventHandler\Media|\danog\MadelineProto\LocalFile|\danog\MadelineProto\RemoteUrl|\danog\MadelineProto\BotApiFileId|\Amp\ByteStream\ReadableStream $file, string $caption = '', \danog\MadelineProto\ParseMode $parseMode = \danog\MadelineProto\ParseMode::TEXT, ?callable $callback = null, ?string $fileName = null, ?int $ttl = null, bool $spoiler = false, ?int $replyToMsgId = null, ?int $topMsgId = null, ?array $replyMarkup = null, string|int|null $sendAs = null, ?int $scheduleDate = null, bool $silent = false, bool $noForwards = false, bool $background = false, bool $clearDraft = false, bool $updateStickersetsOrder = false, bool $forceResend = false, ?\Amp\Cancellation $cancellation = null): \danog\MadelineProto\EventHandler\Message
{
return $this->wrapper->getAPI()->sendPhoto($peer, $file, $caption, $parseMode, $callback, $fileName, $ttl, $spoiler, $replyToMsgId, $topMsgId, $replyMarkup, $sendAs, $scheduleDate, $silent, $noForwards, $background, $clearDraft, $updateStickersetsOrder, $cancellation);
return $this->wrapper->getAPI()->sendPhoto($peer, $file, $caption, $parseMode, $callback, $fileName, $ttl, $spoiler, $replyToMsgId, $topMsgId, $replyMarkup, $sendAs, $scheduleDate, $silent, $noForwards, $background, $clearDraft, $updateStickersetsOrder, $forceResend, $cancellation);
}
/**
* Set NOOP update handler, ignoring all updates.

View File

@ -260,15 +260,16 @@ final class Client extends ClientAbstract
* @param string|FileCallbackInterface $dir Directory where to download the file
* @param callable $cb Callback
*/
public function downloadToDir(mixed $messageMedia, string|FileCallbackInterface $dir, ?callable $cb = null)
public function downloadToDir(mixed $messageMedia, string|FileCallbackInterface $dir, ?callable $cb = null, ?Cancellation $cancellation = null)
{
if (\is_object($dir) && $dir instanceof FileCallbackInterface) {
$cb = $dir;
$dir = $dir->getFile();
}
$params = [$messageMedia, $dir, &$cb];
$params = [$messageMedia, $dir, &$cb, &$cancellation];
$wrapper = Wrapper::create($params, $this->session, $this->logger);
$wrapper->wrap($cb, false);
$wrapper->wrap($cancellation, false);
return $this->__call('downloadToDir', $wrapper);
}
/**
@ -278,15 +279,16 @@ final class Client extends ClientAbstract
* @param string|FileCallbackInterface $file Downloaded file path
* @param callable $cb Callback
*/
public function downloadToFile(mixed $messageMedia, string|FileCallbackInterface $file, ?callable $cb = null)
public function downloadToFile(mixed $messageMedia, string|FileCallbackInterface $file, ?callable $cb = null, ?Cancellation $cancellation = null)
{
if (\is_object($file) && $file instanceof FileCallbackInterface) {
$cb = $file;
$file = $file->getFile();
}
$params = [$messageMedia, $file, &$cb];
$params = [$messageMedia, $file, &$cb, &$cancellation];
$wrapper = Wrapper::create($params, $this->session, $this->logger);
$wrapper->wrap($cb, false);
$wrapper->wrap($cancellation, false);
return $this->__call('downloadToFile', $wrapper);
}
/**
@ -303,17 +305,18 @@ final class Client extends ClientAbstract
* @param int $end Offset where to stop downloading (inclusive)
* @param int $part_size Size of each chunk
*/
public function downloadToCallable(mixed $messageMedia, callable $callable, ?callable $cb = null, bool $seekable = true, int $offset = 0, int $end = -1, ?int $part_size = null)
public function downloadToCallable(mixed $messageMedia, callable $callable, ?callable $cb = null, bool $seekable = true, int $offset = 0, int $end = -1, ?int $part_size = null, ?Cancellation $cancellation = null)
{
$messageMedia = ($this->getDownloadInfo($messageMedia));
if (\is_object($callable) && $callable instanceof FileCallbackInterface) {
$cb = $callable;
$callable = $callable->getFile();
}
$params = [$messageMedia, &$callable, &$cb, $seekable, $offset, $end, $part_size, ];
$params = [$messageMedia, &$callable, &$cb, $seekable, $offset, $end, $part_size, &$cancellation];
$wrapper = Wrapper::create($params, $this->session, $this->logger);
$wrapper->wrap($callable, false);
$wrapper->wrap($cb, false);
$wrapper->wrap($cancellation, false);
return $this->__call('downloadToCallable', $wrapper);
}
/**

View File

@ -23,6 +23,7 @@ namespace danog\MadelineProto;
use Amp\ByteStream\ReadableStream;
use Amp\Cache\Cache;
use Amp\Cache\LocalCache;
use Amp\Cancellation;
use Amp\DeferredFuture;
use Amp\Dns\DnsResolver;
use Amp\Future;
@ -713,7 +714,7 @@ final class MTProto implements TLCallback, LoggerGetter
/**
* Provide a stream for a file, URL or amp stream.
*/
public function getStream(Message|Media|LocalFile|RemoteUrl|BotApiFileId|ReadableStream $stream): ReadableStream
public function getStream(Message|Media|LocalFile|RemoteUrl|BotApiFileId|ReadableStream $stream, ?Cancellation $cancellation = null): ReadableStream
{
if ($stream instanceof LocalFile) {
return openFile($stream->file, 'r');
@ -723,6 +724,7 @@ final class MTProto implements TLCallback, LoggerGetter
$request->setTransferTimeout(INF);
return $this->getHTTPClient()->request(
$request,
$cancellation
)->getBody();
}
if ($stream instanceof Message) {
@ -732,10 +734,10 @@ final class MTProto implements TLCallback, LoggerGetter
}
}
if ($stream instanceof Media) {
return $stream->getStream();
return $stream->getStream(cancellation: $cancellation);
}
if ($stream instanceof BotApiFileId) {
return $this->downloadToReturnedStream($stream);
return $this->downloadToReturnedStream($stream, cancellation: $cancellation);
}
return $stream;
}

View File

@ -20,6 +20,7 @@ declare(strict_types=1);
namespace danog\MadelineProto\MTProtoTools;
use Amp\Cancellation;
use Amp\DeferredFuture;
use Amp\Future;
use Amp\Http\Client\Request;
@ -933,14 +934,14 @@ trait Files
*
* @return non-empty-string Downloaded file name
*/
public function downloadToDir(mixed $messageMedia, string|FileCallbackInterface $dir, ?callable $cb = null): string
public function downloadToDir(mixed $messageMedia, string|FileCallbackInterface $dir, ?callable $cb = null, ?Cancellation $cancellation = null): string
{
if (\is_object($dir) && $dir instanceof FileCallbackInterface) {
$cb = $dir;
$dir = $dir->getFile();
}
$messageMedia = ($this->getDownloadInfo($messageMedia));
return $this->downloadToFile($messageMedia, $dir.'/'.$messageMedia['name'].$messageMedia['ext'], $cb);
return $this->downloadToFile($messageMedia, $dir.'/'.$messageMedia['name'].$messageMedia['ext'], $cb, $cancellation);
}
/**
* Download file.
@ -951,7 +952,7 @@ trait Files
*
* @return non-empty-string Downloaded file name
*/
public function downloadToFile(mixed $messageMedia, string|FileCallbackInterface $file, ?callable $cb = null): string
public function downloadToFile(mixed $messageMedia, string|FileCallbackInterface $file, ?callable $cb = null, ?Cancellation $cancellation = null): string
{
if (\is_object($file) && $file instanceof FileCallbackInterface) {
$cb = $file;
@ -969,7 +970,7 @@ trait Files
$this->logger->logger('Waiting for lock of file to download...');
$unlock = Tools::flock("$file.lock", LOCK_EX);
$this->logger->logger('Got lock of file to download');
async($this->downloadToStream(...), $messageMedia, $stream, $cb, $size, -1)->finally(function () use ($stream, $unlock, $file): void {
async($this->downloadToStream(...), $messageMedia, $stream, $cb, $size, -1, $cancellation)->finally(function () use ($stream, $unlock, $file): void {
$stream->close();
$unlock();
try {
@ -992,7 +993,7 @@ trait Files
* @param int $end Offset where to stop downloading (inclusive)
* @param int $part_size Size of each chunk
*/
public function downloadToCallable(mixed $messageMedia, callable $callable, ?callable $cb = null, bool $seekable = true, int $offset = 0, int $end = -1, ?int $part_size = null): void
public function downloadToCallable(mixed $messageMedia, callable $callable, ?callable $cb = null, bool $seekable = true, int $offset = 0, int $end = -1, ?int $part_size = null, ?Cancellation $cancellation = null): void
{
$messageMedia = ($this->getDownloadInfo($messageMedia));
if (\is_object($callable) && $callable instanceof FileCallbackInterface) {
@ -1074,7 +1075,7 @@ trait Files
$params[0]['previous_promise'] = true;
$start = \microtime(true);
$old_dc = null;
$size = $this->downloadPart($messageMedia, $cdn, $datacenter, $old_dc, $ige, $cb, $initParam = \array_shift($params), $callable, $seekable);
$size = $this->downloadPart($messageMedia, $cdn, $datacenter, $old_dc, $ige, $cb, $initParam = \array_shift($params), $callable, $seekable, $cancellation);
if ($initParam['part_end_at'] - $initParam['part_start_at'] !== $size) {
// Premature end for undefined length files
$origCb(100, 0, 0);
@ -1086,7 +1087,7 @@ trait Files
$promises = [];
foreach ($params as $key => $param) {
$param['previous_promise'] = $previous_promise;
$previous_promise = async($this->downloadPart(...), $messageMedia, $cdn, $datacenter, $old_dc, $ige, $cb, $param, $callable, $seekable);
$previous_promise = async($this->downloadPart(...), $messageMedia, $cdn, $datacenter, $old_dc, $ige, $cb, $param, $callable, $seekable, $cancellation);
$previous_promise->map(static function (int $res) use (&$size): void {
$size += $res;
});
@ -1137,7 +1138,7 @@ trait Files
* @param boolean $seekable Whether the download file is seekable
* @param boolean $postpone Whether to postpone method call
*/
private function downloadPart(array &$messageMedia, bool &$cdn, int &$datacenter, ?int &$old_dc, ?IGE &$ige, callable $cb, array $offset, callable $callable, bool $seekable, bool $postpone = false): int
private function downloadPart(array &$messageMedia, bool &$cdn, int &$datacenter, ?int &$old_dc, ?IGE &$ige, callable $cb, array $offset, callable $callable, bool $seekable, ?Cancellation $cancellation): int
{
do {
if (!$cdn) {
@ -1151,7 +1152,7 @@ trait Files
$res = $this->methodCallAsyncRead(
$cdn ? 'upload.getCdnFile' : 'upload.getFile',
$basic_param + $offset,
['heavy' => true, 'FloodWaitLimit' => 0, 'datacenter' => &$datacenter, 'postpone' => $postpone]
['heavy' => true, 'FloodWaitLimit' => 0, 'datacenter' => &$datacenter, 'cancellation' => $cancellation]
);
break;
} catch (FloodWaitError $e) {
@ -1186,7 +1187,7 @@ trait Files
$this->config['expires'] = 0;
$this->getConfig();
try {
$this->addCdnHashes($messageMedia['file_token'], $this->methodCallAsyncRead('upload.reuploadCdnFile', ['file_token' => $messageMedia['file_token'], 'request_token' => $res['request_token']], ['heavy' => true, 'datacenter' => $old_dc]));
$this->addCdnHashes($messageMedia['file_token'], $this->methodCallAsyncRead('upload.reuploadCdnFile', ['file_token' => $messageMedia['file_token'], 'request_token' => $res['request_token']], ['heavy' => true, 'datacenter' => $old_dc, 'cancellation' => $cancellation]));
} catch (RPCErrorException $e) {
switch ($e->rpc) {
case 'FILE_TOKEN_INVALID':
@ -1213,7 +1214,7 @@ trait Files
if (isset($messageMedia['cdn_key'])) {
$ivec = \substr($messageMedia['cdn_iv'], 0, 12).\pack('N', $offset['offset'] >> 4);
$res['bytes'] = Crypt::ctrEncrypt($res['bytes'], $messageMedia['cdn_key'], $ivec);
$this->checkCdnHash($messageMedia['file_token'], $offset['offset'], $res['bytes'], $old_dc);
$this->checkCdnHash($messageMedia['file_token'], $offset['offset'], $res['bytes'], $old_dc, $cancellation);
}
if (isset($messageMedia['key'])) {
$res['bytes'] = $ige->decrypt($res['bytes']);
@ -1244,11 +1245,11 @@ trait Files
$this->cdn_hashes[$file][$hash['offset']] = ['limit' => $hash['limit'], 'hash' => (string) $hash['hash']];
}
}
private function checkCdnHash(string $file, int $offset, string $data, int &$datacenter): void
private function checkCdnHash(string $file, int $offset, string $data, int &$datacenter, ?Cancellation $cancellation): void
{
while (\strlen($data)) {
if (!isset($this->cdn_hashes[$file][$offset])) {
$this->addCdnHashes($file, $this->methodCallAsyncRead('upload.getCdnFileHashes', ['file_token' => $file, 'offset' => $offset], ['datacenter' => $datacenter]));
$this->addCdnHashes($file, $this->methodCallAsyncRead('upload.getCdnFileHashes', ['file_token' => $file, 'offset' => $offset], ['datacenter' => $datacenter, 'cancellation' => $cancellation]));
}
if (!isset($this->cdn_hashes[$file][$offset])) {
throw new Exception('Could not fetch CDN hashes for offset '.$offset);

View File

@ -69,6 +69,8 @@ trait FilesAbstraction
* @param boolean $background Send this message as background message
* @param boolean $clearDraft Clears the draft field
* @param boolean $updateStickersetsOrder Whether to move used stickersets to top
* @param boolean $forceResend Whether to forcefully resend the file, even if its type and name are the same.
* @param Cancellation $cancellation Cancellation.
*
*/
public function sendDocument(
@ -92,6 +94,7 @@ trait FilesAbstraction
bool $background = false,
bool $clearDraft = false,
bool $updateStickersetsOrder = false,
bool $forceResend,
?Cancellation $cancellation = null,
): Message {
if ($file instanceof Message) {
@ -123,6 +126,7 @@ trait FilesAbstraction
replyMarkup: $replyMarkup,
scheduleDate: $scheduleDate,
sendAs: $sendAs,
forceResend: $forceResend,
cancellation: $cancellation
);
}
@ -146,6 +150,8 @@ trait FilesAbstraction
* @param boolean $background Send this message as background message
* @param boolean $clearDraft Clears the draft field
* @param boolean $updateStickersetsOrder Whether to move used stickersets to top
* @param boolean $forceResend Whether to forcefully resend the file, even if its type and name are the same.
* @param Cancellation $cancellation Cancellation.
*
*/
public function sendPhoto(
@ -167,6 +173,7 @@ trait FilesAbstraction
bool $background = false,
bool $clearDraft = false,
bool $updateStickersetsOrder = false,
bool $forceResend = false,
?Cancellation $cancellation = null,
): Message {
if ($file instanceof Message) {
@ -198,6 +205,7 @@ trait FilesAbstraction
replyMarkup: $replyMarkup,
scheduleDate: $scheduleDate,
sendAs: $sendAs,
forceResend: $forceResend,
cancellation: $cancellation
);
}
@ -230,7 +238,8 @@ trait FilesAbstraction
bool $background,
bool $clearDraft,
bool $updateStickersetsOrder,
?Cancellation $cancellation = null,
bool $forceResend,
?Cancellation $cancellation,
): Message {
$peer = $this->getId($peer);
if ($file instanceof Media) {
@ -253,6 +262,7 @@ trait FilesAbstraction
if ($file instanceof $type
&& ($fileName ?? $file->fileName) === $file->fileName
&& !$file->protected
&& !$forceResend
) {
// Re-use
$reuseId = $file->botApiFileId;
@ -261,6 +271,7 @@ trait FilesAbstraction
&& $file->getTypeClass() === $type
&& ($fileName ?? $file->fileName) === $file->fileName
&& !$file->protected
&& !$forceResend
) {
// Re-use
$reuseId = $file->fileId;
@ -299,7 +310,7 @@ trait FilesAbstraction
if (!\extension_loaded('gd')) {
throw Exception::extension('gd');
}
$file = buffer($this->getStream($file), $cancellation);
$file = buffer($this->getStream($file, $cancellation), $cancellation);
$img = \imagecreatefromstring($file);
$width = \imagesx($img);
$height = \imagesy($img);
@ -326,7 +337,7 @@ trait FilesAbstraction
unset($stream);
$file = new ReadableBuffer($file);
} elseif ($thumb !== null) {
$thumb = buffer($this->getStream($thumb), $cancellation);
$thumb = buffer($this->getStream($thumb, $cancellation), $cancellation);
if (!\extension_loaded('gd')) {
throw Exception::extension('gd');
}
@ -368,6 +379,7 @@ trait FilesAbstraction
if ($file instanceof $type
&& ($fileName ?? $file->fileName) === $file->fileName
&& $file->encrypted
&& !$forceResend
) {
// Reuse
$file = $file->location;

View File

@ -23,6 +23,7 @@ use Amp\ByteStream\ReadableStream;
use Amp\ByteStream\StreamException;
use Amp\ByteStream\WritableResourceStream;
use Amp\ByteStream\WritableStream;
use Amp\Cancellation;
use Amp\File\File;
use Amp\File\Whence;
use Amp\Http\HttpStatus;
@ -82,7 +83,7 @@ trait FilesLogic
* @param null|string $mime MIME type of file to download, required for bot API file IDs.
* @param null|string $name Name of file to download, required for bot API file IDs.
*/
public function downloadToBrowser(array|string|FileCallbackInterface|Message $messageMedia, ?callable $cb = null, ?int $size = null, ?string $name = null, ?string $mime = null): void
public function downloadToBrowser(array|string|FileCallbackInterface|Message $messageMedia, ?callable $cb = null, ?int $size = null, ?string $name = null, ?string $mime = null, ?Cancellation $cancellation = null): void
{
if (\is_object($messageMedia) && $messageMedia instanceof FileCallbackInterface) {
$cb = $messageMedia;
@ -128,7 +129,8 @@ trait FilesLogic
\ob_end_flush();
\ob_implicit_flush();
}
$this->downloadToStream($messageMedia, \fopen('php://output', 'w'), $cb, ...$result->getServeRange());
[$start, $end] = $result->getServeRange();
$this->downloadToStream($messageMedia, \fopen('php://output', 'w'), $cb, $start, $end, $cancellation);
}
}
/**
@ -139,11 +141,11 @@ trait FilesLogic
* @param int $offset Offset where to start downloading
* @param int $end Offset where to end download
*/
public function downloadToReturnedStream(mixed $messageMedia, ?callable $cb = null, int $offset = 0, int $end = -1): ReadableStream
public function downloadToReturnedStream(mixed $messageMedia, ?callable $cb = null, int $offset = 0, int $end = -1, ?Cancellation $cancellation = null): ReadableStream
{
$pipe = new Pipe(1024*1024);
$sink = $pipe->getSink();
async($this->downloadToStream(...), $messageMedia, $sink, $cb, $offset, $end)->finally($sink->close(...));
async($this->downloadToStream(...), $messageMedia, $sink, $cb, $offset, $end, $cancellation)->finally($sink->close(...));
return $pipe->getSource();
}
/**
@ -155,7 +157,7 @@ trait FilesLogic
* @param int $offset Offset where to start downloading
* @param int $end Offset where to end download
*/
public function downloadToStream(mixed $messageMedia, mixed $stream, ?callable $cb = null, int $offset = 0, int $end = -1): void
public function downloadToStream(mixed $messageMedia, mixed $stream, ?callable $cb = null, int $offset = 0, int $end = -1, ?Cancellation $cancellation = null): void
{
$messageMedia = $this->getDownloadInfo($messageMedia);
if (\is_object($stream) && $stream instanceof FileCallbackInterface) {
@ -193,7 +195,7 @@ trait FilesLogic
}
return \strlen($payload);
};
$this->downloadToCallable($messageMedia, $callable, $cb, $seekable, $offset, $end);
$this->downloadToCallable($messageMedia, $callable, $cb, $seekable, $offset, $end, null, $cancellation);
}
/**
@ -208,7 +210,7 @@ trait FilesLogic
* @param null|string $name Name of file to download, required for bot API file IDs.
* @param null|string $mime MIME type of file to download, required for bot API file IDs.
*/
public function downloadToResponse(array|string|FileCallbackInterface|Message $messageMedia, ServerRequest $request, ?callable $cb = null, ?int $size = null, ?string $mime = null, ?string $name = null): Response
public function downloadToResponse(array|string|FileCallbackInterface|Message $messageMedia, ServerRequest $request, ?callable $cb = null, ?int $size = null, ?string $mime = null, ?string $name = null, ?Cancellation $cancellation = null): Response
{
if (\is_object($messageMedia) && $messageMedia instanceof FileCallbackInterface) {
$cb = $messageMedia;
@ -235,7 +237,8 @@ trait FilesLogic
$body = null;
if ($result->shouldServe()) {
$pipe = new Pipe(1024 * 1024);
EventLoop::queue($this->downloadToStream(...), $messageMedia, $pipe->getSink(), $cb, ...$result->getServeRange());
[$start, $end] = $result->getServeRange();
EventLoop::queue($this->downloadToStream(...), $messageMedia, $pipe->getSink(), $cb, $start, $end, $cancellation);
$body = $pipe->getSource();
} elseif (!\in_array($result->getCode(), [HttpStatus::OK, HttpStatus::PARTIAL_CONTENT], true)) {
$body = $result->getCodeExplanation();