This commit is contained in:
2023-04-16 01:45:34 +08:00
parent 46baac8bbd
commit 11c21f01a2
35 changed files with 36 additions and 1377 deletions
-12
View File
@@ -1,12 +0,0 @@
<?php
namespace Kiri\Abstracts;
abstract class AbstractServer extends Component
{
public string $name = 'http';
}
+1 -13
View File
@@ -13,10 +13,9 @@ namespace Kiri\Abstracts;
use Exception;
use Kiri;
use Kiri\Di\LocalService;
use Kiri\Error\{ErrorHandler, StdoutLogger, StdoutLoggerInterface};
use Kiri\Error\{StdoutLogger, StdoutLoggerInterface};
use Kiri\Exception\{InitException};
use Kiri\Di\ContainerInterface;
use Kiri\Server\{Server};
use Psr\Log\LoggerInterface;
use Kiri\Events\EventProvider;
@@ -225,17 +224,6 @@ abstract class BaseMain extends Component
}
/**
*
* @return Server
* @throws
*/
public function getServer(): Server
{
return Kiri::getDi()->get(Server::class);
}
/**
* @param string $name
* @return mixed|null
+2
View File
@@ -1,4 +1,6 @@
<?php
declare(strict_types=1);
namespace Kiri;
+3
View File
@@ -1,6 +1,9 @@
<?php
declare(strict_types=1);
namespace Kiri;
+6 -31
View File
@@ -14,14 +14,11 @@ use Exception;
use Kiri;
use Kiri\Abstracts\Component;
use Kiri\Core\Json;
use Kiri\Annotation\Inject;
use Kiri\Events\EventDispatch;
use Kiri\Message\Events\OnAfterRequest;
use Kiri\Message\Handler\Formatter\IFormatter;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Kiri\Server\Events\OnShutdown;
use ReflectionException;
use Kiri\Di\Inject\Container;
/**
* Class ErrorHandler
@@ -32,10 +29,6 @@ use ReflectionException;
class ErrorHandler extends Component implements ErrorInterface
{
/** @var ?IFormatter $message */
private ?IFormatter $message = NULL;
/**
* @var string
*/
@@ -45,7 +38,7 @@ class ErrorHandler extends Component implements ErrorInterface
/**
* @var EventDispatch
*/
#[Inject(EventDispatch::class)]
#[Container(EventDispatch::class)]
public EventDispatch $dispatch;
@@ -114,7 +107,7 @@ class ErrorHandler extends Component implements ErrorInterface
$message = array_shift($messages);
$this->dispatch->dispatch(new OnShutdown());
$this->dispatch->dispatch(new Kiri\Events\OnSystemError());
$this->sendError($message, $lastError['file'], $lastError['line']);
}
@@ -125,14 +118,13 @@ class ErrorHandler extends Component implements ErrorInterface
*
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws ReflectionException
* @throws Exception
*/
public function exceptionHandler(\Throwable $exception)
{
$this->category = 'exception';
$this->dispatch->dispatch(new OnAfterRequest());
$this->dispatch->dispatch(new Kiri\Events\OnSystemError());
$this->sendError($exception->getMessage(), $exception->getFile(), $exception->getLine());
}
@@ -158,7 +150,7 @@ class ErrorHandler extends Component implements ErrorInterface
$this->logger->error('On error handler', [$data]);
$this->dispatch->dispatch(new OnAfterRequest());
$this->dispatch->dispatch(new Kiri\Events\OnSystemError());
throw new \ErrorException($error[1], $error[0], 1, $error[2], $error[3]);
}
@@ -181,24 +173,7 @@ class ErrorHandler extends Component implements ErrorInterface
return $data;
}
/**
* @return mixed
*/
public function getErrorMessage(): mixed
{
$message = $this->message;
$this->message = NULL;
return $message->getData();
}
/**
* @return bool
*/
public function getAsError(): bool
{
return $this->message !== NULL;
}
/**
* @param $message
-53
View File
@@ -1,53 +0,0 @@
<?php
namespace Kiri\Error;
use Exception;
use Kiri\Message\Aspect\OnAspectInterface;
use Kiri\Message\Aspect\OnJoinPointInterface;
use Kiri\Message\Constrict\RequestInterface;
use Kiri;
use Psr\Log\LoggerInterface;
/**
* Class LoggerAspect
* @package Kiri\Error
*/
class LoggerAspect implements OnAspectInterface
{
/**
* @param OnJoinPointInterface $joinPoint
* @return mixed
* @throws Exception
*/
public function process(OnJoinPointInterface $joinPoint): mixed
{
$time = microtime(true);
$response = $joinPoint->process();
$this->print_runtime($time);
return $response;
}
/**
* @param $startTime
* @throws Exception
*/
private function print_runtime($startTime)
{
$request = Kiri::getDi()->get(RequestInterface::class);
$runTime = round(microtime(true) - $startTime, 6);
$logger = Kiri::getDi()->get(LoggerInterface::class);
$logger->debug(sprintf('run %s use time %6f', $request->getUri()->__toString(), $runTime));
}
}
+2
View File
@@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace Kiri\Error;
use Kiri\Abstracts\Logger;
+8
View File
@@ -0,0 +1,8 @@
<?php
namespace Kiri\Events;
class OnSystemError
{
}
-11
View File
@@ -7,12 +7,7 @@ namespace Kiri\Pool;
use Database\Mysql\PDO;
use Exception;
use Kiri\Abstracts\Component;
use Kiri\Abstracts\Config;
use Kiri\Annotation\Inject;
use Kiri\Di\ContainerInterface;
use Kiri\Exception\ConfigException;
use Kiri\Server\Abstracts\StatusEnum;
use Kiri\Server\WorkerStatus;
/**
@@ -25,12 +20,6 @@ class Pool extends Component
/** @var array<PoolItem> */
private array $_connections = [];
/**
* @var WorkerStatus
*/
#[Inject(WorkerStatus::class)]
public WorkerStatus $status;
/**
* @param $name
+1 -1
View File
@@ -1,9 +1,9 @@
<?php
declare(strict_types=1);
namespace Kiri\Pool;
use Closure;
use Kiri\Annotation\Inject;
use Kiri\Di\Context;
use Swoole\Coroutine\Channel;
+2
View File
@@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace Kiri\Pool;
use Kiri\Di\Context;
+3
View File
@@ -1,5 +1,8 @@
<?php
declare(strict_types=1);
namespace Kiri\Pool;
interface QueueInterface
+2
View File
@@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace Kiri\Pool;
+2
View File
@@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace Kiri\Pool;
interface StopHeartbeatCheck
-122
View File
@@ -1,122 +0,0 @@
<?php
namespace Kiri\Redis;
use Exception;
use Kiri;
use Kiri\Abstracts\Logger;
use Kiri\Exception\RedisConnectException;
use Kiri\Pool\StopHeartbeatCheck;
use Kiri\Server\Events\OnWorkerExit;
use RedisException;
use Swoole\Timer;
use function error;
/**
*
*/
class Helper implements StopHeartbeatCheck
{
private ?\Redis $pdo = null;
public string $host;
public int $port;
public int $database = 0;
public string $auth = '';
public string $prefix = '';
public int $timeout = 30;
public int $read_timeout = 30;
public array $pool = [];
private int $_timer = -1;
/**
* @param array $config
*/
public function __construct(array $config)
{
$this->host = $config['host'];
$this->port = $config['port'];
$this->database = $config['databases'];
$this->auth = $config['auth'];
$this->prefix = $config['prefix'];
$this->timeout = $config['timeout'];
$this->read_timeout = $config['read_timeout'];
$this->pool = $config['pool'];
}
/**
* clear client heartbeat
*/
public function stopHeartbeatCheck(): void
{
$this->_timer = -1;
}
/**
* @param string $name
* @param array $arguments
* @return mixed
* @throws RedisConnectException|RedisException
*/
public function __call(string $name, array $arguments)
{
if (!method_exists($this, $name)) {
return $this->_pdo()->{$name}(...$arguments);
}
return $this->{$name}(...$arguments);
}
/**
* @return \Redis
* @throws Exception
* @throws RedisException
*/
public function _pdo(): \Redis
{
if (!($this->pdo instanceof \Redis) || !$this->pdo->ping('isOk')) {
$this->pdo = $this->newClient();
}
return $this->pdo;
}
/**
* @return \Redis
* @throws Exception
*/
private function newClient(): \Redis
{
$redis = new \Redis();
if (!$redis->connect($this->host, $this->port, $this->timeout)) {
throw new RedisConnectException(sprintf('The Redis Connect %s::%d Fail.', $this->host, $this->port));
}
if (!empty($this->auth) && !$redis->auth($this->auth)) {
throw new RedisConnectException(sprintf('Redis Error: %s, Host %s, Auth %s', $redis->getLastError(), $this->host, $this->auth));
}
if ($this->read_timeout < 0) {
$this->read_timeout = 0;
}
$redis->select($this->database);
if ($this->read_timeout > 0) {
$redis->setOption(\Redis::OPT_READ_TIMEOUT, $this->read_timeout);
}
$redis->setOption(\Redis::OPT_PREFIX, $this->prefix);
return $redis;
}
}
-212
View File
@@ -1,212 +0,0 @@
<?php
namespace Kiri\Reload;
use Exception;
use Kiri\Abstracts\Config;
use Kiri\Annotation\Inject;
use Kiri\Error\StdoutLoggerInterface;
use Kiri\Server\Abstracts\BaseProcess;
use Kiri\Server\ServerInterface;
use Swoole\Event;
use Swoole\Process;
use Swoole\Timer;
/**
*
*/
class Inotify extends BaseProcess
{
private mixed $inotify = null;
private mixed $events;
private array $watchFiles = [];
public bool $isReloading = FALSE;
public string $name = 'inotify listen';
public array $dirs = [];
protected int $cid = -1;
const IG_DIR = [APP_PATH . 'commands', APP_PATH . '.git', APP_PATH . '.gitee'];
#[Inject(StdoutLoggerInterface::class)]
public StdoutLoggerInterface $logger;
/**
* @param Process $process
* @return void
* @throws Exception
*/
public function process(Process $process): void
{
// TODO: Implement process() method.
set_error_handler([$this, 'error']);
set_exception_handler([$this, 'error']);
if (!extension_loaded('inotify')) {
while (true) {
if ($this->isStop()) {
break;
}
sleep(1);
}
return;
}
$this->dirs = Config::get('reload.inotify', []);
$this->start();
}
public function onSigterm(): static
{
pcntl_signal(SIGTERM, function () {
$this->isStop = true;
});
return $this;
}
/**
* @return void
*/
public function error(): void
{
}
/**
* @throws Exception
*/
public function start()
{
$this->inotify = inotify_init();
$this->events = IN_MODIFY | IN_DELETE | IN_CREATE | IN_MOVE;
foreach ($this->dirs as $dir) {
if (!is_dir($dir)) continue;
$this->watch($dir);
}
Event::add($this->inotify, [$this, 'check']);
Event::cycle(function () {
if ($this->isStop()) {
Event::del($this->inotify);
}
}, true);
Event::wait();
}
/**
* 开始监听
* @throws Exception
*/
public function check()
{
if (!($events = inotify_read($this->inotify))) {
return;
}
if ($this->isReloading) {
return;
}
$LISTEN_TYPE = [IN_CREATE, IN_DELETE, IN_MODIFY, IN_MOVED_TO, IN_MOVED_FROM];
foreach ($events as $ev) {
if (!in_array($ev['mask'], $LISTEN_TYPE)) {
continue;
}
//非重启类型
if (str_ends_with($ev['name'], '.php')) {
if ($this->isReloading) {
break;
}
$this->isReloading = TRUE;
Timer::after(3000, fn() => $this->reload());
}
}
}
/**
* @throws Exception
*/
public function reload()
{
$swollen = \Kiri::getDi()->get(ServerInterface::class);
$swollen->reload();
$this->clearWatch();
foreach ($this->dirs as $root) {
$this->watch($root);
}
$this->isReloading = FALSE;
}
/**
* @throws Exception
*/
public function clearWatch()
{
foreach ($this->watchFiles as $wd) {
@inotify_rm_watch($this->inotify, $wd);
}
$this->watchFiles = [];
}
/**
* @param $dir
* @return bool
* @throws Exception
*/
public function watch($dir): bool
{
//目录不存在
if (!is_dir($dir)) {
return $this->logger->addError("[$dir] is not a directory.");
}
//避免重复监听
if (isset($this->watchFiles[$dir])) {
return FALSE;
}
if (in_array($dir, self::IG_DIR)) {
return FALSE;
}
$wd = @inotify_add_watch($this->inotify, $dir, $this->events);
$this->watchFiles[$dir] = $wd;
$files = scandir($dir);
foreach ($files as $f) {
if ($f == '.' || $f == '..') {
continue;
}
$path = $dir . '/' . $f;
//递归目录
if (is_dir($path)) {
$this->watch($path);
} else if (!str_ends_with($f, '.php')) {
continue;
}
//检测文件类型
if (strstr($f, '.') == '.php') {
$wd = @inotify_add_watch($this->inotify, $path, $this->events);
$this->watchFiles[$path] = $wd;
}
}
return TRUE;
}
}
-166
View File
@@ -1,166 +0,0 @@
<?php
namespace Kiri\Reload;
use DirectoryIterator;
use Exception;
use Kiri\Abstracts\Config;
use Kiri\Annotation\Inject;
use Kiri\Server\Abstracts\BaseProcess;
use Kiri\Server\ServerInterface;
use Psr\Log\LoggerInterface;
use Swoole\Process;
use Swoole\Timer;
class Scanner extends BaseProcess
{
private array $md5Map = [];
public bool $isReloading = FALSE;
public string $name = 'hot reload';
protected bool $enable_coroutine = true;
private array $dirs = [];
/**
* @var LoggerInterface
*/
#[Inject(LoggerInterface::class)]
public LoggerInterface $logger;
/**
* @throws Exception
*/
public function process(Process $process): void
{
$this->dirs = Config::get('reload.inotify', []);
$this->loadDirs();
Timer::tick(3000, fn() => $this->loadDirs(true));
}
/**
* @param bool $isReload
* @throws Exception
*/
private function loadDirs(bool $isReload = FALSE)
{
echo 'file tick ' . date('Y-m-d H:i:s') . PHP_EOL;
try {
if ($this->isReloading) {
return;
}
foreach ($this->dirs as $value) {
if ($this->isReloading) {
break;
}
$value = new DirectoryIterator($value);
if ($value->isDir()) {
$this->loadByDir($value, $isReload);
}
}
} catch (\Throwable $throwable) {
$this->logger->error($throwable->getMessage(), [$throwable]);
}
}
/**
* @param DirectoryIterator $iterator
* @param bool $isReload
* @return void
* @throws Exception
*/
private function loadByDir(DirectoryIterator $iterator, bool $isReload = FALSE): void
{
foreach ($iterator as $path) {
if ($this->isReloading) {
return;
}
if (!$this->isNeedCheck($path)) {
continue;
}
if ($path->isDir()) {
$this->loadByDir(new DirectoryIterator($path->getRealPath()), $isReload);
}
if ($this->checkFile($path, $isReload)) {
$this->isReloading = TRUE;
$this->timerReload();
break;
}
}
}
private function isNeedCheck(DirectoryIterator $path): bool
{
if ($path->isDot() || str_starts_with($path->getFilename(), '.')) {
return false;
}
if ($path->getExtension() !== 'php') {
return false;
}
return true;
}
/**
* @param DirectoryIterator $value
* @param $isReload
* @return bool
*/
private function checkFile(DirectoryIterator $value, $isReload): bool
{
$md5 = md5($value->getRealPath());
$mTime = filectime($value->getRealPath());
if (!isset($this->md5Map[$md5])) {
if ($isReload) {
return TRUE;
}
$this->md5Map[$md5] = $mTime;
} else {
if ($this->md5Map[$md5] != $mTime) {
if ($isReload) {
return TRUE;
}
$this->md5Map[$md5] = $mTime;
}
}
return FALSE;
}
/**
* @return $this
*/
public function onSigterm(): static
{
pcntl_signal(SIGTERM, function () {
Timer::clearAll();
$this->onProcessStop();
});
return $this;
}
/**
* @throws Exception
*/
public function timerReload()
{
$this->logger->warning('file change');
$swow = \Kiri::getDi()->get(ServerInterface::class);
$swow->reload();
$this->loadDirs();
$this->isReloading = FALSE;
}
}