diff --git a/README.md b/README.md index f55045f4..0602c0d8 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,34 @@ $http->start(); > When using Swoole, you can use the command `php src/server.php` to run the HTTP server locally, but you need Swoole installed. For setup with Docker, check out our [example application](/example) +#### Using Swoole HTTP server (non-coroutine) + +For the traditional multi-process `Swoole\Http\Server` with worker management and graceful reload support: + +```php +use Utopia\DI\Container; +use Utopia\Http\Http; +use Utopia\Http\Request; +use Utopia\Http\Response; +use Utopia\Http\Adapter\Swoole\HttpServer; + +$container = new Container(); + +Http::get('/') + ->inject('request') + ->inject('response') + ->action( + function(Request $request, Response $response) { + $response->send('Hello from Swoole HTTP Server'); + } + ); + +$http = new Http(new HttpServer('0.0.0.0', 80), 'America/New_York', $container); +$http->start(); +``` + +> The `HttpServer` adapter uses `Swoole\Http\Server` instead of `Swoole\Coroutine\Http\Server`. It supports the same API as the coroutine-based `Server` adapter and can be used interchangeably. + ### Parameters Parameters are used to receive input into endpoint action from the HTTP request. Parameters could be defined as URL parameters or in a body with a structure such as JSON. diff --git a/src/Http/Adapter/Swoole/HttpServer.php b/src/Http/Adapter/Swoole/HttpServer.php new file mode 100644 index 00000000..01550141 --- /dev/null +++ b/src/Http/Adapter/Swoole/HttpServer.php @@ -0,0 +1,60 @@ +server = new SwooleServer($host, $port); + $this->server->set(\array_merge($settings, [ + 'enable_coroutine' => true, + 'http_parse_cookie' => false, + ])); + $this->container = $container ?? new Container(); + } + + public function onRequest(callable $callback) + { + $this->server->on('request', function (SwooleRequest $request, SwooleResponse $response) use ($callback) { + $requestContainer = new Container($this->container); + $requestContainer->set('swooleRequest', fn () => $request); + $requestContainer->set('swooleResponse', fn () => $response); + + Coroutine::getContext()[self::REQUEST_CONTAINER_CONTEXT_KEY] = $requestContainer; + + $utopiaRequest = new Request($request); + $utopiaResponse = new Response($response); + + \call_user_func($callback, $utopiaRequest, $utopiaResponse); + }); + } + + public function getContainer(): Container + { + return Coroutine::getContext()[self::REQUEST_CONTAINER_CONTEXT_KEY] ?? $this->container; + } + + public function onStart(callable $callback) + { + $this->server->on('start', function () use ($callback) { + \call_user_func($callback, $this); + }); + } + + public function start() + { + $this->server->start(); + } +} diff --git a/tests/e2e/server-swoole-http.php b/tests/e2e/server-swoole-http.php new file mode 100644 index 00000000..cf2a006b --- /dev/null +++ b/tests/e2e/server-swoole-http.php @@ -0,0 +1,24 @@ +inject('swooleRequest') + ->inject('swooleResponse') + ->action(function (SwooleRequest $swooleRequest, SwooleResponse $swooleResponse) { + $method = $swooleRequest->getMethod(); + $swooleResponse->header('Content-Type', 'text/plain'); + $swooleResponse->header('Cache-Control', 'no-cache'); + $swooleResponse->setStatusCode(200); + $swooleResponse->write($method); + $swooleResponse->end(); + }); + +$server = new HttpServer('0.0.0.0', 80); +$http = new Http($server, 'UTC'); +$http->start();