1
0
mirror of https://github.com/danog/MadelineProto.git synced 2024-11-30 05:38:57 +01:00
This commit is contained in:
Daniil Gentili 2023-07-10 10:12:46 +02:00
parent 7e69782e74
commit b896ae8699
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
43 changed files with 185 additions and 98 deletions

View File

@ -25,3 +25,4 @@ Fixes:
- Reduce memory usage during flood waits by tweaking config defaults.
- Reduce memory usage by clearing the min database automatically as needed.
- Automatically try caching all dialogs if a peer not found error is about to be thrown
- Fix some issues with pure phar installs

View File

@ -309,6 +309,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#tocamelcase-string-input-string" name="toCamelCase">Convert to camelCase: toCamelCase</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#tosnakecase-string-input-string" name="toSnakeCase">Convert to snake_case: toSnakeCase</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#packunsignedint-int-value-string" name="packUnsignedInt">Convert value to unsigned base256 int: packUnsignedInt</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#stringtostream-string-str-amp-bytestream-readablebuffer" name="stringToStream">Converts a string into an async amphp stream: stringToStream</a>
* <a href="https://docs.madelineproto.xyz/API_docs/methods/channels.createForumTopic.html" name="channels.createForumTopic">Create a forum topic; requires manage_topics rights: channels.createForumTopic</a>
* <a href="https://docs.madelineproto.xyz/API_docs/methods/channels.createChannel.html" name="channels.createChannel">Create a supergroup/channel: channels.createChannel</a>
* <a href="https://docs.madelineproto.xyz/API_docs/methods/phone.createGroupCall.html" name="phone.createGroupCall">Create a group call or livestream: phone.createGroupCall</a>

2
docs

@ -1 +1 @@
Subproject commit 6936aa2703675f1b144d613e69e4922b51ea358f
Subproject commit d6cc1fffc9ce3a14d44bb8dd30fdb81e7101e361

View File

