From 0d24ae6192c9bd0456bf002ea96d588c4dd50c21 Mon Sep 17 00:00:00 2001 From: sunxyw <31698606+sunxyw@users.noreply.github.com> Date: Wed, 28 Dec 2022 22:05:03 +0800 Subject: [PATCH] add command manual plugin (#210) --- config/global.php | 1 + src/Module/Example/Hello123.php | 12 ++ src/ZM/Annotation/OneBot/CommandHelp.php | 35 +++++ src/ZM/Event/Listener/WorkerEventListener.php | 2 + src/ZM/Plugin/CommandManualPlugin.php | 127 ++++++++++++++++++ src/ZM/Plugin/PluginManager.php | 2 + 6 files changed, 179 insertions(+) create mode 100644 src/ZM/Annotation/OneBot/CommandHelp.php create mode 100644 src/ZM/Plugin/CommandManualPlugin.php diff --git a/config/global.php b/config/global.php index 7edb0b24..8d3f9cce 100644 --- a/config/global.php +++ b/config/global.php @@ -73,6 +73,7 @@ $config['plugin'] = [ $config['native_plugin'] = [ 'onebot12' => true, // OneBot v12 协议支持 'onebot12-ban-other-ws' => true, // OneBot v12 协议支持,禁止其他 WebSocket 连接 + 'command-manual' => true, ]; /* 静态文件读取器 */ diff --git a/src/Module/Example/Hello123.php b/src/Module/Example/Hello123.php index 9b0d1978..e84dab3b 100644 --- a/src/Module/Example/Hello123.php +++ b/src/Module/Example/Hello123.php @@ -7,7 +7,11 @@ namespace Module\Example; use OneBot\Driver\Event\WebSocket\WebSocketMessageEvent; use ZM\Annotation\Http\Route; use ZM\Annotation\Middleware\Middleware; +use ZM\Annotation\OneBot\BotCommand; use ZM\Annotation\OneBot\BotEvent; +use ZM\Annotation\OneBot\CommandArgument; +use ZM\Annotation\OneBot\CommandHelp; +use ZM\Context\BotContext; use ZM\Middleware\TimerMiddleware; class Hello123 @@ -24,4 +28,12 @@ class Hello123 { logger()->info("收到了 {$event->getType()}.{$event->getDetailType()} 事件"); } + + #[BotCommand('echo', 'echo')] + #[CommandArgument('text', '要回复的内容', required: true)] + #[CommandHelp('复读机', '只需要发送 echo+内容 即可自动复读', 'echo 你好 会回复 你好')] + public function repeat(\OneBotEvent $event, BotContext $context): void + { + $context->reply($event->getMessage()); + } } diff --git a/src/ZM/Annotation/OneBot/CommandHelp.php b/src/ZM/Annotation/OneBot/CommandHelp.php new file mode 100644 index 00000000..d2cdc8ac --- /dev/null +++ b/src/ZM/Annotation/OneBot/CommandHelp.php @@ -0,0 +1,35 @@ + PluginManager::addPlugin(['name' => $name, 'internal' => true, 'object' => new OneBot12Adapter(parser: $parser)]), 'onebot12-ban-other-ws' => PluginManager::addPlugin(['name' => $name, 'internal' => true, 'object' => new OneBot12Adapter(submodule: $name)]), + 'command-manual' => PluginManager::addPlugin(['name' => $name, 'internal' => true, 'object' => new CommandManualPlugin($parser)]), }; } diff --git a/src/ZM/Plugin/CommandManualPlugin.php b/src/ZM/Plugin/CommandManualPlugin.php new file mode 100644 index 00000000..5646ad20 --- /dev/null +++ b/src/ZM/Plugin/CommandManualPlugin.php @@ -0,0 +1,127 @@ + 'command', 'header' => false, 'indent' => false], + ['type' => 'description', 'header' => false, 'indent' => false], + ['type' => 'usage', 'header' => false, 'indent' => false], + ['type' => 'arguments', 'header' => '可用参数:', 'indent' => true], + ['type' => 'examples', 'header' => '使用示例:', 'indent' => true], + ]; + + /** + * 命令(帮助)列表,键为命令名,值为命令帮助 + * + * @var array + */ + private array $command_list = []; + + public function __construct(AnnotationParser $parser) + { + parent::__construct(__DIR__); + + if (config('command_manual.template') !== null) { + $this->template = config('command_manual.template'); + } + + $parser->addSpecialParser(BotCommand::class, [$this, 'parseBotCommand']); + $parser->addSpecialParser(CommandHelp::class, fn () => false); + + $this->addBotCommand( + BotCommand::make('help', 'help') + ->withArgument('command', '要查询的指令名', required: true) + ->on([$this, 'onHelp']) + ); + logger()->info('CommandManualPlugin loaded.'); + } + + /** + * 解析 BotCommand 的参数和帮助 + * + * @param BotCommand $command 命令对象 + * @param null|array $same_method_annotations 同一个方法的所有注解 + */ + public function parseBotCommand(BotCommand $command, ?array $same_method_annotations = null): ?bool + { + if ($same_method_annotations) { + foreach ($same_method_annotations as $v) { + if ($v instanceof CommandHelp) { + $help = $v; + break; + } + } + } + $help = $help ?? new CommandHelp('', '', ''); + $section = ''; + foreach ($this->template as $v) { + $content = $this->getSectionContent($command, $v['type'], $help); + $this->addSection($section, $content, $v); + } + $this->command_list[$command->name] = $section; + return true; + } + + public function onHelp(BotContext $context): void + { + $command = $context->getParam('command'); + if (isset($this->command_list[$command])) { + $context->reply($this->command_list[$command]); + } else { + $context->reply('未找到指令 ' . $command); + } + } + + private function addSection(string &$section, string $content, array $options): void + { + if (!$content) { + return; + } + if ($options['header']) { + $section .= $options['header'] . PHP_EOL; + } + if ($options['indent']) { + $content = ' ' . str_replace(PHP_EOL, PHP_EOL . ' ', $content); + $content = rtrim($content); + } + $section .= $content . PHP_EOL; + } + + private function getSectionContent(BotCommand $command, string $type, CommandHelp $help): string + { + switch ($type) { + case 'command': + return $command->name; + case 'description': + return $help->description; + case 'usage': + return $help->usage; + case 'arguments': + $ret = ''; + foreach ($command->getArguments() as $argument) { + /* @var CommandArgument $argument */ + $ret .= $argument->name . ' - ' . $argument->description . PHP_EOL; + } + return $ret; + case 'examples': + return $help->example; + default: + return ''; + } + } +} diff --git a/src/ZM/Plugin/PluginManager.php b/src/ZM/Plugin/PluginManager.php index 3792b43f..3736a71d 100644 --- a/src/ZM/Plugin/PluginManager.php +++ b/src/ZM/Plugin/PluginManager.php @@ -7,6 +7,7 @@ namespace ZM\Plugin; use ZM\Annotation\AnnotationMap; use ZM\Annotation\AnnotationParser; use ZM\Annotation\Framework\BindEvent; +use ZM\Annotation\OneBot\BotCommand; use ZM\Annotation\OneBot\BotEvent; use ZM\Exception\PluginException; use ZM\Store\FileSystem; @@ -191,6 +192,7 @@ class PluginManager } // 将 BotCommand 加入事件监听 foreach ($obj->getBotCommands() as $cmd) { + AnnotationMap::$_list[BotCommand::class][] = $cmd; $parser->parseSpecial($cmd); } } elseif (isset($plugin['autoload'], $plugin['dir'])) {