From 8335cfed69f6eae3cdc738755d630f2cd7f24061 Mon Sep 17 00:00:00 2001 From: sunxyw Date: Mon, 4 Apr 2022 00:10:42 +0800 Subject: [PATCH 1/4] add implode_when_necessary global function --- src/ZM/global_functions.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/ZM/global_functions.php b/src/ZM/global_functions.php index 296565b5..460768e8 100644 --- a/src/ZM/global_functions.php +++ b/src/ZM/global_functions.php @@ -626,6 +626,18 @@ function zm_internal_errcode($code): string return "[ErrCode:{$code}] "; } +/** + * 将可能为数组的参数转换为字符串 + * + * 如传入字符串则为原样返回 + * + * @param array|string $string_or_array + */ +function implode_when_necessary($string_or_array): string +{ + return is_array($string_or_array) ? implode(', ', $string_or_array) : $string_or_array; +} + /** * 以下为废弃的函数,将于未来移除 */ From 306e992789217127f033bf317491623171256a8e Mon Sep 17 00:00:00 2001 From: sunxyw Date: Mon, 4 Apr 2022 00:11:58 +0800 Subject: [PATCH 2/4] add all bots proxy for ZMRobot --- src/ZM/API/Proxies/Bot/AbstractBotProxy.php | 74 +++++++++++++++++++++ src/ZM/API/Proxies/Bot/AllBotsProxy.php | 43 ++++++++++++ src/ZM/API/ZMRobot.php | 24 +++++++ 3 files changed, 141 insertions(+) create mode 100644 src/ZM/API/Proxies/Bot/AbstractBotProxy.php create mode 100644 src/ZM/API/Proxies/Bot/AllBotsProxy.php diff --git a/src/ZM/API/Proxies/Bot/AbstractBotProxy.php b/src/ZM/API/Proxies/Bot/AbstractBotProxy.php new file mode 100644 index 00000000..1581aa07 --- /dev/null +++ b/src/ZM/API/Proxies/Bot/AbstractBotProxy.php @@ -0,0 +1,74 @@ +bot = $bot; + } + + /** + * 在传入的机器人实例上调用方法 + * + * @param string $name 方法名 + * @param array $arguments 参数 + * @return mixed + */ + public function __call(string $name, array $arguments) + { + return $this->bot->{$name}(...$arguments); + } + + /** + * 获取传入的机器人实例的属性 + * + * @param string $name 属性名 + * @return mixed + */ + public function __get(string $name) + { + return $this->bot->{$name}; + } + + /** + * 设置传入的机器人实例的属性 + * + * @param string $name 属性名 + * @param mixed $value 属性值 + */ + public function __set(string $name, $value) + { + $this->bot->{$name} = $value; + } + + /** + * 判断传入的机器人实例的属性是否存在 + * + * @param string $name 属性名 + */ + public function __isset(string $name): bool + { + return isset($this->bot->{$name}); + } +} diff --git a/src/ZM/API/Proxies/Bot/AllBotsProxy.php b/src/ZM/API/Proxies/Bot/AllBotsProxy.php new file mode 100644 index 00000000..c9f4ddec --- /dev/null +++ b/src/ZM/API/Proxies/Bot/AllBotsProxy.php @@ -0,0 +1,43 @@ + 返回一个包含所有执行结果的数组,键名为机器人ID + */ + public function __call(string $name, array $arguments) + { + // 如果调用的方法为代理方法,则传入当前代理作为参数 + // 一般此情况代表用户进行嵌套代理,即 `->all()->allGroups()` 等情况 + $reflection = new ReflectionMethod(ZMRobot::class, $name); + if (($return = $reflection->getReturnType()) && $return instanceof ReflectionNamedType && str_contains($return->getName(), 'Proxy')) { + Console::debug("Trying to construct proxy {$name} inside proxy, returning nested proxy."); + // 插入当前代理作为第一个参数 + array_unshift($arguments, $this); + return $this->bot->{$name}(...$arguments); + } + + $result = []; + // 遍历所有机器人实例 + foreach ($this->bot::getAllRobot() as $bot) { + Console::debug("Calling {$name} on bot {$bot->getSelfId()}."); + $result[$bot->getSelfId()] = $bot->{$name}(...$arguments); + } + return $result; + } +} diff --git a/src/ZM/API/ZMRobot.php b/src/ZM/API/ZMRobot.php index 23dd8c6e..2c16dd96 100644 --- a/src/ZM/API/ZMRobot.php +++ b/src/ZM/API/ZMRobot.php @@ -4,6 +4,9 @@ declare(strict_types=1); namespace ZM\API; +use ZM\API\Proxies\Bot as Proxies; +use ZM\Console\Console; + /** * Class ZMRobot * @since 1.2 @@ -11,4 +14,25 @@ namespace ZM\API; */ class ZMRobot extends OneBotV11 { + /** + * 获取一个会在所有机器人实例上执行的代理 + */ + public function all(Proxies\AbstractBotProxy $proxy = null): Proxies\AllBotsProxy + { + $bot = $proxy ?: $this; + $bot_id = implode_when_necessary($bot->getSelfId()); + Console::debug("Constructing AllBotsProxy for ZMRobot({$bot_id})"); + return new Proxies\AllBotsProxy($bot); + } + + /** + * 获取一个会在所有群上执行的代理 + */ + public function allGroups(Proxies\AbstractBotProxy $proxy = null): Proxies\AllGroupsProxy + { + $bot = $proxy ?: $this; + $bot_id = implode_when_necessary($bot->getSelfId()); + Console::debug("Constructing AllGroupsProxy for ZMRobot({$bot_id})"); + return new Proxies\AllGroupsProxy($bot); + } } From 9b59cec22aef09711621ef70c5cf0ac6370967b9 Mon Sep 17 00:00:00 2001 From: sunxyw Date: Mon, 4 Apr 2022 00:12:28 +0800 Subject: [PATCH 3/4] add all groups proxy for ZMRobot --- src/ZM/API/Proxies/Bot/AllGroupsProxy.php | 43 +++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/ZM/API/Proxies/Bot/AllGroupsProxy.php diff --git a/src/ZM/API/Proxies/Bot/AllGroupsProxy.php b/src/ZM/API/Proxies/Bot/AllGroupsProxy.php new file mode 100644 index 00000000..afc1048c --- /dev/null +++ b/src/ZM/API/Proxies/Bot/AllGroupsProxy.php @@ -0,0 +1,43 @@ + 返回一个包含所有执行结果的数组,键名为群号 + */ + public function __call(string $name, array $arguments) + { + // 如果调用的方法并非群组方法,则直接返回输出 + // 因为目前所有群组方法都是以 `group_id` 作为第一个参数,故以此来判断 + $reflection = new \ReflectionMethod(ZMRobot::class, $name); + if (!$reflection->getNumberOfParameters() || $reflection->getParameters()[0]->getName() !== 'group_id') { + Console::warning("Trying to call non-group method {$name} on AllGroupsProxy, skipped."); + return $this->bot->{$name}(...$arguments); + } + + $result = []; + // 获取并遍历所有群组 + $groups = $this->bot->getGroupList()['data']; + foreach ($groups as $group) { + $arguments[0] = $group['group_id']; + $bot_id = implode_when_necessary($this->bot->getSelfId()); + Console::debug("Calling {$name} on group {$group['group_id']} on bot {$bot_id}."); + // 在群组上调用方法 + $result[$group['group_id']] = $this->bot->{$name}(...$arguments); + } + return $result; + } +} From c06e38d71f26b07b3df8cf43afca3fb050317e84 Mon Sep 17 00:00:00 2001 From: sunxyw Date: Mon, 4 Apr 2022 00:14:56 +0800 Subject: [PATCH 4/4] add ZMRobot proxies usage example --- src/Module/Example/Hello.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Module/Example/Hello.php b/src/Module/Example/Hello.php index 1e3de096..8dba02f8 100644 --- a/src/Module/Example/Hello.php +++ b/src/Module/Example/Hello.php @@ -27,6 +27,7 @@ use ZM\Utils\ZMUtil; /** * Class Hello + * * @since 2.0 */ class Hello @@ -134,6 +135,7 @@ class Hello * 问法2:从1到20的随机数 * @CQCommand("随机数") * @CQCommand(pattern="*从*到*的随机数") + * * @return string */ public function randNum() @@ -171,6 +173,7 @@ class Hello /** * 使用自定义参数的路由参数 * @RequestMapping("/whoami/{name}") + * * @param array $param 参数 * @return string 返回的 HTML Body */ @@ -182,6 +185,7 @@ class Hello /** * 在机器人连接后向终端输出信息 * @OnOpenEvent("qq") + * * @param ConnectionObject $conn WebSocket 连接对象 */ public function onConnect(ConnectionObject $conn) @@ -201,6 +205,7 @@ class Hello /** * 阻止 Chrome 自动请求 /favicon.ico 导致的多条请求并发和干扰 * @OnRequestEvent(rule="ctx()->getRequest()->server['request_uri'] == '/favicon.ico'",level=200) + * * @throws InterruptException */ public function onRequest() @@ -230,4 +235,13 @@ class Hello array_unshift($helps, '帮助:'); return implode("\n", $helps); } + + /** + * @CQCommand("proxy") + */ + #[CQCommand('proxy')] + public function proxy() + { + bot()->all()->allGroups()->sendGroupMsg(0, ctx()->getMessage()); + } }