改名
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Route\Annotation;
|
||||
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
use Snowflake\Abstracts\BaseAnnotation;
|
||||
use Snowflake\Snowflake;
|
||||
|
||||
/**
|
||||
* Class Annotation
|
||||
*/
|
||||
class Annotation extends \Snowflake\Annotation\Annotation
|
||||
{
|
||||
|
||||
const HTTP_EVENT = 'http:event:';
|
||||
const CLOSE = 'Close';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @Interceptor(LoginInterceptor)
|
||||
*/
|
||||
private $Interceptor = 'required|not empty';
|
||||
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $Limits = 'required|not empty';
|
||||
|
||||
protected $_annotations = [];
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $reflect
|
||||
* @param $method
|
||||
* @param $annotations
|
||||
* @return mixed|null
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function read($reflect, $method, $annotations)
|
||||
{
|
||||
$method = $reflect->getMethod($method);
|
||||
|
||||
$_annotations = $this->getDocCommentAnnotation($annotations, $method->getDocComment());
|
||||
|
||||
$array = [];
|
||||
foreach ($_annotations as $keyName => $annotation) {
|
||||
if (!in_array($keyName, $annotations)) {
|
||||
continue;
|
||||
}
|
||||
$array[$keyName] = $this->pop($this->getName(...$annotation));
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $controller
|
||||
* @param $methodName
|
||||
* @param $events
|
||||
* @return array|void
|
||||
* @throws
|
||||
*/
|
||||
public function createHandler($controller, $methodName, $events)
|
||||
{
|
||||
return Snowflake::createObject($events[2]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param $events
|
||||
* @return bool
|
||||
*/
|
||||
public function isLegitimate($events)
|
||||
{
|
||||
return isset($events[2]) && !empty($events[2]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $events
|
||||
* @return false|string
|
||||
*/
|
||||
public function getName($name, $events)
|
||||
{
|
||||
return self::HTTP_EVENT . $name . ':' . $events[2];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Route\Annotation;
|
||||
|
||||
|
||||
use Snowflake\Annotation\Annotation;
|
||||
|
||||
/**
|
||||
* Class Tcp
|
||||
* @package HttpServer\Route\Annotation
|
||||
*/
|
||||
class Tcp extends Annotation
|
||||
{
|
||||
|
||||
|
||||
const CONNECT = 'Connect';
|
||||
const PACKET = 'Packet';
|
||||
const RECEIVE = 'Receive';
|
||||
const CLOSE = 'Close';
|
||||
|
||||
private $Message = 'required|not empty';
|
||||
|
||||
|
||||
private $Handshake;
|
||||
|
||||
|
||||
private $Close;
|
||||
|
||||
|
||||
/**
|
||||
* @param $controller
|
||||
* @param $methodName
|
||||
* @param $events
|
||||
* @return array
|
||||
*/
|
||||
public function createHandler($controller, $methodName, $events)
|
||||
{
|
||||
return [$controller, $methodName];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $events
|
||||
* @return bool|void
|
||||
*/
|
||||
public function isLegitimate($events)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $events
|
||||
* @param $comment
|
||||
* @return false|string
|
||||
*/
|
||||
public function getName($events, $comment = [])
|
||||
{
|
||||
$prefix = 'TCP:ANNOTATION:' . ltrim($events, ':');
|
||||
if (isset($comment[2]) && !empty($comment[2])) {
|
||||
return $prefix . ':' . $comment[2];
|
||||
}
|
||||
return $prefix;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace HttpServer\Route\Annotation;
|
||||
|
||||
|
||||
use Snowflake\Annotation\Annotation;
|
||||
|
||||
/**
|
||||
* Class Websocket
|
||||
* @package Snowflake\Annotation
|
||||
*/
|
||||
class Websocket extends Annotation
|
||||
{
|
||||
|
||||
const MESSAGE = 'Message';
|
||||
const HANDSHAKE = 'Handshake';
|
||||
const CLOSE = 'Close';
|
||||
|
||||
private $Message = 'required|not empty';
|
||||
|
||||
|
||||
private $Handshake;
|
||||
|
||||
|
||||
private $Close;
|
||||
|
||||
|
||||
/**
|
||||
* @param $controller
|
||||
* @param $methodName
|
||||
* @param $events
|
||||
* @return array
|
||||
*/
|
||||
public function createHandler($controller, $methodName, $events)
|
||||
{
|
||||
return [$controller, $methodName];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $events
|
||||
* @return bool|void
|
||||
*/
|
||||
public function isLegitimate($events)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $events
|
||||
* @param $comment
|
||||
* @return false|string
|
||||
*/
|
||||
public function getName($events, $comment = [])
|
||||
{
|
||||
$prefix = 'WEBSOCKET:ANNOTATION:' . ltrim($events, ':');
|
||||
if (isset($comment[2]) && !empty($comment[2])) {
|
||||
return $prefix . ':' . $comment[2];
|
||||
}
|
||||
return $prefix;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Route;
|
||||
|
||||
|
||||
/**
|
||||
* Class Any
|
||||
* @package Snowflake\Snowflake\Route
|
||||
*/
|
||||
class Any
|
||||
{
|
||||
|
||||
private $nodes = [];
|
||||
|
||||
/**
|
||||
* Any constructor.
|
||||
* @param array $nodes
|
||||
*/
|
||||
public function __construct(array $nodes)
|
||||
{
|
||||
$this->nodes = $nodes;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $arguments
|
||||
* @return $this
|
||||
*/
|
||||
public function __call($name, $arguments)
|
||||
{
|
||||
foreach ($this->nodes as $node) {
|
||||
$node->{$name}(...$arguments);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Route;
|
||||
|
||||
|
||||
use Closure;
|
||||
use Exception;
|
||||
use HttpServer\Http\Context;
|
||||
use HttpServer\Http\Request;
|
||||
use HttpServer\Http\Response;
|
||||
|
||||
/**
|
||||
* Class CoreMiddleware
|
||||
* @package Snowflake\Snowflake\Route
|
||||
* 跨域中间件
|
||||
*/
|
||||
class CoreMiddleware implements \HttpServer\IInterface\Middleware
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Closure $next
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function handler(Request $request, Closure $next)
|
||||
{
|
||||
$header = $request->headers;
|
||||
|
||||
/** @var Response $response */
|
||||
$response = Context::getContext('response');
|
||||
$request_method = $header->getHeader('access-control-request-method');
|
||||
$request_headers = $header->getHeader('access-control-request-headers');
|
||||
$response->addHeader('Access-Control-Allow-Headers', $request_headers);
|
||||
$response->addHeader('Access-Control-Request-Method', $request_method);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Route\Dispatch;
|
||||
|
||||
|
||||
use HttpServer\Controller;
|
||||
use HttpServer\Http\Context;
|
||||
use Snowflake\Snowflake;
|
||||
|
||||
/**
|
||||
* Class Dispatch
|
||||
* @package HttpServer\Route\Dispatch
|
||||
*/
|
||||
class Dispatch
|
||||
{
|
||||
|
||||
protected $handler;
|
||||
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* @param $handler
|
||||
* @param $request
|
||||
* @return static
|
||||
*/
|
||||
public static function create($handler, $request)
|
||||
{
|
||||
$class = new static();
|
||||
$class->handler = $handler;
|
||||
$class->request = $request;
|
||||
if ($handler instanceof \Closure) {
|
||||
$class->bind();
|
||||
}
|
||||
$class->bindParam();
|
||||
return $class;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* 执行函数
|
||||
*/
|
||||
public function dispatch()
|
||||
{
|
||||
return call_user_func($this->handler, $this->request);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 设置作用域
|
||||
*/
|
||||
protected function bind()
|
||||
{
|
||||
$class = $this->bindRequest(new Controller());
|
||||
$this->handler = \Closure::bind($this->handler, $class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $controller
|
||||
* @return mixed
|
||||
*/
|
||||
protected function bindRequest($controller)
|
||||
{
|
||||
$controller->request = Context::getContext('request');
|
||||
$controller->headers = $controller->request->headers;
|
||||
$controller->input = $controller->request->params;
|
||||
return $controller;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 参数绑定
|
||||
*/
|
||||
protected function bindParam()
|
||||
{
|
||||
if ($this->handler instanceof \Closure) {
|
||||
return;
|
||||
}
|
||||
$controller = $this->handler[0];
|
||||
$this->bindRequest($controller);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Route;
|
||||
|
||||
|
||||
use HttpServer\Exception\AuthException;
|
||||
use HttpServer\Route\Filter\BodyFilter;
|
||||
use HttpServer\Route\Filter\FilterException;
|
||||
use HttpServer\Route\Filter\HeaderFilter;
|
||||
use HttpServer\Route\Filter\QueryFilter;
|
||||
use Exception;
|
||||
use HttpServer\Application;
|
||||
use Snowflake\Snowflake;
|
||||
|
||||
/**
|
||||
* Class Filter
|
||||
* @package Snowflake\Snowflake\Route
|
||||
*/
|
||||
class Filter extends Application
|
||||
{
|
||||
|
||||
/** @var Filter\Filter[] */
|
||||
private $_filters = [];
|
||||
|
||||
/** @var array */
|
||||
public $grant = [];
|
||||
|
||||
/**
|
||||
* @param array $value
|
||||
* @return BodyFilter|bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function setBody(array $value)
|
||||
{
|
||||
if (empty($value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @var BodyFilter $class */
|
||||
$class = Snowflake::createObject(BodyFilter::class);
|
||||
$class->rules = [];
|
||||
$class->params = Input()->params();
|
||||
|
||||
return $this->_filters[] = $class;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $value
|
||||
* @return HeaderFilter|bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function setHeader(array $value)
|
||||
{
|
||||
if (empty($value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @var HeaderFilter $class */
|
||||
$class = Snowflake::createObject(HeaderFilter::class);
|
||||
$class->rules = [];
|
||||
$class->params = request()->headers->getHeaders();
|
||||
|
||||
return $this->_filters[] = $class;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $value
|
||||
* @return QueryFilter|bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function setQuery(array $value)
|
||||
{
|
||||
if (empty($value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @var QueryFilter $class */
|
||||
$class = Snowflake::createObject(QueryFilter::class);
|
||||
$class->rules = [];
|
||||
$class->params = request()->headers->getHeaders();
|
||||
|
||||
return $this->_filters[] = $class;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function handler()
|
||||
{
|
||||
if (($error = $this->filters()) !== true) {
|
||||
throw new FilterException($error);
|
||||
}
|
||||
if (!$this->grant()) {
|
||||
throw new AuthException('Authentication error.');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function filters()
|
||||
{
|
||||
if (empty($this->_filters)) {
|
||||
return true;
|
||||
}
|
||||
foreach ($this->_filters as $filter) {
|
||||
if (!$filter->check()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|mixed
|
||||
*/
|
||||
private function grant()
|
||||
{
|
||||
if (!is_callable($this->grant, true)) {
|
||||
return true;
|
||||
}
|
||||
return call_user_func($this->grant);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Route\Filter;
|
||||
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class BodyFilter
|
||||
* @package Snowflake\Snowflake\Route\Filter
|
||||
*/
|
||||
class BodyFilter extends Filter
|
||||
{
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function check()
|
||||
{
|
||||
return $this->validator();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Route\Filter;
|
||||
|
||||
|
||||
use Exception;
|
||||
use HttpServer\Application;
|
||||
use validator\Validator;
|
||||
|
||||
/**
|
||||
* Class Filter
|
||||
* @package Snowflake\Snowflake\Route\Filter
|
||||
*/
|
||||
abstract class Filter extends Application
|
||||
{
|
||||
|
||||
public $rules = [];
|
||||
|
||||
public $params = [];
|
||||
|
||||
abstract public function check();
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function validator()
|
||||
{
|
||||
$validator = Validator::getInstance();
|
||||
$validator->setParams($this->params);
|
||||
foreach ($this->rules as $val) {
|
||||
$field = array_shift($val);
|
||||
if (empty($val)) {
|
||||
continue;
|
||||
}
|
||||
$validator->make($field, $val);
|
||||
}
|
||||
if (!$validator->validation()) {
|
||||
return $this->addError($validator->getError());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Route\Filter;
|
||||
|
||||
|
||||
use Throwable;
|
||||
|
||||
class FilterException extends \Exception
|
||||
{
|
||||
|
||||
public function __construct($message = "", $code = 0, Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Route\Filter;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class HeaderFilter
|
||||
* @package Snowflake\Snowflake\Route\Filter
|
||||
*/
|
||||
class HeaderFilter extends Filter
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function check()
|
||||
{
|
||||
return $this->validator();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Route\Filter;
|
||||
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class QueryFilter
|
||||
* @package Snowflake\Snowflake\Route\Filter
|
||||
*/
|
||||
class QueryFilter extends Filter
|
||||
{
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function check()
|
||||
{
|
||||
return $this->validator();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Route;
|
||||
|
||||
|
||||
use Exception;
|
||||
use HttpServer\Application;
|
||||
use Snowflake\Snowflake;
|
||||
|
||||
/**
|
||||
* Class TcpListen
|
||||
* @package Snowflake\Snowflake\Route
|
||||
*/
|
||||
class Handler extends Application
|
||||
{
|
||||
|
||||
/** @var Router */
|
||||
protected $router;
|
||||
|
||||
/**
|
||||
* Listen constructor.
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->router = Snowflake::app()->router;
|
||||
|
||||
parent::__construct([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $config
|
||||
* @param $handler
|
||||
*/
|
||||
public function group($config, $handler)
|
||||
{
|
||||
$this->router->group($config, $handler, $this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param $handler
|
||||
* @return Handler
|
||||
*/
|
||||
public function handler($route, $handler)
|
||||
{
|
||||
return $this->router->addRoute($route, $handler, 'receive');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: admin
|
||||
* Date: 2019-03-20
|
||||
* Time: 02:17
|
||||
*/
|
||||
|
||||
namespace HttpServer\Route;
|
||||
|
||||
use Closure;
|
||||
use Exception;
|
||||
use HttpServer\Route\Dispatch\Dispatch;
|
||||
|
||||
/**
|
||||
* Class Middleware
|
||||
* @package Snowflake\Snowflake\Route
|
||||
*/
|
||||
class Middleware
|
||||
{
|
||||
|
||||
/** @var array */
|
||||
private $middleWares = [];
|
||||
|
||||
/**
|
||||
* @param $call
|
||||
* @return $this
|
||||
*/
|
||||
public function set($call)
|
||||
{
|
||||
$this->middleWares[] = $call;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $array
|
||||
* @return $this
|
||||
*/
|
||||
public function setMiddleWares(array $array)
|
||||
{
|
||||
$this->middleWares = $array;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Node $node
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getGenerate($node)
|
||||
{
|
||||
$last = function ($passable) use ($node) {
|
||||
return Dispatch::create($node->handler, $passable)->dispatch();
|
||||
};
|
||||
$middleWares = $this->annotation($node);
|
||||
$data = array_reduce(array_reverse($middleWares), $this->core(), $last);
|
||||
$this->middleWares = [];
|
||||
return $node->callback = $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Node $node
|
||||
* @return array
|
||||
*/
|
||||
public function annotation($node)
|
||||
{
|
||||
$middleWares = $this->middleWares;
|
||||
if (!$node->hasInterceptor()) {
|
||||
return $middleWares;
|
||||
}
|
||||
foreach ($node->getInterceptor() as $item) {
|
||||
$middleWares[] = $item[0];
|
||||
}
|
||||
return $middleWares;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Closure
|
||||
*/
|
||||
public function core()
|
||||
{
|
||||
return function ($stack, $pipe) {
|
||||
return function ($passable) use ($stack, $pipe) {
|
||||
if ($pipe instanceof \HttpServer\IInterface\Middleware) {
|
||||
return $pipe->handler($passable, $stack);
|
||||
} else {
|
||||
return $pipe($passable, $stack);
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Route;
|
||||
|
||||
|
||||
use HttpServer\Http\Request;
|
||||
use Exception;
|
||||
use HttpServer\Application;
|
||||
use HttpServer\Route\Annotation\Annotation;
|
||||
use Snowflake\Snowflake;
|
||||
|
||||
/**
|
||||
* Class Node
|
||||
* @package Snowflake\Snowflake\Route
|
||||
*/
|
||||
class Node extends Application
|
||||
{
|
||||
|
||||
public $path;
|
||||
public $index = 0;
|
||||
public $method;
|
||||
|
||||
/** @var Node[] $childes */
|
||||
public $childes = [];
|
||||
|
||||
public $group = [];
|
||||
public $options = null;
|
||||
|
||||
private $_error = '';
|
||||
|
||||
public $rules = [];
|
||||
public $handler;
|
||||
public $htmlSuffix = '.html';
|
||||
public $enableHtmlSuffix = false;
|
||||
public $namespace = [];
|
||||
public $middleware = [];
|
||||
public $callback = [];
|
||||
|
||||
private $_interceptors = [];
|
||||
|
||||
/**
|
||||
* @param $handler
|
||||
* @return Node
|
||||
* @throws
|
||||
*/
|
||||
public function bindHandler($handler)
|
||||
{
|
||||
if ($handler instanceof \Closure) {
|
||||
$this->handler = $handler;
|
||||
} else if (is_string($handler) && strpos($handler, '@') !== false) {
|
||||
list($controller, $action) = explode('@', $handler);
|
||||
if (!empty($this->namespace)) {
|
||||
$controller = implode('\\', $this->namespace) . '\\' . $controller;
|
||||
}
|
||||
$this->handler = $this->getReflect($controller, $action);
|
||||
} else if ($handler != null && !is_callable($handler, true)) {
|
||||
$this->_error = 'Controller is con\'t exec.';
|
||||
} else {
|
||||
$this->handler = $handler;
|
||||
}
|
||||
return $this->restructure();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hasInterceptor()
|
||||
{
|
||||
return count($this->_interceptors) > 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getInterceptor()
|
||||
{
|
||||
return $this->_interceptors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $request
|
||||
* @return bool
|
||||
*/
|
||||
public function methodAllow(Request $request)
|
||||
{
|
||||
if ($this->method == $request->getMethod()) {
|
||||
return true;
|
||||
}
|
||||
return $this->method == 'any';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function checkSuffix()
|
||||
{
|
||||
if ($this->enableHtmlSuffix) {
|
||||
$url = request()->getUri();
|
||||
$nowLength = strlen($this->htmlSuffix);
|
||||
if (strpos($url, $this->htmlSuffix) !== strlen($url) - $nowLength) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return $this->checkRule();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
private function checkRule()
|
||||
{
|
||||
if (empty($this->rules)) {
|
||||
return true;
|
||||
}
|
||||
foreach ($this->rules as $rule) {
|
||||
if (!isset($rule['class'])) {
|
||||
$rule['class'] = Filter::class;
|
||||
}
|
||||
/** @var Filter $object */
|
||||
$object = Snowflake::createObject($rule);
|
||||
if (!$object->handler()) {
|
||||
return false;
|
||||
};
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $controller
|
||||
* @param string $action
|
||||
* @return null|array
|
||||
* @throws Exception
|
||||
*/
|
||||
private function getReflect(string $controller, string $action)
|
||||
{
|
||||
try {
|
||||
$reflect = Snowflake::getDi()->getReflect($controller);
|
||||
if (!$reflect->isInstantiable()) {
|
||||
throw new Exception($controller . ' Class is con\'t Instantiable.');
|
||||
}
|
||||
|
||||
if (!empty($action) && !$reflect->hasMethod($action)) {
|
||||
throw new Exception('method ' . $action . ' not exists at ' . $controller . '.');
|
||||
}
|
||||
|
||||
/** @var Annotation $annotation */
|
||||
$annotation = Snowflake::app()->annotation->get('http');
|
||||
if (!empty($annotations = $annotation->getAnnotation(Annotation::class))) {
|
||||
$this->_interceptors = $annotation->read($reflect, $action, $annotations);
|
||||
}
|
||||
return [$reflect->newInstance(), $action];
|
||||
} catch (Exception $exception) {
|
||||
$this->_error = $exception->getMessage();
|
||||
$this->error($exception->getMessage(), 'router');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* 错误信息
|
||||
*/
|
||||
public function getError()
|
||||
{
|
||||
return $this->_error;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Node $node
|
||||
* @param string $field
|
||||
* @return Node
|
||||
*/
|
||||
public function addChild(Node $node, string $field)
|
||||
{
|
||||
/** @var Node $oLod */
|
||||
$oLod = $this->childes[$field] ?? null;
|
||||
if (!empty($oLod)) {
|
||||
$node = $oLod;
|
||||
}
|
||||
$this->childes[$field] = $node;
|
||||
return $this->childes[$field];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $rule
|
||||
* @return $this
|
||||
*/
|
||||
public function filter($rule)
|
||||
{
|
||||
if (empty($rule)) {
|
||||
return $this;
|
||||
}
|
||||
if (!isset($rule[0])) {
|
||||
$rule = [$rule];
|
||||
}
|
||||
foreach ($rule as $value) {
|
||||
if (empty($value)) {
|
||||
continue;
|
||||
}
|
||||
$this->rules[] = $value;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $search
|
||||
* @return Node|mixed
|
||||
*/
|
||||
public function findNode(string $search)
|
||||
{
|
||||
if (empty($this->childes)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isset($this->childes[$search])) {
|
||||
return $this->childes[$search];
|
||||
}
|
||||
|
||||
$_searchMatch = '/<(\w+)?:(.+)?>/';
|
||||
foreach ($this->childes as $key => $val) {
|
||||
if (preg_match($_searchMatch, $key, $match)) {
|
||||
\Input()->addGetParam($match[1] ?? '--', $search);
|
||||
return $this->childes[$key];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $options
|
||||
* @return $this
|
||||
*/
|
||||
public function bindOptions($options)
|
||||
{
|
||||
if (is_object($options)) {
|
||||
$this->options = $options;
|
||||
} else {
|
||||
$options = array_filter($options);
|
||||
$last = $options[count($options) - 1];
|
||||
if (empty($last)) {
|
||||
return $this;
|
||||
}
|
||||
$this->options = $last;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $alias
|
||||
* @return $this
|
||||
* 别称
|
||||
*/
|
||||
public function alias(string $alias)
|
||||
{
|
||||
$_alias = $alias;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
* @param int $duration
|
||||
* @param bool $isBindConsumer
|
||||
* @return $this
|
||||
* @throws Exception
|
||||
*/
|
||||
public function limits(int $limit, int $duration = 60, bool $isBindConsumer = false)
|
||||
{
|
||||
$limits = Snowflake::app()->getLimits();
|
||||
$limits->addLimits($this->path, $limit, $duration, $isBindConsumer);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $middles
|
||||
* @throws
|
||||
*/
|
||||
public function bindMiddleware(array $middles)
|
||||
{
|
||||
$_tmp = [];
|
||||
if (empty($middles)) {
|
||||
return;
|
||||
}
|
||||
$this->middleware = $this->each($middles, $_tmp);
|
||||
$this->restructure();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
private function restructure()
|
||||
{
|
||||
if (empty($this->handler)) {
|
||||
return $this;
|
||||
}
|
||||
$made = Snowflake::createObject(Middleware::class);
|
||||
$made->setMiddleWares($this->middleware);
|
||||
$made->getGenerate($this);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $array
|
||||
* @param $_temp
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
private function each($array, $_temp)
|
||||
{
|
||||
if (empty($array)) {
|
||||
return $_temp;
|
||||
}
|
||||
foreach ($array as $class) {
|
||||
if (is_array($class)) {
|
||||
$_temp = $this->each($class, $_temp);
|
||||
} else {
|
||||
$_temp[] = Snowflake::createObject($class);
|
||||
}
|
||||
}
|
||||
return $_temp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,514 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Route;
|
||||
|
||||
use Closure;
|
||||
use Exception;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Class Router
|
||||
* @package Snowflake\Snowflake\Route
|
||||
*/
|
||||
class Router extends Application implements RouterInterface
|
||||
{
|
||||
/** @var Node[] $nodes */
|
||||
public $nodes = [];
|
||||
public $groupTacks = [];
|
||||
public $dir = 'App\\Http\\Controllers';
|
||||
|
||||
/** @var string[] */
|
||||
public $methods = ['get', 'post', 'options', 'put', 'delete', 'receive'];
|
||||
|
||||
/**
|
||||
* @throws ConfigException
|
||||
* 初始化函数路径
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->dir = Config::get('http.namespace', false, $this->dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
* @param $handler
|
||||
* @param string $method
|
||||
* @return mixed|Node|null
|
||||
* @throws
|
||||
*/
|
||||
public function addRoute($path, $handler, $method = 'any')
|
||||
{
|
||||
if (!isset($this->nodes[$method])) {
|
||||
$this->nodes[$method] = [];
|
||||
}
|
||||
list($first, $explode) = $this->split($path);
|
||||
$parent = $this->nodes[$method][$first] ?? null;
|
||||
if (empty($parent)) {
|
||||
$parent = $this->NodeInstance($first, 0, $method);
|
||||
$this->nodes[$method][$first] = $parent;
|
||||
}
|
||||
if ($first !== '/') {
|
||||
$parent = $this->bindNode($parent, $explode, $method);
|
||||
}
|
||||
return $parent->bindHandler($handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Node $parent
|
||||
* @param array $explode
|
||||
* @param $method
|
||||
* @return Node
|
||||
*/
|
||||
private function bindNode($parent, $explode, $method)
|
||||
{
|
||||
$a = 0;
|
||||
if (empty($explode)) {
|
||||
return $parent->addChild($this->NodeInstance('/', $a, $method), '/');
|
||||
}
|
||||
foreach ($explode as $value) {
|
||||
if (empty($value)) {
|
||||
continue;
|
||||
}
|
||||
++$a;
|
||||
|
||||
$search = $parent->findNode($value);
|
||||
if ($search === null) {
|
||||
$parent = $parent->addChild($this->NodeInstance($value, $a, $method), $value);
|
||||
} else {
|
||||
$parent = $search;
|
||||
}
|
||||
}
|
||||
return $parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param $handler
|
||||
* @return Node|mixed|null
|
||||
*/
|
||||
public function socket($route, $handler)
|
||||
{
|
||||
return $this->addRoute($route, $handler, 'socket');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param $handler
|
||||
* @param int $port
|
||||
* @return Node|mixed|null
|
||||
*/
|
||||
public function gRpc($route, $handler, $port = 33007)
|
||||
{
|
||||
$route = ltrim($route, '/');
|
||||
if (!empty($port)) {
|
||||
$route = $port . '/' . $route;
|
||||
}
|
||||
return $this->addRoute($route, $handler, 'grpc');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param $handler
|
||||
* @return Node|mixed|null
|
||||
*/
|
||||
public function task($route, $handler)
|
||||
{
|
||||
return $this->addRoute($route, $handler, 'Task');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param $handler
|
||||
* @return mixed|Node|null
|
||||
* @throws
|
||||
*/
|
||||
public function post($route, $handler)
|
||||
{
|
||||
return $this->addRoute($route, $handler, 'post');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param $handler
|
||||
* @return mixed|Node|null
|
||||
* @throws
|
||||
*/
|
||||
public function get($route, $handler)
|
||||
{
|
||||
return $this->addRoute($route, $handler, 'get');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param $handler
|
||||
* @return mixed|Node|null
|
||||
* @throws
|
||||
*/
|
||||
public function options($route, $handler)
|
||||
{
|
||||
return $this->addRoute($route, $handler, 'options');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $port
|
||||
* @param Closure $closure
|
||||
* @throws
|
||||
*/
|
||||
public function listen(int $port, Closure $closure)
|
||||
{
|
||||
$stdClass = Snowflake::createObject(Handler::class);
|
||||
$this->group(['prefix' => $port], $closure, $stdClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param $handler
|
||||
* @return Any
|
||||
*/
|
||||
public function any($route, $handler)
|
||||
{
|
||||
$nodes = [];
|
||||
foreach (['get', 'post', 'options', 'put', 'delete'] as $method) {
|
||||
$nodes[] = $this->addRoute($route, $handler, $method);
|
||||
}
|
||||
return new Any($nodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param $handler
|
||||
* @return mixed|Node|null
|
||||
* @throws
|
||||
*/
|
||||
public function delete($route, $handler)
|
||||
{
|
||||
return $this->addRoute($route, $handler, 'delete');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param $handler
|
||||
* @return mixed|Node|null
|
||||
* @throws
|
||||
*/
|
||||
public function put($route, $handler)
|
||||
{
|
||||
return $this->addRoute($route, $handler, 'put');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @param $index
|
||||
* @param $method
|
||||
* @return Node
|
||||
* @throws
|
||||
*/
|
||||
public function NodeInstance($value, $index = 0, $method = 'get')
|
||||
{
|
||||
$node = new Node();
|
||||
$node->childes = [];
|
||||
$node->path = $value;
|
||||
$node->index = $index;
|
||||
$node->method = $method;
|
||||
|
||||
$name = array_column($this->groupTacks, 'namespace');
|
||||
|
||||
$dir = array_column($this->groupTacks, 'dir');
|
||||
if (!empty($dir)) {
|
||||
array_unshift($name, implode('\\', $dir));
|
||||
} else {
|
||||
if ($method == 'package' || $method == 'receive') {
|
||||
$dir = 'App\\Listener';
|
||||
} else {
|
||||
$dir = $this->dir;
|
||||
}
|
||||
array_unshift($name, $dir);
|
||||
}
|
||||
|
||||
if (!empty($name) && $name = array_filter($name)) {
|
||||
$node->namespace = $name;
|
||||
}
|
||||
|
||||
$name = array_column($this->groupTacks, 'middleware');
|
||||
if (!empty($name) && $name = array_filter($name)) {
|
||||
$node->bindMiddleware($name);
|
||||
}
|
||||
|
||||
$options = array_column($this->groupTacks, 'options');
|
||||
if (!empty($options) && is_array($options)) {
|
||||
$node->bindOptions($options);
|
||||
}
|
||||
|
||||
$rules = array_column($this->groupTacks, 'filter');
|
||||
$rules = array_shift($rules);
|
||||
if (!empty($rules) && is_array($rules)) {
|
||||
$node->filter($rules);
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $config
|
||||
* @param callable $callback
|
||||
* 路由分组
|
||||
* @param null $stdClass
|
||||
*/
|
||||
public function group(array $config, callable $callback, $stdClass = null)
|
||||
{
|
||||
$this->groupTacks[] = $config;
|
||||
if ($stdClass) {
|
||||
$callback($stdClass);
|
||||
} else {
|
||||
$callback($this);
|
||||
}
|
||||
array_pop($this->groupTacks);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function addPrefix()
|
||||
{
|
||||
$prefix = array_column($this->groupTacks, 'prefix');
|
||||
|
||||
$prefix = array_filter($prefix);
|
||||
|
||||
if (empty($prefix)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return '/' . implode('/', $prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $explode
|
||||
* @param $method
|
||||
* @return Node|null
|
||||
* 查找指定路由
|
||||
*/
|
||||
public function tree_search($explode, $method)
|
||||
{
|
||||
if (empty($explode)) {
|
||||
return $this->nodes[$method]['/'] ?? null;
|
||||
}
|
||||
$first = array_shift($explode);
|
||||
if (!($parent = $this->nodes[$method][$first] ?? null)) {
|
||||
return null;
|
||||
}
|
||||
if (empty($explode)) {
|
||||
return $parent->findNode('/');
|
||||
}
|
||||
while ($value = array_shift($explode)) {
|
||||
$node = $parent->findNode($value);
|
||||
if (!$node) {
|
||||
break;
|
||||
}
|
||||
$parent = $node;
|
||||
}
|
||||
return $parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
* @return array
|
||||
* '*'
|
||||
*/
|
||||
public function split($path)
|
||||
{
|
||||
$prefix = $this->addPrefix();
|
||||
$path = ltrim($path, '/');
|
||||
if (!empty($prefix)) {
|
||||
$path = $prefix . '/' . $path;
|
||||
}
|
||||
|
||||
$explode = array_filter(explode('/', $path));
|
||||
if (empty($explode)) {
|
||||
return ['/', []];
|
||||
}
|
||||
|
||||
$first = array_shift($explode);
|
||||
if (empty($explode)) {
|
||||
$explode = [];
|
||||
}
|
||||
return [$first, $explode];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function each()
|
||||
{
|
||||
$paths = [];
|
||||
foreach ($this->nodes as $node) {
|
||||
/** @var Node[] $node */
|
||||
foreach ($node as $_node) {
|
||||
if ($_node->path == '/') {
|
||||
continue;
|
||||
}
|
||||
$path = strtoupper($_node->method) . ' : ' . $_node->path;
|
||||
if (!empty($_node->childes)) {
|
||||
$path = $this->readByChild($_node->childes, $path);
|
||||
}
|
||||
$paths[] = $path;
|
||||
}
|
||||
}
|
||||
return $this->readByArray($paths);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $array
|
||||
* @param array $returns
|
||||
* @return array
|
||||
*/
|
||||
private function readByArray($array, $returns = [])
|
||||
{
|
||||
foreach ($array as $value) {
|
||||
if (empty($value)) {
|
||||
continue;
|
||||
}
|
||||
if (is_array($value)) {
|
||||
$returns = $this->readByArray($value, $returns);
|
||||
} else {
|
||||
[$method, $route] = explode(' : ', $value);
|
||||
|
||||
$returns[] = ['method' => $method, 'route' => $route];
|
||||
}
|
||||
}
|
||||
return $returns;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $child
|
||||
* @param string $paths
|
||||
* @return array
|
||||
*/
|
||||
private function readByChild($child, $paths = '')
|
||||
{
|
||||
$newPath = [];
|
||||
/** @var Node $item */
|
||||
foreach ($child as $item) {
|
||||
if ($item->path == '/') {
|
||||
continue;
|
||||
}
|
||||
if (!empty($item->childes)) {
|
||||
$newPath[] = $this->readByChild($item->childes, $paths . '/' . $item->path);
|
||||
} else {
|
||||
[$first, $route] = explode(' : ', $paths);
|
||||
|
||||
$newPath[] = strtoupper($item->method) . ' : ' . $route . '/' . $item->path;
|
||||
}
|
||||
|
||||
}
|
||||
return $newPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @throws
|
||||
*/
|
||||
public function dispatch()
|
||||
{
|
||||
$request = Context::getContext('request');
|
||||
if (!($node = $this->find_path($request))) {
|
||||
return JSON::to(404, 'Page not found.');
|
||||
}
|
||||
if (empty($node->callback)) {
|
||||
if (!empty($node->getError())) {
|
||||
return JSON::to(500, $node->getError());
|
||||
}
|
||||
return JSON::to(404, 'Page not found.');
|
||||
}
|
||||
return call_user_func($node->callback, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $request
|
||||
* @return Node|false|int|mixed|string|null
|
||||
*/
|
||||
private function find_path($request)
|
||||
{
|
||||
$node = $this->tree_search($request->getExplode(), $request->getMethod());
|
||||
if ($node instanceof Node) {
|
||||
return $node;
|
||||
}
|
||||
if (!$request->isOption) {
|
||||
return null;
|
||||
}
|
||||
$node = $this->tree_search(['*'], $request->getMethod());
|
||||
if (!($node instanceof Node)) {
|
||||
return null;
|
||||
}
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws
|
||||
*/
|
||||
public function loadRouterSetting()
|
||||
{
|
||||
$prefix = APP_PATH . 'app/Http/';
|
||||
|
||||
/** @var Annotation $annotation */
|
||||
$annotation = Snowflake::app()->annotation;
|
||||
$annotation->register('http', Annotation::class);
|
||||
|
||||
$annotation = $annotation->get('http');
|
||||
$annotation->registration_notes($prefix . 'Interceptor', 'App\Http\Interceptor');
|
||||
$annotation->registration_notes($prefix . 'Limits', 'App\Http\Limits');
|
||||
|
||||
$this->loadRouteDir(APP_PATH . '/routes');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
* @throws Exception
|
||||
* 加载目录下的路由文件
|
||||
*/
|
||||
private function loadRouteDir($path)
|
||||
{
|
||||
$files = glob($path . '/*');
|
||||
for ($i = 0; $i < count($files); $i++) {
|
||||
if (is_dir($files[$i])) {
|
||||
$this->loadRouteDir($files[$i]);
|
||||
} else {
|
||||
$this->loadRouterFile($files[$i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $files
|
||||
* @throws Exception
|
||||
*/
|
||||
private function loadRouterFile($files)
|
||||
{
|
||||
try {
|
||||
$router = $this;
|
||||
include_once "{$files}";
|
||||
} catch (Exception $exception) {
|
||||
$this->error($exception->getMessage());
|
||||
} finally {
|
||||
if (isset($exception)) {
|
||||
unset($exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user