From 8b583f2a4de47a7e40bd5fa042fed8eea6986961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mr=C2=B7x?= Date: Mon, 31 Aug 2020 22:33:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- http-server/Abstracts/MiddlewareHandler.php | 15 -- .../{IMiddleware.php => Middleware.php} | 2 +- http-server/Route/Annotation/Annotation.php | 53 ++++++ http-server/Route/CoreMiddleware.php | 12 +- http-server/Route/Dispatch/Dispatch.php | 8 +- http-server/Route/Middleware.php | 3 +- http-server/Route/Node.php | 14 +- http-server/Route/Router.php | 13 ++ http-server/config.php | 16 +- system/Abstracts/BaseAnnotation.php | 109 +++++++++++- system/Annotation/Annotation.php | 157 ++++++++++++++---- system/Annotation/Definition/Http.php | 85 ++++++++++ system/Annotation/Definition/Websocket.php | 50 ++---- system/Di/Container.php | 15 ++ 14 files changed, 450 insertions(+), 102 deletions(-) delete mode 100644 http-server/Abstracts/MiddlewareHandler.php rename http-server/IInterface/{IMiddleware.php => Middleware.php} (90%) create mode 100644 http-server/Route/Annotation/Annotation.php create mode 100644 system/Annotation/Definition/Http.php diff --git a/http-server/Abstracts/MiddlewareHandler.php b/http-server/Abstracts/MiddlewareHandler.php deleted file mode 100644 index f2beaeba..00000000 --- a/http-server/Abstracts/MiddlewareHandler.php +++ /dev/null @@ -1,15 +0,0 @@ -headers; diff --git a/http-server/Route/Dispatch/Dispatch.php b/http-server/Route/Dispatch/Dispatch.php index 4bcb29f9..d4654085 100644 --- a/http-server/Route/Dispatch/Dispatch.php +++ b/http-server/Route/Dispatch/Dispatch.php @@ -61,12 +61,10 @@ class Dispatch */ protected function bindParam() { - /** @var Controller $controller */ - if (is_array($this->handler)) { - $controller = $this->handler[0]; - } else { - $controller = $this->handler; + if ($this->handler instanceof \Closure) { + return; } + $controller = $this->handler[0]; $controller->request = Context::getContext('request'); $controller->headers = $controller->request->headers; $controller->input = $controller->request->params; diff --git a/http-server/Route/Middleware.php b/http-server/Route/Middleware.php index 207c0f80..8cae7325 100644 --- a/http-server/Route/Middleware.php +++ b/http-server/Route/Middleware.php @@ -10,7 +10,6 @@ namespace HttpServer\Route; use Closure; use Exception; -use HttpServer\IInterface\IMiddleware; use HttpServer\Route\Dispatch\Dispatch; /** @@ -65,7 +64,7 @@ class Middleware { return function ($stack, $pipe) { return function ($passable) use ($stack, $pipe) { - if ($pipe instanceof IMiddleware) { + if ($pipe instanceof \HttpServer\IInterface\Middleware) { return $pipe->handler($passable, $stack); } else { return $pipe($passable, $stack); diff --git a/http-server/Route/Node.php b/http-server/Route/Node.php index 1dd98a66..4e5ef828 100644 --- a/http-server/Route/Node.php +++ b/http-server/Route/Node.php @@ -7,6 +7,7 @@ namespace HttpServer\Route; use HttpServer\Http\Request; use Exception; use HttpServer\Application; +use HttpServer\Route\Annotation\Annotation; use Snowflake\Snowflake; /** @@ -36,6 +37,8 @@ class Node extends Application public $middleware = []; public $callback = []; + private $_interceptors = []; + /** * @param $handler * @return Node @@ -118,7 +121,7 @@ class Node extends Application private function getReflect(string $controller, string $action) { try { - $reflect = new \ReflectionClass($controller); + $reflect = Snowflake::getDi()->getReflect($controller); if (!$reflect->isInstantiable()) { throw new Exception($controller . ' Class is con\'t Instantiable.'); } @@ -126,6 +129,15 @@ class Node extends Application if (!empty($action) && !$reflect->hasMethod($action)) { throw new Exception('method ' . $action . ' not exists at ' . $controller . '.'); } + + /** @var Annotation $annotation */ + $annotation = Snowflake::createObject(Annotation::class); + if (!empty($methods)) { + $annotations = $annotation->instance($reflect); + if (isset($annotations['Interceptor'])) { + } + + } return [$reflect->newInstance(), $action]; } catch (Exception $exception) { $this->_error = $exception->getMessage(); diff --git a/http-server/Route/Router.php b/http-server/Route/Router.php index 9d921a63..f40ad38b 100644 --- a/http-server/Route/Router.php +++ b/http-server/Route/Router.php @@ -9,9 +9,12 @@ use HttpServer\Http\Context; use HttpServer\Controller; use HttpServer\IInterface\RouterInterface; use HttpServer\Application; +use HttpServer\Route\Annotation\Annotation; +use ReflectionException; use Snowflake\Config; use Snowflake\Core\JSON; use Snowflake\Exception\ConfigException; +use Snowflake\Exception\NotFindClassException; use Snowflake\Snowflake; /** @@ -498,10 +501,20 @@ class Router extends Application implements RouterInterface /** * @param $file + * @throws ReflectionException + * @throws NotFindClassException */ private function loadFile($file) { $router = $this; + + $prefix = APP_PATH . 'app/Http/'; + + /** @var Annotation $annotation */ + $annotation = Snowflake::createObject(Annotation::class); + $annotation->registration_notes($prefix . 'Interceptor', 'App\Http\Interceptor'); + $annotation->registration_notes($prefix . 'Limits', 'App\Http\Limits'); + include_once "$file"; } diff --git a/http-server/config.php b/http-server/config.php index 831d257f..0a06fe8b 100644 --- a/http-server/config.php +++ b/http-server/config.php @@ -93,10 +93,9 @@ return [ ], 'events' => [ Event::SERVER_WORKER_START => function () { + $path = APP_PATH . 'app/Websocket'; $websocket = Snowflake::get()->annotation->websocket; -// $websocket->path = $this->socketControllers; - $websocket->namespace = 'App\\Sockets\\'; - $websocket->registration_notes(); + $websocket->registration_notes($path, 'App\\Sockets\\'); }, Event::SERVER_HANDSHAKE => function (Request $request, Response $response) { $this->error($request->fd . ' connect.'); @@ -105,8 +104,15 @@ return [ }, Event::SERVER_MESSAGE => function (\Swoole\WebSocket\Server $server, Frame $frame) { $this->error('websocket SERVER_MESSAGE.'); - - return $server->push($frame->fd, 'hello word~'); + if (is_null($json = json_decode($frame->data, true))) { + return $server->push($frame->fd, 'format error~'); + } + $websocket = Snowflake::get()->annotation->websocket; + if ($websocket->has($json['path'])) { + return $websocket->runWith($json['path'], [$frame->fd, $json]); + } else { + return $server->push($frame->fd, 'hello word~'); + } }, Event::SERVER_CLOSE => function (int $fd) { $this->error($fd . ' disconnect.'); diff --git a/system/Abstracts/BaseAnnotation.php b/system/Abstracts/BaseAnnotation.php index b2d14897..0aa926e1 100644 --- a/system/Abstracts/BaseAnnotation.php +++ b/system/Abstracts/BaseAnnotation.php @@ -4,6 +4,12 @@ namespace Snowflake\Abstracts; +use Exception; +use ReflectionClass; +use ReflectionException; +use ReflectionMethod; +use Snowflake\Exception\NotFindClassException; +use Snowflake\Snowflake; /** * Class BaseAnnotation @@ -12,9 +18,108 @@ namespace Snowflake\Abstracts; abstract class BaseAnnotation extends Component { - public function each() - { + /** + * @param ReflectionClass $reflect + * @return array + */ + protected function getPrivates(ReflectionClass $reflect) + { + $arrays = []; + $properties = $reflect->getProperties(ReflectionMethod::IS_PRIVATE); + foreach ($properties as $property) { + $arrays[] = $property->getName(); + } + return $arrays; } + + /** + * @param ReflectionClass $reflect + * @param array $rules + * @return array + * @throws Exception + */ + public function instance($reflect, $rules = []) + { + $annotations = $this->getPrivates($reflect); + + $classMethods = $reflect->getMethods(ReflectionMethod::IS_PUBLIC); + if (!$reflect->isInstantiable()) { + throw new Exception('Class ' . $reflect->getName() . ' cannot be instantiated.'); + } + + $object = $reflect->newInstance(); + + $array = []; + foreach ($classMethods as $classMethod) { + $array = $this->resolveDocComment($classMethod, $object, $annotations, $array); + } + return $array; + } + + + /** + * @param ReflectionMethod $function + * @param $object + * @param $annotations + * @param $array + * @return array + * @throws + */ + protected function resolveDocComment($function, $object, $annotations, $array) + { + $comment = $function->getDocComment(); + foreach ($annotations as $annotation) { + preg_match('/@(' . $annotation . ')\((.*?)\)/', $comment, $events); + if (!isset($events[1])) { + continue; + } + if (!($_key = $this->getName($function, $events))) { + continue; + } + if (isset($events[2])) { + $handler = Snowflake::createObject($events[2]); + } else { + $handler = [$object, $events[1]]; + } + if (!isset($array[$annotation])) { + $array[$annotation] = []; + } + $array[$annotation][] = [$_key, $handler]; + } + return $array; + } + + + /** + * @param $rule + * @param $content + * @param $rules + * @return bool + * @throws ReflectionException + * @throws NotFindClassException + * @throws Exception + */ + public function check($rule, $content, $rules) + { + if (empty($rule)) { + return true; + } + $explode = explode('|', $rule); + foreach ($explode as $value) { + $reflect = array_merge($rules[$value], [ + 'value' => $content + ]); + $validator = Snowflake::createObject($reflect); + if (!$validator->check()) { + throw new Exception($validator->getMessage()); + } + } + return false; + } + + + abstract public function runWith($path); + } diff --git a/system/Annotation/Annotation.php b/system/Annotation/Annotation.php index 8988dd04..fa75f10b 100644 --- a/system/Annotation/Annotation.php +++ b/system/Annotation/Annotation.php @@ -6,19 +6,24 @@ namespace Snowflake\Annotation; use Exception; use ReflectionClass; use ReflectionException; +use ReflectionMethod; use Snowflake\Abstracts\BaseAnnotation; use Snowflake\Exception\NotFindClassException; use Snowflake\Snowflake; +use validator\RequiredValidator; +use validator\RequiredValidator as NotEmptyValidator; /** * Class Annotation * @package Snowflake\Snowflake\Annotation * @property Websocket $websocket + * @property Http $http */ class Annotation extends BaseAnnotation { protected $_Scan_directory = []; + protected $params = []; public $namespace = ''; @@ -27,8 +32,19 @@ class Annotation extends BaseAnnotation public $path = ''; + private $rules = [ + 'required' => [ + 'class' => RequiredValidator::class + ], + 'not empty' => [ + 'class' => NotEmptyValidator::class + ] + ]; + + private $_classMap = [ - 'websocket' => Websocket::class + 'websocket' => Websocket::class, + 'http' => Http::class ]; @@ -43,59 +59,126 @@ class Annotation extends BaseAnnotation /** + * @param $path + * @param $namespace * @throws ReflectionException */ - public function registration_notes() + public function registration_notes($path, $namespace) { - if (!is_array($this->path)) { - return; - } - foreach ($this->path as $item) { - $this->scanning($item); + foreach ($path as $item) { + $this->scanning($item, $namespace); } } + + /** + * @return string + * @throws + */ + public function getHttp() + { + return Snowflake::createObject($this->_classMap['http']); + } + + + /** + * @return string + * @throws + */ + public function getWebsocket() + { + return Snowflake::createObject($this->_classMap['websocket']); + } + + /** + * @param ReflectionClass $reflect + * @Message(updatePosition) + * @throws Exception + */ + public function resolve(ReflectionClass $reflect) + { + $controller = $reflect->newInstance(); + + $methods = $this->getPrivates($reflect); + + foreach ($methods as $function) { + $comment = $function->getDocComment(); + $methodName = $function->getName(); + + preg_match('/@(' . $function . ')\((.*?)\)/', $comment, $events); + if (!isset($events[1])) { + continue; + } + if (!$this->isLegitimate($events)) { + continue; + } + $_key = $this->getName($function, $events); + if (empty($events[2])) { + $this->push($_key, [$controller, $methodName]); + } else { + $handler = $this->createHandler($controller, $methodName, $events[2]); + + $this->push($_key, $handler, [request(), [$controller, $methodName]]); + } + } + } + + + /** + * @param $events + * @throws Exception + */ + public function isLegitimate($events) + { + throw new Exception('Undefined analytic function.'); + } + + + /** + * @param $function + * @param $events + * @throws Exception + */ + public function getName($function, $events) + { + throw new Exception('Undefined analytic function.'); + } + + + /** + * @param $controller + * @param $methodName + * @param $events + * @throws Exception + */ + public function createHandler($controller, $methodName, $events) + { + throw new Exception('Undefined analytic function.'); + } + + /** * @param string $path + * @param $namespace * @throws ReflectionException * @throws Exception */ - protected function scanning($path = '') + protected function scanning($path, $namespace) { - if (empty($path)) { - $path = rtrim($this->path, '/'); - } + $di = Snowflake::getDi(); foreach (glob($path . '/*') as $file) { if (is_dir($file)) { - $this->scanning($path); + $this->scanning($path, $namespace); } $explode = explode('/', $file); $class = str_replace('.php', '', end($explode)); - $reflect = new ReflectionClass($this->namespace . $class); - - $methods = $reflect->getMethods(\ReflectionMethod::IS_PUBLIC); - if (empty($methods) || !$reflect->isInstantiable()) { - continue; - } - $this->resolve($reflect, $methods); + $this->resolve($di->getReflect($namespace . '\\' . $class)); } } - - /** - * @param ReflectionClass $class - * @param array $methods - * @throws Exception - */ - public function resolve(ReflectionClass $class, array $methods) - { - throw new Exception('Undefined analytic function.'); - } - - /** * @param $path * @param mixed ...$param @@ -106,17 +189,25 @@ class Annotation extends BaseAnnotation if (!$this->has($path)) { return null; } - return call_user_func($this->_Scan_directory[$path], ...$param); + $callback = $this->_Scan_directory[$path]; + if (!isset($this->params[$path])) { + return $callback(...$param); + } + return $callback(...$this->params[$path]); } /** * @param $name * @param $callback + * @param array $params */ - public function push($name, $callback) + public function push($name, $callback, $params = []) { $this->_Scan_directory[$name] = $callback; + if (!empty($params)) { + $this->params[$name] = $params; + } } diff --git a/system/Annotation/Definition/Http.php b/system/Annotation/Definition/Http.php new file mode 100644 index 00000000..ac21ba11 --- /dev/null +++ b/system/Annotation/Definition/Http.php @@ -0,0 +1,85 @@ +getReflect($namespace); + + $object = $class->newInstance(); + + + $method = $class->getMethod('Interceptor'); + + + return [$object, 'Interceptor']; + } + + + /** + * @param $controller + * @param $methodName + * @param $handler + * @return array + * @throws ReflectionException + */ + public function createInterceptor($controller, $methodName, $handler) + { + $namespace = 'App\Interceptor\\' . $handler; + $class = Snowflake::getDi()->getReflect($namespace); + + $object = $class->newInstance(); + + return [$object, 'Interceptor', [request(), [$controller, $methodName]]]; + } + + + /** + * @param $name + * @param $events + * @return false|string + */ + public function getName($name, $events) + { + return self::HTTP_EVENT . $name . ':' . $events[1]; + } + +} diff --git a/system/Annotation/Definition/Websocket.php b/system/Annotation/Definition/Websocket.php index 68521ec9..8be0f31c 100644 --- a/system/Annotation/Definition/Websocket.php +++ b/system/Annotation/Definition/Websocket.php @@ -12,55 +12,41 @@ use ReflectionClass; class Websocket extends Annotation { - const MESSAGE = 'WEBSOCKET:MESSAGE:'; - const EVENT = 'WEBSOCKET:EVENT:'; + const WEBSOCKET_ANNOTATION = 'WEBSOCKET:ANNOTATION:'; - public $Message; + private $Message = 'required|not empty'; - public $Event; + private $Handshake; + + + private $Close; /** - * @param ReflectionClass $reflect - * @param array $methods + * @param $controller + * @param $methodName + * @param $events + * @return array */ - public function resolve(ReflectionClass $reflect, array $methods) + public function createHandler($controller, $methodName, $events) { - $controller = $reflect->newInstance(); - - foreach ($methods as $function) { - $comment = $function->getDocComment(); - $methodName = $function->getName(); - - preg_match('/@Event\((.*)?\)/', $comment, $events); - if (!isset($events[1])) { - continue; - } - - if (!($_key = $this->getName($events, $comment))) { - continue; - } - $this->push($_key, [$controller, $methodName]); - } + return [$controller, $methodName]; } + /** * @param $events * @param $comment * @return false|string */ - private function getName($events, $comment) + public function getName($events, $comment) { - $event = $events[1]; - if ($event !== 'message') { - return self::EVENT . $event; + $prefix = self::WEBSOCKET_ANNOTATION . $events; + if (isset($comment[2])) { + return $prefix . ':' . $comment[2]; } - preg_match('/@Message\((.*)?\)/', $comment, $message); - if (isset($message[1])) { - return false; - } - return self::MESSAGE . $message[1]; + return $prefix; } } diff --git a/system/Di/Container.php b/system/Di/Container.php index 0907453c..5e72e0a3 100644 --- a/system/Di/Container.php +++ b/system/Di/Container.php @@ -182,6 +182,21 @@ class Container extends BaseObject return [$reflection, $dependencies]; } + + /** + * @param $class + * @return mixed + * @throws ReflectionException + */ + public function getReflect($class): ReflectionClass + { + if (!isset($this->_reflection[$class])) { + $this->resolveDependencies($class); + } + return $this->_reflection[$class]; + } + + /** * @param $class */