Server.php 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * This file is part of Hyperf.
  5. *
  6. * @link https://www.hyperf.io
  7. * @document https://hyperf.wiki
  8. * @contact group@hyperf.io
  9. * @license https://github.com/hyperf/hyperf/blob/master/LICENSE
  10. */
  11. namespace Hyperf\Server;
  12. use Hyperf\Contract\MiddlewareInitializerInterface;
  13. use Hyperf\Framework\Bootstrap;
  14. use Hyperf\Framework\Event\BeforeMainServerStart;
  15. use Hyperf\Framework\Event\BeforeServerStart;
  16. use Hyperf\Server\Exception\RuntimeException;
  17. use Psr\Container\ContainerInterface;
  18. use Psr\EventDispatcher\EventDispatcherInterface;
  19. use Psr\Log\LoggerInterface;
  20. use Swoole\Http\Server as SwooleHttpServer;
  21. use Swoole\Server as SwooleServer;
  22. use Swoole\Server\Port as SwoolePort;
  23. use Swoole\WebSocket\Server as SwooleWebSocketServer;
  24. class Server implements ServerInterface
  25. {
  26. protected bool $enableHttpServer = false;
  27. protected bool $enableWebsocketServer = false;
  28. protected ?SwooleServer $server = null;
  29. protected array $onRequestCallbacks = [];
  30. public function __construct(protected ContainerInterface $container, protected LoggerInterface $logger, protected EventDispatcherInterface $eventDispatcher)
  31. {
  32. }
  33. public function init(ServerConfig $config): ServerInterface
  34. {
  35. $this->initServers($config);
  36. return $this;
  37. }
  38. public function start(): void
  39. {
  40. $this->server->start();
  41. }
  42. public function getServer(): SwooleServer
  43. {
  44. return $this->server;
  45. }
  46. protected function initServers(ServerConfig $config)
  47. {
  48. $servers = $this->sortServers($config->getServers());
  49. foreach ($servers as $server) {
  50. $name = $server->getName();
  51. $type = $server->getType();
  52. $host = $server->getHost();
  53. $port = $server->getPort();
  54. $sockType = $server->getSockType();
  55. $callbacks = $server->getCallbacks();
  56. if (! $this->server instanceof SwooleServer) {
  57. $this->server = $this->makeServer($type, $host, $port, $config->getMode(), $sockType);
  58. $callbacks = array_replace($this->defaultCallbacks(), $config->getCallbacks(), $callbacks);
  59. $this->registerSwooleEvents($this->server, $callbacks, $name);
  60. $this->server->set(array_replace($config->getSettings(), $server->getSettings()));
  61. ServerManager::add($name, [$type, current($this->server->ports)]);
  62. if (class_exists(BeforeMainServerStart::class)) {
  63. // Trigger BeforeMainServerStart event, this event only trigger once before main server start.
  64. $this->eventDispatcher->dispatch(new BeforeMainServerStart($this->server, $config->toArray()));
  65. }
  66. } else {
  67. /** @var bool|SwoolePort $slaveServer */
  68. $slaveServer = $this->server->addlistener($host, $port, $sockType);
  69. if (! $slaveServer) {
  70. throw new \RuntimeException("Failed to listen server port [{$host}:{$port}]");
  71. }
  72. $server->getSettings() && $slaveServer->set(array_replace($config->getSettings(), $server->getSettings()));
  73. $this->registerSwooleEvents($slaveServer, $callbacks, $name);
  74. ServerManager::add($name, [$type, $slaveServer]);
  75. }
  76. // Trigger beforeStart event.
  77. if (isset($callbacks[Event::ON_BEFORE_START])) {
  78. [$class, $method] = $callbacks[Event::ON_BEFORE_START];
  79. if ($this->container->has($class)) {
  80. $this->container->get($class)->{$method}();
  81. }
  82. }
  83. if (class_exists(BeforeServerStart::class)) {
  84. // Trigger BeforeServerStart event.
  85. $this->eventDispatcher->dispatch(new BeforeServerStart($name));
  86. }
  87. }
  88. }
  89. /**
  90. * @param Port[] $servers
  91. * @return Port[]
  92. */
  93. protected function sortServers(array $servers): array
  94. {
  95. $sortServers = [];
  96. foreach ($servers as $server) {
  97. switch ($server->getType()) {
  98. case ServerInterface::SERVER_HTTP:
  99. $this->enableHttpServer = true;
  100. if (! $this->enableWebsocketServer) {
  101. array_unshift($sortServers, $server);
  102. } else {
  103. $sortServers[] = $server;
  104. }
  105. break;
  106. case ServerInterface::SERVER_WEBSOCKET:
  107. $this->enableWebsocketServer = true;
  108. array_unshift($sortServers, $server);
  109. break;
  110. default:
  111. $sortServers[] = $server;
  112. break;
  113. }
  114. }
  115. return $sortServers;
  116. }
  117. protected function makeServer(int $type, string $host, int $port, int $mode, int $sockType): SwooleServer
  118. {
  119. switch ($type) {
  120. case ServerInterface::SERVER_HTTP:
  121. return new SwooleHttpServer($host, $port, $mode, $sockType);
  122. case ServerInterface::SERVER_WEBSOCKET:
  123. return new SwooleWebSocketServer($host, $port, $mode, $sockType);
  124. case ServerInterface::SERVER_BASE:
  125. return new SwooleServer($host, $port, $mode, $sockType);
  126. }
  127. throw new RuntimeException('Server type is invalid.');
  128. }
  129. protected function registerSwooleEvents(SwoolePort|SwooleServer $server, array $events, string $serverName): void
  130. {
  131. foreach ($events as $event => $callback) {
  132. if (! Event::isSwooleEvent($event)) {
  133. continue;
  134. }
  135. if (is_array($callback)) {
  136. [$className, $method] = $callback;
  137. if (array_key_exists($className . $method, $this->onRequestCallbacks)) {
  138. $this->logger->warning(sprintf('%s will be replaced by %s. Each server should have its own onRequest callback. Please check your configs.', $this->onRequestCallbacks[$className . $method], $serverName));
  139. }
  140. $this->onRequestCallbacks[$className . $method] = $serverName;
  141. $class = $this->container->get($className);
  142. if (method_exists($class, 'setServerName')) {
  143. // Override the server name.
  144. $class->setServerName($serverName);
  145. }
  146. if ($class instanceof MiddlewareInitializerInterface) {
  147. $class->initCoreMiddleware($serverName);
  148. }
  149. $callback = [$class, $method];
  150. }
  151. $server->on($event, $callback);
  152. }
  153. }
  154. protected function defaultCallbacks()
  155. {
  156. $hasCallback = class_exists(Bootstrap\StartCallback::class)
  157. && class_exists(Bootstrap\ManagerStartCallback::class)
  158. && class_exists(Bootstrap\WorkerStartCallback::class);
  159. if ($hasCallback) {
  160. $callbacks = [
  161. Event::ON_MANAGER_START => [Bootstrap\ManagerStartCallback::class, 'onManagerStart'],
  162. Event::ON_WORKER_START => [Bootstrap\WorkerStartCallback::class, 'onWorkerStart'],
  163. Event::ON_WORKER_STOP => [Bootstrap\WorkerStopCallback::class, 'onWorkerStop'],
  164. Event::ON_WORKER_EXIT => [Bootstrap\WorkerExitCallback::class, 'onWorkerExit'],
  165. ];
  166. if ($this->server->mode === SWOOLE_BASE) {
  167. return $callbacks;
  168. }
  169. return array_merge([
  170. Event::ON_START => [Bootstrap\StartCallback::class, 'onStart'],
  171. ], $callbacks);
  172. }
  173. return [
  174. Event::ON_WORKER_START => function (SwooleServer $server, int $workerId) {
  175. printf('Worker %d started.' . PHP_EOL, $workerId);
  176. },
  177. ];
  178. }
  179. }