From 4e43450c3470df1876c7ccfe30574c6819d7dccf Mon Sep 17 00:00:00 2001 From: whale Date: Thu, 5 Mar 2020 12:03:14 +0800 Subject: [PATCH] fix @Rule type annotation parse function error. fix @RequestMapping parse tree error. --- src/Framework/ZMBuf.php | 4 +- src/ZM/Annotation/AnnotationParser.php | 131 +++++++++++++----- src/ZM/Annotation/CQ/CQBefore.php | 2 +- src/ZM/Annotation/CQ/CQMetaEvent.php | 2 +- src/ZM/Annotation/CQ/CQNotice.php | 2 +- src/ZM/Annotation/CQ/CQRequest.php | 2 +- src/ZM/Annotation/MappingNode.php | 103 -------------- src/ZM/Annotation/Swoole/SwooleEventAfter.php | 6 +- src/ZM/Annotation/Swoole/SwooleEventAt.php | 6 +- src/ZM/Event/Swoole/RequestEvent.php | 108 +++++++++------ src/ZM/Event/Swoole/WorkerStartEvent.php | 2 - 11 files changed, 174 insertions(+), 194 deletions(-) delete mode 100644 src/ZM/Annotation/MappingNode.php diff --git a/src/Framework/ZMBuf.php b/src/Framework/ZMBuf.php index e60c840f..6cd6c95d 100755 --- a/src/Framework/ZMBuf.php +++ b/src/Framework/ZMBuf.php @@ -10,7 +10,6 @@ namespace Framework; use Swoole\Atomic; use swoole_atomic; -use ZM\Annotation\MappingNode; use ZM\connection\WSConnection; use ZM\Utils\Scheduler; use ZM\Utils\SQLPool; @@ -37,7 +36,7 @@ class ZMBuf // swoole server操作对象,每个进程均分配 /** @var swoole_websocket_server $server */ static $server; - /** @var MappingNode Http请求uri路径根节点 */ + /** @var array Http请求uri路径根节点 */ public static $req_mapping_node; /** @var mixed TimeNLP初始化后的对象,每个进程均可初始化 */ public static $time_nlp; @@ -52,6 +51,7 @@ class ZMBuf public static $events = []; /** @var Atomic[] */ public static $atomics; + public static $req_mapping = []; static function get($name, $default = null) { return self::$cache[$name] ?? $default; } diff --git a/src/ZM/Annotation/AnnotationParser.php b/src/ZM/Annotation/AnnotationParser.php index 428d6d17..850c0b8d 100644 --- a/src/ZM/Annotation/AnnotationParser.php +++ b/src/ZM/Annotation/AnnotationParser.php @@ -5,6 +5,7 @@ namespace ZM\Annotation; use Doctrine\Common\Annotations\AnnotationException; use Doctrine\Common\Annotations\AnnotationReader; +use Framework\Console; use Framework\ZMBuf; use ReflectionClass; use ReflectionException; @@ -29,9 +30,15 @@ class AnnotationParser * @throws ReflectionException * @throws AnnotationException */ - public static function registerMods() { + public static function registerMods() + { self::loadAnnotationClasses(); $all_class = getAllClasses(WORKING_DIR . "/src/Module/", "Module"); + ZMBuf::$req_mapping[0] = [ + 'id' => 0, + 'pid' => -1, + 'name' => '/' + ]; $reader = new AnnotationReader(); foreach ($all_class as $v) { $reflection_class = new ReflectionClass($v); @@ -53,21 +60,25 @@ class AnnotationParser if ($vss instanceof Rule) $vss = self::registerRuleEvent($vss, $vs, $reflection_class); else $vss = self::registerMethod($vss, $vs, $reflection_class); - 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; - elseif ($vss instanceof RequestMapping) self::registerRequestMapping($vss, $vs, $reflection_class, $class_prefix); - elseif ($vss instanceof CustomAnnotation) ZMBuf::$events[get_class($vss)][] = $vss; - elseif ($vss instanceof CQBefore) ZMBuf::$events[CQBefore::class][$vss->cq_event][] = $vss; - elseif ($vss instanceof CQAfter) ZMBuf::$events[CQAfter::class][$vss->cq_event][] = $vss; + 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; + elseif ($vss instanceof RequestMapping) self::registerRequestMapping($vss, $vs, $reflection_class, $class_prefix); + elseif ($vss instanceof CustomAnnotation) ZMBuf::$events[get_class($vss)][] = $vss; + elseif ($vss instanceof CQBefore) ZMBuf::$events[CQBefore::class][$vss->cq_event][] = $vss; + elseif ($vss instanceof CQAfter) ZMBuf::$events[CQAfter::class][$vss->cq_event][] = $vss; } } } + echo json_encode(ZMBuf::$req_mapping, 128 | 256); + $tree = self::genTree(ZMBuf::$req_mapping); + echo json_encode($tree, 128 | 256); + ZMBuf::$req_mapping = $tree[0]; //给支持level的排个序 foreach (ZMBuf::$events as $class_name => $v) { if ((new $class_name()) instanceof Level) { @@ -86,7 +97,8 @@ class AnnotationParser } } - private static function getRuleCallback($rule_str) { + private static function getRuleCallback($rule_str) + { $func = null; $rule = $rule_str; if ($rule != "") { @@ -142,15 +154,21 @@ class AnnotationParser }; break; case "dataEqual": //handle websocket message事件时才能用 - $func = function ($data) use ($rest) { return $data == $rest; }; + $func = function ($data) use ($rest) { + return $data == $rest; + }; break; } switch ($asp_name) { case "msgMatch": //handle cq message事件时才能用 - $func = function ($msg) use ($rest) { return matchPattern($rest, $msg); }; + $func = function ($msg) use ($rest) { + return matchPattern($rest, $msg); + }; break; case "msgEqual": //handle cq message事件时才能用 - $func = function ($msg) use ($rest) { return trim($msg) == $rest; }; + $func = function ($msg) use ($rest) { + return trim($msg) == $rest; + }; break; } @@ -158,20 +176,25 @@ class AnnotationParser return $func; } - private static function registerRuleEvent(?AnnotationBase $vss, ReflectionMethod $method, ReflectionClass $class) { + private static function registerRuleEvent(?AnnotationBase $vss, ReflectionMethod $method, ReflectionClass $class) + { $vss->callback = self::getRuleCallback($vss->getRule()); $vss->method = $method->getName(); $vss->class = $class->getName(); return $vss; } - private static function registerMethod(?AnnotationBase $vss, ReflectionMethod $method, ReflectionClass $class) { + private static function registerMethod(?AnnotationBase $vss, ReflectionMethod $method, ReflectionClass $class) + { $vss->method = $method->getName(); $vss->class = $class->getName(); return $vss; } - private static function registerRequestMapping(RequestMapping $vss, ReflectionMethod $method, ReflectionClass $class, string $prefix) { + private static function registerRequestMapping(RequestMapping $vss, ReflectionMethod $method, ReflectionClass $class, string $prefix) + { + $array = ZMBuf::$req_mapping; + $uid = count($array); $prefix_exp = explode("/", $prefix); $route_exp = explode("/", $vss->route); foreach ($prefix_exp as $k => $v) { @@ -184,31 +207,62 @@ class AnnotationParser unset($route_exp[$k]); } } - $a = ZMBuf::$req_mapping_node; - $p = $a; if ($prefix_exp == [] && $route_exp == []) { - $p->setMethod($method->getName()); - $p->setClass($class->getName()); - $p->setRequestMethod($vss->request_method); + $array[$uid - 1]['method'] = $method->getName(); + $array[$uid - 1]['class'] = $class->getName(); + $array[$uid - 1]['request_method'] = $vss->request_method; + ZMBuf::$req_mapping = $array; return; } + $pid = 0; while (($shift = array_shift($prefix_exp)) !== null) { - $p->addRoute($shift, new MappingNode($shift)); - $p = $p->getRoute($shift); + foreach ($array as $k => $v) { + if ($v["name"] == $shift && $pid == ($v["pid"] ?? -1)) { + $pid = $v["id"]; + continue 2; + } + } + Console::info('Adding prefix "' . $shift . "\", " . json_encode($array[$uid - 1])); + $array[$uid++] = [ + 'id' => $uid - 1, + 'pid' => $pid, + 'name' => $shift + ]; + $pid = $uid - 1; } while (($shift = array_shift($route_exp)) !== null) { - if (mb_substr($shift, 0, 1) == "{" && mb_substr($shift, -1, 1) == "}") { + /*if (mb_substr($shift, 0, 1) == "{" && mb_substr($shift, -1, 1) == "}") { $p->removeAllRoute(); + Console::info("移除本节点其他所有路由中"); + }*/ + foreach ($array as $k => $v) { + if ($v["name"] == $shift && $pid == ($v["pid"] ?? -1)) { + $pid = $v["id"]; + continue 2; + } } - $p->addRoute($shift, new MappingNode($shift)); - $p = $p->getRoute($shift); + 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; } - $p->setMethod($method->getName()); - $p->setClass($class->getName()); - $p->setRequestMethod($vss->request_method); + $array[$uid - 1]['method'] = $method->getName(); + $array[$uid - 1]['class'] = $class->getName(); + $array[$uid - 1]['request_method'] = $vss->request_method; + ZMBuf::$req_mapping = $array; } - private static function loadAnnotationClasses() { + private static function loadAnnotationClasses() + { $class = getAllClasses(WORKING_DIR . "/src/ZM/Annotation/", "ZM\\Annotation"); foreach ($class as $v) { $s = WORKING_DIR . '/src/' . str_replace("\\", "/", $v) . ".php"; @@ -220,4 +274,15 @@ class AnnotationParser require_once $s; } } + + public static function genTree($items) + { + $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; + } } \ No newline at end of file diff --git a/src/ZM/Annotation/CQ/CQBefore.php b/src/ZM/Annotation/CQ/CQBefore.php index d7ea4d91..fc0daf75 100644 --- a/src/ZM/Annotation/CQ/CQBefore.php +++ b/src/ZM/Annotation/CQ/CQBefore.php @@ -35,7 +35,7 @@ class CQBefore extends AnnotationBase implements Level /** * @param mixed $level */ - public function setLevel($level): void { + public function setLevel($level) { $this->level = $level; } diff --git a/src/ZM/Annotation/CQ/CQMetaEvent.php b/src/ZM/Annotation/CQ/CQMetaEvent.php index 000f922b..fb185ef5 100644 --- a/src/ZM/Annotation/CQ/CQMetaEvent.php +++ b/src/ZM/Annotation/CQ/CQMetaEvent.php @@ -34,7 +34,7 @@ class CQMetaEvent extends AnnotationBase implements Level /** * @param int $level */ - public function setLevel(int $level): void { + public function setLevel(int $level) { $this->level = $level; } } \ No newline at end of file diff --git a/src/ZM/Annotation/CQ/CQNotice.php b/src/ZM/Annotation/CQ/CQNotice.php index b24fcc88..9f8e582c 100644 --- a/src/ZM/Annotation/CQ/CQNotice.php +++ b/src/ZM/Annotation/CQ/CQNotice.php @@ -36,7 +36,7 @@ class CQNotice extends AnnotationBase implements Level /** * @param int $level */ - public function setLevel(int $level): void { + public function setLevel(int $level) { $this->level = $level; } } \ No newline at end of file diff --git a/src/ZM/Annotation/CQ/CQRequest.php b/src/ZM/Annotation/CQ/CQRequest.php index bdf6cd91..a2a7cee7 100644 --- a/src/ZM/Annotation/CQ/CQRequest.php +++ b/src/ZM/Annotation/CQ/CQRequest.php @@ -36,7 +36,7 @@ class CQRequest extends AnnotationBase implements Level /** * @param int $level */ - public function setLevel(int $level): void { + public function setLevel(int $level) { $this->level = $level; } } \ No newline at end of file diff --git a/src/ZM/Annotation/MappingNode.php b/src/ZM/Annotation/MappingNode.php deleted file mode 100644 index f93a52df..00000000 --- a/src/ZM/Annotation/MappingNode.php +++ /dev/null @@ -1,103 +0,0 @@ -node = $node_name; } - - public function addRoute(string $route_name, MappingNode $route_node) { $this->route[$route_name] = $route_node; } - - /** - * @param string $shift - * @return MappingNode|null - */ - public function getRoute(string $shift) { - return $this->route[$shift] ?? null; - } - - public function getRealRoute(string $shift, array &$bind_params) { - if (mb_substr(key($this->route), 0, 1) == "{" && mb_substr(key($this->route), -1, 1) == "}") { - $param_name = mb_substr(current($this->route)->getNodeName(), 1, -1); - $bind_params[$param_name] = $shift; - return current($this->route); - } else return $this->route[$shift] ?? null; - } - - public function setMethod($method) { $this->method = $method; } - - public function setClass($class) { $this->class = $class; } - - public function setRequestMethod($method) { - if (is_string($method)) $this->request_method = [$method]; - else $this->request_method = $method; - } - - public function getNodeName() { return $this->node; } - - public function getRule() { return $this->rule; } - - public function setRule(Closure $rule): void { $this->rule = $rule; } - - public function removeAllRoute() { $this->route = []; } - - /** - * @return null - */ - public function getMethod() { - return $this->method; - } - - /** - * @return array - */ - public function getRequestMethod(): array { - return $this->request_method; - } - - /** - * @return null - */ - public function getClass() { - return $this->class; - } - - /** - * @return string - */ - public function getNode(): string { - return $this->node; - } - - public function __toString() { - $str = "[" . $this->node . "] => "; - if ($this->class != "" && $this->class != null) - $str .= "\n\t" . $this->class . "->" . $this->method . ": " . implode(", ", $this->request_method); - $str .= "\n\t[Route] => ["; - foreach ($this->route as $k => $v) { - $r = $v; - $r = explode("\n", $r); - foreach ($r as $ks => $vs) { - $r[$ks] = "\t" . $r[$ks]; - } - $r = implode("\n", $r); - $str .= "\n\t" . $r; - } - $str .= "\n]"; - return $str; - } -} \ No newline at end of file diff --git a/src/ZM/Annotation/Swoole/SwooleEventAfter.php b/src/ZM/Annotation/Swoole/SwooleEventAfter.php index fe3d341b..6626a69e 100644 --- a/src/ZM/Annotation/Swoole/SwooleEventAfter.php +++ b/src/ZM/Annotation/Swoole/SwooleEventAfter.php @@ -40,7 +40,7 @@ class SwooleEventAfter extends AnnotationBase implements Rule, Level /** * @param string $type */ - public function setType(string $type): void { + public function setType(string $type) { $this->type = $type; } @@ -54,7 +54,7 @@ class SwooleEventAfter extends AnnotationBase implements Rule, Level /** * @param string $rule */ - public function setRule(string $rule): void { + public function setRule(string $rule) { $this->rule = $rule; } @@ -68,7 +68,7 @@ class SwooleEventAfter extends AnnotationBase implements Rule, Level /** * @param int $level */ - public function setLevel(int $level): void { + public function setLevel(int $level) { $this->level = $level; } diff --git a/src/ZM/Annotation/Swoole/SwooleEventAt.php b/src/ZM/Annotation/Swoole/SwooleEventAt.php index 7f91df13..1b09baa4 100644 --- a/src/ZM/Annotation/Swoole/SwooleEventAt.php +++ b/src/ZM/Annotation/Swoole/SwooleEventAt.php @@ -41,7 +41,7 @@ class SwooleEventAt extends AnnotationBase implements Rule, Level /** * @param string $type */ - public function setType(string $type): void { + public function setType(string $type) { $this->type = $type; } @@ -55,7 +55,7 @@ class SwooleEventAt extends AnnotationBase implements Rule, Level /** * @param string $rule */ - public function setRule(string $rule): void { + public function setRule(string $rule) { $this->rule = $rule; } @@ -69,7 +69,7 @@ class SwooleEventAt extends AnnotationBase implements Rule, Level /** * @param int $level */ - public function setLevel(int $level): void { + public function setLevel(int $level) { $this->level = $level; } diff --git a/src/ZM/Event/Swoole/RequestEvent.php b/src/ZM/Event/Swoole/RequestEvent.php index b91eb3d2..dd18b514 100644 --- a/src/ZM/Event/Swoole/RequestEvent.php +++ b/src/ZM/Event/Swoole/RequestEvent.php @@ -25,7 +25,8 @@ class RequestEvent implements SwooleEvent */ private $response; - public function __construct(Request $request, Response $response) { + public function __construct(Request $request, Response $response) + { $this->request = $request; $this->response = $response; } @@ -33,60 +34,76 @@ class RequestEvent implements SwooleEvent /** * @inheritDoc */ - public function onActivate() { + public function onActivate() + { ZMUtil::checkWait(); foreach (ZMBuf::globals("http_header") as $k => $v) { $this->response->setHeader($k, $v); } $uri = $this->request->server["request_uri"]; - if ($uri != "/") { - $uri = explode("/", $uri); - $uri = array_diff($uri, ["..", "", "."]); - $node = ZMBuf::$req_mapping_node; - $params = []; - while (true) { - $r = array_shift($uri); - if ($r === null) break; - if (($node2 = $node->getRealRoute($r, $params)) !== null) { - $node = $node2; + $uri = explode("/", $uri); + $uri = array_diff($uri, ["..", "", "."]); + $node = ZMBuf::$req_mapping; + $params = []; + while (true) { + $r = array_shift($uri); + if ($r === null) break; + if (($cnt = count($node["son"])) == 1) { + if (isset($node["param_route"])) { + foreach ($node["son"] as $k => $v) { + if ($v["id"] == $node["param_route"]) { + $node = $v; + $params[mb_substr($v["name"], 1, -1)] = $r; + continue 2; + } + } + } elseif ($node["son"][0]["name"] == $r) { + $node = $node["son"][0]; continue; } else { $this->responseStatus(404); return $this; } - } - if ($node->getRule() === null || call_user_func($node->getRule(), $this->request) === true) { //判断规则是否存在,如果有规则则走一遍规则 - if (in_array(strtoupper($this->request->server["request_method"]), $node->getRequestMethod())) { //判断目标方法在不在里面 - $c_name = $node->getClass(); - /** @var ModBase $class */ - $class = new $c_name(["request" => $this->request, "response" => $this->response, "params" => $params], ModHandleType::SWOOLE_REQUEST); - $r = call_user_func_array([$class, $node->getMethod()], [$params]); - if (is_string($r) && !$this->response->isEnd()) $this->response->end($r); - if ($class->block_continue) return $this; - if ($this->response->isEnd()) return $this; + } elseif ($cnt >= 1) { + if (isset($node["param_route"])) { + foreach ($node["son"] as $k => $v) { + if ($v["id"] == $node["param_route"]) { + $node = $v; + $params[mb_substr($v["name"], 1, -1)] = $r; + continue 2; + } + } + } + foreach ($node["son"] as $k => $v) { + if ($v["name"] == $r) { + $node = $v; + continue 2; + } } } - } else { - if (($node = ZMBuf::$req_mapping_node)->getMethod() !== null) { - if (in_array(strtoupper($this->request->server["request_method"]), $node->getRequestMethod())) { //判断目标方法在不在里面 - $c_name = $node->getClass(); - /** @var ModBase $class */ - $class = new $c_name(["request" => $this->request, "response" => $this->response], ModHandleType::SWOOLE_REQUEST); - $r = call_user_func_array([$class, $node->getMethod()], []); - if (is_string($r) && !$this->response->isEnd()) $this->response->end($r); - if ($class->block_continue) return $this; - if ($this->response->isEnd()) return $this; - } - } - foreach (ZMBuf::$events[SwooleEventAt::class] ?? [] as $v) { - if (strtolower($v->type) == "request" && $this->parseSwooleRule($v)) { - $c = $v->class; - $class = new $c(["request" => $this->request, "response" => $this->response]); - $r = call_user_func_array([$class, $v->method], []); - if ($class->block_continue) break; - } + $this->responseStatus(404); + return $this; + } + + if (in_array(strtoupper($this->request->server["request_method"]), $node["request_method"] ?? [])) { //判断目标方法在不在里面 + $c_name = $node["class"]; + /** @var ModBase $class */ + $class = new $c_name(["request" => $this->request, "response" => $this->response, "params" => $params], ModHandleType::SWOOLE_REQUEST); + $r = call_user_func_array([$class, $node["method"]], [$params]); + if (is_string($r) && !$this->response->isEnd()) $this->response->end($r); + if ($class->block_continue) return $this; + if ($this->response->isEnd()) return $this; + } + + foreach (ZMBuf::$events[SwooleEventAt::class] ?? [] as $v) { + if (strtolower($v->type) == "request" && $this->parseSwooleRule($v)) { + $c = $v->class; + $class = new $c(["request" => $this->request, "response" => $this->response]); + $r = call_user_func_array([$class, $v->method], []); + if ($class->block_continue) break; } } + if (!$this->response->isEnd()) { $this->response->status(404); $this->response->end(ZMUtil::getHttpCodePage(404)); @@ -97,7 +114,8 @@ class RequestEvent implements SwooleEvent /** * @inheritDoc */ - public function onAfter() { + public function onAfter() + { foreach (ZMBuf::$events[SwooleEventAfter::class] ?? [] as $v) { if (strtolower($v->type) == "request" && $this->parseSwooleRule($v)) { $c = $v->class; @@ -109,12 +127,14 @@ class RequestEvent implements SwooleEvent return $this; } - private function responseStatus(int $int) { + private function responseStatus(int $int) + { $this->response->status($int); $this->response->end(); } - private function parseSwooleRule($v) { + private function parseSwooleRule($v) + { switch ($v->rule) { case "containsGet": case "containsPost": diff --git a/src/ZM/Event/Swoole/WorkerStartEvent.php b/src/ZM/Event/Swoole/WorkerStartEvent.php index 01736459..942ed0a4 100644 --- a/src/ZM/Event/Swoole/WorkerStartEvent.php +++ b/src/ZM/Event/Swoole/WorkerStartEvent.php @@ -10,7 +10,6 @@ use Swoole\Coroutine; use Swoole\Timer; use ZM\Annotation\AnnotationBase; use ZM\Annotation\AnnotationParser; -use ZM\Annotation\MappingNode; use ZM\Annotation\Swoole\SwooleEventAfter; use ZM\Connection\ConnectionManager; use ZM\DB\DB; @@ -58,7 +57,6 @@ class WorkerStartEvent implements SwooleEvent } ZMBuf::$server = $this->server; ZMBuf::$atomics['reload_time']->add(1); - ZMBuf::$req_mapping_node = new MappingNode("/"); Console::info("监听console输入"); Console::listenConsole(); //这个方法只能在这里调用,且如果worker_num不为1的话,此功能不可用