Files
kiri-http-server/CoroutineServer.php
T

254 lines
5.8 KiB
PHP
Raw Normal View History

2023-04-01 22:36:17 +08:00
<?php
namespace Kiri\Server;
use Exception;
use Kiri\Abstracts\Config;
use Kiri\Di\ContainerInterface;
use Kiri\Di\LocalService;
use Kiri\Events\EventDispatch;
use Kiri\Exception\ConfigException;
use Kiri\Exception\NotFindClassException;
use Kiri\Server\Abstracts\ProcessManager;
use Kiri\Server\Abstracts\TraitServer;
use Kiri\Server\Config as SConfig;
use Kiri\Server\Events\OnServerBeforeStart;
use Kiri\Server\Events\OnShutdown;
2023-04-02 23:34:07 +08:00
use Kiri\Server\Events\OnWorkerExit;
use Kiri\Server\Events\OnWorkerStart;
2023-04-01 22:36:17 +08:00
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Psr\Log\LoggerInterface;
use ReflectionException;
use Swoole\Coroutine;
use Swoole\Coroutine\Server as ScServer;
use Swoole\Coroutine\Http\Server as SchServer;
use Swoole\Http\Request;
use Swoole\Http\Response;
2023-04-02 23:49:09 +08:00
use Swoole\Process;
2023-04-01 22:36:17 +08:00
use Swoole\Server;
class CoroutineServer implements ServerInterface
{
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
use TraitServer;
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
/** @var array<SchServer|ScServer> */
private array $servers = [];
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
/**
* @var Server|null
*/
private Server|null $server = null;
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
/**
* @param Config $config
* @param ContainerInterface $container
* @param EventDispatch $dispatch
* @param LoggerInterface $logger
* @param ProcessManager $processManager
*/
public function __construct(public Config $config,
public ContainerInterface $container,
public EventDispatch $dispatch,
public LoggerInterface $logger,
public ProcessManager $processManager)
{
}
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
/**
* @param array $service
* @param int $daemon
* @return void
* @throws ConfigException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws Exception
*/
public function initCoreServers(array $service, int $daemon = 0): void
{
$service = $this->genConfigService($service);
foreach ($service as $value) {
2023-04-01 22:38:04 +08:00
if ($value->getType() == Constant::SERVER_TYPE_HTTP) {
2023-04-01 22:36:17 +08:00
$this->addListener($value);
}
}
$rpcService = Config::get('rpc', []);
if (!empty($rpcService)) {
$this->addListener(instance(SConfig::class, [], $rpcService));
}
2023-04-02 23:32:55 +08:00
$this->container->setBindings(ServerInterface::class, $this);
2023-04-01 22:36:17 +08:00
// $this->processManager->batch(Config::get('processes', []));
}
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
/**
* @param SConfig $config
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function addListener(SConfig $config): void
{
2023-04-01 23:49:43 +08:00
$server = new SchServer($config->getHost(), $config->getPort(), false, true);
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
$events = $config->getEvents()[Constant::REQUEST] ?? null;
if (is_null($events)) {
$events = [\Kiri\Message\Server::class, 'onRequest'];
}
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
$events[0] = $this->container->get($events[0]);
$server->handle('/', $events);
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
$this->servers[] = $server;
}
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
/**
* @param string $name
* @return ScServer|SchServer|null
*/
public function getServer(string $name = ''): ScServer|SchServer|null
{
return $this->servers[$name] ?? null;
}
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
/**
* @return bool
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function shutdown(): bool
{
foreach ($this->servers as $server) {
$server->shutdown();
}
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
$this->dispatch->dispatch(new OnShutdown());
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
return true;
}
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
/**
* @param $no
* @param array $signInfo
* @return void
*/
public function onSigint($no, array $signInfo): void
{
try {
$this->logger->alert('Pid ' . getmypid() . ' get signo ' . $no);
$this->shutdown();
} catch (\Throwable $exception) {
$this->logger->error($exception->getMessage());
}
}
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
/**
* @param Server\Port|Server $base
* @param array $events
* @return void
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function onEventListen(Server\Port|Server $base, array $events): void
{
foreach ($events as $name => $event) {
if (is_array($event) && is_string($event[0])) {
$event[0] = $this->container->get($event[0]);
}
$base->on($name, $event);
}
}
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
/**
* @return void
*/
public function start(): void
{
Coroutine\run(function () {
$this->dispatch->dispatch(new OnServerBeforeStart());
2023-04-02 23:49:09 +08:00
2023-04-01 23:12:58 +08:00
$this->onSignal(Config::get('signal', []));
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
$this->onTasker();
foreach ($this->servers as $server) {
2023-04-01 23:57:36 +08:00
Coroutine::create(static function () use ($server) {
2023-04-02 23:34:07 +08:00
$this->dispatch->dispatch(new OnWorkerStart($server, 0));
2023-04-01 22:36:17 +08:00
$server->start();
2023-04-02 23:34:07 +08:00
$this->dispatch->dispatch(new OnWorkerExit($server, 0));
2023-04-01 22:36:17 +08:00
});
}
});
}
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
private Coroutine\Channel $channel;
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
/**
* @return void
* @throws ConfigException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function onTasker(): void
{
$config = Config::get('server.settings', []);
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
if (isset($config[Constant::OPTION_TASK_WORKER_NUM])) {
if ($config[Constant::OPTION_TASK_WORKER_NUM] < 1) {
return;
}
}
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
$taskEvents = $config['events'][Constant::TASK] ?? null;
$finishEvents = $config['events'][Constant::FINISH] ?? null;
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
if (is_null($taskEvents)) {
return;
}
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
$taskEvents[0] = $this->container->get($taskEvents[0]);
if (!is_null($finishEvents)) {
$finishEvents[0] = $this->container->get($finishEvents[0]);
}
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
$this->channel = new Coroutine\Channel($config[Constant::OPTION_TASK_WORKER_NUM]);
for ($i = 0; $i < $config[Constant::OPTION_TASK_WORKER_NUM]; $i++) {
2023-04-01 23:57:36 +08:00
Coroutine::create(static fn() => $this->taskRunner($i, $taskEvents, $finishEvents));
2023-04-01 22:36:17 +08:00
}
}
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
/**
* @param $taskId
* @param $callback
* @param $finishEvents
* @return void
*/
private function taskRunner($taskId, $callback, $finishEvents): void
{
$taskData = $this->channel->pop();
if (!is_null($taskData)) {
$result = $callback($taskId, $taskData);
if (is_callable($finishEvents, true)) {
$finishEvents($taskId, $result);
}
}
$this->taskRunner($taskId, $callback, $finishEvents);
}
2023-04-02 23:49:09 +08:00
2023-04-01 22:36:17 +08:00
}