@ -24,6 +24,11 @@ use danog\MadelineProto\Broadcast\Progress;
use danog\MadelineProto\Broadcast\Status;
use danog\MadelineProto\EventHandler;
use danog\MadelineProto\EventHandler\Attributes\Cron;
use danog\MadelineProto\EventHandler\Attributes\Handler;
use danog\MadelineProto\EventHandler\Filter\FilterCommand;
use danog\MadelineProto\EventHandler\Filter\FilterText;
use danog\MadelineProto\EventHandler\Message;
use danog\MadelineProto\EventHandler\SimpleFilter\Incoming;
use danog\MadelineProto\Logger;
use danog\MadelineProto\Settings;
use danog\MadelineProto\Settings\Database\Mysql;
@ -124,85 +129,68 @@ class MyEventHandler extends EventHandler
}
/**
* Handle updates from supergroups and channels.
*
* @param array $update Update
*/
public function onUpdateNewChannelMessage(array $update): void
{
$this->onUpdateNewMessage($update);
}
/**
* Handle updates from users.
* Handle incoming updates from users, chats and channels.
*
* 100+ other types of onUpdate... method types are available, see https://docs.madelineproto.xyz/API_docs/types/Update.html for the full list.
* You can also use onAny to catch all update types (only for debugging)
* A special onUpdateCustomEvent method can also be defined, to send messages to the event handler from an API instance, using the sendCustomEvent method.
*
* @param array $update Update
*/
public function onUpdateNewMessage(array $update): void
#[Handler]
public function handleMessage(Incoming&Message $message): void
{
if ($update['message']['_'] === 'messageEmpty') {
return;
}
$this->logger($update);
// Chat ID
$id = $this->getId($update);
// Sender ID, not always present
$from_id = isset($update['message']['from_id'])
? $this->getId($update['message']['from_id'])
: null;
$this->logger($message);
// In this example code, send the "This userbot is powered by MadelineProto!" message only once per chat.
// Ignore all further messages coming from this chat.
if (!isset($this->notifiedChats[$id])) {
$this->notifiedChats[$id] = true;
if (!isset($this->notifiedChats[$message->chatId])) {
$this->notifiedChats[$message->chatId] = true;
$this->messages->sendMessage(
peer: $update,
peer: $message->chatId,
message: "This userbot is powered by [MadelineProto](https://t.me/MadelineProto)!",
reply_to_msg_id: $update['message']['id'] ?? null,
reply_to_msg_id: $message->id,
parse_mode: 'Markdown'
);
}
}
#[FilterCommand('restart')]
public function restartCommand(Incoming&Message $message): void
{
// If the message is a /restart command from an admin, restart to reload changes to the event handler code.
if (($update['message']['message'] ?? '') === '/restart'
&& $from_id === $this->adminId
) {
if ($message->senderId === $this->adminId) {
// Make sure to run in a bash while loop when running via CLI to allow self-restarts.
$this->restart();
}
}
#[FilterCommand('broadcast')]
public function broadcastCommand(Incoming&Message $message): void
{
// We can broadcast messages to all users.
if (($update['message']['message'] ?? '') === '/broadcast'
&& $from_id === $this->adminId
) {
if (!isset($update['message']['reply_to']['reply_to_msg_id'])) {
if ($message->senderId === $this->adminId) {
if (!$message->replyToMsgId) {
$this->messages->sendMessage(
peer: $update,
peer: $message->senderId,
message: "You should reply to the message you want to broadcast.",
reply_to_msg_id: $update['message']['id'] ?? null,
reply_to_msg_id: $message->id,
);
return;
}
$this->broadcastForwardMessages(
from_peer: $update,
message_ids: [$update['message']['reply_to']['reply_to_msg_id']],
from_peer: $message->senderId,
message_ids: [$message->replyToMsgId],
drop_author: true,
pin: true,
);
return;
}
}
if (($update['message']['message'] ?? '') === 'ping') {
$this->messages->sendMessage(['message' => 'pong', 'peer' => $update]);
}
#[FilterText('ping')]
public function pingCommand(Incoming&Message $message): void
{
$this->messages->sendMessage(['message' => 'pong', 'peer' => $message->chatId]);
}
}

View File

@ -28,10 +28,11 @@ use Closure;
use danog\Loop\PeriodicLoop;
use danog\MadelineProto\Db\DbPropertiesTrait;
use danog\MadelineProto\EventHandler\Attributes\Cron;
use danog\MadelineProto\EventHandler\Attributes\Handler;
use danog\MadelineProto\EventHandler\Attributes\Periodic;
use danog\MadelineProto\EventHandler\Filter\Combinator\FiltersAnd;
use danog\MadelineProto\EventHandler\Filter\Filter;
use danog\MadelineProto\EventHandler\Handler;
use danog\MadelineProto\EventHandler\Filter\FilterAllowAll;
use danog\MadelineProto\EventHandler\Update;
use Generator;
use mysqli;
@ -191,18 +192,20 @@ abstract class EventHandler extends AbstractAPI
$this->periodicLoops[$method]->start();
continue;
}
if (!($handler = $methodRefl->getAttributes(Handler::class))) {
continue;
}
$filter = $methodRefl->getAttributes(
Filter::class,
ReflectionAttribute::IS_INSTANCEOF
)[0] ?? null;
if (!$filter) {
continue;
if (!($handler = $methodRefl->getAttributes(Handler::class))) {
continue;
}
$filter = new FilterAllowAll;
} else {
$filter = $filter->newInstance();
}
$filter = new FiltersAnd(
$filter->newInstance(),
$filter,
Filter::fromReflectionType($methodRefl->getParameters()[0]->getType())
);
$filter = $filter->initialize($this) ?? $filter;

View File

@ -2,6 +2,7 @@
namespace danog\MadelineProto\EventHandler\Filter\Combinator;
use Attribute;
use danog\MadelineProto\EventHandler;
use danog\MadelineProto\EventHandler\Filter\Filter;
use danog\MadelineProto\EventHandler\Update;
@ -9,6 +10,7 @@ use danog\MadelineProto\EventHandler\Update;
/**
* NOTs a filter.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FilterNot extends Filter
{
public function __construct(private readonly Filter $filter)

View File

@ -2,6 +2,7 @@
namespace danog\MadelineProto\EventHandler\Filter\Combinator;
use Attribute;
use danog\MadelineProto\EventHandler;
use danog\MadelineProto\EventHandler\Filter\Filter;
use danog\MadelineProto\EventHandler\Filter\FilterAllowAll;
@ -11,6 +12,7 @@ use Webmozart\Assert\Assert;
/**
* ANDs multiple filters.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FiltersAnd extends Filter
{
/** @var array<Filter> */
@ -27,6 +29,8 @@ final class FiltersAnd extends Filter
$filter = $filter->initialize($API) ?? $filter;
if ($filter instanceof self) {
$final = \array_merge($final, $filter->filters);
} else {
$final []= $filter;
}
}
$final = \array_filter(
@ -34,10 +38,11 @@ final class FiltersAnd extends Filter
fn (Filter $f): bool => !$f instanceof FilterAllowAll,
);
$final = \array_values($final);
if (\count($final) === 1) {
return $final[0];
}
return new self(...$final);
return match (\count($final)) {
0 => new FilterAllowAll,
1 => $final[0],
default => new self(...$final)
};
}
public function apply(Update $update): bool
{

View File

@ -2,6 +2,7 @@
namespace danog\MadelineProto\EventHandler\Filter\Combinator;
use Attribute;
use danog\MadelineProto\EventHandler;
use danog\MadelineProto\EventHandler\Filter\Filter;
use danog\MadelineProto\EventHandler\Filter\FilterAllowAll;
@ -11,6 +12,7 @@ use Webmozart\Assert\Assert;
/**
* ORs multiple filters.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FiltersOr extends Filter
{
/** @var array<Filter> */
@ -27,6 +29,8 @@ final class FiltersOr extends Filter
$filter = $filter->initialize($API) ?? $filter;
if ($filter instanceof self) {
$final = \array_merge($final, $filter->filters);
} else {
$final []= $filter;
}
}
foreach ($final as $f) {
@ -34,10 +38,11 @@ final class FiltersOr extends Filter
return $f;
}
}
if (\count($final) === 1) {
return $final[0];
}
return new self(...$final);
return match (\count($final)) {
0 => new FilterAllowAll,
1 => $final[0],
default => new self(...$final)
};
}
public function apply(Update $update): bool
{

View File

@ -2,11 +2,10 @@
namespace danog\MadelineProto\EventHandler\Filter;
use Attribute;
use danog\MadelineProto\EventHandler;
use danog\MadelineProto\EventHandler\BasicFilter\Incoming;
use danog\MadelineProto\EventHandler\Filter\Combinator\FiltersAnd;
use danog\MadelineProto\EventHandler\Filter\Combinator\FiltersOr;
use danog\MadelineProto\EventHandler\SimpleFilter\Incoming;
use danog\MadelineProto\EventHandler\SimpleFilter\Outgoing;
use danog\MadelineProto\EventHandler\Update;
use ReflectionIntersectionType;
@ -14,7 +13,6 @@ use ReflectionNamedType;
use ReflectionType;
use ReflectionUnionType;
#[Attribute(Attribute::TARGET_METHOD)]
abstract class Filter
{
abstract public function apply(Update $update): bool;

View File

@ -2,11 +2,13 @@
namespace danog\MadelineProto\EventHandler\Filter;
use Attribute;
use danog\MadelineProto\EventHandler\Update;
/**
* Allow all updates.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FilterAllowAll extends Filter
{
public function apply(Update $update): bool

View File

@ -2,17 +2,19 @@
namespace danog\MadelineProto\EventHandler\Filter;
use Attribute;
use danog\MadelineProto\EventHandler\Update;
use Webmozart\Assert\Assert;
/**
* Allow only updates of a certain class type.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FilterClass extends Filter
{
public function __construct(private readonly string $class)
{
Assert::true(\is_subclass_of($class, Update::class));
Assert::true(\is_subclass_of($class, Update::class), "$class is not a subclass of Update!");
}
public function apply(Update $update): bool
{

View File

@ -2,6 +2,7 @@
namespace danog\MadelineProto\EventHandler\Filter;
use Attribute;
use danog\MadelineProto\EventHandler\Message;
use danog\MadelineProto\EventHandler\Update;
use Webmozart\Assert\Assert;
@ -9,11 +10,12 @@ use Webmozart\Assert\Assert;
/**
* Allow only messages containing the specified command.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FilterCommand extends Filter
{
public function __construct(private readonly string $command)
{
Assert::true(\preg_match("/^\w+$/", $command));
Assert::true(\preg_match("/^\w+$/", $command) === 1, "An invalid command was specified!");
}
public function apply(Update $update): bool
{

View File

@ -2,6 +2,7 @@
namespace danog\MadelineProto\EventHandler\Filter;
use Attribute;
use danog\MadelineProto\EventHandler\Message;
use danog\MadelineProto\EventHandler\Update;
use Webmozart\Assert\Assert;
@ -9,13 +10,14 @@ use Webmozart\Assert\Assert;
/**
* Allow only messages containing one of the specified commands.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FilterCommands extends Filter
{
private readonly array $commands;
public function __construct(string ...$commands)
{
foreach ($commands as $command) {
Assert::true(\preg_match("/^\w+$/", $command));
Assert::true(\preg_match("/^\w+$/", $command) === 1, "An invalid command was specified!");
}
$this->commands = $commands;
}

View File

@ -2,12 +2,14 @@
namespace danog\MadelineProto\EventHandler\Filter;
use Attribute;
use danog\MadelineProto\EventHandler\Message;
use danog\MadelineProto\EventHandler\Update;
/**
* Allow only forwarded messages.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FilterForwarded extends Filter
{
public function apply(Update $update): bool

View File

@ -2,12 +2,14 @@
namespace danog\MadelineProto\EventHandler\Filter;
use Attribute;
use danog\MadelineProto\EventHandler\AbstractMessage;
use danog\MadelineProto\EventHandler\Update;
/**
* Allow only incoming messages.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FilterIncoming extends Filter
{
public function apply(Update $update): bool

View File

@ -2,12 +2,14 @@
namespace danog\MadelineProto\EventHandler\Filter;
use Attribute;
use danog\MadelineProto\EventHandler\Message;
use danog\MadelineProto\EventHandler\Update;
/**
* Allow any media messages.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FilterMedia extends Filter
{
public function apply(Update $update): bool

View File

@ -2,12 +2,14 @@
namespace danog\MadelineProto\EventHandler\Filter;
use Attribute;
use danog\MadelineProto\EventHandler\AbstractMessage;
use danog\MadelineProto\EventHandler\Update;
/**
* Allow only outgoing messages.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FilterOutgoing extends Filter
{
public function apply(Update $update): bool

View File

@ -2,6 +2,7 @@
namespace danog\MadelineProto\EventHandler\Filter;
use Attribute;
use danog\MadelineProto\EventHandler;
use danog\MadelineProto\EventHandler\Message;
use danog\MadelineProto\EventHandler\Update;
@ -9,6 +10,7 @@ use danog\MadelineProto\EventHandler\Update;
/**
* Allow messages coming from or sent to a certain peer.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FilterPeer extends Filter
{
private readonly int $peerResolved;

View File

@ -2,6 +2,7 @@
namespace danog\MadelineProto\EventHandler\Filter;
use Attribute;
use danog\MadelineProto\EventHandler\Message;
use danog\MadelineProto\EventHandler\Update;
use Webmozart\Assert\Assert;
@ -9,6 +10,7 @@ use Webmozart\Assert\Assert;
/**
* Allow only messages matching the specified regex.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FilterRegex extends Filter
{
public function __construct(private readonly string $regex)

View File

@ -2,12 +2,14 @@
namespace danog\MadelineProto\EventHandler\Filter;
use Attribute;
use danog\MadelineProto\EventHandler\Message;
use danog\MadelineProto\EventHandler\Update;
/**
* Allow messages that reply to other messages.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FilterReply extends Filter
{
public function apply(Update $update): bool

View File

@ -2,6 +2,7 @@
namespace danog\MadelineProto\EventHandler\Filter;
use Attribute;
use danog\MadelineProto\EventHandler;
use danog\MadelineProto\EventHandler\Message\GroupMessage;
use danog\MadelineProto\EventHandler\Update;
@ -9,6 +10,7 @@ use danog\MadelineProto\EventHandler\Update;
/**
* Allow incoming or outgoing group messages made by a certain sender.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FilterSender extends Filter
{
private readonly int $peerResolved;

View File

@ -2,16 +2,22 @@
namespace danog\MadelineProto\EventHandler\Filter;
use Attribute;
use danog\MadelineProto\EventHandler\Message;
use danog\MadelineProto\EventHandler\Update;
/**
* Allow text-only messages.
* Allow only messages with a specific content.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FilterText extends Filter
{
public function __construct(
private readonly string $content
) {
}
public function apply(Update $update): bool
{
return $update instanceof Message && $update->media === null;
return $update instanceof Message && $update->message === $this->content;
}
}

View File

@ -2,6 +2,7 @@
namespace danog\MadelineProto\EventHandler\Filter\Media;
use Attribute;
use danog\MadelineProto\EventHandler\Filter\Filter;
use danog\MadelineProto\EventHandler\Media\Audio;
use danog\MadelineProto\EventHandler\Message;
@ -10,6 +11,7 @@ use danog\MadelineProto\EventHandler\Update;
/**
* Allow that only matches audio files.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FilterAudio extends Filter
{
public function apply(Update $update): bool

View File

@ -2,6 +2,7 @@
namespace danog\MadelineProto\EventHandler\Filter\Media;
use Attribute;
use danog\MadelineProto\EventHandler\Filter\Filter;
use danog\MadelineProto\EventHandler\Media\Document;
use danog\MadelineProto\EventHandler\Message;
@ -10,6 +11,7 @@ use danog\MadelineProto\EventHandler\Update;
/**
* Allow that only matches documents.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FilterDocument extends Filter
{
public function apply(Update $update): bool

View File

@ -2,6 +2,7 @@
namespace danog\MadelineProto\EventHandler\Filter\Media;
use Attribute;
use danog\MadelineProto\EventHandler\Filter\Filter;
use danog\MadelineProto\EventHandler\Media\DocumentPhoto;
use danog\MadelineProto\EventHandler\Message;
@ -10,6 +11,7 @@ use danog\MadelineProto\EventHandler\Update;
/**
* Allow that only matches documents containing an image.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FilterDocumentPhoto extends Filter
{
public function apply(Update $update): bool

View File

@ -2,6 +2,7 @@
namespace danog\MadelineProto\EventHandler\Filter\Media;
use Attribute;
use danog\MadelineProto\EventHandler\Filter\Filter;
use danog\MadelineProto\EventHandler\Media\Gif;
use danog\MadelineProto\EventHandler\Message;
@ -10,6 +11,7 @@ use danog\MadelineProto\EventHandler\Update;
/**
* Allow that only matches GIFs.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FilterGif extends Filter
{
public function apply(Update $update): bool

View File

@ -2,6 +2,7 @@
namespace danog\MadelineProto\EventHandler\Filter\Media;
use Attribute;
use danog\MadelineProto\EventHandler\Filter\Filter;
use danog\MadelineProto\EventHandler\Media\Photo;
use danog\MadelineProto\EventHandler\Message;
@ -10,6 +11,7 @@ use danog\MadelineProto\EventHandler\Update;
/**
* Allow that only matches photos.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FilterPhoto extends Filter
{
public function apply(Update $update): bool

View File

@ -2,6 +2,7 @@
namespace danog\MadelineProto\EventHandler\Filter\Media;
use Attribute;
use danog\MadelineProto\EventHandler\Filter\Filter;
use danog\MadelineProto\EventHandler\Media\RoundVideo;
use danog\MadelineProto\EventHandler\Message;
@ -10,6 +11,7 @@ use danog\MadelineProto\EventHandler\Update;
/**
* Allow that only matches round videos.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FilterRoundVideo extends Filter
{
public function apply(Update $update): bool

View File

@ -2,6 +2,7 @@
namespace danog\MadelineProto\EventHandler\Filter\Media;
use Attribute;
use danog\MadelineProto\EventHandler\Filter\Filter;
use danog\MadelineProto\EventHandler\Media\AbstractSticker;
use danog\MadelineProto\EventHandler\Message;
@ -10,6 +11,7 @@ use danog\MadelineProto\EventHandler\Update;
/**
* Allow that only matches stickers.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FilterSticker extends Filter
{
public function apply(Update $update): bool

View File

@ -2,6 +2,7 @@
namespace danog\MadelineProto\EventHandler\Filter\Media;
use Attribute;
use danog\MadelineProto\EventHandler\Filter\Filter;
use danog\MadelineProto\EventHandler\Media\Video;
use danog\MadelineProto\EventHandler\Message;
@ -10,6 +11,7 @@ use danog\MadelineProto\EventHandler\Update;
/**
* Allow that only matches videos.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FilterVideo extends Filter
{
public function apply(Update $update): bool

View File

@ -2,6 +2,7 @@
namespace danog\MadelineProto\EventHandler\Filter\Media;
use Attribute;
use danog\MadelineProto\EventHandler\Filter\Filter;
use danog\MadelineProto\EventHandler\Media\Voice;
use danog\MadelineProto\EventHandler\Message;
@ -10,6 +11,7 @@ use danog\MadelineProto\EventHandler\Update;
/**
* Allow that only matches voice messages.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class FilterVoice extends Filter
{
public function apply(Update $update): bool

View File

@ -4,11 +4,12 @@ namespace danog\MadelineProto\EventHandler;
use danog\MadelineProto\Ipc\IpcCapable;
use danog\MadelineProto\MTProto;
use JsonSerializable;
/**
* Represents a generic media.
*/
abstract class Media extends IpcCapable
abstract class Media extends IpcCapable implements JsonSerializable
{
/** Media filesize */
public readonly int $size;
@ -20,7 +21,7 @@ abstract class Media extends IpcCapable
public readonly string $fileExt;
/** Media creation date */
public readonly bool $creationDate;
public readonly int $creationDate;
/** Media MIME type */
public readonly string $mimeType;
@ -55,8 +56,16 @@ abstract class Media extends IpcCapable
] = $API->getDownloadInfo($rawMedia);
$this->fileName = "$name.".$this->fileExt;
$this->creationDate = $rawMedia['date'];
$this->creationDate = ($rawMedia['document'] ?? $rawMedia['photo'])['date'];
$this->ttl = $rawMedia['ttl_seconds'] ?? null;
$this->spoiler = $rawMedia['spoiler'] ?? false;
}
public function jsonSerialize(): mixed
{
$v = \get_object_vars($this);
unset($v['API'], $v['session']);
$v['_'] = static::class;
return $v;
}
}

