e
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
define('SUCCESS', 0);
|
||||
define('NO_AUTH', 401);
|
||||
|
||||
define('ERROR_MESSAGES', [
|
||||
SUCCESS => 'ok',
|
||||
NO_AUTH => ''
|
||||
]);
|
||||
|
||||
if (!function_exists('message')) {
|
||||
|
||||
/**
|
||||
* @param $code
|
||||
* @param $replace
|
||||
* @param string $default
|
||||
* @return mixed|string
|
||||
*/
|
||||
function message($code, $replace, $default = '')
|
||||
{
|
||||
if (!isset(ERROR_MESSAGES[$code])) {
|
||||
if (!empty($default)) {
|
||||
return $default;
|
||||
}
|
||||
return 'unknown error';
|
||||
}
|
||||
return sprintf(ERROR_MESSAGES[$code], $replace);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
|
||||
defined('APP_PATH') or define('APP_PATH', __DIR__ . '/../../');
|
||||
|
||||
use HttpServer\Http\Response;
|
||||
use Snowflake\Snowflake;
|
||||
|
||||
if (!function_exists('make')) {
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $default
|
||||
* @return stdClass
|
||||
* @throws
|
||||
*/
|
||||
function make($name, $default)
|
||||
{
|
||||
if (Snowflake::has($name)) {
|
||||
$class = Snowflake::get()->$name;
|
||||
} else if (Snowflake::has($default)) {
|
||||
$class = Snowflake::get()->$default;
|
||||
} else {
|
||||
$class = Snowflake::createObject($default);
|
||||
Snowflake::setAlias($name, $default);
|
||||
}
|
||||
return $class;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (!function_exists('storage')) {
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
* @param string $path
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
function storage($fileName = '', $path = '')
|
||||
{
|
||||
$basePath = Snowflake::getStoragePath();
|
||||
// if (empty($path)) {
|
||||
// return $basePath . '/' . $fileName;
|
||||
// } else if (empty($fileName)) {
|
||||
// return initDir($basePath, $path);
|
||||
// }
|
||||
return initDir($basePath, $path) . $fileName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $basePath
|
||||
* @param $path
|
||||
* @return false|string
|
||||
* @throws Exception
|
||||
*/
|
||||
function initDir($basePath, $path)
|
||||
{
|
||||
$explode = array_filter(explode('/', $path));
|
||||
foreach ($explode as $value) {
|
||||
$path .= $value . '/';
|
||||
if (!is_dir($basePath . $path)) {
|
||||
// mkdir($basePath . $path);
|
||||
}
|
||||
if (!is_dir($basePath . $path)) {
|
||||
// throw new Exception('System error, directory ' . $basePath . $path . ' is not writable');
|
||||
}
|
||||
}
|
||||
return realpath($basePath . $path);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (!function_exists('alias')) {
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @param $name
|
||||
*/
|
||||
function alias($class, $name)
|
||||
{
|
||||
Snowflake::setAlias($class, $name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (!function_exists('name')) {
|
||||
|
||||
function name($name)
|
||||
{
|
||||
swoole_set_process_name($name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!function_exists('response')) {
|
||||
|
||||
/**
|
||||
* @return Response|stdClass
|
||||
* @throws
|
||||
*/
|
||||
function response()
|
||||
{
|
||||
if (!Snowflake::has('response')) {
|
||||
return make('response', Response::class);
|
||||
}
|
||||
return Snowflake::get()->response;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!function_exists('redirect')) {
|
||||
|
||||
function redirect($url)
|
||||
{
|
||||
return response()->redirect($url);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!function_exists('env')) {
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param null $default
|
||||
* @return array|false|string|null
|
||||
*/
|
||||
function env($key, $default = null)
|
||||
{
|
||||
$env = getenv($key);
|
||||
if ($env === false) {
|
||||
return $default;
|
||||
}
|
||||
return $env;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Abstracts;
|
||||
|
||||
|
||||
|
||||
use Swoole\Coroutine;
|
||||
|
||||
abstract class BaseContext
|
||||
{
|
||||
protected static $pool = [];
|
||||
|
||||
static function get($key)
|
||||
{
|
||||
$cid = Coroutine::getuid();
|
||||
if ($cid < 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if(isset(self::$pool[$cid][$key])){
|
||||
return self::$pool[$cid][$key];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static function put($key, $item)
|
||||
{
|
||||
$cid = Coroutine::getuid();
|
||||
if ($cid > 0)
|
||||
{
|
||||
self::$pool[$cid][$key] = $item;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static function delete($key = null)
|
||||
{
|
||||
$cid = Coroutine::getuid();
|
||||
if ($cid > 0)
|
||||
{
|
||||
if($key){
|
||||
unset(self::$pool[$cid][$key]);
|
||||
}else{
|
||||
unset(self::$pool[$cid]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Abstracts;
|
||||
|
||||
|
||||
use Snowflake\Abstracts\Component;
|
||||
|
||||
abstract class HttpService extends Component
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Abstracts;
|
||||
|
||||
use HttpServer\IInterface\IMiddleware;
|
||||
|
||||
/**
|
||||
* Class MiddlewareHandler
|
||||
* @package BeReborn\Route
|
||||
*/
|
||||
abstract class MiddlewareHandler implements IMiddleware
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/11/8 0008
|
||||
* Time: 18:37
|
||||
*/
|
||||
|
||||
namespace HttpServer\Abstracts;
|
||||
|
||||
|
||||
use HttpServer\Application;
|
||||
use Swoole\WebSocket\Server;
|
||||
|
||||
/**
|
||||
* Class ServerBase
|
||||
* @package BeReborn\Server
|
||||
*/
|
||||
abstract class ServerBase extends Application
|
||||
{
|
||||
|
||||
/** @var Server */
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* @return Server
|
||||
*/
|
||||
public function getServer()
|
||||
{
|
||||
return $this->server;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $server
|
||||
*/
|
||||
public function setServer($server)
|
||||
{
|
||||
$this->server = $server;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer;
|
||||
|
||||
|
||||
use Exception;
|
||||
use HttpServer\Abstracts\HttpService;
|
||||
use Snowflake\Snowflake;
|
||||
|
||||
/**
|
||||
* Class Application
|
||||
* @package HttpServer
|
||||
*/
|
||||
class Application extends HttpService
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @param string $category
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function write($message, $category = 'app')
|
||||
{
|
||||
$logger = Snowflake::get()->logger;
|
||||
$logger->write($message, $category);
|
||||
$logger->insert();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $methods
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __get($methods)
|
||||
{
|
||||
if (method_exists($this, $methods)) {
|
||||
return $this->{$methods}();
|
||||
}
|
||||
$handler = 'get' . ucfirst($methods);
|
||||
if (method_exists($this, $handler)) {
|
||||
return $this->{$handler}();
|
||||
}
|
||||
if (property_exists($this, $methods)) {
|
||||
return $this->$methods;
|
||||
}
|
||||
$message = sprintf('method %s::%s not exists.', get_called_class(), $methods);
|
||||
throw new Exception($message);
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
namespace HttpServer\Client;
|
||||
|
||||
use HttpServer\Application;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class Result
|
||||
*
|
||||
* @package app\components
|
||||
*
|
||||
* @property $code
|
||||
* @property $message
|
||||
* @property $count
|
||||
* @property $data
|
||||
*/
|
||||
class Result extends Application
|
||||
{
|
||||
public $code;
|
||||
public $message;
|
||||
public $count = 0;
|
||||
public $data;
|
||||
public $header;
|
||||
public $httpStatus = 200;
|
||||
|
||||
public $startTime = 0;
|
||||
public $requestTime = 0;
|
||||
public $runTime = 0;
|
||||
|
||||
public $statusCode = [100, 101, 200, 201, 202, 203, 204, 205, 206];
|
||||
|
||||
|
||||
/**
|
||||
* Result constructor.
|
||||
* @param array $data
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(array $data, $config = [])
|
||||
{
|
||||
parent::__construct($config);
|
||||
|
||||
foreach ($data as $key => $val) {
|
||||
$this->$key = $val;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
return $this->$name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $value
|
||||
* @return $this|void
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
$this->$name = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getHeaders()
|
||||
{
|
||||
$_tmp = [];
|
||||
if (!is_array($this->header)) {
|
||||
return $_tmp;
|
||||
}
|
||||
foreach ($this->header as $key => $val) {
|
||||
if ($key == 0) {
|
||||
$_tmp['pro'] = $val;
|
||||
} else {
|
||||
$trim = explode(': ', $val);
|
||||
|
||||
$_tmp[strtolower($trim[0])] = $trim[1];
|
||||
}
|
||||
}
|
||||
return $_tmp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getTime()
|
||||
{
|
||||
return [
|
||||
'startTime' => $this->startTime,
|
||||
'requestTime' => $this->requestTime,
|
||||
'runTime' => $this->runTime,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $data
|
||||
* @return $this
|
||||
* @throws Exception
|
||||
*/
|
||||
public function setAttr($key, $data)
|
||||
{
|
||||
if (!property_exists($this, $key)) {
|
||||
throw new Exception('未查找到相应对象属性');
|
||||
}
|
||||
$this->$key = $data;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $status
|
||||
* @return bool
|
||||
*/
|
||||
public function isResultsOK($status = 0)
|
||||
{
|
||||
if (!$this->httpIsOk()) {
|
||||
return false;
|
||||
}
|
||||
return $this->code === $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function httpIsOk()
|
||||
{
|
||||
return in_array($this->httpStatus, $this->statusCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getResponse()
|
||||
{
|
||||
$headers = $this->getHeaders();
|
||||
if (!isset($headers['content-type'])) {
|
||||
return $this->data;
|
||||
}
|
||||
if (!is_string($this->data)) {
|
||||
return $this->data;
|
||||
}
|
||||
switch (trim($headers['content-type'])) {
|
||||
case 'application/json; encoding=utf-8';
|
||||
case 'application/json;';
|
||||
case 'application/json';
|
||||
case 'text/plain';
|
||||
return json_decode($this->data, true);
|
||||
break;
|
||||
}
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $data
|
||||
* @return $this
|
||||
*/
|
||||
public function append($key, $data)
|
||||
{
|
||||
$this->data[$key] = $data;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getMessage()
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCode()
|
||||
{
|
||||
return $this->code;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer;
|
||||
|
||||
|
||||
use HttpServer\Http\HttpHeaders;
|
||||
use HttpServer\Http\HttpParams;
|
||||
use HttpServer\Http\Request;
|
||||
use Exception;
|
||||
use Snowflake\Snowflake;
|
||||
|
||||
/**
|
||||
* Class WebController
|
||||
* @package BeReborn\Web
|
||||
*/
|
||||
class Controller extends Application
|
||||
{
|
||||
|
||||
/** @var HttpParams $input */
|
||||
protected $input;
|
||||
|
||||
|
||||
/** @var HttpHeaders */
|
||||
protected $headers;
|
||||
|
||||
|
||||
/** @var Request */
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* @param HttpParams $input
|
||||
*/
|
||||
public function setInput(HttpParams $input): void
|
||||
{
|
||||
$this->input = $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param HttpHeaders $headers
|
||||
*/
|
||||
public function setHeaders(HttpHeaders $headers): void
|
||||
{
|
||||
$this->headers = $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*/
|
||||
public function setRequest(Request $request): void
|
||||
{
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return HttpParams
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getInput(): HttpParams
|
||||
{
|
||||
if (!$this->input) {
|
||||
$this->input = $this->getRequest()->params;
|
||||
}
|
||||
return $this->input;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return HttpHeaders
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getHeaders(): HttpHeaders
|
||||
{
|
||||
if (!$this->headers) {
|
||||
$this->headers = $this->getRequest()->headers;
|
||||
}
|
||||
return $this->headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Request
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getRequest(): Request
|
||||
{
|
||||
if (!$this->request) {
|
||||
$this->request = Snowflake::get()->request;
|
||||
}
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return mixed|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
$method = 'get' . ucfirst($name);
|
||||
if (method_exists($this, $method)) {
|
||||
return $this->$method();
|
||||
}
|
||||
return parent::__get($name);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Events;
|
||||
|
||||
|
||||
use Exception;
|
||||
use HttpServer\Application;
|
||||
use Snowflake\Error\Logger;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Timer;
|
||||
|
||||
abstract class Callback extends Application
|
||||
{
|
||||
|
||||
/** @var \Snowflake\Application */
|
||||
protected $container;
|
||||
|
||||
|
||||
/**
|
||||
* Callback constructor.
|
||||
* @param $container
|
||||
*/
|
||||
public function __construct($container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param $server
|
||||
* @param $worker_id
|
||||
* @param $message
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function clear($server, $worker_id, $message)
|
||||
{
|
||||
Timer::clearAll();
|
||||
$event = Snowflake::get()->event;
|
||||
|
||||
$event->offName(Event::EVENT_AFTER_REQUEST);
|
||||
$event->offName(Event::EVENT_BEFORE_REQUEST);
|
||||
$this->eventNotify($message, $event);
|
||||
|
||||
Snowflake::clearProcessId($server->worker_pid);
|
||||
Logger::write($this->_MESSAGE[$message] . $worker_id);
|
||||
Logger::clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
const EVENT_ERROR = 'WORKER:ERROR';
|
||||
const EVENT_STOP = 'WORKER:STOP';
|
||||
const EVENT_EXIT = 'WORKER:EXIT';
|
||||
|
||||
|
||||
private $_MESSAGE = [
|
||||
self::EVENT_ERROR => 'The server error. at No.',
|
||||
self::EVENT_STOP => 'The server stop. at No.',
|
||||
self::EVENT_EXIT => 'The server exit. at No.',
|
||||
];
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @param $event
|
||||
*/
|
||||
private function eventNotify($message, $event)
|
||||
{
|
||||
switch ($message) {
|
||||
case self::EVENT_ERROR:
|
||||
if (!$event->exists(Event::SERVER_WORKER_ERROR)) {
|
||||
return;
|
||||
}
|
||||
$event->trigger(Event::SERVER_WORKER_ERROR);
|
||||
break;
|
||||
case self::EVENT_EXIT:
|
||||
if (!$event->exists(Event::SERVER_WORKER_EXIT)) {
|
||||
return;
|
||||
}
|
||||
$event->trigger(Event::SERVER_WORKER_EXIT);
|
||||
break;
|
||||
case self::EVENT_STOP:
|
||||
if (!$event->exists(Event::SERVER_WORKER_STOP)) {
|
||||
return;
|
||||
}
|
||||
$event->trigger(Event::SERVER_WORKER_STOP);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Events;
|
||||
|
||||
|
||||
use HttpServer\Http\Context;
|
||||
use HttpServer\Http\Request as HRequest;
|
||||
use HttpServer\Http\Response as HResponse;
|
||||
use HttpServer\ServerManager;
|
||||
use ReflectionException;
|
||||
use Snowflake\Application;
|
||||
use Snowflake\Core\JSON;
|
||||
use Snowflake\Exception\NotFindClassException;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Error;
|
||||
use Swoole\Http\Request;
|
||||
use Swoole\Http\Response;
|
||||
use Exception;
|
||||
use Swoole\Http\Server;
|
||||
|
||||
class Http extends Server
|
||||
{
|
||||
|
||||
/** @var Application */
|
||||
protected $application;
|
||||
|
||||
|
||||
/**
|
||||
* Receive constructor.
|
||||
* @param $application
|
||||
* @param $host
|
||||
* @param null $port
|
||||
* @param null $mode
|
||||
* @param null $sock_type
|
||||
*/
|
||||
public function __construct($application, $host, $port = null, $mode = null, $sock_type = null)
|
||||
{
|
||||
parent::__construct($host, $port, $mode, $sock_type);
|
||||
$this->application = $application;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $settings
|
||||
* @param array $events
|
||||
* @param array $config
|
||||
* @return mixed|void
|
||||
* @throws NotFindClassException
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function set(array $settings, $events = [], $config = [])
|
||||
{
|
||||
parent::set($settings);
|
||||
ServerManager::set($this, $settings, $this->application, $events, $config);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function onHandler(Request $request, Response $response)
|
||||
{
|
||||
try {
|
||||
[$sRequest, $sResponse] = static::setContext($request, $response);
|
||||
$sResponse->send(Snowflake::get()->router->dispatch(), 200);
|
||||
} catch (Error | \Throwable $exception) {
|
||||
if (!isset($sResponse)) {
|
||||
$response->status(200);
|
||||
$response->end($exception->getMessage());
|
||||
} else {
|
||||
$sResponse->send($this->format($exception), 200);
|
||||
}
|
||||
} finally {
|
||||
$dividing_line = str_pad('', 100, '-');
|
||||
$this->application->debug($dividing_line, 'app');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $exception
|
||||
* @return false|int|mixed|string
|
||||
* @throws Exception
|
||||
*/
|
||||
public function format($exception)
|
||||
{
|
||||
$errorInfo = [
|
||||
'message' => $exception->getMessage(),
|
||||
'file' => $exception->getFile(),
|
||||
'line' => $exception->getLine()
|
||||
];
|
||||
$this->application->error(var_export($errorInfo, true));
|
||||
|
||||
$code = $exception->getCode() ?? 500;
|
||||
$trance = array_slice($exception->getTrace(), 0, 10);
|
||||
Snowflake::get()->logger->write(print_r($trance, true), 'exception');
|
||||
|
||||
return JSON::to($code, $errorInfo['message']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $request
|
||||
* @param $response
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function setContext($request, $response): array
|
||||
{
|
||||
$request = Context::setContext('request', HRequest::create($request));
|
||||
$response = Context::setContext('response', HResponse::create($response));
|
||||
return [$request, $response];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Events;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Server;
|
||||
|
||||
/**
|
||||
* Class OnPacket
|
||||
* @package HttpServer\Events\Trigger
|
||||
*/
|
||||
class Packet extends Service
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Server $server
|
||||
* @param $data
|
||||
* @param $clientInfo
|
||||
* @return mixed
|
||||
* @throws
|
||||
*/
|
||||
public function onHandler($server, $data, $clientInfo)
|
||||
{
|
||||
try {
|
||||
$client = [$clientInfo['address'], $clientInfo['port']];
|
||||
if (empty($data = $this->unpack($data))) {
|
||||
throw new Exception('Format error.');
|
||||
}
|
||||
$client[] = $this->pack($data);
|
||||
return $server->sendto(...$client);
|
||||
} catch (\Throwable $exception) {
|
||||
$client[] = $this->pack(['message' => $exception->getMessage()]);
|
||||
return $server->sendto(...$client);
|
||||
} finally {
|
||||
$event = Snowflake::get()->event;
|
||||
$event->trigger(Event::SERVER_WORKER_STOP);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Events;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Snowflake\Core\JSON;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Server;
|
||||
|
||||
/**
|
||||
* Class Receive
|
||||
* @package HttpServer\Events
|
||||
*/
|
||||
class Receive extends Service
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Server $server
|
||||
* @param int $fd
|
||||
* @param int $reactorId
|
||||
* @param string $data
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onReceive(\Swoole\Server $server, int $fd, int $reactorId, string $data)
|
||||
{
|
||||
try {
|
||||
$client = [$fd];
|
||||
if (empty($data = $this->unpack($data))) {
|
||||
throw new Exception('Format error.');
|
||||
}
|
||||
$client[] = $this->pack($data);
|
||||
return $server->send(...$client);
|
||||
} catch (\Throwable $exception) {
|
||||
$client[] = $this->pack(['message' => $exception->getMessage()]);
|
||||
return $server->send(...$client);
|
||||
} finally {
|
||||
$event = Snowflake::get()->event;
|
||||
$event->trigger(Event::SERVER_WORKER_STOP);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Events;
|
||||
|
||||
|
||||
use Exception;
|
||||
use HttpServer\Application;
|
||||
use HttpServer\ServerManager;
|
||||
use ReflectionException;
|
||||
use Snowflake\Core\JSON;
|
||||
use Snowflake\Exception\ComponentException;
|
||||
use Snowflake\Exception\NotFindClassException;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Process\Pool;
|
||||
use Swoole\Server;
|
||||
use Closure;
|
||||
|
||||
/**
|
||||
* Class Service
|
||||
* @package HttpServer\Events
|
||||
*/
|
||||
abstract class Service extends Server
|
||||
{
|
||||
|
||||
/** @var \Snowflake\Application */
|
||||
protected $application;
|
||||
|
||||
|
||||
/** @var Closure|array */
|
||||
public $unpack;
|
||||
|
||||
|
||||
/** @var Closure|array */
|
||||
public $pack;
|
||||
|
||||
|
||||
/**
|
||||
* Receive constructor.
|
||||
* @param $application
|
||||
* @param $host
|
||||
* @param null $port
|
||||
* @param null $mode
|
||||
* @param null $sock_type
|
||||
*/
|
||||
public function __construct($application, $host, $port = null, $mode = null, $sock_type = null)
|
||||
{
|
||||
parent::__construct($host, $port, $mode, $sock_type);
|
||||
$this->application = $application;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $settings
|
||||
* @param array $events
|
||||
* @param array $config
|
||||
* @return mixed|void
|
||||
* @throws NotFindClassException
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function set(array $settings, $events = [], $config = [])
|
||||
{
|
||||
parent::set($settings);
|
||||
ServerManager::set($this, $settings, $this->application, $events, $config);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $callbacks
|
||||
*/
|
||||
protected function bindCallback($callbacks)
|
||||
{
|
||||
if (empty($callbacks) || !is_array($callbacks)) {
|
||||
return;
|
||||
}
|
||||
foreach ($callbacks as $callback) {
|
||||
$this->on($callback[0], [$this, $callback[1][1]]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $eventName
|
||||
* @return array
|
||||
* @throws NotFindClassException
|
||||
* @throws ReflectionException
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function createHandler($eventName)
|
||||
{
|
||||
$classPrefix = 'HttpServer\Events\Trigger\On' . ucfirst($eventName);
|
||||
if (!class_exists($classPrefix)) {
|
||||
throw new Exception('class not found.');
|
||||
}
|
||||
$class = Snowflake::createObject($classPrefix, [Snowflake::get()]);
|
||||
return [$class, 'onHandler'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function pack($data)
|
||||
{
|
||||
$callback = $this->pack;
|
||||
if (is_callable($callback, true)) {
|
||||
return $callback($data);
|
||||
}
|
||||
return JSON::encode($data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @return mixed
|
||||
*/
|
||||
public function unpack($data)
|
||||
{
|
||||
$callback = $this->unpack;
|
||||
if (is_callable($callback, true)) {
|
||||
return $callback($data);
|
||||
}
|
||||
return JSON::decode($data);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Events\Trigger;
|
||||
|
||||
|
||||
use HttpServer\Events\Callback;
|
||||
|
||||
class OnAfterReload extends Callback
|
||||
{
|
||||
|
||||
|
||||
public function onHandler()
|
||||
{
|
||||
// TODO: Implement onHandler() method.
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Events\Trigger;
|
||||
|
||||
|
||||
use HttpServer\Events\Callback;
|
||||
|
||||
class OnBeforeReload extends Callback
|
||||
{
|
||||
|
||||
public function onHandler()
|
||||
{
|
||||
// TODO: Implement onHandler() method.
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Events\Trigger;
|
||||
|
||||
|
||||
use HttpServer\Events\Callback;
|
||||
|
||||
class OnClose extends Callback
|
||||
{
|
||||
|
||||
public function onHandler()
|
||||
{
|
||||
// TODO: Implement onHandler() method.
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Events\Trigger;
|
||||
|
||||
|
||||
use Exception;
|
||||
use HttpServer\Events\Callback;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Server;
|
||||
|
||||
/**
|
||||
* Class OnConnect
|
||||
* @package HttpServer\Events\Trigger
|
||||
*/
|
||||
class OnConnect extends Callback
|
||||
{
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param Server $server
|
||||
* @param int $fd
|
||||
* @param int $reactorId
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onHandler(\Swoole\Server $server, int $fd, int $reactorId)
|
||||
{
|
||||
$event = Snowflake::get()->event;
|
||||
if (!$event->exists(Event::RECEIVE_CONNECTION)) {
|
||||
return;
|
||||
}
|
||||
$event->trigger(Event::RECEIVE_CONNECTION, [$server, $fd, $reactorId]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Events\Trigger;
|
||||
|
||||
|
||||
use Exception;
|
||||
use HttpServer\Events\Callback;
|
||||
use Swoole\Server;
|
||||
|
||||
class OnFinish extends Callback
|
||||
{
|
||||
/**
|
||||
* @param Server $server
|
||||
* @param $task_id
|
||||
* @param $data
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onHandler(Server $server, $task_id, $data)
|
||||
{
|
||||
$data = json_decode($data, true);
|
||||
$data['work_id'] = $task_id;
|
||||
$this->write(var_export($data, true), 'Task');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Events\Trigger;
|
||||
|
||||
|
||||
use HttpServer\Events\Callback;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Server;
|
||||
|
||||
class OnManagerStart extends Callback
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Server $server
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function onHandler(Server $server)
|
||||
{
|
||||
$this->debug('manager start.');
|
||||
Snowflake::setProcessId($server->manager_pid);
|
||||
|
||||
$events = Snowflake::get()->event;
|
||||
if ($events->exists(Event::SERVER_MANAGER_START)) {
|
||||
$events->trigger(Event::SERVER_MANAGER_START, null, $server);
|
||||
}
|
||||
if (Snowflake::isLinux()) {
|
||||
name('Server Manager.');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Events\Trigger;
|
||||
|
||||
|
||||
use HttpServer\Events\Callback;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Server;
|
||||
|
||||
/**
|
||||
* Class OnManagerStop
|
||||
* @package HttpServer\Events\Trigger
|
||||
*/
|
||||
class OnManagerStop extends Callback
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $server
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function onHandler(Server $server)
|
||||
{
|
||||
$this->warning('manager stop.');
|
||||
|
||||
$events = Snowflake::get()->event;
|
||||
if ($events->exists(Event::SERVER_MANAGER_STOP)) {
|
||||
$events->trigger(Event::SERVER_MANAGER_STOP, [$server]);
|
||||
}
|
||||
|
||||
// $runPath = storage(null, 'workerIds');
|
||||
// foreach (glob($runPath . '/*') as $item) {
|
||||
// if (!file_exists($item)) {
|
||||
// continue;
|
||||
// }
|
||||
// @unlink($item);
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Events\Trigger;
|
||||
|
||||
|
||||
use HttpServer\Events\Callback;
|
||||
|
||||
class OnPipeMessage extends Callback
|
||||
{
|
||||
|
||||
public function onHandler()
|
||||
{
|
||||
// TODO: Implement onHandler() method.
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Events\Trigger;
|
||||
|
||||
|
||||
use Exception;
|
||||
use HttpServer\Events\Callback;
|
||||
use Snowflake\Core\JSON;
|
||||
use Snowflake\Error\Logger;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Server;
|
||||
use Closure;
|
||||
|
||||
class OnShutdown extends Callback
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Server $server
|
||||
*/
|
||||
public function onHandler(Server $server)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Events\Trigger;
|
||||
|
||||
|
||||
use HttpServer\Events\Callback;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Server;
|
||||
|
||||
class OnStart extends Callback
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Server $server
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function onHandler($server)
|
||||
{
|
||||
$time = storage('socket.sock');
|
||||
Snowflake::writeFile($time, $server->master_pid);
|
||||
|
||||
$event = Snowflake::get()->event;
|
||||
if ($event->exists(Event::SERVER_EVENT_START)) {
|
||||
$event->trigger(Event::SERVER_EVENT_START, null, $server);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Events\Trigger\Trigger;
|
||||
|
||||
|
||||
use HttpServer\Events\Callback;
|
||||
use HttpServer\IInterface\Task as ITask;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Server;
|
||||
use Swoole\Timer;
|
||||
use Exception;
|
||||
|
||||
class OnTask extends Callback
|
||||
{
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onHandler()
|
||||
{
|
||||
$parameter = func_get_args();
|
||||
if (count($parameter) < 4) {
|
||||
$this->onContinueTask(...func_get_args());
|
||||
} else {
|
||||
$this->onTask(...func_get_args());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Server $server
|
||||
* @param int $task_id
|
||||
* @param int $from_id
|
||||
* @param string $data
|
||||
*
|
||||
* @return mixed|void
|
||||
* @throws Exception
|
||||
* 异步任务
|
||||
*/
|
||||
public function onTask(Server $server, $task_id, $from_id, $data)
|
||||
{
|
||||
$time = microtime(TRUE);
|
||||
if (empty($data)) {
|
||||
return $server->finish('null data');
|
||||
}
|
||||
$finish = $this->runTaskHandler($data);
|
||||
if (!$finish) {
|
||||
$finish = [];
|
||||
}
|
||||
$finish['runTime'] = [
|
||||
'startTime' => $time,
|
||||
'runTime' => microtime(TRUE) - $time,
|
||||
'endTime' => microtime(TRUE),
|
||||
];
|
||||
$server->finish(json_encode($finish));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Server $server
|
||||
* @param Server\Task $task
|
||||
* @return mixed|void
|
||||
* @throws Exception
|
||||
* 异步任务
|
||||
*/
|
||||
public function onContinueTask(Server $server, Server\Task $task)
|
||||
{
|
||||
$time = microtime(TRUE);
|
||||
if (empty($task->data)) {
|
||||
return $task->finish('null data');
|
||||
}
|
||||
$finish = $this->runTaskHandler($task->data);
|
||||
if (!$finish) {
|
||||
$finish = [];
|
||||
}
|
||||
$finish['runTime'] = [
|
||||
'startTime' => $time,
|
||||
'runTime' => microtime(TRUE) - $time,
|
||||
'endTime' => microtime(TRUE),
|
||||
];
|
||||
$task->finish(json_encode($finish));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @return array|null
|
||||
* @throws Exception
|
||||
*/
|
||||
private function runTaskHandler($data)
|
||||
{
|
||||
$serialize = $this->before($data);
|
||||
try {
|
||||
$params = $serialize->getParams();
|
||||
if (is_object($params)) {
|
||||
$params = get_object_vars($params);
|
||||
}
|
||||
$finish['class'] = get_class($serialize);
|
||||
$finish['params'] = $params;
|
||||
$finish['status'] = 'success';
|
||||
$finish['info'] = $serialize->handler();
|
||||
} catch (\Throwable $exception) {
|
||||
$finish['status'] = 'error';
|
||||
$finish['info'] = $this->format($exception);
|
||||
$this->error($exception, 'Task');
|
||||
} finally {
|
||||
$event = Snowflake::get()->event;
|
||||
$event->trigger(Event::RELEASE_ALL);
|
||||
|
||||
$this->endCoroutine();
|
||||
Timer::clearAll();
|
||||
}
|
||||
return $finish;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @return ITask|null
|
||||
*/
|
||||
protected function before($data)
|
||||
{
|
||||
if (empty($serialize = unserialize($data))) {
|
||||
return null;
|
||||
}
|
||||
if (!($serialize instanceof ITask)) {
|
||||
return null;
|
||||
}
|
||||
return $serialize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $exception
|
||||
* @return string
|
||||
*/
|
||||
private function format($exception)
|
||||
{
|
||||
return $exception->getMessage() . " on line " . $exception->getLine() . " at file " . $exception->getFile();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Events\Trigger;
|
||||
|
||||
|
||||
use HttpServer\Events\Callback;
|
||||
|
||||
class OnWorkerError extends Callback
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $server
|
||||
* @param $worker_id
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function onHandler($server, $worker_id)
|
||||
{
|
||||
$this->clear($server, $worker_id, self::EVENT_ERROR);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Events\Trigger;
|
||||
|
||||
|
||||
use HttpServer\Events\Callback;
|
||||
|
||||
class OnWorkerExit extends Callback
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $server
|
||||
* @param $worker_id
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function onHandler($server, $worker_id)
|
||||
{
|
||||
$this->clear($server, $worker_id, self::EVENT_EXIT);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Events\Trigger;
|
||||
|
||||
|
||||
use Exception;
|
||||
use HttpServer\Events\Callback;
|
||||
use Snowflake\Error\Logger;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Server;
|
||||
|
||||
/**
|
||||
* Class OnWorkerStart
|
||||
* @package HttpServer\Events\Trigger
|
||||
*/
|
||||
class OnWorkerStart extends Callback
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param Server $server
|
||||
* @param int $worker_id
|
||||
*
|
||||
* @return mixed|void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onHandler(Server $server, $worker_id)
|
||||
{
|
||||
Logger::$worker_id = $worker_id;
|
||||
|
||||
Snowflake::setProcessId($server->worker_pid);
|
||||
|
||||
$get_name = $this->get_process_name($server, $worker_id);
|
||||
if (!empty($get_name) && !Snowflake::isMac()) {
|
||||
swoole_set_process_name($get_name);
|
||||
}
|
||||
$this->setWorkerAction($server, $worker_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $worker_id
|
||||
* @param $socket
|
||||
* @throws Exception
|
||||
*/
|
||||
private function setWorkerAction($socket, $worker_id)
|
||||
{
|
||||
try {
|
||||
$event = Snowflake::get()->event;
|
||||
if ($event->exists(Event::SERVER_WORKER_START)) {
|
||||
$event->trigger(Event::SERVER_WORKER_START);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
Logger::write($exception->getMessage(), 'worker');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $socket
|
||||
* @param $worker_id
|
||||
* @return string
|
||||
*/
|
||||
private function get_process_name($socket, $worker_id)
|
||||
{
|
||||
$prefix = 'system:';
|
||||
if ($worker_id >= $socket->setting['worker_num']) {
|
||||
return $prefix . ': Task: No.' . $worker_id;
|
||||
} else {
|
||||
return $prefix . ': worker: No.' . $worker_id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Events\Trigger;
|
||||
|
||||
|
||||
use HttpServer\Events\Callback;
|
||||
|
||||
class OnWorkerStop extends Callback
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param $server
|
||||
* @param $worker_id
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function onHandler($server, $worker_id)
|
||||
{
|
||||
$this->clear($server, $worker_id, self::EVENT_STOP);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/11/8 0008
|
||||
* Time: 18:15
|
||||
*/
|
||||
|
||||
namespace HttpServer\Events;
|
||||
|
||||
use BeReborn;
|
||||
use Exception;
|
||||
use HttpServer\ServerManager;
|
||||
use Snowflake\Error\Logger;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Exception\NotFindClassException;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Http\Request as SRequest;
|
||||
use Swoole\Http\Response as SResponse;
|
||||
use Swoole\WebSocket\Frame;
|
||||
use Swoole\WebSocket\Server;
|
||||
|
||||
/**
|
||||
* Class ServerWebSocket
|
||||
* @package BeReborn\Server
|
||||
*/
|
||||
class WebSocket extends Server
|
||||
{
|
||||
public $namespace = 'App\\Sockets\\';
|
||||
|
||||
public $callback = [];
|
||||
|
||||
|
||||
public $application;
|
||||
|
||||
|
||||
/**
|
||||
* WebSocket constructor.
|
||||
* @param $application
|
||||
* @param $host
|
||||
* @param null $port
|
||||
* @param null $mode
|
||||
* @param null $sock_type
|
||||
*/
|
||||
public function __construct($application, $host, $port = null, $mode = null, $sock_type = null)
|
||||
{
|
||||
$this->application = $application;
|
||||
parent::__construct($host, $port, $mode, $sock_type);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $settings
|
||||
* @param array $events
|
||||
* @param $config
|
||||
* @return mixed|void
|
||||
* @throws \ReflectionException
|
||||
* @throws NotFindClassException
|
||||
*/
|
||||
public function set(array $settings, $events = [], $config = [])
|
||||
{
|
||||
parent::set($settings);
|
||||
ServerManager::set($this, $settings, $this->application, $events, $config);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Server $server
|
||||
* @param Frame $frame
|
||||
* @throws
|
||||
*/
|
||||
public function onMessage(Server $server, Frame $frame)
|
||||
{
|
||||
try {
|
||||
$event = Snowflake::get()->event;
|
||||
if ($event->exists(Event::SERVER_MESSAGE)) {
|
||||
$event->trigger(Event::SERVER_MESSAGE, [$server, $frame]);
|
||||
return;
|
||||
}
|
||||
if ($frame->opcode == 0x08) {
|
||||
return;
|
||||
}
|
||||
$json = json_decode($frame->data, true);
|
||||
|
||||
$manager = Snowflake::get()->annotation;
|
||||
$manager->runWith($this->getName($json), [$frame->fd, $server]);
|
||||
} catch (Exception $exception) {
|
||||
// $this->error($exception->getMessage(), __METHOD__, __FILE__);
|
||||
// $this->addError($exception->getMessage());
|
||||
} finally {
|
||||
$event = Snowflake::get()->event;
|
||||
$event->trigger(Event::EVENT_AFTER_REQUEST);
|
||||
Logger::insert();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $json
|
||||
* @return string
|
||||
*/
|
||||
private function getName($json)
|
||||
{
|
||||
return 'WEBSOCKET:MESSAGE:' . $json['route'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SRequest $request
|
||||
* @param SResponse $response
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function connect($request, $response)
|
||||
{
|
||||
$manager = Snowflake::get()->event;
|
||||
if ($manager->exists(Event::SERVER_HANDSHAKE)) {
|
||||
return $manager->trigger(Event::SERVER_HANDSHAKE, [$request, $response]);
|
||||
}
|
||||
$response->status(502);
|
||||
$response->end();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SRequest $request
|
||||
* @param SResponse $response
|
||||
* @return bool|string
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onHandshake(SRequest $request, SResponse $response)
|
||||
{
|
||||
/** @var Server $server */
|
||||
$secWebSocketKey = $request->header['sec-websocket-key'];
|
||||
$patten = '#^[+/0-9A-Za-z]{21}[AQgw]==$#';
|
||||
if (0 === preg_match($patten, $secWebSocketKey) || 16 !== strlen(base64_decode($secWebSocketKey))) {
|
||||
return false;
|
||||
}
|
||||
$key = base64_encode(sha1(
|
||||
$request->header['sec-websocket-key'] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',
|
||||
TRUE
|
||||
));
|
||||
$headers = [
|
||||
'Upgrade' => 'websocket',
|
||||
'Connection' => 'Upgrade',
|
||||
'Sec-websocket-Accept' => $key,
|
||||
'Sec-websocket-Version' => '13',
|
||||
];
|
||||
if (isset($request->header['sec-websocket-protocol'])) {
|
||||
$headers['Sec-websocket-Protocol'] = $request->header['sec-websocket-protocol'];
|
||||
}
|
||||
foreach ($headers as $key => $val) {
|
||||
$response->header($key, $val);
|
||||
}
|
||||
if (isset($request->get['debug']) && $request->get['debug'] == 'test') {
|
||||
$response->status(101);
|
||||
$response->end();
|
||||
return true;
|
||||
} else {
|
||||
return $this->connect($request, $response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Server $server
|
||||
* @param int $fd
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onClose(Server $server, int $fd)
|
||||
{
|
||||
$event = Snowflake::get()->event;
|
||||
try {
|
||||
if ($event->exists(Event::SERVER_CLOSE)) {
|
||||
$event->trigger(Event::SERVER_CLOSE, [$fd]);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
// $this->addError($exception->getMessage());
|
||||
} finally {
|
||||
$event->trigger(Event::RELEASE_ALL);
|
||||
Logger::insert();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/5/25 0025
|
||||
* Time: 10:14
|
||||
*/
|
||||
|
||||
namespace HttpServer\Exception;
|
||||
|
||||
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Class AuthException
|
||||
* @package BeReborn\Exception
|
||||
*/
|
||||
class AuthException extends \Exception
|
||||
{
|
||||
|
||||
public function __construct($message = "", $code = 0, Throwable $previous = NULL)
|
||||
{
|
||||
parent::__construct($message, 7000, $previous);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Exception;
|
||||
|
||||
|
||||
class RequestException extends \Exception
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Http;
|
||||
|
||||
use HttpServer\Abstracts\BaseContext;
|
||||
use Swoole\Coroutine;
|
||||
|
||||
/**
|
||||
* Class Context
|
||||
* @package Yoc\http
|
||||
*/
|
||||
class Context extends BaseContext
|
||||
{
|
||||
|
||||
protected static $_requests = [];
|
||||
|
||||
protected static $_response = [];
|
||||
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param $context
|
||||
* @param null $key
|
||||
* @return mixed
|
||||
*/
|
||||
public static function setContext($id, $context, $key = null)
|
||||
{
|
||||
if (static::inCoroutine()) {
|
||||
return self::setCoroutine($id, $context, $key);
|
||||
} else {
|
||||
return self::setStatic($id, $context, $key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param $context
|
||||
* @param null $key
|
||||
* @return mixed
|
||||
*/
|
||||
private static function setStatic($id, $context, $key = null)
|
||||
{
|
||||
if (!empty($key)) {
|
||||
if (!is_array(static::$_requests[$id])) {
|
||||
static::$_requests[$id] = [$key => $context];
|
||||
} else {
|
||||
static::$_requests[$id][$key] = $context;
|
||||
}
|
||||
} else {
|
||||
static::$_requests[$id] = $context;
|
||||
}
|
||||
return $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param $context
|
||||
* @param null $key
|
||||
* @return
|
||||
*/
|
||||
private static function setCoroutine($id, $context, $key = null)
|
||||
{
|
||||
if (!static::hasContext($id)) {
|
||||
Coroutine::getContext()[$id] = [];
|
||||
}
|
||||
if (!empty($key)) {
|
||||
if (!is_array(Coroutine::getContext()[$id])) {
|
||||
Coroutine::getContext()[$id] = [$key => $context];
|
||||
} else {
|
||||
Coroutine::getContext()[$id][$key] = $context;
|
||||
}
|
||||
} else {
|
||||
Coroutine::getContext()[$id] = $context;
|
||||
}
|
||||
return $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param null $key
|
||||
* @return false|mixed
|
||||
*/
|
||||
public static function autoIncr($id, $key = null)
|
||||
{
|
||||
if (!static::inCoroutine()) {
|
||||
return false;
|
||||
}
|
||||
if (!isset(Coroutine::getContext()[$id][$key])) {
|
||||
return false;
|
||||
}
|
||||
return Coroutine::getContext()[$id][$key] += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param null $key
|
||||
* @return false|mixed
|
||||
*/
|
||||
public static function autoDecr($id, $key = null)
|
||||
{
|
||||
if (!static::inCoroutine()) {
|
||||
return false;
|
||||
}
|
||||
if (!isset(Coroutine::getContext()[$id][$key])) {
|
||||
return false;
|
||||
}
|
||||
return Coroutine::getContext()[$id][$key] -= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param null $key
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getContext($id, $key = null)
|
||||
{
|
||||
if (static::inCoroutine()) {
|
||||
$array = Coroutine::getContext()[$id] ?? null;
|
||||
} else {
|
||||
$array = static::$_requests[$id] ?? null;
|
||||
}
|
||||
if (empty($key) || !is_array($array)) {
|
||||
return $array;
|
||||
}
|
||||
return $array[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getAllContext()
|
||||
{
|
||||
if (static::inCoroutine()) {
|
||||
return Coroutine::getContext() ?? [];
|
||||
} else {
|
||||
return static::$_requests ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param null $key
|
||||
*/
|
||||
public static function deleteId($id, $key = null)
|
||||
{
|
||||
if (!static::hasContext($id, $key)) {
|
||||
return;
|
||||
}
|
||||
if (static::inCoroutine()) {
|
||||
if (!empty($key)) {
|
||||
Coroutine::getContext()[$id][$key] = null;
|
||||
} else {
|
||||
Coroutine::getContext()[$id] = null;
|
||||
}
|
||||
} else {
|
||||
unset(static::$_requests[$id]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param null $key
|
||||
* @return mixed
|
||||
*/
|
||||
public static function hasContext($id, $key = null)
|
||||
{
|
||||
if (static::inCoroutine()) {
|
||||
$data = Coroutine::getContext()[$id] ?? null;
|
||||
} else {
|
||||
$data = static::$_requests[$id] ?? null;
|
||||
}
|
||||
if (empty($data)) {
|
||||
return false;
|
||||
}
|
||||
if (empty($key)) {
|
||||
return true;
|
||||
} else if (!is_array($data)) {
|
||||
return false;
|
||||
}
|
||||
return isset($data[$key]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function inCoroutine()
|
||||
{
|
||||
return Coroutine::getCid() > 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Http;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class File
|
||||
* @package BeReborn\Http
|
||||
*/
|
||||
class File
|
||||
{
|
||||
|
||||
public $name = '';
|
||||
public $tmp_name = '';
|
||||
public $error = '';
|
||||
public $type = '';
|
||||
public $size = '';
|
||||
|
||||
private $newName = '';
|
||||
private $errorInfo = [
|
||||
0 => 'UPLOAD_ERR_OK.',
|
||||
1 => 'The uploaded file exceeds the upload_max_filesize directive in php.ini.',
|
||||
2 => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.',
|
||||
3 => 'The uploaded file was only partially uploaded.',
|
||||
4 => 'No file was uploaded.',
|
||||
6 => 'Missing a temporary folder.',
|
||||
7 => 'Failed to write file to disk.',
|
||||
8 => 'A PHP extension stopped the file upload.'
|
||||
];
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function saveTo(string $path)
|
||||
{
|
||||
if ($this->hasError()) {
|
||||
throw new Exception($this->getErrorInfo());
|
||||
}
|
||||
|
||||
@move_uploaded_file($this->tmp_name, $path);
|
||||
if (!file_exists($path)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function rename()
|
||||
{
|
||||
if (!empty($this->newName)) {
|
||||
return $this->newName;
|
||||
}
|
||||
$param = ['tmp_name' => $this->getTmpPath()];
|
||||
$this->newName = \BeReborn::rename($param);
|
||||
return $this->newName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTmpPath()
|
||||
{
|
||||
return $this->tmp_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*
|
||||
* check file have error
|
||||
*/
|
||||
public function hasError()
|
||||
{
|
||||
return $this->error !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*
|
||||
* get upload error info
|
||||
*/
|
||||
public function getErrorInfo()
|
||||
{
|
||||
if (!isset($this->errorInfo[$this->error])) {
|
||||
return 'Unknown upload error.';
|
||||
}
|
||||
return $this->errorInfo[$this->error];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/4/8 0008
|
||||
* Time: 17:51
|
||||
*/
|
||||
|
||||
namespace HttpServer\Http\Formatter;
|
||||
|
||||
|
||||
use BeReborn\Core\JSON;
|
||||
use HttpServer\Application;
|
||||
use Swoole\Http\Response;
|
||||
use HttpServer\IInterface\IFormatter;
|
||||
|
||||
/**
|
||||
* Class HtmlFormatter
|
||||
* @package BeReborn\Http\Formatter
|
||||
*/
|
||||
class HtmlFormatter extends Application implements IFormatter
|
||||
{
|
||||
|
||||
public $data;
|
||||
|
||||
/** @var Response */
|
||||
public $status;
|
||||
|
||||
public $header = [];
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @return $this
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function send($data)
|
||||
{
|
||||
if (!is_string($data)) {
|
||||
$data = JSON::encode($data);
|
||||
}
|
||||
$this->data = $data;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
$data = $this->data;
|
||||
$this->clear();
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function clear()
|
||||
{
|
||||
unset($this->data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/4/8 0008
|
||||
* Time: 17:18
|
||||
*/
|
||||
|
||||
namespace HttpServer\Http\Formatter;
|
||||
|
||||
use Exception;
|
||||
use HttpServer\Application;
|
||||
use HttpServer\IInterface\IFormatter;
|
||||
|
||||
/**
|
||||
* Class JsonFormatter
|
||||
* @package BeReborn\Http\Formatter
|
||||
*/
|
||||
class JsonFormatter extends Application implements IFormatter
|
||||
{
|
||||
public $data;
|
||||
|
||||
public $status = 200;
|
||||
|
||||
public $header = [];
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @return $this|IFormatter
|
||||
* @throws Exception
|
||||
*/
|
||||
public function send($data)
|
||||
{
|
||||
if (!is_string($data)) {
|
||||
$data = json_encode($data);
|
||||
}
|
||||
$this->data = $data;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
$data = $this->data;
|
||||
$this->clear();
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
public function clear()
|
||||
{
|
||||
unset($this->data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/4/8 0008
|
||||
* Time: 17:29
|
||||
*/
|
||||
|
||||
namespace HttpServer\Http\Formatter;
|
||||
|
||||
|
||||
use HttpServer\Application;
|
||||
use SimpleXMLElement;
|
||||
use Swoole\Http\Response;
|
||||
use HttpServer\IInterface\IFormatter;
|
||||
|
||||
|
||||
/**
|
||||
* Class XmlFormatter
|
||||
* @package BeReborn\Http\Formatter
|
||||
*/
|
||||
class XmlFormatter extends Application implements IFormatter
|
||||
{
|
||||
|
||||
public $data = '';
|
||||
|
||||
/** @var Response */
|
||||
public $status;
|
||||
|
||||
public $header = [];
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @return $this
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function send($data)
|
||||
{
|
||||
if (!is_string($data)) {
|
||||
// TODO: Implement send() method.
|
||||
$dom = new SimpleXMLElement('<xml/>');
|
||||
|
||||
$this->toXml($dom, $data);
|
||||
|
||||
$this->data = $dom->saveXML();
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
$data = $this->data;
|
||||
$this->clear();
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SimpleXMLElement $dom
|
||||
* @param $data
|
||||
*/
|
||||
public function toXml($dom, $data)
|
||||
{
|
||||
foreach ($data as $key => $val) {
|
||||
if (is_numeric($key)) {
|
||||
$key = 'item' . $key;
|
||||
}
|
||||
if (is_array($val)) {
|
||||
$node = $dom->addChild($key);
|
||||
$this->toXml($node, $val);
|
||||
} else if (is_object($val)) {
|
||||
$val = get_object_vars($val);
|
||||
$node = $dom->addChild($key);
|
||||
$this->toXml($node, $val);
|
||||
} else {
|
||||
$dom->addChild($key, htmlspecialchars($val));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function clear()
|
||||
{
|
||||
unset($this->data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: admin
|
||||
* Date: 2019-03-18
|
||||
* Time: 14:54
|
||||
*/
|
||||
|
||||
namespace HttpServer\Http;
|
||||
|
||||
/**
|
||||
* Class HttpHeaders
|
||||
* @package BeReborn\Http
|
||||
*/
|
||||
class HttpHeaders
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private $headers = [];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private $response = [];
|
||||
|
||||
/**
|
||||
* HttpHeaders constructor.
|
||||
* @param $headers
|
||||
*/
|
||||
public function __construct($headers)
|
||||
{
|
||||
$this->headers = $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $value
|
||||
*/
|
||||
public function setHeader($name, $value)
|
||||
{
|
||||
$this->response[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $headers
|
||||
*/
|
||||
public function setHeaders(array $headers)
|
||||
{
|
||||
foreach ($headers as $key => $val) {
|
||||
$this->response[$key] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $value
|
||||
*/
|
||||
public function replace($name, $value)
|
||||
{
|
||||
$this->headers[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $value
|
||||
*/
|
||||
public function addHeader($name, $value)
|
||||
{
|
||||
$this->headers[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $headers
|
||||
* @return $this
|
||||
*/
|
||||
public function addHeaders(array $headers)
|
||||
{
|
||||
if (empty($headers)) {
|
||||
return $this;
|
||||
}
|
||||
if (!empty($this->headers)) {
|
||||
$headers = array_merge($this->headers, $headers);
|
||||
}
|
||||
$this->headers = $headers;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getResponseHeaders()
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function getHeader($name)
|
||||
{
|
||||
return $this->headers[$name] ?? null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return mixed|string|null
|
||||
*/
|
||||
public function get($name)
|
||||
{
|
||||
return $this->getHeader($name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return bool
|
||||
*/
|
||||
public function exists($name)
|
||||
{
|
||||
return isset($this->headers[$name]) && $this->headers[$name] != null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getHeaders()
|
||||
{
|
||||
return $this->headers;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,404 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: admin
|
||||
* Date: 2019-03-18
|
||||
* Time: 14:54
|
||||
*/
|
||||
|
||||
namespace HttpServer\Http;
|
||||
|
||||
use BeReborn\Core\JSON;
|
||||
use Exception;
|
||||
use HttpServer\Exception\RequestException;
|
||||
|
||||
/**
|
||||
* Class HttpParams
|
||||
* @package BeReborn\Http
|
||||
*/
|
||||
class HttpParams
|
||||
{
|
||||
|
||||
/** @var array */
|
||||
private $body = [];
|
||||
|
||||
/** @var array */
|
||||
private $gets = [];
|
||||
|
||||
/** @var array */
|
||||
private $files = [];
|
||||
|
||||
/**
|
||||
* HttpParams constructor.
|
||||
* @param $body
|
||||
* @param $get
|
||||
* @param $files
|
||||
*/
|
||||
public function __construct($body, $get, $files)
|
||||
{
|
||||
$this->body = $body;
|
||||
$this->gets = $get ?? [];
|
||||
$this->files = $files ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function offset()
|
||||
{
|
||||
return ($this->page() - 1) * $this->size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* 批量添加数据
|
||||
*/
|
||||
public function setPosts($data)
|
||||
{
|
||||
if (!is_array($data)) {
|
||||
return;
|
||||
}
|
||||
foreach ($data as $key => $vla) {
|
||||
$this->body[$key] = $vla;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
*/
|
||||
public function addGetParam(string $key, string $value)
|
||||
{
|
||||
$this->gets[$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
private function page()
|
||||
{
|
||||
return (int)$this->get('page', 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function size()
|
||||
{
|
||||
return (int)$this->get('size', 20);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $defaultValue
|
||||
* @param $call
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function get($name, $defaultValue = null, $call = null)
|
||||
{
|
||||
return $this->gets[$name] ?? $defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $defaultValue
|
||||
* @param $call
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function post($name, $defaultValue = null, $call = null)
|
||||
{
|
||||
$data = $this->body[$name] ?? $defaultValue;
|
||||
if ($call !== null) {
|
||||
$data = call_user_func($call, $data);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return false|string
|
||||
* @throws Exception
|
||||
*/
|
||||
public function json($name)
|
||||
{
|
||||
$data = $this->array($name);
|
||||
if (empty($data)) {
|
||||
return JSON::encode([]);
|
||||
} else if (!is_array($data)) {
|
||||
return JSON::encode([]);
|
||||
}
|
||||
return JSON::encode($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function gets()
|
||||
{
|
||||
return $this->gets;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function params()
|
||||
{
|
||||
return array_merge($this->body ?? [], $this->files ?? []);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function load()
|
||||
{
|
||||
return array_merge($this->files, $this->body, $this->gets);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param array $defaultValue
|
||||
* @return array|mixed
|
||||
*/
|
||||
public function array($name, $defaultValue = [])
|
||||
{
|
||||
return $this->body[$name] ?? $defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return mixed|File|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function file($name)
|
||||
{
|
||||
if (!isset($this->files[$name])) {
|
||||
return null;
|
||||
}
|
||||
$param = $this->files[$name];
|
||||
$param['class'] = File::class;
|
||||
return \BeReborn::createObject($param);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param bool $isNeed
|
||||
* @return mixed|null
|
||||
* @throws RequestException
|
||||
*/
|
||||
private function required($name, $isNeed = false)
|
||||
{
|
||||
$int = $this->body[$name] ?? NULL;
|
||||
if (is_null($int) && $isNeed === true) {
|
||||
throw new RequestException("You need to add request parameter $name");
|
||||
}
|
||||
return $int;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param bool $isNeed
|
||||
* @param null $min
|
||||
* @param null $max
|
||||
* @return int
|
||||
* @throws Exception
|
||||
*/
|
||||
public function int($name, $isNeed = FALSE, $min = NULL, $max = NULL)
|
||||
{
|
||||
$int = $this->required($name, $isNeed);
|
||||
if ($int === null) return null;
|
||||
if (is_array($min)) {
|
||||
list($min, $max) = $min;
|
||||
}
|
||||
if (is_null($int)) {
|
||||
$length = 0;
|
||||
} else {
|
||||
$length = strlen(floatval($int));
|
||||
}
|
||||
if (!is_numeric($int) || intval($int) != $int) {
|
||||
throw new RequestException("The request parameter $name must integer.");
|
||||
}
|
||||
$this->between($length, $min, $max);
|
||||
return (int)$int;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param bool $isNeed
|
||||
* @param int $round
|
||||
* @return float
|
||||
* @throws Exception
|
||||
*/
|
||||
public function float($name, $isNeed = FALSE, $round = 0)
|
||||
{
|
||||
$int = $this->required($name, $isNeed);
|
||||
if ($int === null) {
|
||||
return null;
|
||||
}
|
||||
if ($round > 0) {
|
||||
return round(floatval($int), $round);
|
||||
} else {
|
||||
return floatval($int);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param bool $isNeed
|
||||
* @param null $length
|
||||
*
|
||||
* @return string
|
||||
* @throws
|
||||
*/
|
||||
public function string($name, $isNeed = FALSE, $length = NULL)
|
||||
{
|
||||
$string = $this->required($name, $isNeed);
|
||||
if ($string === null || $length === null) {
|
||||
return $string;
|
||||
}
|
||||
if (!is_string($string)) {
|
||||
$string = json_encode($string, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
$_length = strlen($string);
|
||||
if (is_array($length)) {
|
||||
if (count($length) < 2) {
|
||||
array_unshift($length, 0);
|
||||
}
|
||||
$this->between($_length, ...$length);
|
||||
} else if (is_numeric($length) && $_length != $length) {
|
||||
throw new RequestException("The length of the string must be $length characters");
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $_length
|
||||
* @param $min
|
||||
* @param $max
|
||||
* @throws RequestException
|
||||
*/
|
||||
private function between($_length, $min, $max)
|
||||
{
|
||||
if ($min !== NULL && $_length < $min) {
|
||||
throw new RequestException("The minimum value cannot be lower than $min");
|
||||
}
|
||||
if ($max !== NULL && $_length > $max) {
|
||||
throw new RequestException("Maximum cannot exceed $max, has length " . $_length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param bool $isNeed
|
||||
*
|
||||
* @return string
|
||||
* @throws RequestException
|
||||
*/
|
||||
public function email($name, $isNeed = FALSE)
|
||||
{
|
||||
$email = $this->required($name, $isNeed);
|
||||
if ($email === null) {
|
||||
return null;
|
||||
}
|
||||
if (!preg_match('/^\w+([.-_]\w+)+@\w+(\.\w+)+$/', $email)) {
|
||||
throw new RequestException("Request parameter $name is in the wrong format", 4001);
|
||||
}
|
||||
return $email;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param bool $isNeed
|
||||
*
|
||||
* @return string
|
||||
* @throws RequestException
|
||||
*/
|
||||
public function bool($name, $isNeed = FALSE)
|
||||
{
|
||||
$email = $this->required($name, $isNeed);
|
||||
if ($email === null) {
|
||||
return false;
|
||||
}
|
||||
return (bool)$email;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $default
|
||||
*
|
||||
* @return mixed|null
|
||||
* @throws RequestException
|
||||
*/
|
||||
public function timestamp($name, $default = NULL)
|
||||
{
|
||||
$value = $this->required($name, false);
|
||||
if ($value === null) {
|
||||
return $default;
|
||||
}
|
||||
if (!is_numeric($value)) {
|
||||
throw new RequestException('The request param :attribute not is a timestamp value');
|
||||
}
|
||||
if (strlen((string)$value) != 10) {
|
||||
throw new RequestException('The request param :attribute not is a timestamp value');
|
||||
}
|
||||
if (!date('YmdHis', $value)) {
|
||||
throw new RequestException('The request param :attribute format error', 4001);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $default
|
||||
*
|
||||
* @return mixed|null
|
||||
* @throws RequestException
|
||||
*/
|
||||
public function datetime($name, $default = NULL)
|
||||
{
|
||||
$value = $this->required($name, false);
|
||||
if ($value === null) {
|
||||
return $default;
|
||||
}
|
||||
$match = '/^\d{4}.*?([1-12]).*([1-31]).*?[0-23].*?[0-59].*?[0-59].*?$/';
|
||||
$match = preg_match($match, $value, $result);
|
||||
if (!$match || $result[0] != $value) {
|
||||
throw new RequestException('The request param :attribute format error', 4001);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $default
|
||||
* @return mixed|null
|
||||
* @throws RequestException
|
||||
*/
|
||||
public function ip($name, $default = NULL)
|
||||
{
|
||||
$value = $this->required($name, false);
|
||||
if ($value == NULL) {
|
||||
return $default;
|
||||
}
|
||||
$match = preg_match('/^\d{1,3}(\.\d{1,3}){3}$/', $value, $result);
|
||||
if (!$match || $result[0] != $value) {
|
||||
throw new RequestException('The request param :attribute format error', 4001);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
$load = $this->load();
|
||||
|
||||
return $load[$name] ?? null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,424 @@
|
||||
<?php
|
||||
|
||||
namespace HttpServer\Http;
|
||||
|
||||
use Snowflake\Core\Help;
|
||||
use Exception;
|
||||
use HttpServer\Application;
|
||||
use HttpServer\IInterface\AuthIdentity;
|
||||
|
||||
defined('REQUEST_OK') or define('REQUEST_OK', 0);
|
||||
defined('REQUEST_FAIL') or define('REQUEST_FAIL', 500);
|
||||
|
||||
/**
|
||||
* Class HttpRequest
|
||||
*
|
||||
* @package BeReborn\HttpRequest
|
||||
*
|
||||
* @property-read $isPost
|
||||
* @property-read $isGet
|
||||
* @property-read $isOption
|
||||
* @property-read $isDelete
|
||||
* @property-read $isHttp
|
||||
* @property-read $method
|
||||
* @property-read $identity
|
||||
* @property-read $isPackage
|
||||
* @property-read $isReceive
|
||||
*/
|
||||
class Request extends Application
|
||||
{
|
||||
|
||||
/** @var int $fd */
|
||||
public $fd = 0;
|
||||
|
||||
/** @var HttpParams */
|
||||
public $params;
|
||||
|
||||
/** @var HttpHeaders */
|
||||
public $headers;
|
||||
|
||||
/** @var bool */
|
||||
public $isCli = FALSE;
|
||||
|
||||
/** @var float */
|
||||
public $startTime;
|
||||
|
||||
public $uri = '';
|
||||
|
||||
public $statusCode = 200;
|
||||
|
||||
/** @var string[] */
|
||||
private $explode = [];
|
||||
|
||||
const PLATFORM_MAC_OX = 'mac';
|
||||
const PLATFORM_IPHONE = 'iphone';
|
||||
const PLATFORM_ANDROID = 'android';
|
||||
const PLATFORM_WINDOWS = 'windows';
|
||||
|
||||
|
||||
/**
|
||||
* @var AuthIdentity|null
|
||||
*/
|
||||
private $_grant = null;
|
||||
|
||||
|
||||
/**
|
||||
* @param $fd
|
||||
*/
|
||||
public function setFd($fd)
|
||||
{
|
||||
$this->fd = $fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isFavicon()
|
||||
{
|
||||
return $this->getUri() === 'favicon.ico';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getIdentity()
|
||||
{
|
||||
return $this->_grant;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isHead()
|
||||
{
|
||||
$result = $this->headers->getHeader('request_method') == 'head';
|
||||
if ($result) {
|
||||
$this->setStatus(101);
|
||||
} else {
|
||||
$this->setStatus(200);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $status
|
||||
* @return mixed
|
||||
*/
|
||||
public function setStatus($status)
|
||||
{
|
||||
return $this->statusCode = $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getStatus()
|
||||
{
|
||||
return $this->statusCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getIsPackage()
|
||||
{
|
||||
return $this->headers->getHeader('request_method') == 'package';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getIsReceive()
|
||||
{
|
||||
return $this->headers->getHeader('request_method') == 'receive';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
*/
|
||||
public function setGrantAuthorization($value)
|
||||
{
|
||||
$this->_grant = $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hasGrant()
|
||||
{
|
||||
return $this->_grant !== null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function parseUri()
|
||||
{
|
||||
$array = [];
|
||||
$explode = explode('/', $this->headers->getHeader('request_uri'));
|
||||
foreach ($explode as $item) {
|
||||
if (empty($item)) {
|
||||
continue;
|
||||
}
|
||||
$array[] = $item;
|
||||
}
|
||||
return $this->uri = implode('/', ($this->explode = $array));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getExplode()
|
||||
{
|
||||
return $this->explode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed|string
|
||||
*/
|
||||
public function getCurrent()
|
||||
{
|
||||
return current($this->explode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getUri()
|
||||
{
|
||||
if (!$this->headers) {
|
||||
return 'command exec.';
|
||||
}
|
||||
if (!empty($this->uri)) {
|
||||
return $this->uri;
|
||||
}
|
||||
$uri = $this->headers->getHeader('request_uri');
|
||||
$uri = ltrim($uri, '/');
|
||||
if (empty($uri)) return '/';
|
||||
return $uri;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return mixed|string
|
||||
* @throws Exception
|
||||
*/
|
||||
public function adapter()
|
||||
{
|
||||
if (!$this->isHead()) {
|
||||
return router()->runHandler();
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getPlatform()
|
||||
{
|
||||
$user = $this->headers->getHeader('user-agent');
|
||||
$match = preg_match('/\(.*\)?/', $user, $output);
|
||||
if (!$match || count($output) < 1) {
|
||||
return null;
|
||||
}
|
||||
$output = strtolower(array_shift($output));
|
||||
if (strpos('mac', $output)) {
|
||||
return 'mac';
|
||||
} else if (strpos('iphone', $output)) {
|
||||
return 'iphone';
|
||||
} else if (strpos('android', $output)) {
|
||||
return 'android';
|
||||
} else if (strpos('windows', $output)) {
|
||||
return 'windows';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isIos()
|
||||
{
|
||||
return $this->getPlatform() == static::PLATFORM_IPHONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isAndroid()
|
||||
{
|
||||
return $this->getPlatform() == static::PLATFORM_ANDROID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isMacOs()
|
||||
{
|
||||
return $this->getPlatform() == static::PLATFORM_MAC_OX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isWindows()
|
||||
{
|
||||
return $this->getPlatform() == static::PLATFORM_WINDOWS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getIsPost()
|
||||
{
|
||||
return $this->getMethod() == 'post';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getIsHttp()
|
||||
{
|
||||
if (!app()->has('socket')) {
|
||||
return false;
|
||||
}
|
||||
$socket = \BeReborn::$app->getSocket()->getServer();
|
||||
if (empty($this->fd)) {
|
||||
return false;
|
||||
}
|
||||
return $socket->exist($this->fd) && !$socket->isEstablished($this->fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getIsOption()
|
||||
{
|
||||
return $this->getMethod() == 'options';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getIsGet()
|
||||
{
|
||||
return $this->getMethod() == 'get';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getIsDelete()
|
||||
{
|
||||
return $this->getMethod() == 'delete';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* 获取请求类型
|
||||
*/
|
||||
public function getMethod()
|
||||
{
|
||||
$head = $this->headers->getHeader('request_method');
|
||||
return strtolower($head);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getIsCli()
|
||||
{
|
||||
return $this->isCli === TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $value
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
$method = 'set' . ucfirst($name);
|
||||
if (method_exists($this, $method)) {
|
||||
$this->$method($value);
|
||||
} else {
|
||||
parent::__set($name, $value); // TODO: Change the autogenerated stub
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function getIp()
|
||||
{
|
||||
$headers = $this->headers->getHeaders();
|
||||
if (!empty($headers['x-forwarded-for'])) return $headers['x-forwarded-for'];
|
||||
if (!empty($headers['request-ip'])) return $headers['request-ip'];
|
||||
if (!empty($headers['remote_addr'])) return $headers['remote_addr'];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getRuntime()
|
||||
{
|
||||
return sprintf('%.5f', microtime(TRUE) - $this->startTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDebug()
|
||||
{
|
||||
$mainstay = sprintf("%.6f", microtime(true)); // 带毫秒的时间戳
|
||||
|
||||
$timestamp = floor($mainstay); // 时间戳
|
||||
$milliseconds = round(($mainstay - $timestamp) * 1000); // 毫秒
|
||||
|
||||
$datetime = date("Y-m-d H:i:s", $timestamp) . '.' . $milliseconds;
|
||||
|
||||
$tmp = [
|
||||
'[Debug ' . $datetime . '] ',
|
||||
$this->getIp(),
|
||||
$this->getUri(),
|
||||
'`' . $this->headers->getHeader('user-agent') . '`',
|
||||
$this->getRuntime()
|
||||
];
|
||||
|
||||
return implode(' ', $tmp);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $request
|
||||
* @return Request
|
||||
*/
|
||||
public static function create($request)
|
||||
{
|
||||
$sRequest = new Request();
|
||||
$sRequest->fd = $request->fd;
|
||||
$sRequest->startTime = microtime(true);
|
||||
$sRequest->params = new HttpParams(Help::toArray($request->rawContent()), $request->get, $request->files);
|
||||
if (!empty($request->post)) {
|
||||
$sRequest->params->setPosts($request->post ?? []);
|
||||
}
|
||||
$headers = $request->server;
|
||||
if (!empty($request->header)) {
|
||||
$headers = array_merge($headers, $request->header);
|
||||
}
|
||||
$sRequest->headers = new HttpHeaders($headers);
|
||||
$sRequest->parseUri();
|
||||
return $sRequest;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/4/24 0024
|
||||
* Time: 19:39
|
||||
*/
|
||||
|
||||
namespace HttpServer\Http;
|
||||
|
||||
use HttpServer\Application;
|
||||
use HttpServer\Http\Formatter\HtmlFormatter;
|
||||
use HttpServer\Http\Formatter\JsonFormatter;
|
||||
use HttpServer\Http\Formatter\XmlFormatter;
|
||||
use Exception;
|
||||
use Snowflake\Core\Help;
|
||||
use Snowflake\Exception\ComponentException;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Http\Response as SResponse;
|
||||
|
||||
/**
|
||||
* Class Response
|
||||
* @package BeReborn\Http
|
||||
*/
|
||||
class Response extends Application
|
||||
{
|
||||
|
||||
const JSON = 'json';
|
||||
const XML = 'xml';
|
||||
const HTML = 'html';
|
||||
|
||||
/** @var string */
|
||||
public $format = null;
|
||||
|
||||
/** @var int */
|
||||
public $statusCode = 200;
|
||||
|
||||
/** @var SResponse */
|
||||
public $response;
|
||||
public $isWebSocket = false;
|
||||
public $headers = [];
|
||||
|
||||
private $startTime = 0;
|
||||
|
||||
private $_format_maps = [
|
||||
self::JSON => JsonFormatter::class,
|
||||
self::XML => XmlFormatter::class,
|
||||
self::HTML => HtmlFormatter::class
|
||||
];
|
||||
|
||||
public $fd = 0;
|
||||
|
||||
/**
|
||||
* @param $format
|
||||
* @return $this
|
||||
*/
|
||||
public function setFormat($format)
|
||||
{
|
||||
$this->format = $format;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理无用数据
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->fd = 0;
|
||||
$this->isWebSocket = false;
|
||||
$this->format = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getContentType()
|
||||
{
|
||||
if ($this->format == null || $this->format == static::JSON) {
|
||||
return 'application/json;charset=utf-8';
|
||||
} else if ($this->format == static::XML) {
|
||||
return 'application/xml;charset=utf-8';
|
||||
} else {
|
||||
return 'text/html;charset=utf-8';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function sender()
|
||||
{
|
||||
return $this->send(func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $value
|
||||
*/
|
||||
public function addHeader($key, $value)
|
||||
{
|
||||
$response = Context::getContext('response');
|
||||
$response->header($key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $context
|
||||
* @param int $statusCode
|
||||
* @param null $response
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function send($context = '', $statusCode = 200, $response = null)
|
||||
{
|
||||
$sendData = $this->parseData($context);
|
||||
if ($response instanceof SResponse) {
|
||||
$this->response = $response;
|
||||
}
|
||||
if ($this->response instanceof SResponse) {
|
||||
return $this->sendData($this->response, $sendData, $statusCode);
|
||||
} else {
|
||||
return $this->printResult($sendData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $context
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
private function parseData($context)
|
||||
{
|
||||
if (isset($this->_format_maps[$this->format])) {
|
||||
$config['class'] = $this->_format_maps[$this->format];
|
||||
} else {
|
||||
$config['class'] = HtmlFormatter::class;
|
||||
}
|
||||
$formatter = Snowflake::createObject($config);
|
||||
return $formatter->send($context)->getData();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $result
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
private function printResult($result)
|
||||
{
|
||||
$result = Help::toString($result);
|
||||
|
||||
$string = 'Command Result: ' . PHP_EOL;
|
||||
$string .= empty($result) ? 'success!' : $result . PHP_EOL;
|
||||
$string .= 'Command Success!' . PHP_EOL;
|
||||
echo $string;
|
||||
|
||||
$event = Snowflake::get()->event;
|
||||
$event->trigger('CONSOLE_END');
|
||||
|
||||
return 'ok';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $response
|
||||
* @param $sendData
|
||||
* @param $status
|
||||
* @return mixed
|
||||
*/
|
||||
private function sendData($response, $sendData, $status)
|
||||
{
|
||||
$response->status($status);
|
||||
$response->header('Content-Type', $this->getContentType());
|
||||
$response->header('Access-Control-Allow-Origin', '*');
|
||||
$response->header('Run-Time', $this->getRuntime());
|
||||
return $response->end($sendData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $url
|
||||
* @param array $param
|
||||
* @return int
|
||||
*/
|
||||
public function redirect($url, array $param = [])
|
||||
{
|
||||
if (!empty($param)) {
|
||||
$url .= '?' . http_build_query($param);
|
||||
}
|
||||
$url = ltrim($url, '/');
|
||||
if (!preg_match('/^http/', $url)) {
|
||||
$url = '/' . $url;
|
||||
}
|
||||
return $this->response->redirect($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $response
|
||||
* @return mixed
|
||||
* @throws ComponentException
|
||||
*/
|
||||
public static function create($response = null)
|
||||
{
|
||||
$ciResponse = Snowflake::get()->clone('response');
|
||||
$ciResponse->response = $response;
|
||||
$ciResponse->startTime = microtime(true);
|
||||
$ciResponse->format = self::JSON;
|
||||
return $ciResponse;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function sendNotFind()
|
||||
{
|
||||
$this->format = static::HTML;
|
||||
$this->send('', 404);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getRuntime()
|
||||
{
|
||||
return sprintf('%.5f', microtime(TRUE) - $this->startTime);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\IInterface;
|
||||
|
||||
|
||||
/**
|
||||
* Interface AuthIdentity
|
||||
* @package BeReborn\Http
|
||||
*/
|
||||
interface AuthIdentity
|
||||
{
|
||||
|
||||
|
||||
|
||||
public function getIdentity();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/4/8 0008
|
||||
* Time: 17:29
|
||||
*/
|
||||
|
||||
namespace HttpServer\IInterface;
|
||||
|
||||
|
||||
/**
|
||||
* Interface IFormatter
|
||||
* @package BeReborn\Http\Formatter
|
||||
*/
|
||||
interface IFormatter
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $context
|
||||
* @return static
|
||||
*/
|
||||
public function send($context);
|
||||
|
||||
public function getData();
|
||||
|
||||
public function clear();
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\IInterface;
|
||||
|
||||
|
||||
use HttpServer\Http\Request;
|
||||
|
||||
/**
|
||||
* Interface IMiddleware
|
||||
* @package BeReborn\Route
|
||||
*/
|
||||
interface IMiddleware
|
||||
{
|
||||
|
||||
public function handler(Request $request,\Closure $next);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\IInterface;
|
||||
|
||||
|
||||
interface RouterInterface
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\IInterface;
|
||||
|
||||
|
||||
interface Task
|
||||
{
|
||||
|
||||
public function getParams();
|
||||
|
||||
public function handler();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Route;
|
||||
|
||||
|
||||
/**
|
||||
* Class Any
|
||||
* @package BeReborn\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,39 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Route;
|
||||
|
||||
|
||||
use HttpServer\Http\Request;
|
||||
use HttpServer\Http\Response;
|
||||
use HttpServer\Abstracts\MiddlewareHandler;
|
||||
|
||||
/**
|
||||
* Class CoreMiddleware
|
||||
* @package BeReborn\Route
|
||||
* 跨域中间件
|
||||
*/
|
||||
class CoreMiddleware extends MiddlewareHandler
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function handler(Request $request,\Closure $next)
|
||||
{
|
||||
$header = $request->headers;
|
||||
|
||||
/** @var Response $response */
|
||||
$response = \BeReborn::getApp('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,74 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Route\Dispatch;
|
||||
|
||||
|
||||
use HttpServer\Controller;
|
||||
|
||||
/**
|
||||
* 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()
|
||||
{
|
||||
$this->handler = \Closure::bind($this->handler, new Controller());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 参数绑定
|
||||
*/
|
||||
protected function bindParam()
|
||||
{
|
||||
/** @var Controller $controller */
|
||||
if (is_array($this->handler)) {
|
||||
$controller = $this->handler[0];
|
||||
} else {
|
||||
$controller = $this->handler;
|
||||
}
|
||||
$request = \BeReborn::getApp('request');
|
||||
$controller->setRequest($request);
|
||||
$controller->setHeaders($request->headers);
|
||||
$controller->setInput($request->params);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Class Filter
|
||||
* @package BeReborn\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 = \BeReborn::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 = \BeReborn::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 = \BeReborn::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 BeReborn\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 BeReborn\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 BeReborn\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 BeReborn\Route\Filter
|
||||
*/
|
||||
class QueryFilter extends Filter
|
||||
{
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function check()
|
||||
{
|
||||
return $this->validator();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Route;
|
||||
|
||||
|
||||
use Exception;
|
||||
use HttpServer\Application;
|
||||
|
||||
/**
|
||||
* Class TcpListen
|
||||
* @package BeReborn\Route
|
||||
*/
|
||||
class Handler extends Application
|
||||
{
|
||||
|
||||
/** @var Router */
|
||||
protected $router;
|
||||
|
||||
/**
|
||||
* Listen constructor.
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->router = \BeReborn::$app->getRouter();
|
||||
|
||||
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,69 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Route;
|
||||
|
||||
|
||||
use Exception;
|
||||
use HttpServer\Application;
|
||||
|
||||
/**
|
||||
* Class Limits
|
||||
* @package BeReborn\Route
|
||||
*/
|
||||
class Limits extends Application
|
||||
{
|
||||
|
||||
public $route = [];
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param int $limit
|
||||
* @param int $duration
|
||||
* @param bool $isBindConsumer
|
||||
* @return $this
|
||||
* 设置限流
|
||||
*/
|
||||
public function addLimits(string $path, int $limit, int $duration = 60, bool $isBindConsumer = false)
|
||||
{
|
||||
if ($limit < 0) {
|
||||
$limit = 0;
|
||||
}
|
||||
$this->route[$path] = [$limit, $duration, $isBindConsumer];
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $userId
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*
|
||||
* 判断有没有被限流
|
||||
*/
|
||||
public function isRestrictedCurrent(int $userId = 0)
|
||||
{
|
||||
$path = \request()->getUri();
|
||||
if (!isset($this->route[$path])) {
|
||||
return false;
|
||||
}
|
||||
$redis = \BeReborn::getRedis();
|
||||
[$limit, $duration, $isBindConsumer] = $this->route[$path];
|
||||
if ($limit < 1) {
|
||||
return false;
|
||||
}
|
||||
if ($isBindConsumer && $userId < 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$uri = md5($path) . '_' . $userId;
|
||||
if ($redis->incr($uri) > $limit) {
|
||||
return true;
|
||||
}
|
||||
if ($redis->ttl($uri) == -1) {
|
||||
$redis->expire($uri, $duration);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: admin
|
||||
* Date: 2019-03-20
|
||||
* Time: 02:17
|
||||
*/
|
||||
|
||||
namespace HttpServer\Route;
|
||||
|
||||
use Closure;
|
||||
use Exception;
|
||||
use HttpServer\IInterface\IMiddleware;
|
||||
use HttpServer\Route\Dispatch\Dispatch;
|
||||
|
||||
/**
|
||||
* Class Middleware
|
||||
* @package BeReborn\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 $dispatch
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getGenerate($dispatch)
|
||||
{
|
||||
$last = function ($passable) use ($dispatch) {
|
||||
return Dispatch::create($dispatch, $passable)->dispatch();
|
||||
};
|
||||
$data = array_reduce(array_reverse($this->middleWares), $this->core(), $last);
|
||||
$this->middleWares = [];
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Closure
|
||||
*/
|
||||
public function core()
|
||||
{
|
||||
return function ($stack, $pipe) {
|
||||
return function ($passable) use ($stack, $pipe) {
|
||||
if ($pipe instanceof IMiddleware) {
|
||||
return $pipe->handler($passable, $stack);
|
||||
} else {
|
||||
return $pipe($passable, $stack);
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,313 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Route;
|
||||
|
||||
|
||||
use HttpServer\Http\Request;
|
||||
use Exception;
|
||||
use HttpServer\Application;
|
||||
|
||||
/**
|
||||
* Class Node
|
||||
* @package BeReborn\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 = [];
|
||||
|
||||
/**
|
||||
* @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->newExec();
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 = \BeReborn::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 = new \ReflectionClass($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 . '.');
|
||||
}
|
||||
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 = \BeReborn::$app->getLimits();
|
||||
$limits->addLimits($this->path, $limit, $duration, $isBindConsumer);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $middles
|
||||
* @throws
|
||||
*/
|
||||
public function bindMiddleware(array $middles)
|
||||
{
|
||||
$_tmp = [];
|
||||
if (empty($middles)) {
|
||||
return;
|
||||
}
|
||||
foreach ($middles as $middle) {
|
||||
if (empty($middle)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
if (is_array($middle)) {
|
||||
$_tmp = $this->each($middle, $_tmp);
|
||||
} else {
|
||||
$_tmp[] = \BeReborn::createObject($middle);
|
||||
}
|
||||
} catch (Exception $exception) {
|
||||
}
|
||||
}
|
||||
$this->middleware = $_tmp;
|
||||
$this->newExec();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
private function newExec()
|
||||
{
|
||||
if (!empty($this->handler)) {
|
||||
$made = new Middleware();
|
||||
$made->setMiddleWares($this->middleware);
|
||||
$this->callback = $made->getGenerate($this->handler);
|
||||
}
|
||||
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[] = \BeReborn::createObject($class);
|
||||
}
|
||||
}
|
||||
return $_temp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,504 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer\Route;
|
||||
|
||||
use Closure;
|
||||
use Exception;
|
||||
use HttpServer\Http\Context;
|
||||
use HttpServer\Controller;
|
||||
use HttpServer\IInterface\RouterInterface;
|
||||
use HttpServer\Application;
|
||||
use Snowflake\Config;
|
||||
use Snowflake\Core\JSON;
|
||||
use Snowflake\Exception\ConfigException;
|
||||
|
||||
/**
|
||||
* Class Router
|
||||
* @package BeReborn\Route
|
||||
*/
|
||||
class Router extends Application implements RouterInterface
|
||||
{
|
||||
/** @var Node[] $nodes */
|
||||
public $nodes = [];
|
||||
public $groupTacks = [];
|
||||
public $dir = 'App\\Controllers';
|
||||
|
||||
/** @var string[] */
|
||||
public $methods = ['get', 'post', 'options', 'put', 'delete', 'receive'];
|
||||
|
||||
/**
|
||||
* @throws ConfigException
|
||||
* 初始化函数路径
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->dir = Config::get('controller.path', 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 ($handler instanceof \Closure) {
|
||||
$handler = Closure::bind($handler, new Controller());
|
||||
}
|
||||
|
||||
if (empty($parent)) {
|
||||
$parent = $this->NodeInstance($first, 0, $method);
|
||||
$this->nodes[$method][$first] = $parent;
|
||||
}
|
||||
if ($first === '/') {
|
||||
return $parent->bindHandler($handler);
|
||||
}
|
||||
|
||||
$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 = \BeReborn::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 == 'receive') {
|
||||
$dir = 'App\\Tcp';
|
||||
} else if ($method == 'package') {
|
||||
$dir = 'App\\Udp';
|
||||
} 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)) {
|
||||
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 loader()
|
||||
{
|
||||
try {
|
||||
$this->loadDir(APP_PATH . '/routes');
|
||||
} catch (Exception $exception) {
|
||||
$this->error($exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
* @throws Exception
|
||||
* 加载目录下的路由文件
|
||||
*/
|
||||
private function loadDir($path)
|
||||
{
|
||||
try {
|
||||
$files = glob($path . '/*');
|
||||
for ($i = 0; $i < count($files); $i++) {
|
||||
if (is_dir($files[$i])) {
|
||||
$this->loadDir($files[$i]);
|
||||
} else {
|
||||
$this->loadFile($files[$i]);
|
||||
}
|
||||
}
|
||||
} catch (Exception $exception) {
|
||||
$this->error($exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $file
|
||||
*/
|
||||
private function loadFile($file)
|
||||
{
|
||||
$router = $this;
|
||||
include_once "Router.php";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer;
|
||||
|
||||
use HttpServer\Events\Http;
|
||||
use HttpServer\Events\Receive;
|
||||
use HttpServer\Events\Packet;
|
||||
use HttpServer\Events\WebSocket;
|
||||
use Exception;
|
||||
use Snowflake\Snowflake;
|
||||
|
||||
/**
|
||||
* Class Server
|
||||
* @package HttpServer
|
||||
*
|
||||
*
|
||||
* @example [
|
||||
* ['host'=> '127.0.0.1', 'port'=> 5775, 'mode'=> SWOOLE_TCP],
|
||||
* ['host'=> '127.0.0.1', 'port'=> 5775, 'mode'=> SWOOLE_TCP],
|
||||
* ['host'=> '127.0.0.1', 'port'=> 5775, 'mode'=> SWOOLE_TCP],
|
||||
* ['host'=> '127.0.0.1', 'port'=> 5775, 'mode'=> SWOOLE_TCP],
|
||||
* ['host'=> '127.0.0.1', 'port'=> 5775, 'mode'=> SWOOLE_UDP],
|
||||
* ['host'=> '127.0.0.1', 'port'=> 5775, 'mode'=> SWOOLE_TCP]
|
||||
* ]
|
||||
*/
|
||||
class Server extends Application
|
||||
{
|
||||
const HTTP = 'HTTP';
|
||||
const TCP = 'TCP';
|
||||
const PACKAGE = 'PACKAGE';
|
||||
const WEBSOCKET = 'WEBSOCKET';
|
||||
|
||||
private $server = [
|
||||
'HTTP' => [SWOOLE_TCP, Http::class],
|
||||
'TCP' => [SWOOLE_TCP, Receive::class],
|
||||
'PACKAGE' => [SWOOLE_UDP, Packet::class],
|
||||
'WEBSOCKET' => [SWOOLE_SOCK_TCP, WebSocket::class],
|
||||
];
|
||||
|
||||
/**
|
||||
* @param array $configs
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function initCore(array $configs)
|
||||
{
|
||||
$response = [];
|
||||
foreach ($configs as $server) {
|
||||
$response[] = $this->create($server);
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $config
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
private function create($config)
|
||||
{
|
||||
$settings = $config['settings'] ?? [];
|
||||
if (!isset($this->server[$config['type']])) {
|
||||
throw new Exception('Unknown server type(' . $config['type'] . ').');
|
||||
}
|
||||
$server = $this->dispatchCreate($config, $settings);
|
||||
if (isset($config['events'])) {
|
||||
$this->createEventListen($config);
|
||||
}
|
||||
return $server;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $config
|
||||
*/
|
||||
protected function createEventListen($config)
|
||||
{
|
||||
if (!is_array($config['events'])) {
|
||||
return;
|
||||
}
|
||||
$event = Snowflake::get()->event;
|
||||
foreach ($config['events'] as $name => $_event) {
|
||||
$event->on($name, $_event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $config
|
||||
* @param $settings
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
private function dispatchCreate($config, $settings)
|
||||
{
|
||||
switch ($config['type']) {
|
||||
case self::HTTP:
|
||||
$handler = [
|
||||
['request', [Http::class, 'onHandler']]
|
||||
];
|
||||
break;
|
||||
case self::TCP:
|
||||
$handler = [
|
||||
['receive', [Receive::class, 'onReceive']]
|
||||
];
|
||||
break;
|
||||
case self::PACKAGE:
|
||||
$handler = [
|
||||
['packet', [Packet::class, 'onHandler']]
|
||||
];
|
||||
break;
|
||||
case self::WEBSOCKET:
|
||||
$handler = [
|
||||
['handshake', [WebSocket::class, 'onHandshake']],
|
||||
['message', [WebSocket::class, 'onMessage']],
|
||||
['close', [WebSocket::class, 'onClose']],
|
||||
];
|
||||
break;
|
||||
default:
|
||||
throw new Exception('Unknown server type(' . $config['type'] . ').');
|
||||
}
|
||||
return [$this->server[$config['type']], $config, $handler, $settings];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace HttpServer;
|
||||
|
||||
use Exception;
|
||||
use ReflectionException;
|
||||
use Snowflake\Exception\ComponentException;
|
||||
use Snowflake\Exception\NotFindClassException;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Process\Pool;
|
||||
|
||||
class ServerManager
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param $pool
|
||||
* @param $process
|
||||
* @param $application
|
||||
* @param $workerId
|
||||
* @return mixed
|
||||
*/
|
||||
public static function create($pool, $process, $application, $workerId)
|
||||
{
|
||||
if (is_string($process) && class_exists($process)) {
|
||||
return static::createProcess($process, $application, $pool, $workerId);
|
||||
}
|
||||
[$category, $config, $handlers, $settings] = $process;
|
||||
$server = new $category[1](...static::parameter($application, $config, $category));
|
||||
$server->set($settings ?? [], $handlers, $config);
|
||||
static::notice($application, $workerId, $config);
|
||||
if (property_exists($server, 'pack')) {
|
||||
$server->pack = $config['message']['pack'] ?? function ($data) {
|
||||
return $data;
|
||||
};
|
||||
}
|
||||
if (property_exists($server, 'unpack')) {
|
||||
$server->unpack = $config['message']['unpack'] ?? function ($data) {
|
||||
return $data;
|
||||
};
|
||||
}
|
||||
return $server->start();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $application
|
||||
* @param $config
|
||||
* @param $category
|
||||
* @return array
|
||||
*/
|
||||
protected static function parameter($application, $config, $category)
|
||||
{
|
||||
return [$application, $config['host'], $config['port'], SWOOLE_PROCESS, $category[0]];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $process
|
||||
* @param $application
|
||||
* @param $pool
|
||||
* @param $workerId
|
||||
* @return mixed
|
||||
*/
|
||||
protected static function createProcess($process, $application, $pool, $workerId)
|
||||
{
|
||||
$process = new $process($application);
|
||||
$application->debug(sprintf('Worker #%d is running.', $workerId));
|
||||
return $process->start($pool->getProcess($workerId));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $application
|
||||
* @param $workerId
|
||||
* @param $config
|
||||
*/
|
||||
protected static function notice($application, $workerId, $config)
|
||||
{
|
||||
$application->debug(sprintf('Worker #%d Listener %s::%d is running.', $workerId, $config['host'], $config['port']));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $server
|
||||
* @param $settings
|
||||
* @param \Snowflake\Application $application
|
||||
* @param array $events
|
||||
* @param array $config
|
||||
* @return mixed|void
|
||||
* @throws NotFindClassException
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public static function set($server, $settings, $application, $events = [], $config = [])
|
||||
{
|
||||
$server->on('start', static::createHandler('start'));
|
||||
$server->on('workerStop', static::createHandler('workerStop'));
|
||||
$server->on('workerExit', static::createHandler('workerExit'));
|
||||
$server->on('workerStart', static::createHandler('workerStart'));
|
||||
$server->on('workerError', static::createHandler('workerError'));
|
||||
$server->on('managerStop', static::createHandler('managerStop'));
|
||||
$server->on('managerStart', static::createHandler('managerStart'));
|
||||
static::addListener($server, $application, $config);
|
||||
static::bindCallback($server, $events);
|
||||
static::addTask($server, $settings);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $server
|
||||
* @param $settings
|
||||
* @throws NotFindClassException
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
protected static function addTask($server, $settings)
|
||||
{
|
||||
if (($taskNumber = $settings['task_worker_num'] ?? 0) > 0) {
|
||||
$server->on('finish', static::createHandler('finish'));
|
||||
$callback = static::createHandler('task');
|
||||
if ($settings['task_enable_coroutine'] ?? false) {
|
||||
$server->on('task', [$callback, 'onContinueTask']);
|
||||
} else {
|
||||
$server->on('task', [$callback, 'onTask']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $server
|
||||
* @param $application
|
||||
* @param $config
|
||||
* @return void
|
||||
*/
|
||||
protected static function addListener($server, $application, $config)
|
||||
{
|
||||
$grpc = $config['grpc'] ?? [];
|
||||
if (empty($grpc) || !is_array($grpc)) {
|
||||
return;
|
||||
}
|
||||
$listener = $server->addListener($grpc['host'], $grpc['port'], $grpc['mode']);
|
||||
$listener->set($grpc['settings'] ?? []);
|
||||
if (!isset($grpc['receive'])) {
|
||||
$application->error(sprintf('must add listener %s::%s callback', $grpc['host'], $grpc['port']));
|
||||
return;
|
||||
}
|
||||
if ($grpc['receive'] instanceof \Closure) {
|
||||
$grpc['receive'] = \Closure::bind($grpc['receive'], $server);
|
||||
}
|
||||
$listener->on('receive', $grpc['receive']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $server
|
||||
* @param $callbacks
|
||||
*/
|
||||
protected static function bindCallback($server, $callbacks)
|
||||
{
|
||||
if (empty($callbacks) || !is_array($callbacks)) {
|
||||
return;
|
||||
}
|
||||
foreach ($callbacks as $callback) {
|
||||
$server->on($callback[0], [$server, $callback[1][1]]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $eventName
|
||||
* @return array
|
||||
* @throws NotFindClassException
|
||||
* @throws ReflectionException
|
||||
* @throws Exception
|
||||
*/
|
||||
protected static function createHandler($eventName)
|
||||
{
|
||||
$classPrefix = 'HttpServer\Events\Trigger\On' . ucfirst($eventName);
|
||||
if (!class_exists($classPrefix)) {
|
||||
throw new Exception('class not found.');
|
||||
}
|
||||
$class = Snowflake::createObject($classPrefix, [Snowflake::get()]);
|
||||
return [$class, 'onHandler'];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
use HttpServer\Route\Router;
|
||||
use HttpServer\Server;
|
||||
use Snowflake\Snowflake;
|
||||
use Snowflake\Event;
|
||||
use Swoole\Http\Request;
|
||||
use Swoole\Http\Response;
|
||||
use Swoole\WebSocket\Frame;
|
||||
|
||||
return [
|
||||
'servers' => [
|
||||
[
|
||||
'type' => Server::HTTP,
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 9527,
|
||||
'settings' => [
|
||||
'worker_num' => 10,
|
||||
'enable_coroutine' => 1
|
||||
],
|
||||
'events' => [
|
||||
Event::SERVER_WORKER_START => function () {
|
||||
$router = Snowflake::get()->router;
|
||||
$router->loader();
|
||||
},
|
||||
]
|
||||
],
|
||||
[
|
||||
'type' => Server::PACKAGE,
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 9628,
|
||||
'settings' => [
|
||||
'worker_num' => 10,
|
||||
'enable_coroutine' => 1
|
||||
],
|
||||
'message' => [
|
||||
'pack' => function ($data) {
|
||||
return \Snowflake\Core\JSON::encode($data);
|
||||
},
|
||||
'unpack' => function ($data) {
|
||||
return \Snowflake\Core\JSON::decode($data);
|
||||
},
|
||||
],
|
||||
'events' => [
|
||||
]
|
||||
],
|
||||
[
|
||||
'type' => Server::TCP,
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 9629,
|
||||
'settings' => [
|
||||
'worker_num' => 10,
|
||||
'enable_coroutine' => 1
|
||||
],
|
||||
'message' => [
|
||||
'pack' => function ($data) {
|
||||
var_dump($data);
|
||||
return \Snowflake\Core\JSON::encode($data);
|
||||
},
|
||||
'unpack' => function ($data) {
|
||||
return \Snowflake\Core\JSON::decode($data);
|
||||
},
|
||||
],
|
||||
'events' => [
|
||||
Event::RECEIVE_CONNECTION => function ($data) {
|
||||
return 'hello word~';
|
||||
}
|
||||
]
|
||||
],
|
||||
[
|
||||
'type' => Server::WEBSOCKET,
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 9530,
|
||||
'settings' => [
|
||||
'worker_num' => 10,
|
||||
'enable_coroutine' => 1
|
||||
],
|
||||
'grpc' => [
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 5555,
|
||||
'mode' => SWOOLE_SOCK_TCP,
|
||||
'receive' => function ($server, int $fd, int $reactorId, string $data) {
|
||||
$server->push(1, 'success.');
|
||||
$server->send($fd, 'success.');
|
||||
},
|
||||
'settings' => []
|
||||
],
|
||||
'events' => [
|
||||
Event::SERVER_WORKER_START => function () {
|
||||
$websocket = Snowflake::get()->annotation->websocket;
|
||||
// $websocket->path = $this->socketControllers;
|
||||
$websocket->namespace = 'App\\Sockets\\';
|
||||
$websocket->registration_notes();
|
||||
},
|
||||
Event::SERVER_HANDSHAKE => function (Request $request, Response $response) {
|
||||
$this->error($request->fd . ' connect.');
|
||||
$response->status(101);
|
||||
$response->end();
|
||||
},
|
||||
Event::SERVER_MESSAGE => function (\Swoole\WebSocket\Server $server, Frame $frame) {
|
||||
$this->error('websocket SERVER_MESSAGE.');
|
||||
return $server->push($frame->fd, 'hello word~');
|
||||
},
|
||||
Event::SERVER_CLOSE => function (int $fd) {
|
||||
$this->error($fd . ' disconnect.');
|
||||
return 'hello word~';
|
||||
}
|
||||
]
|
||||
],
|
||||
]
|
||||
];
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
|
||||
ini_set('memory_limit', '3096M');
|
||||
|
||||
use Snowflake\Application;
|
||||
|
||||
require_once __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
\Swoole\Coroutine\run(function (){
|
||||
$client = HttpServer\Client\Client::NewRequest();
|
||||
$client->setHost('127.0.0.1');
|
||||
$client->setPort(9628);
|
||||
$client->setErrorField('code');
|
||||
$client->setErrorMsgField('message');
|
||||
var_dump($client->sendTo('', [],SWOOLE_UDP)->getMessage());
|
||||
|
||||
$client = HttpServer\Client\Client::NewRequest();
|
||||
$client->setHost('127.0.0.1');
|
||||
$client->setPort(9629);
|
||||
$client->setErrorField('code');
|
||||
$client->setErrorMsgField('message');
|
||||
var_dump($client->sendTo('', [],SWOOLE_TCP)->getMessage());
|
||||
|
||||
$client = HttpServer\Client\Client::NewRequest();
|
||||
$client->setHost('127.0.0.1');
|
||||
$client->setPort(5555);
|
||||
$client->setErrorField('code');
|
||||
$client->setErrorMsgField('message');
|
||||
var_dump($client->sendTo('', [],SWOOLE_SOCK_TCP)->getMessage());
|
||||
|
||||
$client = HttpServer\Client\Client::NewRequest();
|
||||
$client->setHost('127.0.0.1');
|
||||
$client->setPort(9527);
|
||||
$client->setErrorField('code');
|
||||
$client->setErrorMsgField('message');
|
||||
var_dump($client->send('', [])->getMessage());
|
||||
});
|
||||
$mail = new \PHPMailer\PHPMailer\PHPMailer(true);
|
||||
|
||||
try {
|
||||
//Server settings
|
||||
$mail->SMTPDebug = \PHPMailer\PHPMailer\SMTP::DEBUG_SERVER; // Enable verbose debug output
|
||||
$mail->isSMTP(); // Send using SMTP
|
||||
$mail->Host = 'smtp1.example.com'; // Set the SMTP server to send through
|
||||
$mail->SMTPAuth = true; // Enable SMTP authentication
|
||||
$mail->Username = 'user@example.com'; // SMTP username
|
||||
$mail->Password = 'secret'; // SMTP password
|
||||
$mail->SMTPSecure = \PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_STARTTLS; // Enable TLS encryption; `PHPMailer::ENCRYPTION_SMTPS` encouraged
|
||||
$mail->Port = 587; // TCP port to connect to, use 465 for `PHPMailer::ENCRYPTION_SMTPS` above
|
||||
|
||||
//Recipients
|
||||
$mail->setFrom('from@example.com', 'Mailer');
|
||||
$mail->addAddress('joe@example.net', 'Joe User'); // Add a recipient
|
||||
$mail->addAddress('ellen@example.com'); // Name is optional
|
||||
$mail->addReplyTo('info@example.com', 'Information');
|
||||
$mail->addCC('cc@example.com');
|
||||
$mail->addBCC('bcc@example.com');
|
||||
|
||||
// Attachments
|
||||
$mail->addAttachment('/var/tmp/file.tar.gz'); // Add attachments
|
||||
$mail->addAttachment('/tmp/image.jpg', 'new.jpg'); // Optional name
|
||||
|
||||
// Content
|
||||
$mail->isHTML(true); // Set email format to HTML
|
||||
$mail->Subject = 'Here is the subject';
|
||||
$mail->Body = 'This is the HTML message body <b>in bold!</b>';
|
||||
$mail->AltBody = 'This is the body in plain text for non-HTML mail clients';
|
||||
|
||||
$mail->send();
|
||||
echo 'Message has been sent';
|
||||
} catch (Exception $e) {
|
||||
echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}";
|
||||
}
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Title</title>
|
||||
<style type="text/css">
|
||||
#format {
|
||||
word-break: break-all;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style="background-color: #666;color: #fff;presentation-level: increment;">
|
||||
<pre id="format"></pre>
|
||||
<script type="text/javascript">
|
||||
let sock, tick, format = document.getElementById('format');
|
||||
|
||||
function message(message) {
|
||||
let div = document.createElement('div');
|
||||
div.innerHTML = message.data;
|
||||
div.style.cssText = 'padding:5px 10px;background-color:#222;-webkit-border-radius: 5px;-moz-border-radius: 5px;border-radius: 5px;word-break: break-all;word-wrap: break-word;';
|
||||
div.style.marginBottom = '10px';
|
||||
let count = format.getElementsByTagName('div');
|
||||
|
||||
format.insertBefore(div, count[0]);
|
||||
}
|
||||
|
||||
function close() {
|
||||
setTimeout(function () {
|
||||
connect();
|
||||
sock.onmessage = message;
|
||||
sock.onclose = close;
|
||||
}, 3000);
|
||||
console.log('onClose')
|
||||
}
|
||||
|
||||
function connect() {
|
||||
sock = new WebSocket('ws://127.0.0.1:9530/');
|
||||
sock.onopen = function () {
|
||||
if (tick) {
|
||||
clearInterval(tick)
|
||||
}
|
||||
tick = setInterval(function () {
|
||||
sock.send('tick');
|
||||
}, 30000)
|
||||
}
|
||||
}
|
||||
|
||||
connect();
|
||||
sock.onmessage = message;
|
||||
sock.onclose = close;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Snowflake\Abstracts;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class BaseAnnotation
|
||||
* @package BeReborn\Annotation\Base
|
||||
*/
|
||||
abstract class BaseAnnotation extends Component
|
||||
{
|
||||
|
||||
public function each()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/10/7 0007
|
||||
* Time: 2:13
|
||||
*/
|
||||
|
||||
namespace Snowflake\Abstracts;
|
||||
|
||||
|
||||
use Exception;
|
||||
use HttpServer\Http\Request;
|
||||
use HttpServer\Http\Response;
|
||||
use HttpServer\Route\Router;
|
||||
use HttpServer\Server;
|
||||
use Snowflake\Annotation\Annotation;
|
||||
use Snowflake\Config;
|
||||
use Snowflake\Di\Service;
|
||||
use Snowflake\Error\ErrorHandler;
|
||||
use Snowflake\Error\Logger;
|
||||
use Snowflake\Exception\ComponentException;
|
||||
use Snowflake\Pool\Connection;
|
||||
use Snowflake\Pool\RedisClient;
|
||||
use Snowflake\Processes;
|
||||
use Snowflake\Snowflake;
|
||||
use Snowflake\Event;
|
||||
|
||||
/**
|
||||
* Class BaseApplication
|
||||
* @package BeReborn\Base
|
||||
* @property $json
|
||||
* @property Annotation $annotation
|
||||
* @property Event $event
|
||||
* @property Router $router
|
||||
* @property Processes $processes
|
||||
* @property \Snowflake\Pool\Pool $pool
|
||||
* @property Server $servers
|
||||
* @property Connection $connections
|
||||
*/
|
||||
abstract class BaseApplication extends Service
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $storage = APP_PATH . '/storage';
|
||||
|
||||
public $envPath = APP_PATH . '/.env';
|
||||
|
||||
/**
|
||||
* Init constructor.
|
||||
*
|
||||
* @param array $config
|
||||
*
|
||||
* @throws
|
||||
*/
|
||||
public function __construct(array $config = [])
|
||||
{
|
||||
Snowflake::init($this);
|
||||
|
||||
$this->moreComponents();
|
||||
$this->parseInt($config);
|
||||
$this->initErrorHandler();
|
||||
$this->enableEnvConfig();
|
||||
|
||||
Component::__construct($config);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function enableEnvConfig()
|
||||
{
|
||||
if (!file_exists($this->envPath)) {
|
||||
return [];
|
||||
}
|
||||
$lines = $this->readLinesFromFile($this->envPath);
|
||||
foreach ($lines as $line) {
|
||||
if (!$this->isComment($line) && $this->looksLikeSetter($line)) {
|
||||
[$key, $value] = explode('=', $line);
|
||||
putenv(trim($key) . '=' . trim($value));
|
||||
}
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read lines from the file, auto detecting line endings.
|
||||
*
|
||||
* @param string $filePath
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function readLinesFromFile($filePath)
|
||||
{
|
||||
// Read file into an array of lines with auto-detected line endings
|
||||
$autodetect = ini_get('auto_detect_line_endings');
|
||||
ini_set('auto_detect_line_endings', '1');
|
||||
$lines = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||
ini_set('auto_detect_line_endings', $autodetect);
|
||||
|
||||
return $lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the line in the file is a comment, e.g. begins with a #.
|
||||
*
|
||||
* @param string $line
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isComment($line)
|
||||
{
|
||||
$line = ltrim($line);
|
||||
|
||||
return isset($line[0]) && $line[0] === '#';
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given line looks like it's setting a variable.
|
||||
*
|
||||
* @param string $line
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function looksLikeSetter($line)
|
||||
{
|
||||
return strpos($line, '=') !== false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $config
|
||||
*
|
||||
* @throws
|
||||
*/
|
||||
public function parseInt($config)
|
||||
{
|
||||
foreach ($config as $key => $value) {
|
||||
Config::set($key, $value);
|
||||
}
|
||||
// if (isset($config['id'])) {
|
||||
// $this->id = $config['id'];
|
||||
// unset($config['id']);
|
||||
// }
|
||||
// if (isset($config['storage'])) {
|
||||
// $this->storage = $config['storage'];
|
||||
// unset($config['storage']);
|
||||
// }
|
||||
// if (!empty($this->runtimePath)) {
|
||||
// if (!is_dir($this->runtimePath)) {
|
||||
// mkdir($this->runtimePath, 777);
|
||||
// }
|
||||
//
|
||||
// if (!is_dir($this->runtimePath) || !is_writeable($this->runtimePath)) {
|
||||
// throw new InitException("Directory {$this->runtimePath} does not have write permission");
|
||||
// }
|
||||
// }
|
||||
// if (isset($config['aliases'])) {
|
||||
// $this->classAlias($config);
|
||||
// }
|
||||
//
|
||||
// foreach ($this->moreComponents() as $key => $val) {
|
||||
// if (isset($config['components'][$key])) {
|
||||
// $config['components'][$key] = array_merge($val, $config['components'][$key]);
|
||||
// } else {
|
||||
// $config['components'][$key] = $val;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*/
|
||||
private function classAlias(array &$data)
|
||||
{
|
||||
foreach ($data['aliases'] as $key => $val) {
|
||||
class_alias($val, $key, true);
|
||||
}
|
||||
unset($data['aliases']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return mixed
|
||||
* @throws ComponentException
|
||||
*/
|
||||
public function clone($name)
|
||||
{
|
||||
return clone $this->get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function initErrorHandler()
|
||||
{
|
||||
$this->get('error')->register();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getLocalIps()
|
||||
{
|
||||
return swoole_get_local_ip();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getFirstLocal()
|
||||
{
|
||||
return current($this->getLocalIps());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $ip
|
||||
* @return bool
|
||||
*/
|
||||
public function isLocal($ip)
|
||||
{
|
||||
return $this->getFirstLocal() == $ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function moreComponents()
|
||||
{
|
||||
return $this->setComponents([
|
||||
'error' => ['class' => ErrorHandler::class],
|
||||
'event' => ['class' => Event::class],
|
||||
'annotation' => ['class' => Annotation::class],
|
||||
'processes' => ['class' => Processes::class],
|
||||
'connections' => ['class' => Connection::class],
|
||||
'redis_connections' => ['class' => RedisClient::class],
|
||||
'pool' => ['class' => \Snowflake\Pool\Pool::class],
|
||||
'response' => ['class' => Response::class],
|
||||
'request' => ['class' => Request::class],
|
||||
'config' => ['class' => Config::class],
|
||||
'logger' => ['class' => Logger::class],
|
||||
'router' => ['class' => Router::class],
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/3/30 0030
|
||||
* Time: 14:10
|
||||
*/
|
||||
|
||||
namespace Snowflake\Abstracts;
|
||||
|
||||
use Exception;
|
||||
use Snowflake\Error\Logger;
|
||||
use Snowflake\Snowflake;
|
||||
|
||||
/**
|
||||
* Class BaseObject
|
||||
* @method defer()
|
||||
* @package BeReborn\Base
|
||||
* @method afterInit
|
||||
* @method initialization
|
||||
*/
|
||||
class BaseObject implements Configure
|
||||
{
|
||||
|
||||
/**
|
||||
* BaseAbstract constructor.
|
||||
*
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct($config = [])
|
||||
{
|
||||
// if (!empty($config) && is_array($config)) {
|
||||
// Snowflake::configure($this, $config);
|
||||
// }
|
||||
$this->init();
|
||||
}
|
||||
|
||||
public function init()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function className()
|
||||
{
|
||||
return get_called_class();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $value
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
$method = 'set' . ucfirst($name);
|
||||
if (method_exists($this, $method)) {
|
||||
$this->{$method}($value);
|
||||
} else {
|
||||
$this->error('set ' . $name . ' not exists ' . get_called_class());
|
||||
throw new Exception('The set name ' . $name . ' not find in class ' . get_class($this));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
*
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
$method = 'get' . ucfirst($name);
|
||||
if (method_exists($this, $method)) {
|
||||
return $this->$method();
|
||||
} else {
|
||||
throw new Exception('The get name ' . $name . ' not find in class ' . get_class($this));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $arguments
|
||||
*
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __call($name, $arguments)
|
||||
{
|
||||
if (!method_exists($this, $name)) {
|
||||
throw new Exception("Not find " . get_called_class() . "::($name)");
|
||||
} else {
|
||||
$result = $this->$name(...$arguments);
|
||||
if (method_exists($this, 'defer')) {
|
||||
$this->defer();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @param string $model
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function addError($message, $model = 'app')
|
||||
{
|
||||
if ($message instanceof Exception) {
|
||||
$this->error($message->getMessage(), $message->getFile(), $message->getLine());
|
||||
} else {
|
||||
if (!is_string($message)) {
|
||||
$message = json_encode($message, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
$this->error($message);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param string $method
|
||||
* @param string $file
|
||||
* @throws
|
||||
*/
|
||||
public function debug($message, string $method = __METHOD__, string $file = __FILE__)
|
||||
{
|
||||
if (!is_string($message)) {
|
||||
$message = print_r($message, true);
|
||||
}
|
||||
echo "\033[35m[DEBUG][" . date('Y-m-d H:i:s') . ']: ' . $message . "\033[0m";
|
||||
echo PHP_EOL;
|
||||
Logger::trance($message, 'debug');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param string $method
|
||||
* @param string $file
|
||||
* @throws
|
||||
*/
|
||||
public function info($message, string $method = __METHOD__, string $file = __FILE__)
|
||||
{
|
||||
if (!is_string($message)) {
|
||||
$message = print_r($message, true);
|
||||
}
|
||||
echo "\033[34m[INFO][" . date('Y-m-d H:i:s') . ']: ' . $message . "\033[0m";
|
||||
echo PHP_EOL;
|
||||
Logger::trance($message, 'info');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param string $method
|
||||
* @param string $file
|
||||
* @throws
|
||||
*/
|
||||
public function success($message, string $method = __METHOD__, string $file = __FILE__)
|
||||
{
|
||||
if (!is_string($message)) {
|
||||
$message = print_r($message, true);
|
||||
}
|
||||
echo "\033[36m[SUCCESS][" . date('Y-m-d H:i:s') . ']: ' . $message . "\033[0m";
|
||||
echo PHP_EOL;
|
||||
Logger::trance($message, 'success');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param string $method
|
||||
* @param string $file
|
||||
* @throws
|
||||
*/
|
||||
public function warning($message, string $method = __METHOD__, string $file = __FILE__)
|
||||
{
|
||||
if (!is_string($message)) {
|
||||
$message = print_r($message, true);
|
||||
}
|
||||
echo "\033[33m[SUCCESS][" . date('Y-m-d H:i:s') . ']: ' . $message . "\033[0m";
|
||||
echo PHP_EOL;
|
||||
Logger::trance($message, 'warning');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param string|null $method
|
||||
* @param string|null $file
|
||||
* @throws Exception
|
||||
*/
|
||||
public function error($message, string $method = null, string $file = null)
|
||||
{
|
||||
if (!empty($file)) {
|
||||
echo "\033[41;37m[ERROR][" . date('Y-m-d H:i:s') . ']: ' . $file . "\033[0m";
|
||||
echo PHP_EOL;
|
||||
}
|
||||
if (!is_string($message)) {
|
||||
$message = print_r($message, true);
|
||||
}
|
||||
echo "\033[41;37m[ERROR][" . date('Y-m-d H:i:s') . ']: ' . (empty($method) ? '' : $method . ': ') . $message . "\033[0m";
|
||||
echo PHP_EOL;
|
||||
Logger::error($message, 'error');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/3/30 0030
|
||||
* Time: 14:28
|
||||
*/
|
||||
|
||||
namespace Snowflake\Abstracts;
|
||||
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class Component
|
||||
* @package BeReborn\Base
|
||||
*/
|
||||
class Component extends BaseObject
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $_events = [];
|
||||
|
||||
|
||||
/**
|
||||
* @param $name [事件名称]
|
||||
* @param $callback [回调函数]
|
||||
* @param array $param [函数参数]
|
||||
*
|
||||
* {
|
||||
* 事件名, 回调, 参数
|
||||
* }
|
||||
*/
|
||||
public function on($name, $callback, $param = [])
|
||||
{
|
||||
if (isset($this->_events[$name])) {
|
||||
array_push($this->_events[$name], [$callback, $param]);
|
||||
} else {
|
||||
$this->_events[$name][] = [$callback, $param];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $callback
|
||||
* @return bool
|
||||
*/
|
||||
public function hasEvent($name, $callback = null)
|
||||
{
|
||||
if (!isset($this->_events[$name])) {
|
||||
return false;
|
||||
}
|
||||
if (!is_array($this->_events[$name])) {
|
||||
return false;
|
||||
}
|
||||
foreach ($this->_events[$name] as $event) {
|
||||
[$_callback, $param] = $event;
|
||||
if ($_callback === $callback) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $event
|
||||
* @param array $params
|
||||
* @param bool $isRemove
|
||||
* @throws Exception
|
||||
*/
|
||||
public function trigger($name, $event = null, $params = [], $isRemove = false)
|
||||
{
|
||||
if (isset($this->_events[$name])) {
|
||||
$events = $this->_events[$name];
|
||||
foreach ($events as $key => $_event) {
|
||||
if (!empty($event)) {
|
||||
$_event = $event;
|
||||
}
|
||||
call_user_func($_event, ...$params);
|
||||
if ($isRemove) {
|
||||
unset($this->_events[$name][$key]);
|
||||
of($name, $_event);
|
||||
}
|
||||
}
|
||||
}
|
||||
fire($name, $event);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $handler
|
||||
* @return mixed
|
||||
*/
|
||||
public function off($name, $handler = NULL)
|
||||
{
|
||||
if (!isset($this->_events[$name])) {
|
||||
return of($name, $handler);
|
||||
}
|
||||
|
||||
if (empty($handler)) {
|
||||
unset($this->_events[$name]);
|
||||
|
||||
return of($name, $handler);
|
||||
}
|
||||
|
||||
foreach ($this->_events[$name] as $key => $val) {
|
||||
if ($val[0] != $handler) {
|
||||
continue;
|
||||
}
|
||||
unset($this->_events[$name][$key]);
|
||||
|
||||
break;
|
||||
}
|
||||
return of($name, $handler);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
public function offAll()
|
||||
{
|
||||
$this->_events = [];
|
||||
ofAll();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
$method = 'get' . ucfirst($name);
|
||||
if (method_exists($this, $method)) {
|
||||
return $this->$method();
|
||||
} else if (property_exists($this, $name)) {
|
||||
return $this->$name ?? null;
|
||||
} else {
|
||||
return parent::__get($name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/5/24 0024
|
||||
* Time: 11:50
|
||||
*/
|
||||
|
||||
namespace Snowflake;
|
||||
|
||||
use Exception;
|
||||
use Snowflake\Exception\ConfigException;
|
||||
use Snowflake\Abstracts\Component;
|
||||
|
||||
|
||||
/**
|
||||
* Class Config
|
||||
* @package BeReborn\Base
|
||||
*/
|
||||
class Config extends Component
|
||||
{
|
||||
|
||||
const ERROR_MESSAGE = 'The not find :key in app configs.';
|
||||
|
||||
public $data;
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param bool $try
|
||||
* @param mixed $default
|
||||
* @return null
|
||||
* @throws
|
||||
*/
|
||||
public static function get($key, $try = FALSE, $default = null)
|
||||
{
|
||||
$config = Snowflake::get()->config;
|
||||
if (isset($config->data[$key])) {
|
||||
return $config->data[$key];
|
||||
} else if ($default !== null) {
|
||||
return $default;
|
||||
} else if ($try) {
|
||||
throw new ConfigException(str_replace(':key', $key, self::ERROR_MESSAGE));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $value
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function set($key, $value)
|
||||
{
|
||||
$config = Snowflake::get()->config;
|
||||
return $config->data[$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param bool $must_not_null
|
||||
* @return bool
|
||||
*/
|
||||
public static function has($key, $must_not_null = false)
|
||||
{
|
||||
$config = Snowflake::get()->config;
|
||||
if (!isset($config->data[$key])) {
|
||||
return false;
|
||||
}
|
||||
$config = $config->data[$key];
|
||||
if ($must_not_null === false) {
|
||||
return true;
|
||||
}
|
||||
return !empty($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $value
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
$this->data[$name] = $value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/3/30 0030
|
||||
* Time: 14:11
|
||||
*/
|
||||
|
||||
namespace Snowflake\Abstracts;
|
||||
|
||||
/**
|
||||
* Interface Configure
|
||||
* @package BeReborn\Base
|
||||
*/
|
||||
interface Configure
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Snowflake\Abstracts;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Swoole\Coroutine;
|
||||
use Swoole\Coroutine\Channel;
|
||||
|
||||
/**
|
||||
* Class Pool
|
||||
* @package BeReborn\Pool
|
||||
*/
|
||||
abstract class Pool extends Component
|
||||
{
|
||||
|
||||
/** @var Channel[] */
|
||||
private $_items = [];
|
||||
|
||||
public $max = 60;
|
||||
|
||||
private $is_ticker = false;
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param false $isMaster
|
||||
* @param int $max
|
||||
*/
|
||||
public function initConnections($name, $isMaster = false, $max = 60)
|
||||
{
|
||||
$name = $this->name($name, $isMaster);
|
||||
if (isset($this->_items[$name]) &&
|
||||
$this->_items[$name] instanceof Channel) {
|
||||
return;
|
||||
}
|
||||
$this->_items[$name] = new Channel($max);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param int $timeout
|
||||
* @return mixed
|
||||
*/
|
||||
protected function get($name, $timeout = -1)
|
||||
{
|
||||
if ($this->is_ticker) {
|
||||
Coroutine::sleep(1);
|
||||
}
|
||||
if ($timeout != -1) {
|
||||
$client = $this->_items[$name]->pop($timeout);
|
||||
} else {
|
||||
$client = $this->_items[$name]->pop(60);
|
||||
}
|
||||
if (!$this->checkCanUse(...$client)) {
|
||||
unset($client);
|
||||
return [0, null];
|
||||
} else {
|
||||
return $client;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $cds
|
||||
* @param false $isMaster
|
||||
* @return string
|
||||
*/
|
||||
public function name($cds, $isMaster = false)
|
||||
{
|
||||
return hash('sha1', $cds . ($isMaster ? 'master' : 'slave'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $time
|
||||
* @param $client
|
||||
* @return mixed
|
||||
* 检查连接可靠性
|
||||
* @throws Exception
|
||||
*/
|
||||
public function checkCanUse($time, $client)
|
||||
{
|
||||
throw new Exception('Undefined system processing function.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @throws Exception
|
||||
*/
|
||||
public function desc($name)
|
||||
{
|
||||
throw new Exception('Undefined system processing function.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $config
|
||||
* @param $isMaster
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getConnection(array $config, $isMaster)
|
||||
{
|
||||
throw new Exception('Undefined system processing function.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function hasItem($name)
|
||||
{
|
||||
return $this->hasLength($name) > 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function hasLength($name)
|
||||
{
|
||||
if (!isset($this->_items[$name])) {
|
||||
return 0;
|
||||
}
|
||||
return $this->_items[$name]->length();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $client
|
||||
*/
|
||||
public function push($name, $client)
|
||||
{
|
||||
if (!isset($this->_items[$name])) {
|
||||
return;
|
||||
}
|
||||
if (!$this->_items[$name]->isFull()) {
|
||||
$this->_items[$name]->push([time(), $client]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
*/
|
||||
public function clean($name)
|
||||
{
|
||||
if (!isset($this->_items[$name])) {
|
||||
return;
|
||||
}
|
||||
while ([$time, $client] = $this->_items[$name]->pop(0.001)) {
|
||||
unset($client);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Snowflake\Annotation;
|
||||
|
||||
use Exception;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
use Snowflake\Abstracts\BaseAnnotation;
|
||||
use Snowflake\Exception\NotFindClassException;
|
||||
use Snowflake\Snowflake;
|
||||
|
||||
/**
|
||||
* Class Annotation
|
||||
* @package BeReborn\Annotation
|
||||
* @property Websocket $websocket
|
||||
*/
|
||||
class Annotation extends BaseAnnotation
|
||||
{
|
||||
|
||||
protected $_Scan_directory = [];
|
||||
|
||||
public $namespace = '';
|
||||
|
||||
public $prefix = '';
|
||||
|
||||
public $path = '';
|
||||
|
||||
|
||||
private $_classMap = [
|
||||
'websocket' => Websocket::class
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $class
|
||||
*/
|
||||
public function register($name, $class)
|
||||
{
|
||||
$this->_classMap[$name] = $class;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function registration_notes()
|
||||
{
|
||||
if (!is_array($this->path)) {
|
||||
return;
|
||||
}
|
||||
foreach ($this->path as $item) {
|
||||
$this->scanning($item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @throws ReflectionException
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function scanning($path = '')
|
||||
{
|
||||
if (empty($path)) {
|
||||
$path = rtrim($this->path, '/');
|
||||
}
|
||||
foreach (glob($path . '/*') as $file) {
|
||||
if (is_dir($file)) {
|
||||
$this->scanning($path);
|
||||
}
|
||||
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @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
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function runWith($path, $param)
|
||||
{
|
||||
if (!$this->has($path)) {
|
||||
return null;
|
||||
}
|
||||
return call_user_func($this->_Scan_directory[$path], ...$param);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $callback
|
||||
*/
|
||||
public function push($name, $callback)
|
||||
{
|
||||
$this->_Scan_directory[$name] = $callback;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function has($path)
|
||||
{
|
||||
return isset($this->_Scan_directory[$path]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return mixed|null
|
||||
* @throws ReflectionException
|
||||
* @throws NotFindClassException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
if (isset($this->_classMap[$name])) {
|
||||
return Snowflake::createObject($this->_classMap[$name]);
|
||||
}
|
||||
return parent::__get($name); // TODO: Change the autogenerated stub
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Snowflake\Annotation;
|
||||
|
||||
|
||||
use ReflectionClass;
|
||||
|
||||
/**
|
||||
* Class Websocket
|
||||
* @package Snowflake\Annotation
|
||||
*/
|
||||
class Websocket extends Annotation
|
||||
{
|
||||
|
||||
const MESSAGE = 'WEBSOCKET:MESSAGE:';
|
||||
const EVENT = 'WEBSOCKET:EVENT:';
|
||||
|
||||
public $Message;
|
||||
|
||||
|
||||
public $Event;
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $reflect
|
||||
* @param array $methods
|
||||
*/
|
||||
public function resolve(ReflectionClass $reflect, array $methods)
|
||||
{
|
||||
$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]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $events
|
||||
* @param $comment
|
||||
* @return false|string
|
||||
*/
|
||||
private function getName($events, $comment)
|
||||
{
|
||||
$event = $events[1];
|
||||
if ($event !== 'message') {
|
||||
return self::EVENT . $event;
|
||||
}
|
||||
preg_match('/@Message\((.*)?\)/', $comment, $message);
|
||||
if (isset($message[1])) {
|
||||
return false;
|
||||
}
|
||||
return self::MESSAGE . $message[1];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/4/25 0025
|
||||
* Time: 18:38
|
||||
*/
|
||||
|
||||
namespace Snowflake;
|
||||
|
||||
|
||||
use Exception;
|
||||
use HttpServer\Abstracts\HttpService;
|
||||
use HttpServer\Server;
|
||||
use Snowflake\Abstracts\BaseApplication;
|
||||
|
||||
/**
|
||||
* Class Init
|
||||
*
|
||||
* @package BeReborn\Web
|
||||
*
|
||||
* @property-read Config $config
|
||||
*/
|
||||
class Application extends BaseApplication
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $id = 'uniqueId';
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$process = Snowflake::get()->processes;
|
||||
if (Config::has('servers', true)) {
|
||||
/** @var Server $https */
|
||||
$https = $this->make(Server::class);
|
||||
$servers = $https->initCore(Config::get('servers'));
|
||||
$process->push($servers);
|
||||
}
|
||||
if (Config::has('processes', true)) {
|
||||
$process->push(Config::get('processes'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function start()
|
||||
{
|
||||
$process = Snowflake::get()->processes;
|
||||
$process->start();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $className
|
||||
* @param null $abstracts
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function make($className, $abstracts = null)
|
||||
{
|
||||
return Snowflake::createObject($className);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/5/2 0002
|
||||
* Time: 14:51
|
||||
*/
|
||||
|
||||
namespace Snowflake\Cache;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Snowflake\Abstracts\Component;
|
||||
use Swoole\Coroutine\System;
|
||||
|
||||
/**
|
||||
* Class File
|
||||
* @package BeReborn\Cache
|
||||
*/
|
||||
class File extends Component implements ICache
|
||||
{
|
||||
public $path;
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init(); // TODO: Change the autogenerated stub
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $val
|
||||
*/
|
||||
public function set($key, $val)
|
||||
{
|
||||
if (is_array($val) || is_object($val)) {
|
||||
$val = serialize($val);
|
||||
}
|
||||
$tmpFile = $this->getCacheKey($key);
|
||||
if (!$this->exists($tmpFile)) {
|
||||
touch($tmpFile);
|
||||
}
|
||||
System::writeFile($tmpFile, $val, LOCK_EX);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param array $hashKeys
|
||||
* @return mixed|void
|
||||
*/
|
||||
public function hMget($key, array $hashKeys)
|
||||
{
|
||||
$hash = $this->get($key);
|
||||
if (!is_array($hash)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$nowHash = [];
|
||||
foreach ($hashKeys as $hashKey) {
|
||||
$nowHash[$hashKey] = $hash[$hashKey] ?? null;
|
||||
}
|
||||
return $nowHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param array $val
|
||||
* @return mixed|void
|
||||
*/
|
||||
public function hMset($key, array $val)
|
||||
{
|
||||
$hash = $this->get($key);
|
||||
if (!is_array($hash)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$merge = array_merge($hash, $val);
|
||||
return $this->set($key, $merge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $hashKey
|
||||
* @return mixed|void
|
||||
*/
|
||||
public function hget($key, $hashKey)
|
||||
{
|
||||
$hash = $this->get($key);
|
||||
if (!is_array($hash)) {
|
||||
return false;
|
||||
}
|
||||
return $hash[$hashKey] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $hashKey
|
||||
* @param $hashValue
|
||||
* @return mixed|void
|
||||
*/
|
||||
public function hset($key, $hashKey, $hashValue)
|
||||
{
|
||||
$hash = $this->get($key);
|
||||
if (!is_array($hash)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$hash[$hashKey] = $hashValue;
|
||||
|
||||
return $this->set($key, $hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @return bool
|
||||
*/
|
||||
public function exists($key)
|
||||
{
|
||||
return file_exists($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function get($key)
|
||||
{
|
||||
$tmpFile = $this->getCacheKey($key);
|
||||
if (!$this->exists($tmpFile)) {
|
||||
return NULL;
|
||||
}
|
||||
$content = file_get_contents($tmpFile);
|
||||
return unserialize($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @return string
|
||||
* @throws
|
||||
*/
|
||||
private function getCacheKey($key)
|
||||
{
|
||||
return storage($key,'cache');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/11/8 0008
|
||||
* Time: 16:35
|
||||
*/
|
||||
|
||||
namespace Snowflake\Cache;
|
||||
|
||||
/**
|
||||
* Interface ICache
|
||||
* @package BeReborn\Cache
|
||||
*/
|
||||
interface ICache
|
||||
{
|
||||
/**
|
||||
* @param $key
|
||||
* @param $val
|
||||
* @return mixed
|
||||
*/
|
||||
public function set($key, $val);
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key);
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $hashKeys
|
||||
* @return mixed
|
||||
*/
|
||||
public function hMget($key, array $hashKeys);
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param array $val
|
||||
* @return mixed
|
||||
*/
|
||||
public function hMset($key, array $val);
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $hashKey
|
||||
* @return mixed
|
||||
*/
|
||||
public function hget($key, $hashKey);
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $hashKey
|
||||
* @param $hashValue
|
||||
* @return mixed
|
||||
*/
|
||||
public function hset($key, $hashKey, $hashValue);
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @return bool
|
||||
*/
|
||||
public function exists($key);
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
namespace Snowflake\Cache;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Snowflake\Abstracts\Component;
|
||||
|
||||
/**
|
||||
* Class Memcached
|
||||
* @package Yoc\cache
|
||||
*/
|
||||
class Memcached extends Component implements ICache
|
||||
{
|
||||
|
||||
/** @var \Memcached */
|
||||
private $_memcached;
|
||||
|
||||
public $host = '127.0.0.1';
|
||||
|
||||
public $port = 11211;
|
||||
|
||||
public $timeout = 60;
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->_memcached = new \Memcached();
|
||||
$isConnected = $this->_memcached->addServer(
|
||||
env('cache.memcached.host', $this->host),
|
||||
env('cache.memcached.port', $this->port),
|
||||
env('cache.memcached.timeout', $this->timeout)
|
||||
);
|
||||
if (!$isConnected) {
|
||||
throw new Exception('Cache Memcache Host 127.0.0.1 Connect Fail.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $val
|
||||
* @return mixed|void
|
||||
*/
|
||||
public function set($key, $val)
|
||||
{
|
||||
// TODO: Implement set() method.
|
||||
if (is_array($val) || is_object($val)) {
|
||||
$val = serialize($val);
|
||||
}
|
||||
|
||||
$this->_memcached->set($key, $val);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @return mixed|void
|
||||
*/
|
||||
public function get($key)
|
||||
{
|
||||
// TODO: Implement get() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param array $hashKeys
|
||||
* @return mixed|void
|
||||
*/
|
||||
public function hMget($key, array $hashKeys)
|
||||
{
|
||||
// TODO: Implement hMget() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param array $val
|
||||
* @return mixed|void
|
||||
*/
|
||||
public function hMset($key, array $val)
|
||||
{
|
||||
// TODO: Implement hMset() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $hashKey
|
||||
* @return mixed|void
|
||||
*/
|
||||
public function hget($key, $hashKey)
|
||||
{
|
||||
// TODO: Implement hget() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $hashKey
|
||||
* @param $hashValue
|
||||
* @return mixed|void
|
||||
*/
|
||||
public function hset($key, $hashKey, $hashValue)
|
||||
{
|
||||
// TODO: Implement hset() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @return bool|void
|
||||
*/
|
||||
public function exists($key)
|
||||
{
|
||||
// TODO: Implement exists() method.
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/4/27 0027
|
||||
* Time: 11:00
|
||||
*/
|
||||
|
||||
namespace Snowflake\Cache;
|
||||
|
||||
use Exception;
|
||||
use Snowflake\Abstracts\Component;
|
||||
use Snowflake\Config;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Coroutine;
|
||||
|
||||
/**
|
||||
* Class Redis
|
||||
* @package BeReborn\Cache
|
||||
* @see \Redis
|
||||
* @method append($key, $value): int
|
||||
* @method auth($password):
|
||||
* @method bgSave()
|
||||
* @method bgrewriteaof()
|
||||
* @method bitcount($key)
|
||||
* @method bitop($operation, $ret_key, $key, $other_keys = NULL)
|
||||
* @method bitpos($key, $bit, $start = NULL, $end = NULL)
|
||||
* @method blPop($key, $timeout_or_key, $extra_args = NULL)
|
||||
* @method brPop($key, $timeout_or_key, $extra_args = NULL)
|
||||
* @method brpoplpush($src, $dst, $timeout)
|
||||
* @method bzPopMax($key, $timeout_or_key, $extra_args = NULL)
|
||||
* @method bzPopMin($key, $timeout_or_key, $extra_args = NULL)
|
||||
* @method clearLastError()
|
||||
* @method client($cmd, $args = NULL)
|
||||
* @method close()
|
||||
* @method command($args = NULL)
|
||||
* @method config($cmd, $key, $value = NULL)
|
||||
* @method connect($host, $port = NULL, $timeout = NULL, $retry_interval = NULL)
|
||||
* @method dbSize()
|
||||
* @method debug($key)
|
||||
* @method decr($key)
|
||||
* @method decrBy($key, $value)
|
||||
* @method delete($key, $other_keys = NULL)
|
||||
* @method discard()
|
||||
* @method dump($key)
|
||||
* @method echo ($msg)
|
||||
* @method eval($script, $args = NULL, $num_keys = NULL)
|
||||
* @method evalsha($script_sha, $args = NULL, $num_keys = NULL)
|
||||
* @method exec()
|
||||
* @method exists($key, $other_keys = NULL)
|
||||
* @method expireAt($key, $timestamp)
|
||||
* @method flushAll($async = NULL)
|
||||
* @method flushDB($async = NULL)
|
||||
* @method geoadd($key, $lng, $lat, $member, $other_triples = NULL)
|
||||
* @method geodist($key, $src, $dst, $unit = NULL)
|
||||
* @method geohash($key, $member, $other_members = NULL)
|
||||
* @method geopos($key, $member, $other_members = NULL)
|
||||
* @method georadius($key, $lng, $lan, $radius, $unit, $opts = [])
|
||||
* @method georadius_ro($key, $lng, $lan, $radius, $unit, $opts = [])
|
||||
* @method georadiusbymember($key, $member, $radius, $unit, $opts = [])
|
||||
* @method georadiusbymember_ro($key, $member, $radius, $unit, $opts = [])
|
||||
* @method get($key)
|
||||
* @method getAuth()
|
||||
* @method getBit($key, $offset)
|
||||
* @method getDBNum()
|
||||
* @method getHost()
|
||||
* @method getKeys($pattern)
|
||||
* @method getLastError()
|
||||
* @method getMode()
|
||||
* @method getMultiple($keys)
|
||||
* @method getOption($option)
|
||||
* @method getPersistentID()
|
||||
* @method getPort()
|
||||
* @method getRange($key, $start, $end)
|
||||
* @method getReadTimeout()
|
||||
* @method getSet($key, $value)
|
||||
* @method getTimeout()
|
||||
* @method hDel($key, $member, $other_members = NULL)
|
||||
* @method hExists($key, $member)
|
||||
* @method hGet($key, $member)
|
||||
* @method hGetAll($key)
|
||||
* @method hIncrBy($key, $member, $value)
|
||||
* @method hIncrByFloat($key, $member, $value)
|
||||
* @method hKeys($key)
|
||||
* @method hLen($key)
|
||||
* @method hMget($key, $keys)
|
||||
* @method hMset($key, $pairs)
|
||||
* @method hSet($key, $member, $value)
|
||||
* @method hSetNx($key, $member, $value)
|
||||
* @method hStrLen($key, $member)
|
||||
* @method hVals($key)
|
||||
* @method hscan($str_key, $i_iterator, $str_pattern = NULL, $i_count = NULL)
|
||||
* @method incr($key)
|
||||
* @method incrBy($key, $value)
|
||||
* @method incrByFloat($key, $value)
|
||||
* @method info($option = NULL)
|
||||
* @method isConnected()
|
||||
* @method lGet($key, $index)
|
||||
* @method lGetRange($key, $start, $end)
|
||||
* @method lInsert($key, $position, $pivot, $value)
|
||||
* @method lPop($key)
|
||||
* @method lPush($key, $value)
|
||||
* @method lPushx($key, $value)
|
||||
* @method lRemove($key, $value, $count)
|
||||
* @method lSet($key, $index, $value)
|
||||
* @method lSize($key)
|
||||
* @method lastSave()
|
||||
* @method listTrim($key, $start, $stop)
|
||||
* @method migrate($host, $port, $key, $db, $timeout, $copy = NULL, $replace = NULL)
|
||||
* @method move($key, $dbindex)
|
||||
* @method mset($pairs)
|
||||
* @method msetnx($pairs)
|
||||
* @method multi($mode = NULL)
|
||||
* @method object($field, $key)
|
||||
* @method pconnect($host, $port = NULL, $timeout = NULL)
|
||||
* @method persist($key)
|
||||
* @method pexpire($key, $timestamp)
|
||||
* @method pexpireAt($key, $timestamp)
|
||||
* @method pfadd($key, $elements)
|
||||
* @method pfcount($key)
|
||||
* @method pfmerge($dstkey, $keys)
|
||||
* @method ping()
|
||||
* @method pipeline()
|
||||
* @method psetex($key, $expire, $value)
|
||||
* @method psubscribe($patterns, $callback)
|
||||
* @method pttl($key)
|
||||
* @method publish($channel, $message)
|
||||
* @method pubsub($cmd, $args = NULL)
|
||||
* @method punsubscribe($pattern, $other_patterns = NULL)
|
||||
* @method rPop($key)
|
||||
* @method rPush($key, $value)
|
||||
* @method rPushx($key, $value)
|
||||
* @method randomKey()
|
||||
* @method rawcommand($cmd, $args = NULL)
|
||||
* @method renameKey($key, $newkey)
|
||||
* @method renameNx($key, $newkey)
|
||||
* @method restore($ttl, $key, $value)
|
||||
* @method role()
|
||||
* @method rpoplpush($src, $dst)
|
||||
* @method sAdd($key, $value)
|
||||
* @method sAddArray($key, $options)
|
||||
* @method sContains($key, $value)
|
||||
* @method sDiff($key, $other_keys = NULL)
|
||||
* @method sDiffStore($dst, $key, $other_keys = NULL)
|
||||
* @method sInter($key, $other_keys = NULL)
|
||||
* @method sInterStore($dst, $key, $other_keys = NULL)
|
||||
* @method sMembers($key)
|
||||
* @method sMove($src, $dst, $value)
|
||||
* @method sPop($key)
|
||||
* @method sRandMember($key, $count = NULL)
|
||||
* @method sRemove($key, $member, $other_members = NULL)
|
||||
* @method sSize($key)
|
||||
* @method sUnion($key, $other_keys = NULL)
|
||||
* @method sUnionStore($dst, $key, $other_keys = NULL)
|
||||
* @method save()
|
||||
* @method scan($i_iterator, $str_pattern = NULL, $i_count = NULL)
|
||||
* @method script($cmd, $args = NULL)
|
||||
* @method select($dbindex)
|
||||
* @method set($key, $value, $opts = NULL)
|
||||
* @method setBit($key, $offset, $value)
|
||||
* @method setOption($option, $value)
|
||||
* @method setRange($key, $offset, $value)
|
||||
* @method setTimeout($key, $timeout)
|
||||
* @method setex($key, $expire, $value)
|
||||
* @method setnx($key, $value)
|
||||
* @method slaveof($host = NULL, $port = NULL)
|
||||
* @method slowlog($arg, $option = NULL)
|
||||
* @method sort($key, $options = [])
|
||||
* @method sortAsc($key, $pattern = NULL, $get = NULL, $start = NULL, $end = NULL, $getList = NULL)
|
||||
* @method sortAscAlpha($key, $pattern = NULL, $get = NULL, $start = NULL, $end = NULL, $getList = NULL)
|
||||
* @method sortDesc($key, $pattern = NULL, $get = NULL, $start = NULL, $end = NULL, $getList = NULL)
|
||||
* @method sortDescAlpha($key, $pattern = NULL, $get = NULL, $start = NULL, $end = NULL, $getList = NULL)
|
||||
* @method sscan($str_key, $i_iterator, $str_pattern = NULL, $i_count = NULL)
|
||||
* @method strlen($key)
|
||||
* @method subscribe($channels, $callback)
|
||||
* @method swapdb($srcdb, $dstdb)
|
||||
* @method time()
|
||||
* @method ttl($key)
|
||||
* @method type($key)
|
||||
* @method unlink($key, $other_keys = NULL)
|
||||
* @method unsubscribe($channel, $other_channels = NULL)
|
||||
* @method unwatch()
|
||||
* @method wait($numslaves, $timeout)
|
||||
* @method watch($key, $other_keys = NULL)
|
||||
* @method xack($str_key, $str_group, $arr_ids)
|
||||
* @method xadd($str_key, $str_id, $arr_fields, $i_maxlen = NULL, $boo_approximate = NULL)
|
||||
* @method xclaim($str_key, $str_group, $str_consumer, $i_min_idle, $arr_ids, $arr_opts = [])
|
||||
* @method xdel($str_key, $arr_ids)
|
||||
* @method xgroup($str_operation, $str_key = NULL, $str_arg1 = NULL, $str_arg2 = NULL, $str_arg3 = NULL)
|
||||
* @method xinfo($str_cmd, $str_key = NULL, $str_group = NULL)
|
||||
* @method xlen($key)
|
||||
* @method xpending($str_key, $str_group, $str_start = NULL, $str_end = NULL, $i_count = NULL, $str_consumer = NULL)
|
||||
* @method xrange($str_key, $str_start, $str_end, $i_count = NULL)
|
||||
* @method xread($arr_streams, $i_count = NULL, $i_block = NULL)
|
||||
* @method xreadgroup($str_group, $str_consumer, $arr_streams, $i_count = NULL, $i_block = NULL)
|
||||
* @method xrevrange($str_key, $str_start, $str_end, $i_count = NULL)
|
||||
* @method xtrim($str_key, $i_maxlen, $boo_approximate = NULL)
|
||||
* @method zAdd($key, $score, $value)
|
||||
* @method zCard($key)
|
||||
* @method zCount($key, $min, $max)
|
||||
* @method zDelete($key, $member, $other_members = NULL)
|
||||
* @method zDeleteRangeByRank($key, $start, $end)
|
||||
* @method zDeleteRangeByScore($key, $min, $max)
|
||||
* @method zIncrBy($key, $value, $member)
|
||||
* @method zInter($key, $keys, $weights = [], $aggregate = NULL)
|
||||
* @method zLexCount($key, $min, $max)
|
||||
* @method zRange($key, $start, $end, $scores = NULL)
|
||||
* @method zRangeByLex($key, $min, $max, $offset = NULL, $limit = NULL)
|
||||
* @method zRangeByScore($key, $start, $end, $options = [])
|
||||
* @method zRank($key, $member)
|
||||
* @method zRemRangeByLex($key, $min, $max)
|
||||
* @method zRevRange($key, $start, $end, $scores = NULL)
|
||||
* @method zRevRangeByLex($key, $min, $max, $offset = NULL, $limit = NULL)
|
||||
* @method zRevRangeByScore($key, $start, $end, $options = [])
|
||||
* @method zRevRank($key, $member)
|
||||
* @method zScore($key, $member)
|
||||
* @method zUnion($key, $keys, $weights = [], $aggregate = NULL)
|
||||
* @method zscan($str_key, $i_iterator, $str_pattern = NULL, $i_count = NULL)
|
||||
* @method zPopMax($key)
|
||||
* @method zPopMin($key)
|
||||
* @method del($key, $other_keys = NULL)
|
||||
* @method evaluate($script, $args = NULL, $num_keys = NULL)
|
||||
* @method evaluateSha($script_sha, $args = NULL, $num_keys = NULL)
|
||||
* @method expire($key, $timeout)
|
||||
* @method keys($pattern)
|
||||
* @method lLen($key)
|
||||
* @method lindex($key, $index)
|
||||
* @method lrange($key, $start, $end)
|
||||
* @method lrem($key, $value, $count)
|
||||
* @method ltrim($key, $start, $stop)
|
||||
* @method mget($keys)
|
||||
* @method open($host, $port = NULL, $timeout = NULL, $retry_interval = NULL)
|
||||
* @method popen($host, $port = NULL, $timeout = NULL)
|
||||
* @method rename($key, $newkey)
|
||||
* @method sGetMembers($key)
|
||||
* @method scard($key)
|
||||
* @method sendEcho($msg)
|
||||
* @method sismember($key, $value)
|
||||
* @method srem($key, $member, $other_members = NULL)
|
||||
* @method substr($key, $start, $end)
|
||||
* @method zRem($key, $member, $other_members = NULL)
|
||||
* @method zRemRangeByRank($key, $min, $max)
|
||||
* @method zRemRangeByScore($key, $min, $max)
|
||||
* @method zRemove($key, $member, $other_members = NULL)
|
||||
* @method zRemoveRangeByScore($key, $min, $max)
|
||||
* @method zReverseRange($key, $start, $end, $scores = NULL)
|
||||
* @method zSize($key)
|
||||
* @method zinterstore($key, $keys, $weights = [], $aggregate = NULL)
|
||||
* @method zunionstore($key, $keys, $weights = [], $aggregate = NULL)
|
||||
*/
|
||||
class Redis extends Component
|
||||
{
|
||||
public $host = '127.0.0.1';
|
||||
public $auth = 'xl.2005113426';
|
||||
public $port = 6973;
|
||||
public $databases = 0;
|
||||
public $timeout = -1;
|
||||
public $prefix = 'idd';
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$event = Snowflake::get()->event;
|
||||
$event->on(Event::RELEASE_ALL, [$this, 'destroy']);
|
||||
$event->on(Event::EVENT_AFTER_REQUEST, [$this, 'release']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $arguments
|
||||
* @return mixed
|
||||
* @throws
|
||||
*/
|
||||
public function __call($name, $arguments)
|
||||
{
|
||||
try {
|
||||
if (method_exists($this, $name)) {
|
||||
$data = $this->{$name}(...$arguments);
|
||||
} else {
|
||||
$data = $this->proxy()->{$name}(...$arguments);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
$this->error(print_r($exception, true));
|
||||
$data = false;
|
||||
} finally {
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放连接池
|
||||
*/
|
||||
public function release()
|
||||
{
|
||||
$connections = Snowflake::get()->pool->redis;
|
||||
$connections->release($this->get_config(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁连接池
|
||||
*/
|
||||
public function destroy()
|
||||
{
|
||||
$connections = Snowflake::get()->pool->redis;
|
||||
$connections->destroy($this->get_config(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Redis
|
||||
* @throws Exception
|
||||
*/
|
||||
public function proxy()
|
||||
{
|
||||
$connections = Snowflake::get()->pool->redis;
|
||||
|
||||
$config = $this->get_config();
|
||||
$name = $config['host'] . ':' . $config['prefix'] . ':' . $config['databases'];
|
||||
|
||||
$connections->initConnections('redis:' . $name, true);
|
||||
$connections->setLength(env('REDIS.POOL_LENGTH', 100));
|
||||
|
||||
$client = $connections->getConnection($config, true);
|
||||
if (!($client instanceof \Redis)) {
|
||||
throw new Exception('Redis connections more.');
|
||||
}
|
||||
return $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get_config(): array
|
||||
{
|
||||
return [
|
||||
'host' => env('REDIS.HOST', $this->host),
|
||||
'port' => env('REDIS.PORT', $this->port),
|
||||
'auth' => env('REDIS.PASSWORD', $this->auth),
|
||||
'timeout' => env('REDIS.TIMEOUT', 2),
|
||||
'databases' => env('REDIS.DATABASE', $this->databases),
|
||||
'read_timeout' => env('REDIS.READ_TIMEOUT', 10),
|
||||
'prefix' => env('REDIS.PREFIX', 'system:'),
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Snowflake\Console;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Swoole\Coroutine\Channel;
|
||||
|
||||
/**
|
||||
* Class AbstractConsole
|
||||
* @package BeReborn\Console
|
||||
*/
|
||||
abstract class AbstractConsole
|
||||
{
|
||||
|
||||
/**
|
||||
* @var Command[]
|
||||
*/
|
||||
public $commands = [];
|
||||
|
||||
/** @var Dtl $parameters */
|
||||
private $parameters;
|
||||
|
||||
/** @var array */
|
||||
private $_config;
|
||||
|
||||
/**
|
||||
* @param array $config
|
||||
* AbstractConsole constructor.
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct(array $config = [])
|
||||
{
|
||||
$this->_config = $config;
|
||||
$this->signCommand(\BeReborn::createObject(DefaultCommand::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
||||
return $this->_config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function setParameters()
|
||||
{
|
||||
$this->parameters = new Dtl($_SERVER['argv']);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Command $command
|
||||
* @return mixed
|
||||
*/
|
||||
public function execCommand(Command $command)
|
||||
{
|
||||
return $command->handler($this->parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Command|null
|
||||
*/
|
||||
public function search()
|
||||
{
|
||||
$name = $this->parameters->getCommandName();
|
||||
$this->parameters->set('commandList', $this->getCommandList());
|
||||
foreach ($this->commands as $command) {
|
||||
if ($command->command != $name) {
|
||||
continue;
|
||||
}
|
||||
return $command;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Command $abstractConsole
|
||||
*
|
||||
* 注册命令
|
||||
*/
|
||||
public function signCommand(Command $abstractConsole)
|
||||
{
|
||||
$this->commands[] = $abstractConsole;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $kernel
|
||||
* @throws Exception
|
||||
*/
|
||||
public function batch($kernel)
|
||||
{
|
||||
if (is_object($kernel)) {
|
||||
if (!property_exists($kernel, 'commands')) {
|
||||
return;
|
||||
}
|
||||
$kernel = $kernel->commands;
|
||||
}
|
||||
if (!is_array($kernel)) {
|
||||
return;
|
||||
}
|
||||
foreach ($kernel as $command) {
|
||||
$this->signCommand(\BeReborn::createObject($command));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Command $abstractConsole
|
||||
* 释放一个命令
|
||||
*/
|
||||
public function destroyCommand(Command $abstractConsole)
|
||||
{
|
||||
foreach ($this->commands as $index => $command) {
|
||||
if ($abstractConsole === $command) {
|
||||
unset($this->commands[$index]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getCommandList()
|
||||
{
|
||||
$_tmp = [];
|
||||
foreach ($this->commands as $command) {
|
||||
$_tmp[$command->command] = [$command->description, $command];
|
||||
}
|
||||
ksort($_tmp, SORT_ASC);
|
||||
return $_tmp;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/10/7 0007
|
||||
* Time: 2:16
|
||||
*/
|
||||
|
||||
namespace BeReborn\Console;
|
||||
|
||||
|
||||
use BeReborn\Base\BaseApplication;
|
||||
use kafka\Protocol\SyncGroup;
|
||||
use Swoole\Coroutine\Channel;
|
||||
use Swoole\Runtime;
|
||||
use Swoole\Timer;
|
||||
|
||||
/**
|
||||
* Class Application
|
||||
* @package BeReborn\Console
|
||||
*/
|
||||
class Application extends BaseApplication
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $id = 'uniqueId';
|
||||
|
||||
private $console;
|
||||
|
||||
/** @var Channel */
|
||||
private $channel;
|
||||
|
||||
/**
|
||||
* Application constructor.
|
||||
* @param array $config
|
||||
* @throws
|
||||
*/
|
||||
public function __construct(array $config = [])
|
||||
{
|
||||
parent::__construct($config);
|
||||
|
||||
$this->channel = new Channel(1);
|
||||
$this->console = new Console($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @throws
|
||||
*/
|
||||
public function register($class)
|
||||
{
|
||||
if (is_string($class) || is_callable($class, true)) {
|
||||
$class = \BeReborn::createObject($class);
|
||||
}
|
||||
$this->console->signCommand($class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param null $kernel
|
||||
* @return string|void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function run($kernel = null)
|
||||
{
|
||||
setCommand(true);
|
||||
try {
|
||||
$params = '';
|
||||
$kernel = \BeReborn::make($kernel, Kernel::class);
|
||||
|
||||
Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
|
||||
|
||||
$this->console->setParameters();
|
||||
$this->console->batch($kernel);
|
||||
$class = $this->console->search();
|
||||
$params = response()->send($this->console->execCommand($class));
|
||||
} catch (\Exception $exception) {
|
||||
$params = response()->send(implode("\n", [
|
||||
'Msg: ' . $exception->getMessage(),
|
||||
'Line: ' . $exception->getLine(),
|
||||
'File: ' . $exception->getFile()
|
||||
]));
|
||||
} finally {
|
||||
Timer::clearAll();
|
||||
return $params;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Snowflake\Console;
|
||||
|
||||
use Snowflake\Abstracts\BaseObject;
|
||||
|
||||
/**
|
||||
* Class Command
|
||||
* @package BeReborn\Console
|
||||
*/
|
||||
abstract class Command extends BaseObject implements CommandInterface
|
||||
{
|
||||
|
||||
public $command = '';
|
||||
public $description = '';
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* 返回执行的命令名称
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->command;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* 返回命令描述
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Snowflake\Console;
|
||||
|
||||
/**
|
||||
* Interface CommandInterface
|
||||
* @package BeReborn\Console
|
||||
*/
|
||||
interface CommandInterface
|
||||
{
|
||||
|
||||
public function handler(Dtl $dtl);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace BeReborn\Console;
|
||||
|
||||
/**
|
||||
* Class Console
|
||||
* @package BeReborn\Console
|
||||
*/
|
||||
class Console extends AbstractConsole
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace BeReborn\Console;
|
||||
|
||||
/**
|
||||
* Class DefaultCommand
|
||||
* @package BeReborn\Console
|
||||
*/
|
||||
class DefaultCommand extends Command
|
||||
{
|
||||
public $command = 'list';
|
||||
|
||||
public $description = 'help';
|
||||
|
||||
public function handler(Dtl $dtl)
|
||||
{
|
||||
$param = $dtl->get('commandList');
|
||||
|
||||
$last = '';
|
||||
$lists = [str_pad('Commands', 24, ' ', STR_PAD_RIGHT) . '注释'];
|
||||
foreach ($param as $key => $val) {
|
||||
$split = explode(':', $key);
|
||||
if (empty($last) && isset($split[0])) {
|
||||
$lists[] = str_pad("\033[32;40;1;1m" . $split[0] . " \033[0m", 40, ' ', STR_PAD_RIGHT);
|
||||
} else if (isset($split[0]) && $last != $split[0]) {
|
||||
$lists[] = str_pad("\033[32;40;1;1m" . $split[0] . " \033[0m", 40, ' ', STR_PAD_RIGHT);
|
||||
}
|
||||
|
||||
$last = $split[0] ?? '';
|
||||
|
||||
list($method, $ts) = $val;
|
||||
$lists[] = str_pad("\033[32;40;1;1m " . $key . " \033[0m", 40, ' ', STR_PAD_RIGHT) . $method;
|
||||
}
|
||||
return implode(PHP_EOL, $lists);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Snowflake\Console;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
use HttpServer\Http\HttpParams;
|
||||
use HttpServer\Http\Request;
|
||||
|
||||
/**
|
||||
* Class Dtl
|
||||
* @package BeReborn\Console
|
||||
*/
|
||||
class Dtl
|
||||
{
|
||||
|
||||
private $parameters;
|
||||
|
||||
private $command = '';
|
||||
|
||||
/**
|
||||
* Dtl constructor.
|
||||
* @param $parameters
|
||||
* @throws
|
||||
*/
|
||||
public function __construct($parameters)
|
||||
{
|
||||
$this->parameters = $this->resolve($parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCommandName()
|
||||
{
|
||||
return $this->command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $parameters
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function resolve($parameters)
|
||||
{
|
||||
$arrays = [];
|
||||
$parameters = array_slice($parameters, 1);
|
||||
|
||||
$this->command = array_shift($parameters);
|
||||
foreach ($parameters as $parameter) {
|
||||
$explode = explode('=', $parameter);
|
||||
if (count($explode) < 2) {
|
||||
continue;
|
||||
}
|
||||
$arrays[array_shift($explode)] = current($explode);
|
||||
}
|
||||
|
||||
$request = new Request();
|
||||
$request->fd = 0;
|
||||
$request->params = new HttpParams([], $arrays, []);
|
||||
$request->headers = new HttpParams([]);
|
||||
|
||||
Context::setRequest($request);
|
||||
return $arrays;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param null $default
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function get($key, $default = null)
|
||||
{
|
||||
return $this->parameters[$key] ?? $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $value
|
||||
* @return $this
|
||||
*/
|
||||
public function set($key, $value)
|
||||
{
|
||||
$this->parameters[$key] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $array
|
||||
* @return $this
|
||||
*/
|
||||
public function setBatch(array $array)
|
||||
{
|
||||
if (empty($array)) {
|
||||
return $this;
|
||||
}
|
||||
foreach ($array as $key => $value) {
|
||||
$this->parameters[$key] = $value;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* 获取
|
||||
*/
|
||||
public function getAll()
|
||||
{
|
||||
return $this->parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null
|
||||
* 清理
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
return $this->parameters = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false|string
|
||||
*/
|
||||
public function toJson()
|
||||
{
|
||||
return json_encode($this->parameters, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace BeReborn\Console;
|
||||
|
||||
|
||||
interface ICommand
|
||||
{
|
||||
|
||||
public function handler();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace BeReborn\Console;
|
||||
|
||||
|
||||
class Kernel
|
||||
{
|
||||
public $commands = [
|
||||
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/4/4 0004
|
||||
* Time: 14:57
|
||||
*/
|
||||
|
||||
namespace Snowflake\Core;
|
||||
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class ArrayAccess
|
||||
* @package BeReborn\Core
|
||||
*/
|
||||
class ArrayAccess
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function toArray($data)
|
||||
{
|
||||
if (!is_object($data) && !is_array($data)) {
|
||||
return $data;
|
||||
}
|
||||
if (is_object($data)) {
|
||||
$data = self::objToArray($data);
|
||||
}
|
||||
$tmp = [];
|
||||
if (!is_array($data)) {
|
||||
return $data;
|
||||
}
|
||||
foreach ($data as $key => $val) {
|
||||
if (is_array($val) || is_object($val)) {
|
||||
$tmp[$key] = self::toArray($val);
|
||||
} else {
|
||||
$tmp[$key] = $val;
|
||||
}
|
||||
}
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @return array|mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function objToArray($data)
|
||||
{
|
||||
if (!is_object($data)) {
|
||||
return $data;
|
||||
}
|
||||
if (method_exists($data, 'get')) {
|
||||
$data = $data->get();
|
||||
if (is_array($data)) {
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
if (method_exists($data, 'toArray')) {
|
||||
$data = $data->toArray();
|
||||
} else {
|
||||
$data = get_object_vars((object)$data);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $oldArray
|
||||
* @param array $newArray
|
||||
* @return array
|
||||
*/
|
||||
public static function merge(array $oldArray, array $newArray)
|
||||
{
|
||||
if (empty($oldArray)) {
|
||||
return $newArray;
|
||||
} else if (empty($newArray)) {
|
||||
return $oldArray;
|
||||
}
|
||||
foreach ($newArray as $item => $value) {
|
||||
if (!isset($oldArray[$item])) {
|
||||
$oldArray[$item] = $value;
|
||||
}
|
||||
if (is_array($value)) {
|
||||
$oldArray[$item] = self::merge($oldArray[$item], $value);
|
||||
} else {
|
||||
$oldArray[$item] = $value;
|
||||
}
|
||||
}
|
||||
return $oldArray;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: dell
|
||||
* Date: 2019/1/14 0014
|
||||
* Time: 13:50
|
||||
*/
|
||||
|
||||
namespace Snowflake\Core;
|
||||
|
||||
/**
|
||||
* Class DateFormat
|
||||
* @package BeReborn\Core
|
||||
*/
|
||||
class DateFormat
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $time
|
||||
* @return bool|false|int|string
|
||||
*/
|
||||
private static function check($time)
|
||||
{
|
||||
if ($time === null) {
|
||||
$time = time();
|
||||
} else if (is_numeric($time)) {
|
||||
$length = strlen(floatval($time));
|
||||
if ($length != 10 && $length != 13) {
|
||||
return false;
|
||||
}
|
||||
} else if (is_string($time)) {
|
||||
$time = strtotime($time);
|
||||
}
|
||||
|
||||
if (date('Y-m-d', $time)) {
|
||||
return $time;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param null $time
|
||||
* @return bool|false|int
|
||||
*
|
||||
* 获取指定日期当周第一天的时间
|
||||
*/
|
||||
public static function getWeekCurrentDay($time = null)
|
||||
{
|
||||
if (!($time = static::check($time))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$time = strtotime('-' . (date('N') - 1) . 'days', $time);
|
||||
|
||||
return strtotime(date('Y-m-d'), $time);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param null $time
|
||||
* @return bool|false|int
|
||||
*
|
||||
* 获取指定日期当月第一天的时间
|
||||
*/
|
||||
public static function getMonthCurrentDay($time = null)
|
||||
{
|
||||
if (!($time = static::check($time))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return strtotime(date('Y-m', $time) . '-01');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $time
|
||||
* @return bool|false|int|string
|
||||
* 指定的月份有几天
|
||||
*/
|
||||
public static function getMonthTotalDay($time)
|
||||
{
|
||||
if (!($time = static::check($time))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$time = date('t', $time);
|
||||
|
||||
return $time;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $startTime
|
||||
* @param null $endTime
|
||||
* @return string
|
||||
*/
|
||||
public static function mtime($startTime, $endTime = null)
|
||||
{
|
||||
if ($endTime === null) {
|
||||
$endTime = microtime(true);
|
||||
}
|
||||
return sprintf('%.7f', $endTime - $startTime);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Snowflake\Core;
|
||||
|
||||
|
||||
/**
|
||||
* Class Help
|
||||
* @package BeReborn\Core
|
||||
*/
|
||||
class Help
|
||||
{
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public static function toXml(array $data)
|
||||
{
|
||||
$xml = "<xml>";
|
||||
foreach ($data as $key => $val) {
|
||||
if (is_numeric($val)) {
|
||||
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
|
||||
} else {
|
||||
$xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
|
||||
}
|
||||
}
|
||||
$xml .= "</xml>";
|
||||
return $xml;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $xml
|
||||
* @return array|mixed
|
||||
*/
|
||||
public static function toArray($xml)
|
||||
{
|
||||
if (empty($xml)) {
|
||||
return [];
|
||||
} else if (is_array($xml)) {
|
||||
return $xml;
|
||||
}
|
||||
if (!Xml::isXml($xml)) {
|
||||
$xml = JSON::decode($xml);
|
||||
}
|
||||
return $xml;
|
||||
|
||||
/* $matchQuote = '/(<\?xml.*?\?>)?<([a-zA-Z_]+)>(<([a-zA-Z_]+)><!.*?><\/\4>)+<\/\2>/';*/
|
||||
// if (!preg_match($matchQuote, $xml)) {
|
||||
// return self::jsonToArray($xml);
|
||||
// }
|
||||
// try {
|
||||
// $data = @simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||
// if ($data !== false) {
|
||||
// $data = json_decode(json_encode($data), TRUE);
|
||||
// } else {
|
||||
// $data = $xml;
|
||||
// }
|
||||
// } catch (\Exception $exception) {
|
||||
// $data = $xml;
|
||||
// } finally {
|
||||
// return $data;
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
public static function jsonToArray($xml)
|
||||
{
|
||||
$_xml = json_decode($xml, true);
|
||||
if (is_null($_xml)) {
|
||||
return $xml;
|
||||
}
|
||||
return $_xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $xml
|
||||
* @return mixed
|
||||
*/
|
||||
public static function xmlToArray($xml)
|
||||
{
|
||||
if (is_array($xml)) {
|
||||
return $xml;
|
||||
}
|
||||
if (($data = @simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)) !== false) {
|
||||
return json_decode(json_encode($data), TRUE);
|
||||
}
|
||||
if (!is_null($json = json_decode($xml, TRUE))) {
|
||||
return $json;
|
||||
}
|
||||
return $xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $parameter
|
||||
* @return array|false|string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function toString($parameter)
|
||||
{
|
||||
if (!is_string($parameter)) {
|
||||
$parameter = ArrayAccess::toArray($parameter);
|
||||
if (is_array($parameter)) {
|
||||
$parameter = JSON::encode($parameter);
|
||||
}
|
||||
}
|
||||
return $parameter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $json
|
||||
* @return false|mixed|string
|
||||
*/
|
||||
public static function toJson($json)
|
||||
{
|
||||
if (is_object($json)) {
|
||||
$json = get_object_vars($json);
|
||||
}
|
||||
if (is_array($json)) {
|
||||
return json_encode($json, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
$matchQuote = '/(<\?xml.*?\?>)?<([a-zA-Z_]+)>(<([a-zA-Z_]+)><!.*?><\/\4>)+<\/\2>/';
|
||||
if (preg_match($matchQuote, $json)) {
|
||||
$json = self::xmlToArray($json);
|
||||
} else {
|
||||
$json = json_decode($json, true);
|
||||
}
|
||||
if (!is_array($json)) {
|
||||
$json = [];
|
||||
}
|
||||
return json_encode($json, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $length
|
||||
* @return string
|
||||
*
|
||||
* 随机字符串
|
||||
*/
|
||||
public static function random($length = 20)
|
||||
{
|
||||
$res = [];
|
||||
$str = 'abcdefghijklmnopqrstuvwxyz';
|
||||
$str .= strtoupper($str) . '1234567890';
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$rand = substr($str, rand(0, strlen($str) - 2), 1);
|
||||
if (empty($rand)) {
|
||||
$rand = substr($str, strlen($str) - 3, 1);
|
||||
}
|
||||
array_push($res, $rand);
|
||||
}
|
||||
|
||||
return implode($res);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $array
|
||||
* @param $key
|
||||
* @param $type
|
||||
* @return string
|
||||
*/
|
||||
public static function sign(array $array, $key, $type)
|
||||
{
|
||||
ksort($array, SORT_ASC);
|
||||
$string = [];
|
||||
foreach ($array as $hashKey => $val) {
|
||||
if (empty($val)) {
|
||||
continue;
|
||||
}
|
||||
$string[] = $hashKey . '=' . $val;
|
||||
}
|
||||
$string[] = 'key=' . $key;
|
||||
$string = implode('&', $string);
|
||||
if ($type == 'MD5') {
|
||||
return strtoupper(md5($string));
|
||||
} else {
|
||||
return hash('sha256', $string);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: admin
|
||||
* Date: 2019-03-20
|
||||
* Time: 01:04
|
||||
*/
|
||||
|
||||
namespace Snowflake\Core;
|
||||
|
||||
/**
|
||||
* Class JSON
|
||||
* @package BeReborn\Core
|
||||
*/
|
||||
class JSON
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @return false|string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function encode($data)
|
||||
{
|
||||
if (empty($data)) {
|
||||
return $data;
|
||||
}
|
||||
if (is_array($data)) {
|
||||
return self::filter(ArrayAccess::toArray($data));
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @return mixed
|
||||
*/
|
||||
private static function filter($data)
|
||||
{
|
||||
array_walk_recursive($data, function (&$value, $key) {
|
||||
if (!is_numeric($value)) {
|
||||
return;
|
||||
}
|
||||
if (is_int(+$value)) {
|
||||
$value = +$value;
|
||||
}
|
||||
});
|
||||
return json_encode($data, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @param bool $asArray
|
||||
* @return mixed
|
||||
*/
|
||||
public static function decode($data, $asArray = true)
|
||||
{
|
||||
if (is_array($data)) {
|
||||
return $data;
|
||||
}
|
||||
return json_decode($data, $asArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $code
|
||||
* @param string $message
|
||||
* @param array $data
|
||||
* @param int $count
|
||||
* @param array $exPageInfo
|
||||
* @return mixed
|
||||
* @throws
|
||||
*/
|
||||
public static function to($code, $message = '', $data = [], $count = 0, $exPageInfo = [])
|
||||
{
|
||||
$params['code'] = $code;
|
||||
if (!is_string($message)) {
|
||||
$params['param'] = $message;
|
||||
if (!empty($data)) {
|
||||
$params['exPageInfo'] = $data;
|
||||
}
|
||||
$params['message'] = 'System success.';
|
||||
} else {
|
||||
$params['message'] = $message;
|
||||
$params['param'] = $data;
|
||||
}
|
||||
if (!empty($exPageInfo)) {
|
||||
$params['exPageInfo'] = $exPageInfo;
|
||||
}
|
||||
$params['count'] = $count;
|
||||
if (is_numeric($data) || !is_numeric($count)) {
|
||||
$params['count'] = $data;
|
||||
$params['exPageInfo'] = $count;
|
||||
}
|
||||
if ((int)$params['count'] == -100) {
|
||||
$params['count'] = 1;
|
||||
}
|
||||
|
||||
ksort($params, SORT_ASC);
|
||||
|
||||
return static::encode($params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $state
|
||||
* @param $body
|
||||
* @return false|int|string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function output($state, $body)
|
||||
{
|
||||
$params['state'] = $state;
|
||||
$params['body'] = ArrayAccess::toArray($body);
|
||||
|
||||
return static::encode($params);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Snowflake\Core;
|
||||
|
||||
/**
|
||||
* Class Reader
|
||||
* @package BeReborn\Core
|
||||
*/
|
||||
class Reader
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param $filepath
|
||||
* @param int $page
|
||||
* @param int $size
|
||||
* @return array and int
|
||||
*/
|
||||
public static function readerServerLogPagination($filepath, $page = 1, $size = 20)
|
||||
{
|
||||
$count = 0;
|
||||
$strings = [];
|
||||
$offset = ($page - 1) * $size;
|
||||
|
||||
if (!file_exists($filepath)) {
|
||||
return [0, []];
|
||||
}
|
||||
|
||||
//只读方式打开文件
|
||||
$fp = fopen($filepath, "r");
|
||||
|
||||
//开始循环读取$buffer_size
|
||||
while (!feof($fp)) {
|
||||
//读文件到缓冲区
|
||||
$buffer = fgets($fp);
|
||||
$count++;
|
||||
if ($count > $offset && count($strings) < $size) {
|
||||
$strings[] = [
|
||||
'id' => $count,
|
||||
'content' => $buffer
|
||||
];
|
||||
}
|
||||
}
|
||||
//关闭文件
|
||||
fclose($fp);
|
||||
unset($fp);
|
||||
|
||||
return ['total' => $count, 'list' => $strings];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $filename
|
||||
* @param $start
|
||||
* @param $lines
|
||||
* @return mixed
|
||||
*/
|
||||
public static function read_backward_line($filename, $start, $lines)
|
||||
{
|
||||
$lines++;
|
||||
$offset = -1;
|
||||
$read = '';
|
||||
$fp = @fopen($filename, "r");
|
||||
|
||||
$tmpStart = 0;
|
||||
while ($lines && fseek($fp, $offset, SEEK_END) >= 0) {
|
||||
|
||||
$c = fgetc($fp);
|
||||
if ($c == "\n" || $c == "\r") {
|
||||
if (++$tmpStart >= $start)
|
||||
$lines--;
|
||||
}
|
||||
|
||||
|
||||
if ($tmpStart >= $start)
|
||||
$read .= $c;
|
||||
$offset--;
|
||||
}
|
||||
|
||||
$read = trim($read);
|
||||
|
||||
$contents = [];
|
||||
$read = array_reverse(explode("\n", strrev($read)));
|
||||
foreach ($read as $key => $value) {
|
||||
if (empty($value)) {
|
||||
unset($read[$key]);
|
||||
} else {
|
||||
$contents[] = ['content' => $value, 'id' => $key + $start];
|
||||
}
|
||||
}
|
||||
|
||||
$response['total'] = self::read_count_by_file($filename);
|
||||
$response['list'] = $contents;
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $filepath
|
||||
* @return int
|
||||
*/
|
||||
private static function read_count_by_file($filepath)
|
||||
{
|
||||
$count = 0;
|
||||
//只读方式打开文件
|
||||
$fp = fopen($filepath, "r");
|
||||
|
||||
//开始循环读取$buffer_size
|
||||
while (fgets($fp)) {
|
||||
$count++;
|
||||
}
|
||||
//关闭文件
|
||||
fclose($fp);
|
||||
unset($fp);
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $filepath
|
||||
* @param int $page
|
||||
* @param int $size
|
||||
* @return array
|
||||
*/
|
||||
public static function folderPagination($filepath, $page = 1, $size = 20)
|
||||
{
|
||||
$count = 0;
|
||||
$strings = [];
|
||||
$offset = ($page - 1) * $size;
|
||||
|
||||
if (!is_dir($filepath)) {
|
||||
return [0, []];
|
||||
}
|
||||
|
||||
foreach (glob($filepath . '/*') as $key => $value) {
|
||||
$count++;
|
||||
if ($key < $offset || count($strings) >= $size) {
|
||||
continue;
|
||||
}
|
||||
$explode = explode(DIRECTORY_SEPARATOR, $value);
|
||||
|
||||
$addTime = fileatime($value);
|
||||
$changeTime = filectime($value);
|
||||
$modifyTime = filemtime($value);
|
||||
$strings[] = [
|
||||
'id' => $count,
|
||||
'path' => $value,
|
||||
'isDir' => (int)is_dir($value),
|
||||
'name' => end($explode),
|
||||
'atime' => [
|
||||
'format' => date('Y-m-d H:i:s', $addTime),
|
||||
'microtime' => $addTime
|
||||
],
|
||||
'ctime' => [
|
||||
'format' => date('Y-m-d H:i:s', $changeTime),
|
||||
'microtime' => $changeTime
|
||||
],
|
||||
'mtime' => [
|
||||
'format' => date('Y-m-d H:i:s', $modifyTime),
|
||||
'microtime' => $modifyTime
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
array_multisort($strings, array_column($strings, 'isDir'), SORT_DESC);
|
||||
|
||||
return ['total' => $count, 'list' => $strings];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
<?php
|
||||
|
||||
namespace Snowflake\Core;
|
||||
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class Str
|
||||
* @package BeReborn\Core
|
||||
*/
|
||||
class Str
|
||||
{
|
||||
|
||||
const STRING = 'abcdefghijklmnopqrstuvwxyz';
|
||||
|
||||
const NUMBER = '01234567890';
|
||||
|
||||
/**
|
||||
* @param int $length
|
||||
*
|
||||
* @return string
|
||||
* 获取随机字符串
|
||||
*/
|
||||
public static function rand(int $length = 20)
|
||||
{
|
||||
$string = '';
|
||||
if ($length < 1) $length = 20;
|
||||
$default = self::STRING . strtoupper(self::STRING) . self::NUMBER;
|
||||
$default = str_split($default);
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$string .= $default[array_rand($default)];
|
||||
}
|
||||
return (string)$string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $length
|
||||
*
|
||||
* @return int
|
||||
* 获取随机数字
|
||||
*/
|
||||
public static function random(int $length = 20)
|
||||
{
|
||||
$number = '';
|
||||
$default = str_split(self::NUMBER);
|
||||
if ($length < 1) $length = 1;
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$number .= $default[array_rand($default)];
|
||||
}
|
||||
return $number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $string
|
||||
* @param $sublen
|
||||
* @param bool $strip_tags
|
||||
* @param string $append
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function cut_str_utf8($string, $sublen, $strip_tags = true, $append = '...')
|
||||
{
|
||||
if ($strip_tags) {
|
||||
$string = strip_tags($string);
|
||||
}//去掉签标
|
||||
$pa = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|\xe0[\xa0-\xbf][\x80-\xbf]|[\xe1-\xef][\x80-\xbf][\x80-\xbf]|\xf0[\x90-\xbf][\x80-\xbf][\x80-\xbf]|[\xf1-\xf7][\x80-\xbf][\x80-\xbf][\x80-\xbf]/";
|
||||
preg_match_all($pa, $string, $t_string);
|
||||
$str = "";
|
||||
for ($i = 0; $i < count($t_string[0]); $i++) {
|
||||
$str .= $t_string[0][$i];
|
||||
//转为gbk,一个汉字长度为2
|
||||
if (strlen(@iconv('utf-8', 'gbk', $str)) >= $sublen) {
|
||||
if ($i != count($t_string[0]) - 1) $str .= $append;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
*
|
||||
* @param null $callback
|
||||
* @return bool
|
||||
* 判断是否为json字符串
|
||||
*/
|
||||
public static function isJson($data, $callback = null)
|
||||
{
|
||||
$json = !is_null(json_decode($data)) && !is_numeric($data);
|
||||
if ($json && is_callable($callback, true)) {
|
||||
return call_user_func($callback, $data);
|
||||
}
|
||||
return $json;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
*
|
||||
* @param null $callBack
|
||||
* @return bool
|
||||
* 判断是否序列化字符串
|
||||
*/
|
||||
public static function isSerialize($data, $callBack = null)
|
||||
{
|
||||
$false = !empty($data) && unserialize($data) !== false;
|
||||
if ($false && is_callable($callBack, true)) {
|
||||
return call_user_func($callBack, $data);
|
||||
}
|
||||
return $false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $string
|
||||
* @param int $length
|
||||
*
|
||||
* @param string $append
|
||||
* @return string
|
||||
*/
|
||||
public static function cut($string, int $length = 20, $append = '...')
|
||||
{
|
||||
if (empty($string)) {
|
||||
return '';
|
||||
}
|
||||
if ($length < 1) {
|
||||
$length = 1;
|
||||
}
|
||||
$array = str_split($string);
|
||||
if (count($array) <= $length) {
|
||||
return implode('', $array);
|
||||
}
|
||||
$string = implode('', array_slice($array, 0, $length));
|
||||
if (!empty($append)) {
|
||||
$string .= $append;
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $str
|
||||
* @param int $number
|
||||
* @param string $key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function encrypt($str, $number = 10, $key = 'xshucai.com')
|
||||
{
|
||||
$res = [];
|
||||
$add = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
$len = strlen($key) < 0 ? 1 : strlen($key) + 5 > strlen($add) ? strlen($add) - 5 : strlen($key);
|
||||
if ($number < 1) $number = 10;
|
||||
$array = str_split($str);
|
||||
asort($array);
|
||||
$str = implode('', $array);
|
||||
for ($i = 0; $i < $number; $i++) {
|
||||
$_tmp = md5($key) . md5($str) . mb_substr($add, $len, $len + 5, 'utf-8');
|
||||
$res[] = md5($_tmp);
|
||||
}
|
||||
sort($res, SORT_STRING);
|
||||
return hash('sha384', implode('', $res));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $file
|
||||
* @param $type
|
||||
* @return string
|
||||
*/
|
||||
public static function filename($file, $type)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'image/png':
|
||||
return md5_file($file) . '.png';
|
||||
case 'image/jpeg':
|
||||
case 'image/jpg':
|
||||
return md5_file($file) . '.jpg';
|
||||
case 'image/gif':
|
||||
return md5_file($file) . '.gif';
|
||||
break;
|
||||
}
|
||||
return md5_file($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $endTime
|
||||
* @param int|null $startTime
|
||||
* @return array
|
||||
* 剩余天,带分秒
|
||||
*/
|
||||
public static function timeout($endTime, int $startTime = null)
|
||||
{
|
||||
$endTime = $endTime - (!empty($startTime) ? $startTime : time());
|
||||
|
||||
$day = intval($endTime / (3600 * 24));
|
||||
|
||||
$hours = intval(($endTime - ($day * (3600 * 24))) / 3600);
|
||||
|
||||
$minute = intval(($endTime - ($day * (3600 * 24) + $hours * 3600)) / 60);
|
||||
|
||||
$scrod = intval(($endTime - ($day * (3600 * 24) + $hours * 3600 + $minute * 60)));
|
||||
|
||||
return [$day, $hours, $minute, $scrod];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return false|int
|
||||
*/
|
||||
public static function get_sy_time()
|
||||
{
|
||||
$time = strtotime('+1days', strtotime(date('Y-m-d')));
|
||||
|
||||
return $time - time();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
* @return string
|
||||
*/
|
||||
public static function encode(string $string)
|
||||
{
|
||||
return addslashes($string);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
* @return string|string[]|null
|
||||
* 清除标点符号
|
||||
*/
|
||||
public static function clear(string $string)
|
||||
{
|
||||
$char = '。、!?:;﹑•"…‘’“”〝〞∕¦‖— 〈〉﹞﹝「」‹›〖〗】【»«』『〕〔》《﹐¸﹕︰﹔!¡?¿﹖﹌﹏﹋'´ˊˋ―﹫︳︴¯_ ̄﹢﹦﹤‐˜﹟﹩﹠﹪﹡﹨﹍﹉﹎﹊ˇ︵︶︷︸︹︿﹀︺︽︾ˉ﹁﹂﹃﹄︻︼()';
|
||||
return preg_replace(array("/[[:punct:]]/i", '/[' . $char . ']/u', '/[ ]{2,}/'), '', $string);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $user
|
||||
* @param array $param
|
||||
* @param int $requestTime
|
||||
*
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function token($user, $param = [], $requestTime = NULL)
|
||||
{
|
||||
$str = '';
|
||||
if (!$requestTime) {
|
||||
$requestTime = microtime(true);
|
||||
}
|
||||
$_user = str_split(md5($user . md5($user)));
|
||||
ksort($_user);
|
||||
foreach ($_user as $key => $val) {
|
||||
$str .= md5(sha1($key . $val . 'www.xshucai.com'));
|
||||
}
|
||||
if (is_array($param)) {
|
||||
foreach ($param as $key => $val) {
|
||||
$str .= md5($str . sha1($key . md5($val)));
|
||||
}
|
||||
}
|
||||
$str .= sha1(base64_encode($requestTime));
|
||||
|
||||
$md5 = md5($str . $user);
|
||||
|
||||
return preg_replace('/(\w{10})(\w{3})(\w{4})(\w{9})(\w{6})/', '$1-$2-$3-$4-$5', $md5);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: admin
|
||||
* Date: 2019-03-20
|
||||
* Time: 01:03
|
||||
*/
|
||||
|
||||
namespace Snowflake\Core;
|
||||
|
||||
/**
|
||||
* Class Xml
|
||||
* @package BeReborn\Core
|
||||
*/
|
||||
class Xml
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @param bool $asArray
|
||||
* @return array|object
|
||||
*/
|
||||
public static function toArray($data, $asArray = true)
|
||||
{
|
||||
$data = simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||
if ($asArray) {
|
||||
return json_decode(json_encode($data), TRUE);
|
||||
}
|
||||
|
||||
return json_decode(json_encode($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $str
|
||||
* @return bool
|
||||
*/
|
||||
public static function isXml(&$str)
|
||||
{
|
||||
$xml_parser = xml_parser_create();
|
||||
if (!xml_parse($xml_parser, $str, true)) {
|
||||
xml_parser_free($xml_parser);
|
||||
return false;
|
||||
} else {
|
||||
$str = self::toArray($str);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/4/24 0024
|
||||
* Time: 17:27
|
||||
*/
|
||||
|
||||
namespace Snowflake\Di;
|
||||
|
||||
use ReflectionClass;
|
||||
use Snowflake\Abstracts\BaseObject;
|
||||
use ReflectionException;
|
||||
use Snowflake\Exception\NotFindClassException;
|
||||
|
||||
/**
|
||||
* Class Container
|
||||
* @package BeReborn\Di
|
||||
*/
|
||||
class Container extends BaseObject
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*
|
||||
* instance class by className
|
||||
*/
|
||||
private $_singletons = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*
|
||||
* class new instance construct parameter
|
||||
*/
|
||||
private $_constructs = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*
|
||||
* implements \ReflectClass
|
||||
*/
|
||||
private $_reflection = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*
|
||||
* The construct parameter
|
||||
*/
|
||||
private $_param = [];
|
||||
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @param array $constrict
|
||||
* @param array $config
|
||||
*
|
||||
* @return mixed
|
||||
* @throws NotFindClassException
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function get($class, $constrict = [], $config = [])
|
||||
{
|
||||
if (isset($this->_singletons[$class])) {
|
||||
return $this->_singletons[$class];
|
||||
} else if (!isset($this->_constructs[$class])) {
|
||||
return $this->resolve($class, $constrict, $config);
|
||||
}
|
||||
$definition = $this->_constructs[$class];
|
||||
if (is_callable($definition, TRUE)) {
|
||||
return call_user_func($definition, $this, $constrict, $config);
|
||||
} else if (is_array($definition)) {
|
||||
$object = $this->resolveDefinition($definition, $class, $config, $constrict);
|
||||
} else if (is_object($definition)) {
|
||||
return $this->_singletons[$class] = $definition;
|
||||
} else {
|
||||
throw new NotFindClassException($class);
|
||||
}
|
||||
return $this->_singletons[$class] = $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $definition
|
||||
* @param $class
|
||||
* @param $config
|
||||
* @param $constrict
|
||||
* @return mixed
|
||||
* @throws NotFindClassException
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
private function resolveDefinition($definition, $class, $config, $constrict)
|
||||
{
|
||||
if (!isset($definition['class'])) {
|
||||
throw new NotFindClassException($class);
|
||||
}
|
||||
$_className = $definition['class'];
|
||||
unset($definition['class']);
|
||||
|
||||
$config = array_merge($definition, $config);
|
||||
$definition = $this->mergeParam($class, $constrict);
|
||||
|
||||
if ($_className === $class) {
|
||||
$object = $this->resolve($class, $definition, $config);
|
||||
} else {
|
||||
$object = $this->get($class, $definition, $config);
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @param $constrict
|
||||
* @param $config
|
||||
*
|
||||
* @return mixed
|
||||
* @throws NotFindClassException
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
private function resolve($class, $constrict, $config)
|
||||
{
|
||||
/**
|
||||
* @var ReflectionClass $reflect
|
||||
* @var array $dependencies
|
||||
*/
|
||||
list($reflect, $dependencies) = $this->resolveDependencies($class);
|
||||
foreach ($constrict as $index => $param) {
|
||||
$dependencies[$index] = $param;
|
||||
}
|
||||
if (!$reflect->isInstantiable()) {
|
||||
throw new NotFindClassException($reflect->getName());
|
||||
}
|
||||
if (empty($config)) {
|
||||
return $reflect->newInstanceArgs($dependencies ?? []);
|
||||
}
|
||||
|
||||
if (!empty($dependencies) && $reflect->implementsInterface('BeReborn\Base\Configure')) {
|
||||
$dependencies[count($dependencies) - 1] = $config;
|
||||
return $reflect->newInstanceArgs($dependencies);
|
||||
}
|
||||
if (!empty($config)) {
|
||||
$this->_param[$class] = $config;
|
||||
}
|
||||
$object = $reflect->newInstanceArgs($dependencies ?? []);
|
||||
foreach ($config as $key => $val) {
|
||||
$object->{$key} = $val;
|
||||
}
|
||||
if (method_exists($object, 'afterInit')) {
|
||||
call_user_func([$object, 'afterInit']);
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
*
|
||||
* @return array
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
private function resolveDependencies($class)
|
||||
{
|
||||
$dependencies = [];
|
||||
if (isset($this->_reflection[$class])) {
|
||||
$reflection = $this->_reflection[$class];
|
||||
} else {
|
||||
$reflection = new ReflectionClass($class);
|
||||
$this->_reflection[$class] = $reflection;
|
||||
}
|
||||
$constructs = $reflection->getConstructor();
|
||||
if (empty($constructs) || !is_array($constructs)) {
|
||||
return [$reflection, []];
|
||||
}
|
||||
foreach ($constructs->getParameters() as $key => $param) {
|
||||
if (version_compare(PHP_VERSION, '5.6.0', '>=') && $param->isVariadic()) {
|
||||
break;
|
||||
} else if ($param->isDefaultValueAvailable()) {
|
||||
$dependencies[] = $param->getDefaultValue();
|
||||
} else {
|
||||
$c = $param->getClass();
|
||||
$dependencies[] = $c === NULL ? NULL : $c->getName();
|
||||
}
|
||||
}
|
||||
$this->_constructs[$class] = $dependencies;
|
||||
return [$reflection, $dependencies];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
*/
|
||||
public function unset($class)
|
||||
{
|
||||
if (is_array($class) && isset($class['class'])) {
|
||||
$class = $class['class'];
|
||||
} else if (is_object($class)) {
|
||||
$class = get_class($class);
|
||||
}
|
||||
unset(
|
||||
$this->_reflection[$class], $this->_singletons[$class],
|
||||
$this->_param[$class], $this->_constructs[$class]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function flush()
|
||||
{
|
||||
$this->_reflection = [];
|
||||
$this->_singletons = [];
|
||||
$this->_param = [];
|
||||
$this->_constructs = [];
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @param $newParam
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function mergeParam($class, $newParam)
|
||||
{
|
||||
if (empty($this->_param[$class])) {
|
||||
return $newParam;
|
||||
} else if (empty($newParam)) {
|
||||
return $this->_param[$class];
|
||||
}
|
||||
$old = $this->_param[$class];
|
||||
foreach ($newParam as $key => $val) {
|
||||
$old[$key] = $val;
|
||||
}
|
||||
return $old;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/4/25 0025
|
||||
* Time: 18:29
|
||||
*/
|
||||
|
||||
namespace Snowflake\Di;
|
||||
|
||||
|
||||
use Snowflake\Exception\ComponentException;
|
||||
use Snowflake\Abstracts\Component;
|
||||
use Exception;
|
||||
use Snowflake\Snowflake;
|
||||
|
||||
/**
|
||||
* Class Service
|
||||
* @package BeReborn\Di
|
||||
*/
|
||||
class Service extends Component
|
||||
{
|
||||
|
||||
private $_components = [];
|
||||
|
||||
|
||||
private $_definition = [];
|
||||
|
||||
|
||||
protected $_alias = [];
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
*
|
||||
* @return mixed
|
||||
* @throws
|
||||
*/
|
||||
public function get($id)
|
||||
{
|
||||
if (isset($this->_components[$id])) {
|
||||
return $this->_components[$id];
|
||||
}
|
||||
if (isset($this->_definition[$id])) {
|
||||
$object = $this->_definition[$id];
|
||||
if (!is_object($object)) {
|
||||
$object = Snowflake::createObject($object);
|
||||
}
|
||||
} else if (!isset($this->_alias[$id])) {
|
||||
throw new ComponentException("Unknown component ID: $id");
|
||||
} else {
|
||||
$id = $this->_alias[$id];
|
||||
|
||||
$object = Snowflake::createObject($id);
|
||||
}
|
||||
return $this->_components[$id] = $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $className
|
||||
* @param string $alias
|
||||
*/
|
||||
public function setAlias(string $className, string $alias)
|
||||
{
|
||||
$this->_alias[$className] = $alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param $definition
|
||||
*
|
||||
* @return callable|mixed|void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function set($id, $definition)
|
||||
{
|
||||
if ($definition === NULL) {
|
||||
return $this->remove($id);
|
||||
}
|
||||
|
||||
unset($this->_components[$id]);
|
||||
if (is_object($definition) || is_callable($definition, TRUE)) {
|
||||
return $this->_definition[$id] = $definition;
|
||||
} else if (!is_array($definition)) {
|
||||
throw new ComponentException("Unexpected configuration type for the \"$id\" component: " . gettype($definition));
|
||||
}
|
||||
if (!isset($definition['class'])) {
|
||||
throw new ComponentException("The configuration for the \"$id\" component must contain a \"class\" element.");
|
||||
} else {
|
||||
$this->_definition[$id] = $definition;
|
||||
}
|
||||
return $this->_components[$id] = Snowflake::createObject($definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @return bool
|
||||
*/
|
||||
public function has($id)
|
||||
{
|
||||
return isset($this->_definition[$id]) || isset($this->_components[$id]) || isset($this->_alias[$id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @throws Exception
|
||||
*/
|
||||
public function setComponents(array $data)
|
||||
{
|
||||
foreach ($data as $key => $val) {
|
||||
$this->set($key, $val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
if ($this->has($name)) {
|
||||
return $this->get($name);
|
||||
}
|
||||
|
||||
return parent::__get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
*/
|
||||
public function remove($id)
|
||||
{
|
||||
unset($this->_components[$id]);
|
||||
unset($this->_definition[$id]);
|
||||
if (isset($this->_alias[$id])) {
|
||||
unset($this->_components[$this->_alias[$id]]);
|
||||
unset($this->_definition[$this->_alias[$id]]);
|
||||
unset($this->_alias[$id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/4/26 0026
|
||||
* Time: 10:00
|
||||
*/
|
||||
|
||||
namespace Snowflake\Error;
|
||||
|
||||
use Exception;
|
||||
use HttpServer\IInterface\IFormatter;
|
||||
use Snowflake\Abstracts\Component;
|
||||
use Snowflake\Core\JSON;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Snowflake;
|
||||
|
||||
/**
|
||||
* Class ErrorHandler
|
||||
*
|
||||
* @package BeReborn\Base
|
||||
* @property-read $asError
|
||||
*/
|
||||
class ErrorHandler extends Component implements ErrorInterface
|
||||
{
|
||||
|
||||
/** @var IFormatter $message */
|
||||
private $message = NULL;
|
||||
|
||||
public $action;
|
||||
|
||||
public $category = 'app';
|
||||
|
||||
/**
|
||||
* 错误处理注册
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
ini_set('display_errors', 0);
|
||||
set_exception_handler([$this, 'exceptionHandler']);
|
||||
if (defined('HHVM_VERSION')) {
|
||||
set_error_handler([$this, 'errorHandler']);
|
||||
} else {
|
||||
set_error_handler([$this, 'errorHandler']);
|
||||
}
|
||||
register_shutdown_function([$this, 'shutdown']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function shutdown()
|
||||
{
|
||||
$lastError = error_get_last();
|
||||
if ($lastError['type'] !== E_ERROR) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->category = 'shutdown';
|
||||
|
||||
$messages = explode(PHP_EOL, $lastError['message']);
|
||||
|
||||
$message = array_shift($messages);
|
||||
|
||||
$this->sendError($message, $lastError['file'], $lastError['line']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Exception $exception
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function exceptionHandler($exception)
|
||||
{
|
||||
$this->category = 'exception';
|
||||
|
||||
$event = Snowflake::get()->event;
|
||||
$event->trigger(Event::RELEASE_ALL);
|
||||
|
||||
$this->sendError($exception->getMessage(), $exception->getFile(), $exception->getLine());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*
|
||||
* 以异常形式抛出错误,防止执行后续程序
|
||||
*/
|
||||
public function errorHandler()
|
||||
{
|
||||
$error = func_get_args();
|
||||
if (strpos($error[2], 'vendor/Reboot.php') !== FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
$path = ['file' => $error[2], 'line' => $error[3]];
|
||||
|
||||
if ($error[0] === 0) {
|
||||
$error[0] = 500;
|
||||
}
|
||||
|
||||
$data = JSON::to(500, 'Error : ' . $error[1], $path);
|
||||
|
||||
Logger::error($data, 'error');
|
||||
|
||||
$event = Snowflake::get()->event;
|
||||
$event->trigger(Event::RELEASE_ALL);
|
||||
|
||||
throw new \ErrorException($error[1], $error[0], 1, $error[2], $error[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @param $file
|
||||
* @param $line
|
||||
* @param int $code
|
||||
* @return false|string
|
||||
* @throws Exception
|
||||
*/
|
||||
public function sendError($message, $file, $line, $code = 500)
|
||||
{
|
||||
$path = ['file' => $file, 'line' => $line];
|
||||
|
||||
$data = JSON::to($code, $this->category . ': ' . $message, $path);
|
||||
|
||||
Logger::trance($data, $this->category);
|
||||
|
||||
return print_r($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getErrorMessage()
|
||||
{
|
||||
$message = $this->message;
|
||||
$this->message = NULL;
|
||||
return $message->getData();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getAsError()
|
||||
{
|
||||
return $this->message !== NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @param $category
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function writer($message, $category = 'app')
|
||||
{
|
||||
Logger::debug($message, $category);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: admin
|
||||
* Date: 2019-03-20
|
||||
* Time: 10:25
|
||||
*/
|
||||
|
||||
namespace Snowflake\Error;
|
||||
|
||||
/**
|
||||
* Interface ErrorInterface
|
||||
* @package BeReborn\Error
|
||||
*/
|
||||
interface ErrorInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @param $file
|
||||
* @param $line
|
||||
* @param int $code
|
||||
* @return mixed
|
||||
*/
|
||||
public function sendError($message, $file, $line, $code = 500);
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user