diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml index ada98fe..84fa208 100644 --- a/.github/workflows/coding-standards.yml +++ b/.github/workflows/coding-standards.yml @@ -19,7 +19,7 @@ jobs: dependencies: - "locked" php-version: - - "7.4" + - "8.0" operating-system: - "ubuntu-latest" diff --git a/.github/workflows/mutation-tests.yml b/.github/workflows/mutation-tests.yml index 78c4e93..d8f1b35 100644 --- a/.github/workflows/mutation-tests.yml +++ b/.github/workflows/mutation-tests.yml @@ -19,7 +19,7 @@ jobs: dependencies: - "locked" php-version: - - "7.4" + - "8.0" operating-system: - "ubuntu-latest" diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 0fb4782..3bc93d7 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -19,7 +19,7 @@ jobs: dependencies: - "locked" php-version: - - "7.4" + - "8.0" operating-system: - "ubuntu-latest" diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml index 65e638c..7a32c00 100644 --- a/.github/workflows/psalm.yml +++ b/.github/workflows/psalm.yml @@ -19,7 +19,7 @@ jobs: dependencies: - "locked" php-version: - - "7.4" + - "8.0" operating-system: - "ubuntu-latest" diff --git a/composer.json b/composer.json index 1aba18f..b40e6f4 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "antidot-fw/framework": "^0.2.0", "beberlei/assert": "^3.3", "drift/server": "^0.1.20", diff --git a/docs/README.md b/docs/README.md index a891c68..bbfb9fb 100644 --- a/docs/README.md +++ b/docs/README.md @@ -100,6 +100,8 @@ It allows executing promises inside PSR-15 and PSR-7 Middlewares and request han ### PSR-15 Middleware +**Promise Based** + ```php then(static fn(ServerrequestInsterface $request) => $handler->handle($request)) + ->then(static fn(ServerRequestInterface $request) => $handler->handle($request)) ); } } @@ -126,6 +129,8 @@ class SomeMiddleware implements MiddlewareInterface ### PSR-7 Request Handler +**Promise Based** + ```php then( - function(ServerrequestInterface $request): ResponseInterface { + return new PromiseResponse(resolve($request)->then( + function(ServerRequestInterface $request): ResponseInterface { return new Response('Hello World!!!'); } - );; + )); + } +} +``` + +**Coroutine based** + +```php +then(fn (KernelAdapter $adapter): KernelAdapter => $adapter); + ->then(static fn(KernelAdapter $adapter): KernelAdapter => $adapter); } /** - * @psalm-suppress LessSpecificImplementedReturnType * @param ServerRequestInterface $request - * @return PromiseResponse + * @psalm-suppress LessSpecificImplementedReturnType */ - public function handle(ServerRequestInterface $request): PromiseResponse + public function handle(ServerRequestInterface $request): PromiseInterface { - return $this->application->handle($request); + return $this->application + ->handle($request) + ->then([ResolveGenerator::class, 'toResponse']); } public static function getStaticFolder(): ?string diff --git a/src/MiddlewarePipeline.php b/src/MiddlewarePipeline.php index 5ba31ca..1620e68 100644 --- a/src/MiddlewarePipeline.php +++ b/src/MiddlewarePipeline.php @@ -13,7 +13,6 @@ use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; use Ramsey\Uuid\Uuid; -use SplQueue; use Throwable; use function React\Promise\reject; use function React\Promise\resolve; @@ -53,7 +52,6 @@ function (ServerRequestInterface $request) { /** @var string $requestId */ $requestId = $request->getAttribute('request_id'); try { - /** @var MiddlewareInterface $middleware */ $middleware = $this->concurrentPipelines[$requestId]->dequeue(); $response = $middleware->process($request, $this); @@ -84,7 +82,6 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface /** @var string $requestId */ $requestId = $request->getAttribute('request_id'); try { - /** @var MiddlewareQueue $queue */ $queue = $this->concurrentPipelines[$requestId]; $next = new NextHandler($queue, $handler); diff --git a/src/PromiseResponse.php b/src/PromiseResponse.php index f6471e8..8602c74 100644 --- a/src/PromiseResponse.php +++ b/src/PromiseResponse.php @@ -4,10 +4,12 @@ namespace Antidot\React; +use Generator; use React\Promise\PromiseInterface; use RingCentral\Psr7\Response; +use function React\Promise\resolve; -class PromiseResponse extends Response implements PromiseInterface +final class PromiseResponse extends Response implements PromiseInterface { private PromiseInterface $promise; protected $stream; @@ -28,6 +30,25 @@ public function __construct( $this->promise = $promise; } + /** + * @param callable $callback + * @return static + */ + public static function fromGeneratorCallback(callable $callback): self + { + return new self(resolve(function () use ($callback): Generator { + /** @var Generator $generator */ + $generator = $callback(); + + return $generator; + })); + } + + /** + * @param callable|null $onFulfilled + * @param callable|null $onRejected + * @param callable|null $onProgress + */ final public function then( callable $onFulfilled = null, callable $onRejected = null, diff --git a/src/ResolveGenerator.php b/src/ResolveGenerator.php new file mode 100644 index 0000000..cb44bec --- /dev/null +++ b/src/ResolveGenerator.php @@ -0,0 +1,45 @@ +|ResponseInterface|PromiseInterface $generator + */ + public static function toResponse( + callable|ResponseInterface|PromiseInterface $callback + ): PromiseInterface|ResponseInterface { + if (false === is_callable($callback)) { + return $callback; + } + + return new Promise( + static function (callable $resolve, callable $reject) use ($callback): void { + try { + /** @var Generator $generator */ + $generator = $callback(); + while ($generator->valid()) { + $item = $generator->current(); + if ($item instanceof PromiseInterface) { + $item->then(static fn($solved) => $generator->send($solved)); + continue; + } + $generator->send($item); + } + $resolve($generator->getReturn()); + } catch (Throwable $exception) { + $reject($exception); + } + } + ); + } +} diff --git a/src/RunServerCommandFactory.php b/src/RunServerCommandFactory.php index 20c302c..c287956 100644 --- a/src/RunServerCommandFactory.php +++ b/src/RunServerCommandFactory.php @@ -28,13 +28,13 @@ public function __invoke(ContainerInterface $container): RunServerCommand $adapter = $definition->getOption('adapter'); $adapter->setDefault(DriftKernelAdapter::class); $staticFolder = $definition->getOption('static-folder'); - $staticFolder->setDefault($config['static_folder']); + $staticFolder->setDefault((string)$config['static_folder']); $workers = $definition->getOption('workers'); - $workers->setDefault($config['workers']); + $workers->setDefault((string)$config['workers']); $concurrentRequests = $definition->getOption('concurrent-requests'); - $concurrentRequests->setDefault($config['max_concurrency']); + $concurrentRequests->setDefault((string)$config['max_concurrency']); $bufferSize = $definition->getOption('request-body-buffer'); - $bufferSize->setDefault($config['buffer_size']); + $bufferSize->setDefault((string)$config['buffer_size']); return $command; } diff --git a/src/ServerFactory.php b/src/ServerFactory.php index 3b04fe0..64bab5d 100644 --- a/src/ServerFactory.php +++ b/src/ServerFactory.php @@ -14,10 +14,6 @@ use React\Http\Middleware\RequestBodyBufferMiddleware; use React\Http\Middleware\RequestBodyParserMiddleware; use React\Http\Middleware\StreamingRequestMiddleware; -use React\Promise\PromiseInterface; -use function PHPUnit\Framework\assertArrayHasKey; -use function PHPUnit\Framework\assertIsInt; -use function React\Promise\resolve; class ServerFactory { @@ -42,7 +38,11 @@ public function __invoke(ContainerInterface $container): Server new LimitConcurrentRequestsMiddleware($config['max_concurrency']), new RequestBodyBufferMiddleware($config['buffer_size']), new RequestBodyParserMiddleware(), - static fn (ServerRequestInterface $request): PromiseInterface => resolve($application->handle($request)) + static function (ServerRequestInterface $request) use ($application) { + return $application + ->handle($request) + ->then([ResolveGenerator::class, 'toResponse']); + } ); return $server; diff --git a/src/WatchServerCommandFactory.php b/src/WatchServerCommandFactory.php index ca00ee1..0401dd9 100644 --- a/src/WatchServerCommandFactory.php +++ b/src/WatchServerCommandFactory.php @@ -31,11 +31,11 @@ public function __invoke(ContainerInterface $container): WatchServerCommand $definition->setArguments([$path]); $staticFolder = $definition->getOption('static-folder'); - $staticFolder->setDefault($config['static_folder']); + $staticFolder->setDefault((string)$config['static_folder']); $concurrentRequests = $definition->getOption('concurrent-requests'); - $concurrentRequests->setDefault($config['max_concurrency']); + $concurrentRequests->setDefault((string)$config['max_concurrency']); $bufferSize = $definition->getOption('request-body-buffer'); - $bufferSize->setDefault($config['buffer_size']); + $bufferSize->setDefault((string)$config['buffer_size']); return $command; }