View File

@ -26,7 +26,7 @@ final class DocumentPhoto extends Media
$this->width = $attribute['w'];
$this->height = $attribute['h'];
$hasStickers = false;
foreach ($rawMedia['attributes'] as ['_' => $t]) {
foreach ($rawMedia['document']['attributes'] as ['_' => $t]) {
if ($t === 'documentAttributeHasStickers') {
$hasStickers = true;
break;

View File

@ -20,7 +20,7 @@ final class Gif extends AbstractVideo
) {
parent::__construct($API, $rawMedia, $attribute);
$hasStickers = false;
foreach ($rawMedia['attributes'] as ['_' => $t]) {
foreach ($rawMedia['document']['attributes'] as ['_' => $t]) {
if ($t === 'documentAttributeHasStickers') {
$hasStickers = true;
break;

View File

@ -2,11 +2,18 @@
namespace danog\MadelineProto\EventHandler\Media;
use JsonSerializable;
/** Position of the mask */
enum MaskPosition
enum MaskPosition: int implements JsonSerializable
{
case Forehead;
case Eyes;
case Mouth;
case Chin;
case Forehead = 0;
case Eyes = 1;
case Mouth = 2;
case Chin = 3;
public function jsonSerialize(): mixed
{
return $this->value;
}
}

View File

@ -21,7 +21,7 @@ final class Photo extends Media
) {
parent::__construct($API, $rawMedia);
$hasStickers = false;
foreach ($rawMedia['attributes'] as ['_' => $t]) {
foreach ($rawMedia['document']['attributes'] as ['_' => $t]) {
if ($t === 'documentAttributeHasStickers') {
$hasStickers = true;
break;

View File

@ -20,7 +20,7 @@ final class Video extends AbstractVideo
) {
parent::__construct($API, $rawMedia, $attribute);
$hasStickers = false;
foreach ($rawMedia['attributes'] as ['_' => $t]) {
foreach ($rawMedia['document']['attributes'] as ['_' => $t]) {
if ($t === 'documentAttributeHasStickers') {
$hasStickers = true;
break;

View File

@ -30,6 +30,8 @@ abstract class Message extends AbstractMessage
/** Bot command (if present) */
public readonly ?string $command;
/** Bot command type (if present) */
public readonly ?CommandType $commandType;
/** @var list<string> Bot command arguments (if present) */
public readonly ?array $commandArgs;
@ -110,23 +112,22 @@ abstract class Message extends AbstractMessage
? $API->wrapMedia($rawMessage['media'])
: null;
if (
$this->entities
&& $this->entities[0]['_'] === 'messageEntityBotCommand'
&& $this->entities[0]['offset'] === 0
) {
$this->command = StrTools::mbSubstr(
$this->message,
1,
$this->entities[0]['length']-1
);
if (\in_array($this->message[0] ?? '', ['/', '.', '!'], true)) {
$space = \strpos($this->message, ' ', 1) ?: \strlen($this->message);
$this->command = \substr($this->message, 1, $space-1);
$this->commandArgs = \explode(
' ',
StrTools::mbSubstr($this->message, $this->entities[0]['length']+1)
\substr($this->message, $space+1)
);
$this->commandType = match ($this->message[0]) {
'.' => CommandType::DOT,
'/' => CommandType::SLASH,
'!' => CommandType::BANG,
};
} else {
$this->command = null;
$this->commandArgs = null;
$this->commandType = null;
}
}

View File

@ -3,10 +3,18 @@
namespace danog\MadelineProto\EventHandler;
use danog\MadelineProto\Ipc\IpcCapable;
use JsonSerializable;
/**
* Represents a generic update.
*/
abstract class Update extends IpcCapable
abstract class Update extends IpcCapable implements JsonSerializable
{
public function jsonSerialize(): mixed
{
$v = \get_object_vars($this);
unset($v['API'], $v['session']);
$v['_'] = static::class;
return $v;
}
}

View File

@ -116,12 +116,16 @@ class Exception extends \Exception
if ($maps !== '') {
$maps = " ($maps)";
}
Logger::log("========= MANUAL SYSTEM ADMIN ACTION REQUIRED =========", Logger::FATAL_ERROR);
Logger::log("!!!!!!!!! MANUAL SYSTEM ADMIN ACTION REQUIRED !!!!!!!!!", Logger::FATAL_ERROR);
Logger::log("!!!!!!!!! MANUAL SYSTEM ADMIN ACTION REQUIRED !!!!!!!!!", Logger::FATAL_ERROR);
Logger::log("!!!!!!!!! MANUAL SYSTEM ADMIN ACTION REQUIRED !!!!!!!!!", Logger::FATAL_ERROR);
Logger::log("The maximum number of mmap'ed regions was reached$maps: please increase the vm.max_map_count kernel config to 262144 to fix.");
Logger::log("To fix, run the following command as root: echo 262144 | sudo tee /proc/sys/vm/max_map_count");
Logger::log("To persist the change across reboots: echo vm.max_map_count=262144 | sudo tee /etc/sysctl.d/40-madelineproto.conf");
Logger::log("On Windows and WSL, increasing the size of the pagefile might help; please switch to native Linux if the issue persists.");
Logger::log("========= MANUAL SYSTEM ADMIN ACTION REQUIRED =========", Logger::FATAL_ERROR);
Logger::log("!!!!!!!!! MANUAL SYSTEM ADMIN ACTION REQUIRED !!!!!!!!!", Logger::FATAL_ERROR);
Logger::log("!!!!!!!!! MANUAL SYSTEM ADMIN ACTION REQUIRED !!!!!!!!!", Logger::FATAL_ERROR);
Logger::log("!!!!!!!!! MANUAL SYSTEM ADMIN ACTION REQUIRED !!!!!!!!!", Logger::FATAL_ERROR);
}
Logger::log($exception, Logger::FATAL_ERROR);
die(1);

View File

@ -1544,6 +1544,13 @@ abstract class InternalDoc
{
$this->wrapper->getAPI()->stop();
}
/**
* Converts a string into an async amphp stream.
*/
public static function stringToStream(string $str): \Amp\ByteStream\ReadableBuffer
{
return \danog\MadelineProto\Tools::stringToStream($str);
}
/**
* Subscribe to event handler updates for a channel/supergroup we're not a member of.
*

View File

@ -566,7 +566,7 @@ trait Files
}
$has_video = null;
$has_animated = false;
foreach ($media['attributes'] as $attr) {
foreach ($media['document']['attributes'] as $attr) {
$t = $attr['_'];
if ($t === 'documentAttributeImageSize') {
return new DocumentPhoto($this, $media, $attr);

View File

@ -135,10 +135,10 @@ trait UpdateHandler
return;
}
if (\count($this->eventHandlerHandlers) !== 0 && \is_array($update)) {
$update = $this->wrapUpdate($update);
if ($update !== null) {
$obj = $this->wrapUpdate($update);
if ($obj !== null) {
foreach ($this->eventHandlerHandlers as $closure) {
$closure($update);
$closure($obj);
}
}
}