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

Allow automatically pinning broadcasted messages

This commit is contained in:
Daniil Gentili 2023-07-09 15:42:08 +02:00
parent 758354fa85
commit 2b30be0d2c
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
15 changed files with 55 additions and 80 deletions

View File

@ -3,6 +3,7 @@ MadelineProto was updated (8.0.0-beta100)!
Features:
- Thanks to the many translation contributors @ https://weblate.madelineproto.xyz/, MadelineProto is now fully localized in Hebrew, Persian, Kurdish, Uzbek and Italian, with WIP translations in Russian and French!
- You can now use `Tools::callFork` to fork a new green thread!
- You can now automatically pin messages broadcasted using `broadcastMessages`, `broadcastForwardMessages` by using the new `pin: true` parameter!
- The `waveform` attribute of `Voice` objects is now automatically encoded and decoded to an array of 100 integer values!
- Added a custom PeerNotInDbException class for "This peer is not present in the internal peer database" errors
- Added a `label` property to the Button class, directly indicating the button label (instead of manually fetching it as an array key).
@ -11,7 +12,6 @@ Features:
- Added `wrapUpdate`, `wrapMessage`, `wrapMedia`
- You can now use `reportMemoryProfile()` to generate and send a `pprof` memory profile to all report peers to debug the causes of high memory usage.
Fixes:
- Fixed file uploads with ext-uv!
- Many performance improvements and bugfixes!

View File

