From 7e90440afa27577831a2b20e0af998a65dcfc6cb Mon Sep 17 00:00:00 2001 From: Koldo Picaza Date: Sat, 23 Jan 2021 13:08:02 +0100 Subject: [PATCH 1/4] add drift kernel adapter --- src/DriftKernelAdapter.php | 111 +++++++++++++++++++++++++++++++++++++ src/ReactApplication.php | 4 ++ 2 files changed, 115 insertions(+) create mode 100644 src/DriftKernelAdapter.php diff --git a/src/DriftKernelAdapter.php b/src/DriftKernelAdapter.php new file mode 100644 index 0000000..c783f59 --- /dev/null +++ b/src/DriftKernelAdapter.php @@ -0,0 +1,111 @@ +get(Application::class); + assert($application instanceof ReactApplication); + (require $rootPath . '/router/middleware.php')($application, $container); + (require $rootPath . '/router/routes.php')($application, $container); + $this->container = $container; + $this->application = $application; + $this->serverContext = $serverContext; + $this->filesystem = $filesystem; + $this->mimeTypeChecker = $mimeTypeChecker; + $this->rootPath = $rootPath; + } + + /** @psalm-suppress MixedReturnTypeCoercion */ + public static function create( + LoopInterface $loop, + string $rootPath, + ServerContext $serverContext, + FilesystemInterface $filesystem, + OutputPrinter $outputPrinter, + MimeTypeChecker $mimeTypeChecker + ): PromiseInterface { + + return resolve(new self($serverContext, $filesystem, $mimeTypeChecker, $rootPath)) + ->then(fn (KernelAdapter $adapter): KernelAdapter => $adapter); + } + + /** + * @psalm-suppress LessSpecificImplementedReturnType + * @param ServerRequestInterface $request + * @return PromiseResponse + */ + public function handle(ServerRequestInterface $request): PromiseResponse + { + return $this->application->handle($request); + } + + public static function getStaticFolder(): ?string + { + return '/public'; + } + + public function shutDown(): PromiseInterface + { + return resolve('nothing to do'); + } + + /** + * Get watcher folders. + * + * @return string[] + */ + public static function getObservableFolders(): array + { + return ['src', 'public', 'templates']; + } + + /** + * Get watcher folders. + * + * @return string[] + */ + public static function getObservableExtensions(): array + { + return ['php', 'yml', 'yaml', 'xml', 'css', 'js', 'html', 'twig']; + } + + /** + * Get watcher ignoring folders. + * + * @return string[] + */ + public static function getIgnorableFolders(): array + { + return ['var']; + } +} diff --git a/src/ReactApplication.php b/src/ReactApplication.php index 5e74a61..0e90e4c 100644 --- a/src/ReactApplication.php +++ b/src/ReactApplication.php @@ -107,6 +107,10 @@ function (ServerRequestInterface $request) use ($handler): PromiseInterface { )); } + /** + * @param ServerRequestInterface $request + * @return PromiseResponse + */ public function handle(ServerRequestInterface $request): ResponseInterface { return new PromiseResponse(resolve($request) From 50e08aef828440f61a63f2884b8bc542eae278ca Mon Sep 17 00:00:00 2001 From: Koldo Picaza Date: Sat, 23 Jan 2021 23:50:43 +0100 Subject: [PATCH 2/4] add drift server commands to console --- composer.json | 1 + src/Container/Config/ConfigProvider.php | 23 +++++++++-- src/DriftKernelAdapter.php | 2 +- src/RunServerCommandFactory.php | 41 +++++++++++++++++++ src/WatchServerCommandFactory.php | 42 ++++++++++++++++++++ test/Container/Config/ConfigProviderTest.php | 23 +++++++++-- 6 files changed, 124 insertions(+), 8 deletions(-) create mode 100644 src/RunServerCommandFactory.php create mode 100644 src/WatchServerCommandFactory.php diff --git a/composer.json b/composer.json index c13a65d..ae4e896 100644 --- a/composer.json +++ b/composer.json @@ -17,6 +17,7 @@ "php": "^7.4|^8.0", "antidot-fw/framework": "^0.2.0", "beberlei/assert": "^3.3", + "drift/server": "^0.1.18", "psr/container": "^1.0.0", "ramsey/uuid": "^4.1", "react/http": "^1.2" diff --git a/src/Container/Config/ConfigProvider.php b/src/Container/Config/ConfigProvider.php index 8e0e818..ef157ea 100644 --- a/src/Container/Config/ConfigProvider.php +++ b/src/Container/Config/ConfigProvider.php @@ -5,8 +5,12 @@ use Antidot\Application\Http\Application; use Antidot\React\LoopFactory; use Antidot\React\ReactApplicationFactory; +use Antidot\React\RunServerCommandFactory; use Antidot\React\ServerFactory; use Antidot\React\SocketFactory; +use Antidot\React\WatchServerCommandFactory; +use Drift\Server\Console\RunServerCommand; +use Drift\Server\Console\WatchServerCommand; use React\EventLoop\LoopInterface; use React\Http\Server; use React\Socket\Server as Socket; @@ -29,12 +33,23 @@ public function __invoke(): array Socket::class => SocketFactory::class, ], ], + 'console' => [ + 'commands' => [ + 'server:run' => RunServerCommand::class, + 'server:watch' => WatchServerCommand::class + ], + 'factories' => [ + RunServerCommand::class => RunServerCommandFactory::class, + WatchServerCommand::class => WatchServerCommandFactory::class, + ], + ], 'server' => [ + 'host' => '0.0.0.0', + 'port' => 5555, + 'buffer_size' => 4096, + 'max_concurrency' => 100, 'workers' => 1, - 'host' => self::DEFAULT_HOST, - 'port' => self::DEFAULT_PORT, - 'max_concurrency' => self::DEFAULT_CONCURRENCY, - 'buffer_size' => self::DEFAULT_BUFFER_SIZE, + 'static_folder' => 'public' ] ]; } diff --git a/src/DriftKernelAdapter.php b/src/DriftKernelAdapter.php index c783f59..5b6089f 100644 --- a/src/DriftKernelAdapter.php +++ b/src/DriftKernelAdapter.php @@ -71,7 +71,7 @@ public function handle(ServerRequestInterface $request): PromiseResponse public static function getStaticFolder(): ?string { - return '/public'; + return 'public'; } public function shutDown(): PromiseInterface diff --git a/src/RunServerCommandFactory.php b/src/RunServerCommandFactory.php new file mode 100644 index 0000000..20c302c --- /dev/null +++ b/src/RunServerCommandFactory.php @@ -0,0 +1,41 @@ + $globalConfig */ + $globalConfig = $container->get('config'); + /** @var array $config */ + $config = $globalConfig['server']; + + $command = new RunServerCommand(dirname('./'), 'server:run'); + $command->setDescription('Run Drift HTTP Server'); + $definition = $command->getDefinition(); + + $path = new InputArgument('path', InputArgument::OPTIONAL, $definition->getArgument('path')->getDescription()); + $path->setDefault(sprintf('%s:%s', $config['host'], $config['port'])); + $definition->setArguments([$path]); + + $adapter = $definition->getOption('adapter'); + $adapter->setDefault(DriftKernelAdapter::class); + $staticFolder = $definition->getOption('static-folder'); + $staticFolder->setDefault($config['static_folder']); + $workers = $definition->getOption('workers'); + $workers->setDefault($config['workers']); + $concurrentRequests = $definition->getOption('concurrent-requests'); + $concurrentRequests->setDefault($config['max_concurrency']); + $bufferSize = $definition->getOption('request-body-buffer'); + $bufferSize->setDefault($config['buffer_size']); + + return $command; + } +} diff --git a/src/WatchServerCommandFactory.php b/src/WatchServerCommandFactory.php new file mode 100644 index 0000000..ca00ee1 --- /dev/null +++ b/src/WatchServerCommandFactory.php @@ -0,0 +1,42 @@ + $globalConfig */ + $globalConfig = $container->get('config'); + /** @var array $config */ + $config = $globalConfig['server']; + + $command = new WatchServerCommand(dirname('./'), [ + 'bin/console', + 'server:run', + sprintf('--adapter=%s', DriftKernelAdapter::class), + '--debug', + ], 'server:watch'); + $definition = $command->getDefinition(); + $command->setDescription('Watch Drift HTTP Server for development purposes'); + + $path = new InputArgument('path', InputArgument::OPTIONAL, $definition->getArgument('path')->getDescription()); + $path->setDefault(sprintf('%s:%s', $config['host'], $config['port'])); + $definition->setArguments([$path]); + + $staticFolder = $definition->getOption('static-folder'); + $staticFolder->setDefault($config['static_folder']); + $concurrentRequests = $definition->getOption('concurrent-requests'); + $concurrentRequests->setDefault($config['max_concurrency']); + $bufferSize = $definition->getOption('request-body-buffer'); + $bufferSize->setDefault($config['buffer_size']); + + return $command; + } +} diff --git a/test/Container/Config/ConfigProviderTest.php b/test/Container/Config/ConfigProviderTest.php index c81815e..1f8eb69 100644 --- a/test/Container/Config/ConfigProviderTest.php +++ b/test/Container/Config/ConfigProviderTest.php @@ -1,13 +1,19 @@ SocketFactory::class, ] ], + 'console' => [ + 'commands' => [ + 'server:run' => RunServerCommand::class, + 'server:watch' => WatchServerCommand::class + ], + 'factories' => [ + RunServerCommand::class => RunServerCommandFactory::class, + WatchServerCommand::class => WatchServerCommandFactory::class, + ], + ], 'server' => [ - 'workers' => 1, 'host' => '0.0.0.0', - 'port' => 8080, + 'port' => 5555, + 'buffer_size' => 4096, 'max_concurrency' => 100, - 'buffer_size' => 4194304, + 'workers' => 1, + 'static_folder' => 'public' ] ], $configProvider(), From dd551621fc50b1efa73167b59f00f38aac9423dd Mon Sep 17 00:00:00 2001 From: Koldo Picaza Date: Sat, 23 Jan 2021 23:51:06 +0100 Subject: [PATCH 3/4] update readme --- README.md | 116 +++++++++++++++++++++++++++++++++++--------------- composer.json | 3 +- 2 files changed, 84 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index a6721d7..648f633 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,9 @@ * PHP ^7.4|^8.0 * Antidot Framework +* DriftPHP Server * React Http +* React Promises * Ramsey Uuid ## Description @@ -74,44 +76,90 @@ $aggregator = new ConfigAggregator([ return $aggregator->getMergedConfig(); ``` -The create your React Http server +Default Config: ```php -#!/usr/bin/env php [ + 'host' => '0.0.0.0', + 'port' => 5555, + 'buffer_size' => 4096, + 'max_concurrency' => 100, + 'workers' => 1, + 'static_folder' => 'public' + ] +] + +``` + +### Usage -use Antidot\Application\Http\Application; -use Antidot\React\Child; -use Psr\Log\LoggerInterface; -use React\EventLoop\LoopInterface; -use React\Http\Server; -use React\Socket\Server as Socket; - -require 'vendor/autoload.php'; - -call_user_func(static function () { - $container = require 'config/container.php'; - $application = $container->get(Application::class); - (require 'router/middleware.php')($application, $container); - (require 'router/routes.php')($application, $container); - - $loop = $container->get(LoopInterface::class); - Child::fork( - shell_exec('nproc') ? (int)shell_exec('nproc') : 16, - static function () use ($container) { - $server = $container->get(Server::class); - $server->on('error', static function ($err) use ($container) { - $logger = $container->get(LoggerInterface::class); - $logger->critical($err); - }); - - $socket = $container->get(Socket::class); - $server->listen($socket); - }); - - $loop->run(); -}); +Two new commands will be added to the Antidot Framework CLI tool, to allow running the application on top of [Drift server](https://driftphp.io/#/?id=the-server) +* `server:run`: Run Drift HTTP Server +* `server:watch`: Watch Drift HTTP Server for development purposes + +```bash +$ bin/console +... + server + server:run Run Drift HTTP Server + server:watch Watch Drift HTTP Server for development purposes ``` + +```bash +$ bin/console server:run -h +Description: + Run Drift HTTP Server + +Usage: + server:run [options] [--] [] + +Arguments: + path The server will start listening to this address [default: "0.0.0.0:5555"] + +Options: + --static-folder[=STATIC-FOLDER] Static folder path [default: "public"] + --no-static-folder Disable static folder + --debug Enable debug + --no-header Disable the header + --no-cookies Disable cookies + --no-file-uploads Disable file uploads + --concurrent-requests[=CONCURRENT-REQUESTS] Limit of concurrent requests [default: 100] + --request-body-buffer[=REQUEST-BODY-BUFFER] Limit of the buffer used for the Request body. In KiB. [default: 4096] + --adapter[=ADAPTER] Server Adapter [default: "Antidot\React\DriftKernelAdapter"] + --allowed-loop-stops[=ALLOWED-LOOP-STOPS] Number of allowed loop stops [default: 0] + --workers[=WORKERS] Number of workers. Use -1 to get as many workers as physical thread available for your system. Maximum of 128 workers. Option disabled for watch command. [default: 16] + -q, --quiet Do not output any message + +``` + +```bash +$ bin/console server:watch -h +Description: + Watch Drift HTTP Server for development purposes + +Usage: + server:watch [options] [--] [] + +Arguments: + path The server will start listening to this address [default: "0.0.0.0:5555"] + +Options: + --static-folder[=STATIC-FOLDER] Static folder path [default: "public"] + --no-static-folder Disable static folder + --debug Enable debug + --no-header Disable the header + --no-cookies Disable cookies + --no-file-uploads Disable file uploads + --concurrent-requests[=CONCURRENT-REQUESTS] Limit of concurrent requests [default: 512] + --request-body-buffer[=REQUEST-BODY-BUFFER] Limit of the buffer used for the Request body. In KiB. [default: 2048] + --adapter[=ADAPTER] Server Adapter [default: "drift"] + --allowed-loop-stops[=ALLOWED-LOOP-STOPS] Number of allowed loop stops [default: 0] + --workers[=WORKERS] Number of workers. Use -1 to get as many workers as physical thread available for your system. Maximum of 128 workers. Option disabled for watch command. [default: 1] + -q, --quiet Do not output any message + +``` + diff --git a/composer.json b/composer.json index ae4e896..415ada3 100644 --- a/composer.json +++ b/composer.json @@ -55,7 +55,8 @@ "test": "phpunit --colors=always" }, "config": { - "sort-packages": true + "sort-packages": true, + "discard-changes": true }, "extra": { "laminas": { From dbed97bc5cc07efe2b9fbd4b3d88ec0ff2c092f0 Mon Sep 17 00:00:00 2001 From: Koldo Picaza Date: Tue, 2 Feb 2021 18:00:16 +0100 Subject: [PATCH 4/4] add latest drift server --- composer.json | 5 +++- src/Container/Config/ConfigProvider.php | 36 ++++++++++++++++++------- src/DriftKernelAdapter.php | 24 ++++++++++++----- 3 files changed, 48 insertions(+), 17 deletions(-) diff --git a/composer.json b/composer.json index 415ada3..1aba18f 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "php": "^7.4|^8.0", "antidot-fw/framework": "^0.2.0", "beberlei/assert": "^3.3", - "drift/server": "^0.1.18", + "drift/server": "^0.1.20", "psr/container": "^1.0.0", "ramsey/uuid": "^4.1", "react/http": "^1.2" @@ -62,5 +62,8 @@ "laminas": { "config-provider": "Antidot\\React\\Container\\Config\\ConfigProvider" } + }, + "suggest": { + "react/filesystem": "^0.1.2" } } diff --git a/src/Container/Config/ConfigProvider.php b/src/Container/Config/ConfigProvider.php index ef157ea..ee5c7c8 100644 --- a/src/Container/Config/ConfigProvider.php +++ b/src/Container/Config/ConfigProvider.php @@ -33,16 +33,7 @@ public function __invoke(): array Socket::class => SocketFactory::class, ], ], - 'console' => [ - 'commands' => [ - 'server:run' => RunServerCommand::class, - 'server:watch' => WatchServerCommand::class - ], - 'factories' => [ - RunServerCommand::class => RunServerCommandFactory::class, - WatchServerCommand::class => WatchServerCommandFactory::class, - ], - ], + 'console' => $this->getConsoleConfig(), 'server' => [ 'host' => '0.0.0.0', 'port' => 5555, @@ -53,4 +44,29 @@ public function __invoke(): array ] ]; } + + private function getConsoleConfig(): array + { + $hasWatcher = class_exists(WatchServerCommand::class); + + return $hasWatcher + ? [ + 'commands' => [ + 'server:run' => RunServerCommand::class, + 'server:watch' => WatchServerCommand::class + ], + 'factories' => [ + RunServerCommand::class => RunServerCommandFactory::class, + WatchServerCommand::class => WatchServerCommandFactory::class, + ] + ] + : [ + 'commands' => [ + 'server:run' => RunServerCommand::class, + ], + 'factories' => [ + RunServerCommand::class => RunServerCommandFactory::class, + ] + ]; + } } diff --git a/src/DriftKernelAdapter.php b/src/DriftKernelAdapter.php index 5b6089f..b7b99f0 100644 --- a/src/DriftKernelAdapter.php +++ b/src/DriftKernelAdapter.php @@ -18,18 +18,27 @@ final class DriftKernelAdapter implements KernelAdapter { - private FilesystemInterface $filesystem; private ServerContext $serverContext; private MimeTypeChecker $mimeTypeChecker; private string $rootPath; private ContainerInterface $container; private ReactApplication $application; + /** @var object|FilesystemInterface|null */ + private ?object $filesystem = null; + /** + * DriftKernelAdapter constructor. + * @param ServerContext $serverContext + * @param MimeTypeChecker $mimeTypeChecker + * @param string $rootPath + * @psalm-suppress UndefinedClass + * @param FilesystemInterface|null $filesystem + */ public function __construct( ServerContext $serverContext, - FilesystemInterface $filesystem, MimeTypeChecker $mimeTypeChecker, - string $rootPath + string $rootPath, + ?FilesystemInterface $filesystem ) { $container = require $rootPath . '/config/container.php'; assert($container instanceof ContainerInterface); @@ -50,12 +59,15 @@ public static function create( LoopInterface $loop, string $rootPath, ServerContext $serverContext, - FilesystemInterface $filesystem, OutputPrinter $outputPrinter, - MimeTypeChecker $mimeTypeChecker + MimeTypeChecker $mimeTypeChecker, + ?FilesystemInterface $filesystem = null ): PromiseInterface { + if ($filesystem && !class_exists(FilesystemInterface::class)) { + throw new \RuntimeException('Install react/filesystem package.'); + } - return resolve(new self($serverContext, $filesystem, $mimeTypeChecker, $rootPath)) + return resolve(new self($serverContext, $mimeTypeChecker, $rootPath, $filesystem)) ->then(fn (KernelAdapter $adapter): KernelAdapter => $adapter); }