From 3e2911b807594f57d6fd8f9c738b3a28cc9c07cb Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Sun, 5 Mar 2023 22:15:01 +0800 Subject: [PATCH] add middleware arg trait and annotation trait --- src/Globals/global_class_alias.php | 18 ++++++ src/ZM/Annotation/AnnotationHandler.php | 2 +- .../Command/Plugin/PluginInstallCommand.php | 2 +- src/ZM/Middleware/MiddlewareHandler.php | 25 +++++++- src/ZM/Middleware/NeedAnnotationTrait.php | 22 +++++++ src/ZM/Middleware/WebSocketFilter.php | 63 +++++++++++++++++++ src/ZM/Plugin/OneBot/OneBot12Adapter.php | 2 +- 7 files changed, 129 insertions(+), 5 deletions(-) create mode 100644 src/ZM/Middleware/NeedAnnotationTrait.php create mode 100644 src/ZM/Middleware/WebSocketFilter.php diff --git a/src/Globals/global_class_alias.php b/src/Globals/global_class_alias.php index 00d89c17..d27a60f7 100644 --- a/src/Globals/global_class_alias.php +++ b/src/Globals/global_class_alias.php @@ -2,17 +2,21 @@ declare(strict_types=1); +// Framework 类注解 class_alias(\ZM\Annotation\Framework\BindEvent::class, 'BindEvent'); class_alias(\ZM\Annotation\Framework\Cron::class, 'Cron'); class_alias(\ZM\Annotation\Framework\Init::class, 'Init'); class_alias(\ZM\Annotation\Framework\Setup::class, 'Setup'); class_alias(\ZM\Annotation\Framework\Tick::class, 'Tick'); +// Http 类注解 class_alias(\ZM\Annotation\Http\Controller::class, 'Controller'); class_alias(\ZM\Annotation\Http\Route::class, 'Route'); +// Middleware 类注解 class_alias(\ZM\Annotation\Middleware\Middleware::class, 'Middleware'); +// OneBot 类注解 class_alias(\ZM\Annotation\OneBot\BotAction::class, 'BotAction'); class_alias(\ZM\Annotation\OneBot\BotActionResponse::class, 'BotActionResponse'); class_alias(\ZM\Annotation\OneBot\BotCommand::class, 'BotCommand'); @@ -20,14 +24,27 @@ class_alias(\ZM\Annotation\OneBot\BotEvent::class, 'BotEvent'); class_alias(\ZM\Annotation\OneBot\CommandArgument::class, 'CommandArgument'); class_alias(\ZM\Annotation\OneBot\CommandHelp::class, 'CommandHelp'); +// 全局注解 class_alias(\ZM\Annotation\Closed::class, 'Closed'); +// 中间件类 class_alias(\ZM\Middleware\MiddlewareArgTrait::class, 'MiddlewareArgTrait'); +class_alias(\ZM\Middleware\MiddlewareHandler::class, 'MiddlewareHandler'); +class_alias(\ZM\Middleware\NeedAnnotationTrait::class, 'NeedAnnotationTrait'); class_alias(\ZM\Middleware\Pipeline::class, 'Pipeline'); +class_alias(\ZM\Middleware\TimerMiddleware::class, 'TimerMiddleware'); +class_alias(\ZM\Middleware\WebSocketFilter::class, 'WebSocketFilter'); +// 插件、上下文、工具类 class_alias(\ZM\Plugin\ZMPlugin::class, 'ZMPlugin'); class_alias(\ZM\Context\BotContext::class, 'BotContext'); +class_alias(\ZM\Utils\CatCode::class, 'CatCode'); +class_alias(\ZM\Utils\ConnectionUtil::class, 'ConnectionUtil'); +class_alias(\ZM\Utils\MessageUtil::class, 'MessageUtil'); +class_alias(\ZM\Utils\OneBot12FileDownloader::class, 'OneBot12FileDownloader'); +class_alias(\ZM\Utils\OneBot12FileUploader::class, 'OneBot12FileUploader'); class_alias(\ZM\Utils\ZMRequest::class, 'ZMRequest'); +class_alias(\ZM\Utils\ZMUtil::class, 'ZMUtil'); class_alias(\ZM\Store\KV\LightCache::class, 'LightCache'); class_alias(\ZM\Store\KV\Redis\KVRedis::class, 'KVRedis'); @@ -37,6 +54,7 @@ class_alias(\OneBot\Driver\Event\WebSocket\WebSocketCloseEvent::class, 'WebSocke class_alias(\OneBot\Driver\Event\WebSocket\WebSocketMessageEvent::class, 'WebSocketMessageEvent'); class_alias(\OneBot\Driver\Event\Http\HttpRequestEvent::class, 'HttpRequestEvent'); +// OneBot 12 的对象 class_alias(\OneBot\V12\Object\OneBotEvent::class, 'OneBotEvent'); // 下面是 Choir 相关的全局别称 diff --git a/src/ZM/Annotation/AnnotationHandler.php b/src/ZM/Annotation/AnnotationHandler.php index 47c1940d..0b55fe66 100644 --- a/src/ZM/Annotation/AnnotationHandler.php +++ b/src/ZM/Annotation/AnnotationHandler.php @@ -131,7 +131,7 @@ class AnnotationHandler return false; } try { - $this->return_val = middleware()->process($callback, ...$args); + $this->return_val = middleware()->processWithAnnotation($v, $callback, ...$args); // 执行完毕后检查状态,如果状态是规则判断或中间件before不通过,则重置状态后继续执行别的注解函数 if ($this->status == self::STATUS_BEFORE_FAILED || $this->status == self::STATUS_RULE_FAILED) { $this->status = self::STATUS_NORMAL; diff --git a/src/ZM/Command/Plugin/PluginInstallCommand.php b/src/ZM/Command/Plugin/PluginInstallCommand.php index 9e8069a1..bebbdd91 100644 --- a/src/ZM/Command/Plugin/PluginInstallCommand.php +++ b/src/ZM/Command/Plugin/PluginInstallCommand.php @@ -53,7 +53,7 @@ class PluginInstallCommand extends PluginCommand return static::FAILURE; } } catch (\Throwable $e) { - $this->error('niu: ' . $e->getMessage()); + $this->error('插件安装失败: ' . $e->getMessage()); $this->error($e->getTraceAsString()); return static::FAILURE; } diff --git a/src/ZM/Middleware/MiddlewareHandler.php b/src/ZM/Middleware/MiddlewareHandler.php index bddf3c09..7849120a 100644 --- a/src/ZM/Middleware/MiddlewareHandler.php +++ b/src/ZM/Middleware/MiddlewareHandler.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace ZM\Middleware; use OneBot\Util\Singleton; +use ZM\Annotation\AnnotationBase; use ZM\Exception\InvalidArgumentException; class MiddlewareHandler @@ -71,9 +72,9 @@ class MiddlewareHandler $this->reg_map[$stack_id][] = [$name, $args]; } - public function getPipeClosure(callable $callback, $stack_id) + public function getPipeClosure(callable $callback, $stack_id, ?AnnotationBase $annotation = null) { - $pipe_func = function (array $mid_list, ...$args) use ($callback, $stack_id, &$pipe_func) { + $pipe_func = function (array $mid_list, ...$args) use ($callback, $stack_id, $annotation, &$pipe_func) { $return = true; try { while (($item = array_shift($mid_list)) !== null) { @@ -81,6 +82,9 @@ class MiddlewareHandler // 如果是 pipeline 形式的中间件,则使用闭包回去 if (class_exists($item[0]) && is_a($item[0], PipelineInterface::class, true)) { $resolve = resolve($item[0]); + if (method_exists($resolve, 'setAnnotation') && $annotation !== null) { + $resolve->setAnnotation($annotation); + } if (method_exists($resolve, 'setArgs')) { $resolve->setArgs($item[1]); } @@ -158,6 +162,23 @@ class MiddlewareHandler return $final_result ?? null; } + public function processWithAnnotation(AnnotationBase $v, callable $callback, ...$args) + { + $stack_id = $this->getStackId($callback); + unset($this->stack[$stack_id]); + + $this->callable_stack[] = $callback; + + // 遍历执行before并压栈,并在遇到返回false后停止 + try { + $mid_list = ($this->reg_map[$stack_id] ?? []); + $final_result = ($this->getPipeClosure($callback, $stack_id, $v))($mid_list, ...$args); + } finally { + array_pop($this->callable_stack); + } + return $final_result ?? null; + } + /** * 获取正在运行的回调调用对象,可能是Closure、array、string * diff --git a/src/ZM/Middleware/NeedAnnotationTrait.php b/src/ZM/Middleware/NeedAnnotationTrait.php new file mode 100644 index 00000000..8724f538 --- /dev/null +++ b/src/ZM/Middleware/NeedAnnotationTrait.php @@ -0,0 +1,22 @@ +annotation = $annotation; + } + + public function getAnnotation(): ?AnnotationBase + { + return $this->annotation; + } +} diff --git a/src/ZM/Middleware/WebSocketFilter.php b/src/ZM/Middleware/WebSocketFilter.php new file mode 100644 index 00000000..ab0d3585 --- /dev/null +++ b/src/ZM/Middleware/WebSocketFilter.php @@ -0,0 +1,63 @@ +alert('正在走 Filter'); + if (!$this->annotation instanceof BindEvent) { + return null; + } + if (is_a($this->annotation->event_class, WebSocketOpenEvent::class, true)) { + return $this->filterOpen(container()->get(WebSocketOpenEvent::class)) ? $callback(...$params) : null; + } + if (is_a($this->annotation->event_class, WebSocketMessageEvent::class, true)) { + return $this->filterMessageAndClose(container()->get(WebSocketMessageEvent::class)) ? $callback(...$params) : null; + } + if (is_a($this->annotation->event_class, WebSocketCloseEvent::class, true)) { + return $this->filterMessageAndClose(container()->get(WebSocketCloseEvent::class)) ? $callback(...$params) : null; + } + return $callback(...$params); + } + + private function filterOpen(WebSocketOpenEvent $event): bool + { + // 过滤存在 flag 设置的情况 + if (($this->args['flag'] ?? null) !== null && $this->args['flag'] !== $event->getSocketFlag()) { + return false; + } + return true; + } + + private function filterMessageAndClose(WebSocketMessageEvent|WebSocketCloseEvent $event): bool + { + // 过滤存在 flag 设置的情况 + if (($this->args['flag'] ?? null) !== null && $this->args['flag'] !== $event->getSocketFlag()) { + return false; + } + // 过滤连接信息 + $conn = ConnectionUtil::getConnection($event->getFd()); + foreach ($this->args as $k => $v) { + if (!isset($conn[$k])) { + return false; + } + if (is_string($v) && $conn[$k] !== $v) { + return false; + } + } + return true; + } +} diff --git a/src/ZM/Plugin/OneBot/OneBot12Adapter.php b/src/ZM/Plugin/OneBot/OneBot12Adapter.php index 4f18d4fa..3c289ad3 100644 --- a/src/ZM/Plugin/OneBot/OneBot12Adapter.php +++ b/src/ZM/Plugin/OneBot/OneBot12Adapter.php @@ -317,7 +317,7 @@ class OneBot12Adapter extends ZMPlugin logger()->info('检测到 OneBot 12 反向 WS 连接,正在进行认证...'); // 是 OneBot 12 标准的,准许接入,进行鉴权 $request = $event->getRequest(); - $info = ['impl' => $line[1] ?? 'unknown']; + $info = ['impl' => $line[1] ?? 'unknown', 'onebot-version' => '12']; if (($stored_token = $event->getSocketConfig()['access_token'] ?? '') !== '') { // 测试 Header $token = $request->getHeaderLine('Authorization');