mirror of
https://github.com/danog/MadelineProto.git
synced 2024-11-30 04:59:00 +01:00
Allow automatically pinning broadcasted messages
This commit is contained in:
parent
758354fa85
commit
2b30be0d2c
@ -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!
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
);
|
||||
|
@ -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();
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
Loading…
Reference in New Issue
Block a user