mirror of
https://github.com/zhamao-robot/zhamao-framework.git
synced 2026-07-02 14:25:38 +08:00
add middleware arg trait and annotation trait
This commit is contained in:
@@ -2,17 +2,21 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
// Framework 类注解
|
||||||
class_alias(\ZM\Annotation\Framework\BindEvent::class, 'BindEvent');
|
class_alias(\ZM\Annotation\Framework\BindEvent::class, 'BindEvent');
|
||||||
class_alias(\ZM\Annotation\Framework\Cron::class, 'Cron');
|
class_alias(\ZM\Annotation\Framework\Cron::class, 'Cron');
|
||||||
class_alias(\ZM\Annotation\Framework\Init::class, 'Init');
|
class_alias(\ZM\Annotation\Framework\Init::class, 'Init');
|
||||||
class_alias(\ZM\Annotation\Framework\Setup::class, 'Setup');
|
class_alias(\ZM\Annotation\Framework\Setup::class, 'Setup');
|
||||||
class_alias(\ZM\Annotation\Framework\Tick::class, 'Tick');
|
class_alias(\ZM\Annotation\Framework\Tick::class, 'Tick');
|
||||||
|
|
||||||
|
// Http 类注解
|
||||||
class_alias(\ZM\Annotation\Http\Controller::class, 'Controller');
|
class_alias(\ZM\Annotation\Http\Controller::class, 'Controller');
|
||||||
class_alias(\ZM\Annotation\Http\Route::class, 'Route');
|
class_alias(\ZM\Annotation\Http\Route::class, 'Route');
|
||||||
|
|
||||||
|
// Middleware 类注解
|
||||||
class_alias(\ZM\Annotation\Middleware\Middleware::class, 'Middleware');
|
class_alias(\ZM\Annotation\Middleware\Middleware::class, 'Middleware');
|
||||||
|
|
||||||
|
// OneBot 类注解
|
||||||
class_alias(\ZM\Annotation\OneBot\BotAction::class, 'BotAction');
|
class_alias(\ZM\Annotation\OneBot\BotAction::class, 'BotAction');
|
||||||
class_alias(\ZM\Annotation\OneBot\BotActionResponse::class, 'BotActionResponse');
|
class_alias(\ZM\Annotation\OneBot\BotActionResponse::class, 'BotActionResponse');
|
||||||
class_alias(\ZM\Annotation\OneBot\BotCommand::class, 'BotCommand');
|
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\CommandArgument::class, 'CommandArgument');
|
||||||
class_alias(\ZM\Annotation\OneBot\CommandHelp::class, 'CommandHelp');
|
class_alias(\ZM\Annotation\OneBot\CommandHelp::class, 'CommandHelp');
|
||||||
|
|
||||||
|
// 全局注解
|
||||||
class_alias(\ZM\Annotation\Closed::class, 'Closed');
|
class_alias(\ZM\Annotation\Closed::class, 'Closed');
|
||||||
|
|
||||||
|
// 中间件类
|
||||||
class_alias(\ZM\Middleware\MiddlewareArgTrait::class, 'MiddlewareArgTrait');
|
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\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\Plugin\ZMPlugin::class, 'ZMPlugin');
|
||||||
class_alias(\ZM\Context\BotContext::class, 'BotContext');
|
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\ZMRequest::class, 'ZMRequest');
|
||||||
|
class_alias(\ZM\Utils\ZMUtil::class, 'ZMUtil');
|
||||||
class_alias(\ZM\Store\KV\LightCache::class, 'LightCache');
|
class_alias(\ZM\Store\KV\LightCache::class, 'LightCache');
|
||||||
class_alias(\ZM\Store\KV\Redis\KVRedis::class, 'KVRedis');
|
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\WebSocket\WebSocketMessageEvent::class, 'WebSocketMessageEvent');
|
||||||
class_alias(\OneBot\Driver\Event\Http\HttpRequestEvent::class, 'HttpRequestEvent');
|
class_alias(\OneBot\Driver\Event\Http\HttpRequestEvent::class, 'HttpRequestEvent');
|
||||||
|
|
||||||
|
// OneBot 12 的对象
|
||||||
class_alias(\OneBot\V12\Object\OneBotEvent::class, 'OneBotEvent');
|
class_alias(\OneBot\V12\Object\OneBotEvent::class, 'OneBotEvent');
|
||||||
|
|
||||||
// 下面是 Choir 相关的全局别称
|
// 下面是 Choir 相关的全局别称
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ class AnnotationHandler
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$this->return_val = middleware()->process($callback, ...$args);
|
$this->return_val = middleware()->processWithAnnotation($v, $callback, ...$args);
|
||||||
// 执行完毕后检查状态,如果状态是规则判断或中间件before不通过,则重置状态后继续执行别的注解函数
|
// 执行完毕后检查状态,如果状态是规则判断或中间件before不通过,则重置状态后继续执行别的注解函数
|
||||||
if ($this->status == self::STATUS_BEFORE_FAILED || $this->status == self::STATUS_RULE_FAILED) {
|
if ($this->status == self::STATUS_BEFORE_FAILED || $this->status == self::STATUS_RULE_FAILED) {
|
||||||
$this->status = self::STATUS_NORMAL;
|
$this->status = self::STATUS_NORMAL;
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class PluginInstallCommand extends PluginCommand
|
|||||||
return static::FAILURE;
|
return static::FAILURE;
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->error('niu: ' . $e->getMessage());
|
$this->error('插件安装失败: ' . $e->getMessage());
|
||||||
$this->error($e->getTraceAsString());
|
$this->error($e->getTraceAsString());
|
||||||
return static::FAILURE;
|
return static::FAILURE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace ZM\Middleware;
|
namespace ZM\Middleware;
|
||||||
|
|
||||||
use OneBot\Util\Singleton;
|
use OneBot\Util\Singleton;
|
||||||
|
use ZM\Annotation\AnnotationBase;
|
||||||
use ZM\Exception\InvalidArgumentException;
|
use ZM\Exception\InvalidArgumentException;
|
||||||
|
|
||||||
class MiddlewareHandler
|
class MiddlewareHandler
|
||||||
@@ -71,9 +72,9 @@ class MiddlewareHandler
|
|||||||
$this->reg_map[$stack_id][] = [$name, $args];
|
$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;
|
$return = true;
|
||||||
try {
|
try {
|
||||||
while (($item = array_shift($mid_list)) !== null) {
|
while (($item = array_shift($mid_list)) !== null) {
|
||||||
@@ -81,6 +82,9 @@ class MiddlewareHandler
|
|||||||
// 如果是 pipeline 形式的中间件,则使用闭包回去
|
// 如果是 pipeline 形式的中间件,则使用闭包回去
|
||||||
if (class_exists($item[0]) && is_a($item[0], PipelineInterface::class, true)) {
|
if (class_exists($item[0]) && is_a($item[0], PipelineInterface::class, true)) {
|
||||||
$resolve = resolve($item[0]);
|
$resolve = resolve($item[0]);
|
||||||
|
if (method_exists($resolve, 'setAnnotation') && $annotation !== null) {
|
||||||
|
$resolve->setAnnotation($annotation);
|
||||||
|
}
|
||||||
if (method_exists($resolve, 'setArgs')) {
|
if (method_exists($resolve, 'setArgs')) {
|
||||||
$resolve->setArgs($item[1]);
|
$resolve->setArgs($item[1]);
|
||||||
}
|
}
|
||||||
@@ -158,6 +162,23 @@ class MiddlewareHandler
|
|||||||
return $final_result ?? null;
|
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
|
* 获取正在运行的回调调用对象,可能是Closure、array、string
|
||||||
*
|
*
|
||||||
|
|||||||
22
src/ZM/Middleware/NeedAnnotationTrait.php
Normal file
22
src/ZM/Middleware/NeedAnnotationTrait.php
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace ZM\Middleware;
|
||||||
|
|
||||||
|
use ZM\Annotation\AnnotationBase;
|
||||||
|
|
||||||
|
trait NeedAnnotationTrait
|
||||||
|
{
|
||||||
|
protected ?AnnotationBase $annotation = null;
|
||||||
|
|
||||||
|
public function setAnnotation(AnnotationBase $annotation): void
|
||||||
|
{
|
||||||
|
$this->annotation = $annotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAnnotation(): ?AnnotationBase
|
||||||
|
{
|
||||||
|
return $this->annotation;
|
||||||
|
}
|
||||||
|
}
|
||||||
63
src/ZM/Middleware/WebSocketFilter.php
Normal file
63
src/ZM/Middleware/WebSocketFilter.php
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace ZM\Middleware;
|
||||||
|
|
||||||
|
use OneBot\Driver\Event\WebSocket\WebSocketCloseEvent;
|
||||||
|
use OneBot\Driver\Event\WebSocket\WebSocketMessageEvent;
|
||||||
|
use OneBot\Driver\Event\WebSocket\WebSocketOpenEvent;
|
||||||
|
use ZM\Annotation\Framework\BindEvent;
|
||||||
|
use ZM\Utils\ConnectionUtil;
|
||||||
|
|
||||||
|
class WebSocketFilter implements MiddlewareInterface, PipelineInterface
|
||||||
|
{
|
||||||
|
use MiddlewareArgTrait;
|
||||||
|
use NeedAnnotationTrait;
|
||||||
|
|
||||||
|
public function handle(callable $callback, ...$params)
|
||||||
|
{
|
||||||
|
logger()->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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -317,7 +317,7 @@ class OneBot12Adapter extends ZMPlugin
|
|||||||
logger()->info('检测到 OneBot 12 反向 WS 连接,正在进行认证...');
|
logger()->info('检测到 OneBot 12 反向 WS 连接,正在进行认证...');
|
||||||
// 是 OneBot 12 标准的,准许接入,进行鉴权
|
// 是 OneBot 12 标准的,准许接入,进行鉴权
|
||||||
$request = $event->getRequest();
|
$request = $event->getRequest();
|
||||||
$info = ['impl' => $line[1] ?? 'unknown'];
|
$info = ['impl' => $line[1] ?? 'unknown', 'onebot-version' => '12'];
|
||||||
if (($stored_token = $event->getSocketConfig()['access_token'] ?? '') !== '') {
|
if (($stored_token = $event->getSocketConfig()['access_token'] ?? '') !== '') {
|
||||||
// 测试 Header
|
// 测试 Header
|
||||||
$token = $request->getHeaderLine('Authorization');
|
$token = $request->getHeaderLine('Authorization');
|
||||||
|
|||||||
Reference in New Issue
Block a user