diff --git a/docs b/docs index 84c66b69e..8b4df61a4 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit 84c66b69ecdb6407ce254f1d901a253f6b6c00a0 +Subproject commit 8b4df61a4eee0d9783086bcc15014759ac927b03 diff --git a/examples/bot.php b/examples/bot.php index f6d88757f..fa1a32515 100755 --- a/examples/bot.php +++ b/examples/bot.php @@ -32,6 +32,7 @@ use danog\MadelineProto\EventHandler\Message; use danog\MadelineProto\EventHandler\Message\Service\DialogPhotoChanged; use danog\MadelineProto\EventHandler\SimpleFilter\FromAdmin; use danog\MadelineProto\EventHandler\SimpleFilter\Incoming; +use danog\MadelineProto\EventHandler\SimpleFilter\IsReply; use danog\MadelineProto\Logger; use danog\MadelineProto\ParseMode; use danog\MadelineProto\Settings; @@ -239,6 +240,18 @@ class MyEventHandler extends SimpleEventHandler $message->reply('test reply'); } + #[FilterCommand('react')] + public function reactCommand(Message&IsReply $message): void + { + $message->getReply(Message::class)->addReaction('👌'); + } + + #[FilterCommand('unreact')] + public function unreactCommand(Message&IsReply $message): void + { + $message->getReply(Message::class)->delReaction('👌'); + } + #[FilterTextCaseInsensitive('hi')] public function pingCommandCaseInsensitive(Message $message): void { diff --git a/langs/fa.json b/langs/fa.json index 760915d92..e83489b3a 100644 --- a/langs/fa.json +++ b/langs/fa.json @@ -152,5 +152,6 @@ "waveform_must_have_100_values": "آرایه waveformباید 100 مقدار داشته باشد(سایز مورد انتظار 100 است ) !", "waveform_value": "مقدار عددیwaveform باید بین 0 تا 31 باشد!", "could_not_convert_object": "نمیتوان مقدار آبجکت تایپ %s را تبدیل کرد", - "mmapErrorPart1": "بیشترین مقدار حافظه تخصیص داده شده (mmap ) پر شده است (%s ) : لطفا از داخل کانفیگ های مربوط به کرنل مقدار vm.max_map_count را به مقدار 262144 افزایش دهیدتا مشکل رفع گردد." + "mmapErrorPart1": "بیشترین مقدار حافظه تخصیص داده شده (mmap ) پر شده است (%s ) : لطفا از داخل کانفیگ های مربوط به کرنل مقدار vm.max_map_count را به مقدار 262144 افزایش دهیدتا مشکل رفع گردد.", + "could_not_connect_to_MadelineProto": "نمی توان به MadelineProto متصل شد، لطفاً proc_open را فعال کنید یا بازنویسی مسیر وب سرور را غیرفعال کنید تا مشکل رفع شود!" } diff --git a/src/API.php b/src/API.php index 9f6d429ae..a225f6082 100644 --- a/src/API.php +++ b/src/API.php @@ -51,7 +51,7 @@ final class API extends AbstractAPI * * @var string */ - public const RELEASE = '8.0.0-beta125'; + public const RELEASE = '8.0.0-beta126'; /** * Secret chat was not found. * diff --git a/src/Connection.php b/src/Connection.php index 5cdaaf791..2dbc3ce98 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -281,13 +281,13 @@ final class Connection unset($this->new_outgoing[$message_id], $this->outgoing_messages[$message_id]); } } - Assert::true($this->writer->start()); - Assert::true($this->reader->start()); - Assert::true($this->checker->start()); - Assert::true($this->cleanup->start()); - Assert::true($this->waiter->start()); + Assert::true($this->writer->start(), "Could not start writer stream"); + Assert::true($this->reader->start(), "Could not start reader stream"); + Assert::true($this->checker->start(), "Could not start checker stream"); + Assert::true($this->cleanup->start(), "Could not start cleanup stream"); + Assert::true($this->waiter->start(), "Could not start waiter stream"); if ($this->pinger) { - Assert::true($this->pinger->start()); + Assert::true($this->pinger->start(), "Could not start pinger stream"); } } /** diff --git a/src/EventHandler.php b/src/EventHandler.php index 3bf293b1a..8f7aac488 100644 --- a/src/EventHandler.php +++ b/src/EventHandler.php @@ -410,7 +410,7 @@ abstract class EventHandler extends AbstractAPI continue; } $class = $namespace.'\\'.$fileName; - if (!\class_exists($class)) { + if (!\class_exists($class) && !\interface_exists($class) && !\trait_exists($class) && !\enum_exists($class)) { throw new AssertionError("$class was not defined when including $file!"); } if ((new ReflectionClass($class))->getFileName() !== $file) { @@ -441,7 +441,9 @@ abstract class EventHandler extends AbstractAPI $file = $path.\str_replace('\\', DIRECTORY_SEPARATOR, \substr($class, 14)).'.php'; if (\file_exists($file)) { require $file; - Assert::classExists($class, "The $class class wasn't defined while including $file!"); + if (!\class_exists($class) && !\interface_exists($class) && !\trait_exists($class) && !\enum_exists($class)) { + throw new AssertionError("$class was not defined when including $file!"); + } } }); diff --git a/src/EventHandler/Message.php b/src/EventHandler/Message.php index c0c60226c..273e8c04c 100644 --- a/src/EventHandler/Message.php +++ b/src/EventHandler/Message.php @@ -26,7 +26,7 @@ abstract class Message extends AbstractMessage public readonly string $message; /** @var list list of our message reactions */ - protected ?array $reactions = []; + protected array $reactions = []; /** Info about a forwarded message */ public readonly ?ForwardedInfo $fwdInfo; @@ -138,6 +138,13 @@ abstract class Message extends AbstractMessage $this->commandArgs = null; $this->commandType = null; } + + foreach ($rawMessage['reactions']['results'] ?? [] as $r) { + if (isset($r['chosen_order'])) { + // Todo: live synchronization using a message database... + $this->reactions []= $r['reaction']['emoticon'] ?? $r['reaction']['document_id']; + } + } } /** @@ -183,23 +190,12 @@ abstract class Message extends AbstractMessage } /** - * Get our reaction on message return null if message deleted. + * Get our reactions on the message. * - * @return list|null + * @return list */ - public function getReactions(): ?array + public function getOurReactions(): array { - $myReactions = \array_filter( - $this->getClient()->methodCallAsyncRead( - 'messages.getMessageReactionsList', - [ - 'peer' => $this->chatId, - 'id' => $this->id - ] - )['reactions'], - fn (array $r): bool => $r['my'] - ); - $this->reactions += \array_map(fn (array $r) => $r['reaction']['emoticon'] ?? $r['reaction']['document_id'], $myReactions); return $this->reactions; } @@ -209,49 +205,56 @@ abstract class Message extends AbstractMessage * @param string|int $reaction reaction * @param bool $big Whether a bigger and longer reaction should be shown * @param bool $addToRecent Add this reaction to the recent reactions list. + * + * @return list */ - public function addReaction(int|string $reaction, bool $big = false, bool $addToRecent = true): ?Update + public function addReaction(int|string $reaction, bool $big = false, bool $addToRecent = true): array { - $result = $this->getClient()->methodCallAsyncRead( + if (\in_array($reaction, $this->reactions, true)) { + return $this->reactions; + } + $this->getClient()->methodCallAsyncRead( 'messages.sendReaction', [ 'peer' => $this->chatId, 'msg_id' => $this->id, - 'reaction' => match (\is_int($reaction)) { - true => [['_' => 'reactionCustomEmoji', 'document_id' => $reaction]], - default => [['_' => 'reactionEmoji', 'emoticon' => $reaction]] - }, + 'reaction' => \is_int($reaction) + ? [['_' => 'reactionCustomEmoji', 'document_id' => $reaction]] + : [['_' => 'reactionEmoji', 'emoticon' => $reaction]], 'big' => $big, 'add_to_recent' => $addToRecent ] ); $this->reactions[] = $reaction; - return $this->getClient()->wrapUpdate($result); + return $this->reactions; } /** * Delete reaction from message. * * @param string|int $reaction string or int Reaction + * + * @return list */ - public function delReaction(int|string $reaction): ?Update + public function delReaction(int|string $reaction): array { - $this->getReactions(); - if (($key = \array_search($reaction, $this->reactions)) !== false) { - unset($this->reactions[$key]); - $r = \array_map(fn ($reactions) => \is_int($reactions) ? ['_' => 'reactionCustomEmoji', 'document_id' => $reactions] : ['_' => 'reactionEmoji', 'emoticon' => $reactions], $this->reactions); - $r[]= ['_' => 'reactionEmpty']; - $result = $this->getClient()->methodCallAsyncRead( - 'messages.sendReaction', - [ - 'peer' => $this->chatId, - 'msg_id' => $this->id, - 'reaction' => $r, - ] - ); - return $this->getClient()->wrapUpdate($result); + $key = \array_search($reaction, $this->reactions, true); + if ($key === false) { + return $this->reactions; } - return null; + unset($this->reactions[$key]); + $this->reactions = \array_values($this->reactions); + $r = \array_map(fn (string|int $r): array => \is_int($r) ? ['_' => 'reactionCustomEmoji', 'document_id' => $r] : ['_' => 'reactionEmoji', 'emoticon' => $r], $this->reactions); + $r[]= ['_' => 'reactionEmpty']; + $this->getClient()->methodCallAsyncRead( + 'messages.sendReaction', + [ + 'peer' => $this->chatId, + 'msg_id' => $this->id, + 'reaction' => $r, + ] + ); + return $this->reactions; } protected readonly string $html; diff --git a/src/Ipc/Runner/ProcessRunner.php b/src/Ipc/Runner/ProcessRunner.php index 5b97adc5d..2ccdf937f 100644 --- a/src/Ipc/Runner/ProcessRunner.php +++ b/src/Ipc/Runner/ProcessRunner.php @@ -96,7 +96,8 @@ final class ProcessRunner extends RunnerAbstract if (PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg') { try { $root = WebRunner::getAbsoluteRootDir(); - } catch (Throwable) {} + } catch (Throwable) { + } } $envVars = \array_merge( \array_filter($_SERVER, fn ($v, $k): bool => \is_string($v) && !\in_array($k, self::CGI_VARS, true), ARRAY_FILTER_USE_BOTH), diff --git a/src/Lang.php b/src/Lang.php index da22c7fdb..c5951c332 100644 --- a/src/Lang.php +++ b/src/Lang.php @@ -399,7 +399,7 @@ If you intentionally deleted this account, ignore this message.', 'call_error_3' => 'نمیتوان تماس %s را یافت و کامل کرد', 'cli_need_dl.php_link' => 'لطفا هنگام استفاده از getDownloadLink روی CLI (محیط ترمینال)، لینک اسکریپت دانلود را مشخص کنید!', 'constructor_not_found' => 'سازنده برای این نوع پیدا نشد: ', - 'could_not_connect_to_MadelineProto' => 'Could not connect to MadelineProto, please enable proc_open or disable webserver path rewrites to fix!', + 'could_not_connect_to_MadelineProto' => 'نمی توان به MadelineProto متصل شد، لطفاً proc_open را فعال کنید یا بازنویسی مسیر وب سرور را غیرفعال کنید تا مشکل رفع شود!', 'could_not_convert_object' => 'نمیتوان مقدار آبجکت تایپ %s را تبدیل کرد', 'deserialization_error' => 'مشکلی در سریال‌زدایی پیش آمد', 'dl.php_check_logs_make_sure_session_running' => 'هم ربات ایونت‌هندلر مدلین‌پروتو مرتبط و هم سرور IPC مدلین‌پروتو آفلاین هستند، لطفا لاگ‌ها را بررسی کنید و مطمئن شوید حداقل یکی از آنها در حال اجراست!', diff --git a/src/MTProtoTools/PeerHandler.php b/src/MTProtoTools/PeerHandler.php index 0e3f81abc..769f38998 100644 --- a/src/MTProtoTools/PeerHandler.php +++ b/src/MTProtoTools/PeerHandler.php @@ -627,7 +627,7 @@ trait PeerHandler } if (\is_numeric($id)) { $id = (int) $id; - Assert::true($id !== 0); + Assert::true($id !== 0, "An invalid ID was specified!"); if (!$this->chats[$id]) { try { $this->logger->logger("Try fetching {$id} with access hash 0"); diff --git a/src/Serialization.php b/src/Serialization.php index 1aff28794..f3c66bcad 100644 --- a/src/Serialization.php +++ b/src/Serialization.php @@ -199,7 +199,7 @@ abstract class Serialization } elseif (\is_subclass_of($class, EventHandler::class)) { EventHandler::cachePlugins($class); } - } else { + } elseif ($lightState) { $class = $lightState->getEventHandler(); if ($class && !\class_exists($class)) { // Have lock, can't use it diff --git a/src/Stream/Proxy/HttpProxy.php b/src/Stream/Proxy/HttpProxy.php index 4e7ab729e..342dc3bfc 100644 --- a/src/Stream/Proxy/HttpProxy.php +++ b/src/Stream/Proxy/HttpProxy.php @@ -62,8 +62,8 @@ final class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInt } $ctx->setUri('tcp://'.$this->extra['address'].':'.$this->extra['port'])->secure(false); $this->stream = $ctx->getStream(); - Assert::true($this->stream instanceof BufferedStreamInterface); - Assert::true($this->stream instanceof RawStreamInterface); + Assert::isInstanceOf($this->stream, BufferedStreamInterface::class); + Assert::isInstanceOf($this->stream, RawStreamInterface::class); $address = $uri->getHost(); $port = $uri->getPort(); try {