2020-03-02 16:14:20 +08:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace ZM\Annotation;
|
|
|
|
|
|
2020-04-26 17:15:27 +08:00
|
|
|
use Doctrine\Common\Annotations\{AnnotationException, AnnotationReader};
|
|
|
|
|
use Framework\{Console, ZMBuf};
|
2020-03-02 16:14:20 +08:00
|
|
|
use ReflectionClass;
|
|
|
|
|
use ReflectionException;
|
|
|
|
|
use ReflectionMethod;
|
|
|
|
|
use ZM\Annotation\CQ\{CQAfter, CQBefore, CQCommand, CQMessage, CQMetaEvent, CQNotice, CQRequest};
|
2020-04-26 17:15:27 +08:00
|
|
|
use ZM\Annotation\Http\{After, Before, Controller, HandleException, Middleware, MiddlewareClass, RequestMapping};
|
2020-04-29 15:29:56 +08:00
|
|
|
use Swoole\Timer;
|
2020-03-02 16:14:20 +08:00
|
|
|
use ZM\Annotation\Interfaces\CustomAnnotation;
|
|
|
|
|
use ZM\Annotation\Interfaces\Level;
|
2020-04-26 17:15:27 +08:00
|
|
|
use ZM\Annotation\Module\{Closed, InitBuffer, SaveBuffer};
|
2020-04-29 15:29:56 +08:00
|
|
|
use ZM\Annotation\Swoole\{OnStart, OnTick, SwooleEventAfter, SwooleEventAt};
|
2020-03-02 16:14:20 +08:00
|
|
|
use ZM\Annotation\Interfaces\Rule;
|
|
|
|
|
use ZM\Connection\WSConnection;
|
2020-03-25 18:35:16 +08:00
|
|
|
use ZM\Http\MiddlewareInterface;
|
2020-03-02 16:14:20 +08:00
|
|
|
use ZM\Utils\DataProvider;
|
2020-04-29 15:29:56 +08:00
|
|
|
use ZM\Utils\ZMUtil;
|
2020-03-02 16:14:20 +08:00
|
|
|
|
|
|
|
|
class AnnotationParser
|
|
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* 注册各个模块类的注解和模块level的排序
|
|
|
|
|
* @throws ReflectionException
|
|
|
|
|
* @throws AnnotationException
|
|
|
|
|
*/
|
2020-03-25 18:35:16 +08:00
|
|
|
public static function registerMods() {
|
2020-03-02 16:14:20 +08:00
|
|
|
self::loadAnnotationClasses();
|
|
|
|
|
$all_class = getAllClasses(WORKING_DIR . "/src/Module/", "Module");
|
2020-03-05 12:03:14 +08:00
|
|
|
ZMBuf::$req_mapping[0] = [
|
|
|
|
|
'id' => 0,
|
|
|
|
|
'pid' => -1,
|
|
|
|
|
'name' => '/'
|
|
|
|
|
];
|
2020-03-02 16:14:20 +08:00
|
|
|
$reader = new AnnotationReader();
|
|
|
|
|
foreach ($all_class as $v) {
|
|
|
|
|
$reflection_class = new ReflectionClass($v);
|
|
|
|
|
$class_prefix = '';
|
|
|
|
|
$methods = $reflection_class->getMethods(ReflectionMethod::IS_PUBLIC);
|
|
|
|
|
$class_annotations = $reader->getClassAnnotations($reflection_class);
|
2020-04-26 15:56:06 +08:00
|
|
|
$middleware_addon = null;
|
2020-03-02 16:14:20 +08:00
|
|
|
foreach ($class_annotations as $vs) {
|
|
|
|
|
if ($vs instanceof Closed) {
|
|
|
|
|
continue 2;
|
|
|
|
|
} elseif ($vs instanceof Controller) {
|
2020-04-29 15:29:56 +08:00
|
|
|
Console::debug("找到 Controller 中间件: ".$vs->class);
|
2020-03-02 16:14:20 +08:00
|
|
|
$class_prefix = $vs->prefix;
|
|
|
|
|
} elseif ($vs instanceof SaveBuffer) {
|
2020-04-29 15:29:56 +08:00
|
|
|
Console::debug("注册自动保存的缓存变量: ".$vs->buf_name." (Dir:".$vs->sub_folder.")");
|
2020-03-02 16:14:20 +08:00
|
|
|
DataProvider::addSaveBuffer($vs->buf_name, $vs->sub_folder);
|
2020-03-08 16:40:04 +08:00
|
|
|
} elseif ($vs instanceof InitBuffer) {
|
|
|
|
|
ZMBuf::set($vs->buf_name, []);
|
2020-03-25 18:35:16 +08:00
|
|
|
} elseif ($vs instanceof MiddlewareClass) {
|
2020-04-29 15:29:56 +08:00
|
|
|
Console::verbose("正在注册中间件 " . $vs->class);
|
2020-03-25 18:35:16 +08:00
|
|
|
$result = [
|
2020-03-29 16:29:02 +08:00
|
|
|
"class" => "\\" . $reflection_class->getName()
|
2020-03-25 18:35:16 +08:00
|
|
|
];
|
|
|
|
|
foreach ($methods as $vss) {
|
2020-03-29 16:29:02 +08:00
|
|
|
if ($vss->getName() == "getName") {
|
|
|
|
|
/** @var MiddlewareInterface $tmp */
|
|
|
|
|
$tmp = new $v();
|
|
|
|
|
$result["name"] = $tmp->getName();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2020-03-25 18:35:16 +08:00
|
|
|
$method_annotations = $reader->getMethodAnnotations($vss);
|
|
|
|
|
foreach ($method_annotations as $vsss) {
|
|
|
|
|
if ($vss instanceof Rule) $vss = self::registerRuleEvent($vsss, $vss, $reflection_class);
|
|
|
|
|
else $vss = self::registerMethod($vsss, $vss, $reflection_class);
|
2020-03-29 16:29:02 +08:00
|
|
|
//echo get_class($vsss) . PHP_EOL;
|
2020-03-25 18:35:16 +08:00
|
|
|
if ($vsss instanceof Before) $result["before"] = $vsss->method;
|
|
|
|
|
if ($vsss instanceof After) $result["after"] = $vsss->method;
|
|
|
|
|
if ($vsss instanceof HandleException) {
|
2020-03-29 16:29:02 +08:00
|
|
|
$result["exceptions"][$vsss->class_name] = $vsss->method;
|
2020-03-25 18:35:16 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-03-29 16:29:02 +08:00
|
|
|
ZMBuf::$events[MiddlewareClass::class][$result["name"]] = $result;
|
2020-03-25 18:35:16 +08:00
|
|
|
continue 2;
|
2020-04-26 15:56:06 +08:00
|
|
|
} elseif ($vs instanceof Middleware) {
|
|
|
|
|
$middleware_addon = $vs;
|
2020-03-02 16:14:20 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
foreach ($methods as $vs) {
|
|
|
|
|
$method_annotations = $reader->getMethodAnnotations($vs);
|
|
|
|
|
foreach ($method_annotations as $vss) {
|
|
|
|
|
if ($vss instanceof Rule) $vss = self::registerRuleEvent($vss, $vs, $reflection_class);
|
|
|
|
|
else $vss = self::registerMethod($vss, $vs, $reflection_class);
|
|
|
|
|
|
2020-03-05 12:03:14 +08:00
|
|
|
if ($vss instanceof SwooleEventAt) ZMBuf::$events[SwooleEventAt::class][] = $vss;
|
|
|
|
|
elseif ($vss instanceof SwooleEventAfter) ZMBuf::$events[SwooleEventAfter::class][] = $vss;
|
|
|
|
|
elseif ($vss instanceof CQMessage) ZMBuf::$events[CQMessage::class][] = $vss;
|
|
|
|
|
elseif ($vss instanceof CQNotice) ZMBuf::$events[CQNotice::class][] = $vss;
|
|
|
|
|
elseif ($vss instanceof CQRequest) ZMBuf::$events[CQRequest::class][] = $vss;
|
|
|
|
|
elseif ($vss instanceof CQMetaEvent) ZMBuf::$events[CQMetaEvent::class][] = $vss;
|
|
|
|
|
elseif ($vss instanceof CQCommand) ZMBuf::$events[CQCommand::class][] = $vss;
|
2020-04-26 15:56:06 +08:00
|
|
|
elseif ($vss instanceof RequestMapping) {
|
|
|
|
|
self::registerRequestMapping($vss, $vs, $reflection_class, $class_prefix);
|
2020-04-29 15:29:56 +08:00
|
|
|
if ($middleware_addon !== null)
|
2020-04-26 15:56:06 +08:00
|
|
|
ZMBuf::$events[MiddlewareInterface::class][$vss->class][$vss->method] = $middleware_addon->middleware;
|
|
|
|
|
} elseif ($vss instanceof CustomAnnotation) ZMBuf::$events[get_class($vss)][] = $vss;
|
2020-03-05 12:03:14 +08:00
|
|
|
elseif ($vss instanceof CQBefore) ZMBuf::$events[CQBefore::class][$vss->cq_event][] = $vss;
|
|
|
|
|
elseif ($vss instanceof CQAfter) ZMBuf::$events[CQAfter::class][$vss->cq_event][] = $vss;
|
2020-03-25 18:35:16 +08:00
|
|
|
elseif ($vss instanceof OnStart) ZMBuf::$events[OnStart::class][] = $vss;
|
2020-04-15 10:55:10 +08:00
|
|
|
elseif ($vss instanceof Middleware) ZMBuf::$events[MiddlewareInterface::class][$vss->class][$vss->method] = $vss->middleware;
|
2020-04-29 15:29:56 +08:00
|
|
|
elseif ($vss instanceof OnTick) self::addTimerTick($vss);
|
2020-03-02 16:14:20 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-03-05 12:03:14 +08:00
|
|
|
$tree = self::genTree(ZMBuf::$req_mapping);
|
|
|
|
|
ZMBuf::$req_mapping = $tree[0];
|
2020-03-02 16:14:20 +08:00
|
|
|
//给支持level的排个序
|
|
|
|
|
foreach (ZMBuf::$events as $class_name => $v) {
|
2020-03-25 18:35:16 +08:00
|
|
|
if (is_a($class_name, Level::class, true)) {
|
2020-03-02 16:14:20 +08:00
|
|
|
for ($i = 0; $i < count(ZMBuf::$events[$class_name]) - 1; ++$i) {
|
|
|
|
|
for ($j = 0; $j < count(ZMBuf::$events[$class_name]) - $i - 1; ++$j) {
|
|
|
|
|
$l1 = ZMBuf::$events[$class_name][$j]->level;
|
|
|
|
|
$l2 = ZMBuf::$events[$class_name][$j + 1]->level;
|
|
|
|
|
if ($l1 < $l2) {
|
|
|
|
|
$t = ZMBuf::$events[$class_name][$j + 1];
|
|
|
|
|
ZMBuf::$events[$class_name][$j + 1] = ZMBuf::$events[$class_name][$j];
|
|
|
|
|
ZMBuf::$events[$class_name][$j] = $t;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-29 15:29:56 +08:00
|
|
|
if (ZMBuf::isset("timer_count")) {
|
|
|
|
|
Console::info("Added " . ZMBuf::get("timer_count") . " timer(s)!");
|
|
|
|
|
ZMBuf::unsetCache("timer_count");
|
|
|
|
|
}
|
2020-03-02 16:14:20 +08:00
|
|
|
}
|
|
|
|
|
|
2020-03-25 18:35:16 +08:00
|
|
|
private static function getRuleCallback($rule_str) {
|
2020-03-02 16:14:20 +08:00
|
|
|
$func = null;
|
|
|
|
|
$rule = $rule_str;
|
|
|
|
|
if ($rule != "") {
|
|
|
|
|
$asp = explode(":", $rule);
|
|
|
|
|
$asp_name = array_shift($asp);
|
|
|
|
|
$rest = implode(":", $asp);
|
|
|
|
|
//Swoole 事件时走此switch
|
|
|
|
|
switch ($asp_name) {
|
|
|
|
|
case "connectType": //websocket连接类型
|
|
|
|
|
$func = function (WSConnection $connection) use ($rest) {
|
|
|
|
|
return $connection->getType() == $rest ? true : false;
|
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
case "containsGet": //handle http request事件时才能用
|
|
|
|
|
case "containsPost":
|
|
|
|
|
$get_list = explode(",", $rest);
|
|
|
|
|
if ($asp_name == "containsGet")
|
|
|
|
|
$func = function ($request) use ($get_list) {
|
|
|
|
|
foreach ($get_list as $v) if (!isset($request->get[$v])) return false;
|
|
|
|
|
return true;
|
|
|
|
|
};
|
|
|
|
|
else
|
|
|
|
|
$func = function ($request) use ($get_list) {
|
|
|
|
|
foreach ($get_list as $v) if (!isset($request->post[$v])) return false;
|
|
|
|
|
return true;
|
|
|
|
|
};
|
|
|
|
|
/*
|
|
|
|
|
if ($controller_prefix != '') {
|
|
|
|
|
$p = ZMBuf::$req_mapping_node;
|
|
|
|
|
$prefix_exp = explode("/", $controller_prefix);
|
|
|
|
|
foreach ($prefix_exp as $k => $v) {
|
|
|
|
|
if ($v == "" || $v == ".." || $v == ".") {
|
|
|
|
|
unset($prefix_exp[$k]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
while (($shift = array_shift($prefix_exp)) !== null) {
|
|
|
|
|
$p->addRoute($shift, new MappingNode($shift));
|
|
|
|
|
$p = $p->getRoute($shift);
|
|
|
|
|
}
|
|
|
|
|
if ($p->getNodeName() != "/") {
|
|
|
|
|
$p->setMethod($method->getName());
|
|
|
|
|
$p->setClass($class->getName());
|
|
|
|
|
$p->setRule($func);
|
|
|
|
|
return "mapped";
|
|
|
|
|
}
|
|
|
|
|
}*/
|
|
|
|
|
break;
|
|
|
|
|
case "containsJson": //handle http request事件时才能用
|
|
|
|
|
$json_list = explode(",", $rest);
|
|
|
|
|
$func = function ($json) use ($json_list) {
|
|
|
|
|
foreach ($json_list as $v) if (!isset($json[$v])) return false;
|
|
|
|
|
return true;
|
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
case "dataEqual": //handle websocket message事件时才能用
|
2020-03-05 12:03:14 +08:00
|
|
|
$func = function ($data) use ($rest) {
|
|
|
|
|
return $data == $rest;
|
|
|
|
|
};
|
2020-03-02 16:14:20 +08:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
switch ($asp_name) {
|
|
|
|
|
case "msgMatch": //handle cq message事件时才能用
|
2020-03-05 12:03:14 +08:00
|
|
|
$func = function ($msg) use ($rest) {
|
|
|
|
|
return matchPattern($rest, $msg);
|
|
|
|
|
};
|
2020-03-02 16:14:20 +08:00
|
|
|
break;
|
|
|
|
|
case "msgEqual": //handle cq message事件时才能用
|
2020-03-05 12:03:14 +08:00
|
|
|
$func = function ($msg) use ($rest) {
|
|
|
|
|
return trim($msg) == $rest;
|
|
|
|
|
};
|
2020-03-02 16:14:20 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $func;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-25 18:35:16 +08:00
|
|
|
private static function registerRuleEvent(?AnnotationBase $vss, ReflectionMethod $method, ReflectionClass $class) {
|
2020-03-02 16:14:20 +08:00
|
|
|
$vss->callback = self::getRuleCallback($vss->getRule());
|
|
|
|
|
$vss->method = $method->getName();
|
|
|
|
|
$vss->class = $class->getName();
|
|
|
|
|
return $vss;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-25 18:35:16 +08:00
|
|
|
private static function registerMethod(?AnnotationBase $vss, ReflectionMethod $method, ReflectionClass $class) {
|
2020-03-02 16:14:20 +08:00
|
|
|
$vss->method = $method->getName();
|
|
|
|
|
$vss->class = $class->getName();
|
|
|
|
|
return $vss;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-25 18:35:16 +08:00
|
|
|
private static function registerRequestMapping(RequestMapping $vss, ReflectionMethod $method, ReflectionClass $class, string $prefix) {
|
2020-03-05 12:03:14 +08:00
|
|
|
$array = ZMBuf::$req_mapping;
|
|
|
|
|
$uid = count($array);
|
2020-03-02 16:14:20 +08:00
|
|
|
$prefix_exp = explode("/", $prefix);
|
|
|
|
|
$route_exp = explode("/", $vss->route);
|
|
|
|
|
foreach ($prefix_exp as $k => $v) {
|
|
|
|
|
if ($v == "" || $v == ".." || $v == ".") {
|
|
|
|
|
unset($prefix_exp[$k]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
foreach ($route_exp as $k => $v) {
|
|
|
|
|
if ($v == "" || $v == ".." || $v == ".") {
|
|
|
|
|
unset($route_exp[$k]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ($prefix_exp == [] && $route_exp == []) {
|
2020-04-26 17:15:27 +08:00
|
|
|
$array[0]['method'] = $method->getName();
|
|
|
|
|
$array[0]['class'] = $class->getName();
|
|
|
|
|
$array[0]['request_method'] = $vss->request_method;
|
2020-03-05 12:03:14 +08:00
|
|
|
ZMBuf::$req_mapping = $array;
|
2020-03-02 16:14:20 +08:00
|
|
|
return;
|
|
|
|
|
}
|
2020-03-05 12:03:14 +08:00
|
|
|
$pid = 0;
|
2020-03-02 16:14:20 +08:00
|
|
|
while (($shift = array_shift($prefix_exp)) !== null) {
|
2020-03-05 12:03:14 +08:00
|
|
|
foreach ($array as $k => $v) {
|
|
|
|
|
if ($v["name"] == $shift && $pid == ($v["pid"] ?? -1)) {
|
|
|
|
|
$pid = $v["id"];
|
|
|
|
|
continue 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$array[$uid++] = [
|
|
|
|
|
'id' => $uid - 1,
|
|
|
|
|
'pid' => $pid,
|
|
|
|
|
'name' => $shift
|
|
|
|
|
];
|
|
|
|
|
$pid = $uid - 1;
|
2020-03-02 16:14:20 +08:00
|
|
|
}
|
|
|
|
|
while (($shift = array_shift($route_exp)) !== null) {
|
2020-03-05 12:03:14 +08:00
|
|
|
/*if (mb_substr($shift, 0, 1) == "{" && mb_substr($shift, -1, 1) == "}") {
|
2020-03-02 16:14:20 +08:00
|
|
|
$p->removeAllRoute();
|
2020-03-05 12:03:14 +08:00
|
|
|
Console::info("移除本节点其他所有路由中");
|
|
|
|
|
}*/
|
|
|
|
|
foreach ($array as $k => $v) {
|
|
|
|
|
if ($v["name"] == $shift && $pid == ($v["pid"] ?? -1)) {
|
|
|
|
|
$pid = $v["id"];
|
|
|
|
|
continue 2;
|
|
|
|
|
}
|
2020-03-02 16:14:20 +08:00
|
|
|
}
|
2020-03-05 12:03:14 +08:00
|
|
|
if (mb_substr($shift, 0, 1) == "{" && mb_substr($shift, -1, 1) == "}") {
|
|
|
|
|
foreach ($array as $k => $v) {
|
|
|
|
|
if ($pid == $v["id"]) {
|
|
|
|
|
$array[$k]["param_route"] = $uid;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$array[$uid++] = [
|
|
|
|
|
'id' => $uid - 1,
|
|
|
|
|
'pid' => $pid,
|
|
|
|
|
'name' => $shift
|
|
|
|
|
];
|
|
|
|
|
$pid = $uid - 1;
|
2020-03-02 16:14:20 +08:00
|
|
|
}
|
2020-03-05 12:03:14 +08:00
|
|
|
$array[$uid - 1]['method'] = $method->getName();
|
|
|
|
|
$array[$uid - 1]['class'] = $class->getName();
|
|
|
|
|
$array[$uid - 1]['request_method'] = $vss->request_method;
|
|
|
|
|
ZMBuf::$req_mapping = $array;
|
2020-03-02 16:14:20 +08:00
|
|
|
}
|
|
|
|
|
|
2020-03-25 18:35:16 +08:00
|
|
|
private static function loadAnnotationClasses() {
|
2020-03-02 16:14:20 +08:00
|
|
|
$class = getAllClasses(WORKING_DIR . "/src/ZM/Annotation/", "ZM\\Annotation");
|
|
|
|
|
foreach ($class as $v) {
|
|
|
|
|
$s = WORKING_DIR . '/src/' . str_replace("\\", "/", $v) . ".php";
|
|
|
|
|
require_once $s;
|
|
|
|
|
}
|
|
|
|
|
$class = getAllClasses(WORKING_DIR . "/src/Custom/Annotation/", "Custom\\Annotation");
|
|
|
|
|
foreach ($class as $v) {
|
|
|
|
|
$s = WORKING_DIR . '/src/' . str_replace("\\", "/", $v) . ".php";
|
|
|
|
|
require_once $s;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-03-05 12:03:14 +08:00
|
|
|
|
2020-03-25 18:35:16 +08:00
|
|
|
public static function genTree($items) {
|
2020-03-05 12:03:14 +08:00
|
|
|
$tree = array();
|
|
|
|
|
foreach ($items as $item)
|
|
|
|
|
if (isset($items[$item['pid']]))
|
|
|
|
|
$items[$item['pid']]['son'][] = &$items[$item['id']];
|
|
|
|
|
else
|
|
|
|
|
$tree[] = &$items[$item['id']];
|
|
|
|
|
return $tree;
|
|
|
|
|
}
|
2020-04-29 15:29:56 +08:00
|
|
|
|
|
|
|
|
private static function addTimerTick(?OnTick $vss) {
|
|
|
|
|
ZMBuf::set("timer_count", ZMBuf::get("timer_count", 0) + 1);
|
|
|
|
|
Timer::tick($vss->tick_ms, [ZMUtil::getModInstance($vss->class), $vss->method]);
|
|
|
|
|
}
|
2020-03-29 16:29:02 +08:00
|
|
|
}
|