@ -390,7 +390,7 @@ Want to add your own open-source project to this list? [Click here!](https://doc
* <a href="https://docs.madelineproto.xyz/API_docs/methods/messages.getMessageEditData.html" name="messages.getMessageEditData">Find out if a media message's caption can be edited: messages.getMessageEditData</a>
* <a href="https://docs.madelineproto.xyz/API_docs/methods/account.finishTakeoutSession.html" name="account.finishTakeoutSession">Finish account takeout session: account.finishTakeoutSession</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#callfork-generator-amp-future-callable-callable-mixed-args-amp-future-t" name="callFork">Fork a new green thread and execute the passed function in the background: callFork</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#broadcastforwardmessages-mixed-from_peer-list-int-message_ids-bool-drop_author-danog-madelineproto-broadcast-filter-filter-int" name="broadcastForwardMessages">Forwards a list of messages to all peers (users, chats, channels) of the bot: broadcastForwardMessages</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#broadcastforwardmessages-mixed-from_peer-list-int-message_ids-bool-drop_author-danog-madelineproto-broadcast-filter-filter-bool-pin-int" name="broadcastForwardMessages">Forwards a list of messages to all peers (users, chats, channels) of the bot: broadcastForwardMessages</a>
* <a href="https://docs.madelineproto.xyz/API_docs/methods/messages.forwardMessages.html" name="messages.forwardMessages">Forwards messages by their IDs: messages.forwardMessages</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#genvectorhash-array-ints-string" name="genVectorHash">Generate MTProto vector hash: genVectorHash</a>
* <a href="https://docs.madelineproto.xyz/API_docs/methods/auth.exportLoginToken.html" name="auth.exportLoginToken">Generate a login token, for login via QR code. : auth.exportLoginToken</a>
@ -750,7 +750,7 @@ 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#broadcastmessages-array-messages-danog-madelineproto-broadcast-filter-filter-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/PHP/danog/MadelineProto/API.html#broadcastmessages-array-messages-danog-madelineproto-broadcast-filter-filter-bool-pin-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/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/API_docs/methods/messages.sendEncryptedService.html" name="messages.sendEncryptedService">Sends a service message to a secret chat: messages.sendEncryptedService</a>

View File

@ -164,7 +164,7 @@ class MyEventHandler extends EventHandler
}
// We can broadcast messages to all users.
if ($update['message']['message'] === '/broadcast'
if (($update['message']['message'] ?? '') === '/broadcast'
&& $from_id === $this->adminId
) {
if (!isset($update['message']['reply_to']['reply_to_msg_id'])) {
@ -179,6 +179,7 @@ class MyEventHandler extends EventHandler
from_peer: $update,
message_ids: [$update['message']['reply_to']['reply_to_msg_id']],
drop_author: true,
pin: true,
);
return;
}

View File

@ -29,13 +29,13 @@ use danog\MadelineProto\RPCErrorException;
/** @internal */
final class ActionForward implements Action
{
public function __construct(private readonly MTProto $API, private readonly int $from_peer, private readonly array $ids, private readonly bool $drop_author)
public function __construct(private readonly MTProto $API, private readonly int $from_peer, private readonly array $ids, private readonly bool $drop_author, private readonly bool $pin)
{
}
public function act(int $broadcastId, int $peer, Cancellation $cancellation): void
{
try {
$this->API->methodCallAsyncRead(
$updates = $this->API->methodCallAsyncRead(
'messages.forwardMessages',
[
'from_peer' => $this->from_peer,
@ -45,6 +45,20 @@ final class ActionForward implements Action
],
['FloodWaitLimit' => 2*86400]
);
if ($this->pin) {
$updates = $this->API->extractUpdates($updates);
$id = 0;
foreach ($updates as $update) {
if (\in_array($update['_'], ['updateNewMessage', 'updateNewChannelMessage'], true)) {
$id = max($id, $update['message']['id']);
}
}
$this->API->methodCallAsyncRead(
'messages.updatePinnedMessage',
['peer' => $peer, 'id' => $id, 'unpin' => false, 'pm_oneside' => false],
['FloodWaitLimit' => 2*86400]
);
}
} catch (RPCErrorException $e) {
if ($e->rpc === 'INPUT_USER_DEACTIVATED') {
return;

View File

@ -29,7 +29,7 @@ use danog\MadelineProto\RPCErrorException;
/** @internal */
final class ActionSend implements Action
{
public function __construct(private readonly MTProto $API, public readonly array $messages)
public function __construct(private readonly MTProto $API, private readonly array $messages, private readonly bool $pin)
{
}
public function act(int $broadcastId, int $peer, Cancellation $cancellation): void
@ -39,13 +39,20 @@ final class ActionSend implements Action
if ($cancellation->isRequested()) {
return;
}
$this->API->methodCallAsyncRead(
$id = $this->API->extractMessageId($this->API->methodCallAsyncRead(
isset($message['media']['_']) &&
$message['media']['_'] !== 'messageMediaWebPage'
? 'messages.sendMedia'
: 'messages.sendMessage',
\array_merge($message, ['peer' => $peer]),
['FloodWaitLimit' => 2*86400]
));
}
if ($this->pin) {
$this->API->methodCallAsyncRead(
'messages.updatePinnedMessage',
['peer' => $peer, 'id' => $id, 'unpin' => false, 'pm_oneside' => false],
['FloodWaitLimit' => 2*86400]
);
}
} catch (RPCErrorException $e) {

View File

@ -50,10 +50,11 @@ trait Broadcast
* containing a Progress object for all broadcasts currently in-progress.
*
* @param array $messages The messages to send: an array of arrays, containing parameters to pass to messages.sendMessage.
* @param bool $pin Whether to also pin the last sent message.
*/
public function broadcastMessages(array $messages, ?Filter $filter = null): int
public function broadcastMessages(array $messages, ?Filter $filter = null, bool $pin = false): int
{
return $this->broadcastCustom(new ActionSend($this, $messages), $filter);
return $this->broadcastCustom(new ActionSend($this, $messages, $pin), $filter);
}
/**
* Forwards a list of messages to all peers (users, chats, channels) of the bot.
@ -70,10 +71,11 @@ trait Broadcast
* @param mixed $from_peer Bot API ID or Update, from where to forward the messages.
* @param list<int> $message_ids IDs of the messages to forward.
* @param bool $drop_author If true, will forward messages without quoting the original author.
* @param bool $pin Whether to also pin the last sent message.
*/
public function broadcastForwardMessages(mixed $from_peer, array $message_ids, bool $drop_author = false, ?Filter $filter = null): int
public function broadcastForwardMessages(mixed $from_peer, array $message_ids, bool $drop_author = false, ?Filter $filter = null, bool $pin = false): int
{
return $this->broadcastCustom(new ActionForward($this, $this->getID($from_peer), $message_ids, $drop_author), $filter);
return $this->broadcastCustom(new ActionForward($this, $this->getID($from_peer), $message_ids, $drop_author, $pin), $filter);
}
/**

View File

@ -253,10 +253,11 @@ abstract class InternalDoc
* @param mixed $from_peer Bot API ID or Update, from where to forward the messages.
* @param list<int> $message_ids IDs of the messages to forward.
* @param bool $drop_author If true, will forward messages without quoting the original author.
* @param bool $pin Whether to also pin the last sent message.
*/
public function broadcastForwardMessages(mixed $from_peer, array $message_ids, bool $drop_author = false, ?\danog\MadelineProto\Broadcast\Filter $filter = null): int
public function broadcastForwardMessages(mixed $from_peer, array $message_ids, bool $drop_author = false, ?\danog\MadelineProto\Broadcast\Filter $filter = null, bool $pin = false): int
{
return $this->wrapper->getAPI()->broadcastForwardMessages($from_peer, $message_ids, $drop_author, $filter);
return $this->wrapper->getAPI()->broadcastForwardMessages($from_peer, $message_ids, $drop_author, $filter, $pin);
}
/**
* Sends a list of messages to all peers (users, chats, channels) of the bot.
@ -273,10 +274,11 @@ abstract class InternalDoc
* containing a Progress object for all broadcasts currently in-progress.
*
* @param array $messages The messages to send: an array of arrays, containing parameters to pass to messages.sendMessage.
* @param bool $pin Whether to also pin the last sent message.
*/
public function broadcastMessages(array $messages, ?\danog\MadelineProto\Broadcast\Filter $filter = null): int
public function broadcastMessages(array $messages, ?\danog\MadelineProto\Broadcast\Filter $filter = null, bool $pin = false): int
{
return $this->wrapper->getAPI()->broadcastMessages($messages, $filter);
return $this->wrapper->getAPI()->broadcastMessages($messages, $filter, $pin);
}
/**
* Convert generator, promise or any other value to a promise.

View File

@ -118,7 +118,7 @@ final class ReadLoop extends Loop
$buffer = $this->connection->stream->getReadBuffer($payload_length);
} catch (ClosedException $e) {
$this->logger->logger($e->getReason());
if (\strpos($e->getReason(), ' ') === 0) {
if (\str_starts_with($e->getReason(), ' ')) {
$payload = -((int) \substr($e->getReason(), 7));
$this->logger->logger("Received {$payload} from DC ".$this->datacenter, Logger::ERROR);
return $payload;

View File

@ -165,7 +165,7 @@ trait CallHandler
$method,
$methodInfo['type'],
true,
!$this->shared->hasTempAuthKey() && \strpos($method, '.') === false && $method !== 'ping_delay_disconnect',
!$this->shared->hasTempAuthKey() && !\str_contains($method, '.') && $method !== 'ping_delay_disconnect',
$response,
$aargs['cancellation'] ?? null
);

View File

@ -283,7 +283,7 @@ trait ResponseHandler
if ($response['error_message'] === 'PERSISTENT_TIMESTAMP_OUTDATED') {
$response['error_code'] = 500;
}
if (\strpos($response['error_message'], 'FILE_REFERENCE_') === 0) {
if (\str_starts_with($response['error_message'], 'FILE_REFERENCE_')) {
$this->logger->logger("Got {$response['error_message']}, refreshing file reference and repeating method call...");
$this->gotResponseForOutgoingMessage($request);
$msgId = $request->getMsgId();

View File

@ -228,7 +228,8 @@ final class MinDatabase implements TLCallback
/**
* Remove location info for peer.
*/
public function clearPeer(int $id): void {
public function clearPeer(int $id): void
{
unset($this->db[$id]);
}
public function __debugInfo()

View File

@ -120,6 +120,7 @@ trait UpdateHandler
*/
private function eventUpdateHandler(array $update): void
{
$updateType = $update['_'];
if ($update['_'] === 'updateBroadcastProgress') {
$update = $update['progress'];
}
@ -133,7 +134,7 @@ trait UpdateHandler
});
return;
}
if (\count($this->eventHandlerHandlers) !== 0) {
if (\count($this->eventHandlerHandlers) !== 0 && \is_array($update)) {
$update = $this->wrapUpdate($update);
if ($update !== null) {
foreach ($this->eventHandlerHandlers as $closure) {
@ -141,8 +142,8 @@ trait UpdateHandler
}
}
}
if (isset($this->eventHandlerMethods[$update['_']])) {
foreach ($this->eventHandlerMethods[$update['_']] as $closure) {
if (isset($this->eventHandlerMethods[$updateType])) {
foreach ($this->eventHandlerMethods[$updateType] as $closure) {
$closure($update);
}
}

View File

@ -128,7 +128,7 @@ final class HashedBufferedStream implements BufferedProxyStreamInterface, Buffer
*/
public function setExtra($hash): void
{
$rev = \strpos($hash, '_rev');
$rev = \str_contains($hash, '_rev');
$this->rev = false;
if ($rev !== false) {
$hash = \substr($hash, 0, $rev);

View File

@ -227,14 +227,14 @@ final class TL implements TLInterface
$layer = (int) $matches[1];
continue;
}
if (\strpos($line, 'vector#') === 0) {
if (\str_starts_with($line, 'vector#')) {
continue;
}
if (\strpos($line, ' ?= ') !== false) {
if (\str_contains($line, ' ?= ')) {
continue;
}
$line = \preg_replace(['/[(]([\\w\\.]+) ([\\w\\.]+)[)]/', '/\\s+/'], ['$1<$2>', ' '], $line);
if (\strpos($line, ';') === false) {
if (!\str_contains($line, ';')) {
$lineBuf .= $line;
continue;
} elseif ($lineBuf) {

View File

@ -1,53 +0,0 @@
<?php declare(strict_types=1);
$not_subbing = [];
foreach (explode("\n", shell_exec("find src -type f -name '*.php'")) as $file) {
if (!$file) {
continue;
}
if (in_array(basename($file, '.php'), ['APIFactory', 'API', 'Connection', 'Coroutine', 'ReferenceDatabase', 'ProxySocketPool'])) {
continue;
}
if (strpos($file, 'Loop/')) {
continue;
}
if (strpos($file, 'Stream/')) {
continue;
}
if (strpos($file, 'Server/')) {
continue;
}
if (strpos($file, 'Async/')) {
continue;
}
$to_sub = [];
$last_match = null;
foreach (explode("\n", $filec = file_get_contents($file)) as $number => $line) {
if (preg_match("/public function (\w*)[(]/", $line, $matches)) {
$last_match = stripos($matches[1], 'async') === false ? $matches[1] : null;
}
if (preg_match('/function [(]/', $line) && stripos($line, 'public function') === false) {
$last_match = 0;
}
if (strpos($line, 'yield') !== false) {
if ($last_match) {
echo "subbing $last_match for $line at $number in $file".PHP_EOL;
$to_sub[] = $last_match;
} elseif ($last_match === 0) {
echo "============\nNOT SUBBING $last_match for $line at $number in $file\n============".PHP_EOL;
$not_subbing[$file] = $file;
}
}
}
$input = [];
$output = [];
foreach ($to_sub as $func) {
$input[] = "public function $func(";
$output[] = "public function $func".'_async(';
}
if ($input) {
file_put_contents($file, str_replace($input, $output, $filec));
}
}
var_dump(array_values($not_subbing));