From 6e4bb90c0a692860b4448d4a4c282d347ab84d60 Mon Sep 17 00:00:00 2001 From: Maxim Smakouz Date: Tue, 10 May 2022 16:56:52 +0300 Subject: [PATCH] Add configuration generator --- README.md | 12 +- composer.json | 4 +- src/Configuration/Generator.php | 79 ++++++++++ src/Configuration/Plugins.php | 89 +++++++++++ src/Configuration/Presets.php | 18 +++ src/Configuration/Section/AbstractSection.php | 15 ++ src/Configuration/Section/Amqp.php | 24 +++ src/Configuration/Section/Beanstalk.php | 25 +++ src/Configuration/Section/Boltdb.php | 24 +++ src/Configuration/Section/Broadcast.php | 55 +++++++ src/Configuration/Section/Endure.php | 26 ++++ src/Configuration/Section/Fileserver.php | 45 ++++++ src/Configuration/Section/Grpc.php | 55 +++++++ src/Configuration/Section/Http.php | 146 ++++++++++++++++++ src/Configuration/Section/Jobs.php | 122 +++++++++++++++ src/Configuration/Section/Kv.php | 73 +++++++++ src/Configuration/Section/Logs.php | 59 +++++++ src/Configuration/Section/Metrics.php | 47 ++++++ src/Configuration/Section/Nats.php | 24 +++ src/Configuration/Section/Redis.php | 46 ++++++ src/Configuration/Section/Reload.php | 43 ++++++ src/Configuration/Section/Rpc.php | 24 +++ .../Section/SectionInterface.php | 14 ++ src/Configuration/Section/Server.php | 32 ++++ src/Configuration/Section/Service.php | 45 ++++++ src/Configuration/Section/Sqs.php | 28 ++++ src/Configuration/Section/Status.php | 25 +++ src/Configuration/Section/Tcp.php | 53 +++++++ src/Configuration/Section/Temporal.php | 48 ++++++ src/Configuration/Section/Version.php | 23 +++ src/Configuration/Section/Websockets.php | 26 ++++ src/GetBinaryCommand.php | 44 ++++-- 32 files changed, 1380 insertions(+), 13 deletions(-) create mode 100644 src/Configuration/Generator.php create mode 100644 src/Configuration/Plugins.php create mode 100644 src/Configuration/Presets.php create mode 100644 src/Configuration/Section/AbstractSection.php create mode 100644 src/Configuration/Section/Amqp.php create mode 100644 src/Configuration/Section/Beanstalk.php create mode 100644 src/Configuration/Section/Boltdb.php create mode 100644 src/Configuration/Section/Broadcast.php create mode 100644 src/Configuration/Section/Endure.php create mode 100644 src/Configuration/Section/Fileserver.php create mode 100644 src/Configuration/Section/Grpc.php create mode 100644 src/Configuration/Section/Http.php create mode 100644 src/Configuration/Section/Jobs.php create mode 100644 src/Configuration/Section/Kv.php create mode 100644 src/Configuration/Section/Logs.php create mode 100644 src/Configuration/Section/Metrics.php create mode 100644 src/Configuration/Section/Nats.php create mode 100644 src/Configuration/Section/Redis.php create mode 100644 src/Configuration/Section/Reload.php create mode 100644 src/Configuration/Section/Rpc.php create mode 100644 src/Configuration/Section/SectionInterface.php create mode 100644 src/Configuration/Section/Server.php create mode 100644 src/Configuration/Section/Service.php create mode 100644 src/Configuration/Section/Sqs.php create mode 100644 src/Configuration/Section/Status.php create mode 100644 src/Configuration/Section/Tcp.php create mode 100644 src/Configuration/Section/Temporal.php create mode 100644 src/Configuration/Section/Version.php create mode 100644 src/Configuration/Section/Websockets.php diff --git a/README.md b/README.md index 37ccd06..6dfdf21 100644 --- a/README.md +++ b/README.md @@ -28,8 +28,16 @@ RoadRunner includes PSR-7/PSR-17 compatible HTTP and HTTP/2 server and can be us This repository contains commands to help you work with the RoadRunner, such as: - `get-binary` (or `get`) - allows to install the latest version of the RoadRunner compatible with - your environment (operating system, processor architecture, runtime, etc...) - + your environment (operating system, processor architecture, runtime, etc...). + Also, this command creates an example `.rr.yaml` configuration file. If don't use the command without additional options + `plugin` and `preset`, an example with a complete configuration file will be created. + Using the `plugin` option (shortcut `p`) can create an example configuration file with only plugins needed. + For example, with http plugin only: `get-binary -p http`, http and jobs: `get-binary -p http -p jobs`. + Available plugins: `amqp`, `beanstalk`, `boltdb`, `broadcast`, `endure`, `fileserver`, `grpc`, `http`, `jobs`, `kv`, + `logs`, `metrics`, `nats`, `redis`, `reload`, `rpc`, `server`, `service`, `sqs`, `status`, `tcp`, `temporal`, `websockets`. + Using the `preset` option can create an example configuration file with popular plugins for different typical tasks. + For example, with web preset: `get-binary --preset web`. + Available presets: `web` (contains plugins `http`, `jobs`). - `versions` - displays a list of available RoadRunner binary versions. Testing: diff --git a/composer.json b/composer.json index f84acde..a33148b 100644 --- a/composer.json +++ b/composer.json @@ -19,11 +19,13 @@ "require": { "php": ">=7.4", "ext-json": "*", + "composer/semver": "^3.2", "spiral/roadrunner-worker": ">=2.0.2", + "spiral/tokenizer": "^2.13 || ^3.0", "symfony/console": "^4.4|^5.0|^6.0", "symfony/http-client": "^4.4|^5.0|^6.0", "symfony/polyfill-php80": "^1.22", - "composer/semver": "^3.2" + "symfony/yaml": "^5.4 || ^6.0" }, "require-dev": { "jetbrains/phpstorm-attributes": "^1.0", diff --git a/src/Configuration/Generator.php b/src/Configuration/Generator.php new file mode 100644 index 0000000..0abfaf6 --- /dev/null +++ b/src/Configuration/Generator.php @@ -0,0 +1,79 @@ +> */ + protected const REQUIRED_SECTIONS = [ + Version::class, + Rpc::class, + ]; + + public function generate(Plugins $plugins): string + { + $this->collectSections($plugins->getPlugins()); + + return $this->getHeaderComment() . PHP_EOL . Yaml::dump($this->getContent(), 10); + } + + protected function getContent(): array + { + $content = []; + foreach ($this->sections as $section) { + $content += $section->render(); + } + + return $content; + } + + protected function collectSections(array $plugins): void + { + $sections = \array_merge(self::REQUIRED_SECTIONS, $plugins); + + foreach ($sections as $section) { + $this->fromSection(new $section()); + } + } + + /** @psalm-return non-empty-array */ + protected function fromSection(SectionInterface $section): void + { + if (!isset($this->sections[\get_class($section)])) { + $this->sections[\get_class($section)] = $section; + } + + foreach ($section->getRequired() as $required) { + $this->fromSection(new $required()); + } + } + + protected function getHeaderComment(): string + { + $comment = [ + '########################################################################################', + '# THIS IS SAMPLE OF THE CONFIGURATION #', + '# IT\'S NOT A DEFAULT CONFIGURATION, IT\'S JUST A SIMPLE SAMPLE #', + '# MORE DOCS CAN BE FOUND HERE: #', + '########################################################################################', + '', + '# Hint: RR will replace any config options using reference to environment variables,', + '# eg.: `option_key: ${ENVIRONMENT_VARIABLE_NAME}`.', + '', + '# Important: TCP port numbers for each plugin (rpc, http, etc) must be unique!', + '' + ]; + + return \implode(PHP_EOL, $comment); + } +} diff --git a/src/Configuration/Plugins.php b/src/Configuration/Plugins.php new file mode 100644 index 0000000..82fead3 --- /dev/null +++ b/src/Configuration/Plugins.php @@ -0,0 +1,89 @@ +> + * + * All plugins. + */ + private array $available; + + private function __construct(array $plugins) + { + $this->available = $this->getAvailable(); + $this->requestedPlugins = $plugins; + } + + public static function fromPlugins(array $plugins): self + { + return new self($plugins); + } + + public static function fromPreset(string $preset): self + { + $plugins = []; + switch ($preset) { + case Presets::WEB_PRESET_NANE: + $plugins = Presets::WEB_PLUGINS; + } + + return new self(\array_map(function (string $plugin) { + return $plugin::getShortName(); + }, $plugins)); + } + + public function getPlugins(): array + { + if ($this->requestedPlugins === []) { + return $this->available; + } + + $plugins = []; + foreach ($this->available as $plugin) { + if (\in_array($plugin::getShortName(), $this->requestedPlugins, true)) { + $plugins[] = $plugin; + } + } + + return $plugins; + } + + private function getAvailable(): array + { + $finder = new Finder(); + $finder->files()->in(__DIR__ . '/Section')->name('*.php'); + + $locator = new ClassLocator($finder); + + /** @var SectionInterface[] $available */ + $available = []; + foreach ($locator->getClasses() as $class) { + if ($this->isPlugin($class)) { + $available[] = $class->getName(); + } + } + + return $available; + } + + private function isPlugin(\ReflectionClass $class): bool + { + return $class->implementsInterface(SectionInterface::class) && !$class->isAbstract() && !$class->isInterface(); + } +} diff --git a/src/Configuration/Presets.php b/src/Configuration/Presets.php new file mode 100644 index 0000000..e300136 --- /dev/null +++ b/src/Configuration/Presets.php @@ -0,0 +1,18 @@ + [ + 'addr' => 'amqp://guest:guest@127.0.0.1:5672/' + ] + ]; + } + + public static function getShortName(): string + { + return self::NAME; + } +} diff --git a/src/Configuration/Section/Beanstalk.php b/src/Configuration/Section/Beanstalk.php new file mode 100644 index 0000000..c195a9d --- /dev/null +++ b/src/Configuration/Section/Beanstalk.php @@ -0,0 +1,25 @@ + [ + 'addr' => 'tcp://127.0.0.1:11300', + 'timeout' => '10s' + ] + ]; + } + + public static function getShortName(): string + { + return self::NAME; + } +} diff --git a/src/Configuration/Section/Boltdb.php b/src/Configuration/Section/Boltdb.php new file mode 100644 index 0000000..dcd64a4 --- /dev/null +++ b/src/Configuration/Section/Boltdb.php @@ -0,0 +1,24 @@ + [ + 'permissions' => 0777 + ] + ]; + } + + public static function getShortName(): string + { + return self::NAME; + } +} diff --git a/src/Configuration/Section/Broadcast.php b/src/Configuration/Section/Broadcast.php new file mode 100644 index 0000000..c7de66e --- /dev/null +++ b/src/Configuration/Section/Broadcast.php @@ -0,0 +1,55 @@ + [ + 'default' => [ + 'driver' => 'memory', + 'config' => [] + ], + 'default-redis' => [ + 'driver' => 'redis', + 'config' => [ + 'addrs' => [ + 'localhost:6379' + ], + 'master_name' => '', + 'username' => '', + 'password' => '', + 'db' => 0, + 'sentinel_password' => '', + 'route_by_latency' => false, + 'route_randomly' => false, + 'dial_timeout' => 0, + 'max_retries' => 1, + 'min_retry_backoff' => 0, + 'max_retry_backoff' => 0, + 'pool_size' => 0, + 'min_idle_conns' => 0, + 'max_conn_age' => 0, + 'read_timeout' => 0, + 'write_timeout' => 0, + 'pool_timeout' => 0, + 'idle_timeout' => 0, + 'idle_check_freq' => 0, + 'read_only' => false + ] + ] + ] + ]; + } + + public static function getShortName(): string + { + return self::NAME; + } +} diff --git a/src/Configuration/Section/Endure.php b/src/Configuration/Section/Endure.php new file mode 100644 index 0000000..6dea614 --- /dev/null +++ b/src/Configuration/Section/Endure.php @@ -0,0 +1,26 @@ + [ + 'grace_period' => '30s', + 'print_graph' => false, + 'log_level' => 'error' + ] + ]; + } + + public static function getShortName(): string + { + return self::NAME; + } +} diff --git a/src/Configuration/Section/Fileserver.php b/src/Configuration/Section/Fileserver.php new file mode 100644 index 0000000..e50038f --- /dev/null +++ b/src/Configuration/Section/Fileserver.php @@ -0,0 +1,45 @@ + [ + 'address' => '127.0.0.1:10101', + 'calculate_etag' => true, + 'weak' => false, + 'stream_request_body' => true, + 'serve' => [ + [ + 'prefix' => '/foo', + 'root' => '../../../tests', + 'compress' => false, + 'cache_duration' => 10, + 'max_age' => 10, + 'bytes_range' => true + ], + [ + 'prefix' => '/foo/bar', + 'root' => '../../../tests', + 'compress' => false, + 'cache_duration' => 10, + 'max_age' => 10, + 'bytes_range' => true + ] + ] + ] + ]; + } + + public static function getShortName(): string + { + return self::NAME; + } +} diff --git a/src/Configuration/Section/Grpc.php b/src/Configuration/Section/Grpc.php new file mode 100644 index 0000000..70fb06e --- /dev/null +++ b/src/Configuration/Section/Grpc.php @@ -0,0 +1,55 @@ + [ + 'listen' => 'tcp://localhost:9001', + 'proto' => [ + 'first.proto', + 'second.proto' + ], + 'tls' => [ + 'key' => '', + 'cert' => '', + 'root_ca' => '', + 'client_auth_type' => 'no_client_certs' + ], + 'max_send_msg_size' => 50, + 'max_recv_msg_size' => 50, + 'max_connection_idle' => '0s', + 'max_connection_age' => '0s', + 'max_connection_age_grace' => '0s8h', + 'max_concurrent_streams' => 10, + 'ping_time' => '1s', + 'timeout' => '200s', + 'pool' => [ + 'num_workers' => 2, + 'max_jobs' => 0, + 'allocate_timeout' => '60s', + 'destroy_timeout' => 60 + ] + ] + ]; + } + + public function getRequired(): array + { + return [ + Server::class + ]; + } + + public static function getShortName(): string + { + return self::NAME; + } +} diff --git a/src/Configuration/Section/Http.php b/src/Configuration/Section/Http.php new file mode 100644 index 0000000..e7f497c --- /dev/null +++ b/src/Configuration/Section/Http.php @@ -0,0 +1,146 @@ + [ + 'address' => '127.0.0.1:8080', + 'internal_error_code' => 505, + 'access_logs' => false, + 'max_request_size' => 256, + 'middleware' => [ + 'headers', + 'gzip' + ], + 'trusted_subnets' => [ + '10.0.0.0/8', + '127.0.0.0/8', + '172.16.0.0/12', + '192.168.0.0/16', + '::1/128', + 'fc00::/7', + 'fe80::/10' + ], + 'new_relic' => [ + 'app_name' => 'app', + 'license_key' => 'key' + ], + 'cache' => [ + 'driver' => 'memory', + 'cache_methods' => [ + 'GET', + 'HEAD', + 'POST' + ], + 'config' => [] + ], + 'uploads' => [ + 'dir' => '/tmp', + 'forbid' => [ + '.php', + '.exe', + '.bat', + '.sh' + ], + 'allow' => [ + '.html', + '.aaa' + ] + ], + 'headers' => [ + 'cors' => [ + 'allowed_origin' => '*', + 'allowed_headers' => '*', + 'allowed_methods' => 'GET,POST,PUT,DELETE', + 'allow_credentials' => true, + 'exposed_headers' => 'Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma', + 'max_age' => 600 + ], + 'request' => [ + 'input' => 'custom-header', + ], + 'response' => [ + 'X-Powered-By' => 'RoadRunner' + ] + ], + 'static' => [ + 'dir' => '.', + 'forbid' => [''], + 'calculate_etag' => false, + 'weak' => false, + 'allow' => [ + '.txt', + '.php' + ], + 'request' => [ + 'input' => 'custom-header' + ], + 'response' => [ + 'output' => 'output-header' + ] + ], + 'pool' => [ + 'debug' => false, + 'command' => 'php my-super-app.php', + 'num_workers' => 0, + 'max_jobs' => 64, + 'allocate_timeout' => '60s', + 'destroy_timeout' => '60s', + 'supervisor' => [ + 'watch_tick' => '1s', + 'ttl' => '0s', + 'idle_ttl' => '10s', + 'max_worker_memory' => 128, + 'exec_ttl' => '60s' + ] + ], + 'ssl' => [ + 'address' => '127.0.0.1:443', + 'acme' => [ + 'certs_dir' => 'rr_le_certs', + 'email' => 'you-email-here@email', + 'alt_http_port' => 80, + 'alt_tlsalpn_port' => 443, + 'challenge_type' => 'http-01', + 'use_production_endpoint' => true, + 'domains' => [ + 'your-cool-domain.here', + 'your-second-domain.here' + ] + ], + 'redirect' => true, + 'cert' => '/ssl/server.crt', + 'key' => '/ssl/server.key', + 'root_ca' => '/ssl/root.crt' + ], + 'fcgi' => [ + 'address' => 'tcp://0.0.0.0:7921' + ], + 'http2' => [ + 'h2c' => false, + 'max_concurrent_streams' => 128 + ] + ] + ]; + } + + public function getRequired(): array + { + return [ + Server::class + ]; + } + + public static function getShortName(): string + { + return self::NAME; + } +} diff --git a/src/Configuration/Section/Jobs.php b/src/Configuration/Section/Jobs.php new file mode 100644 index 0000000..dea7053 --- /dev/null +++ b/src/Configuration/Section/Jobs.php @@ -0,0 +1,122 @@ + [ + 'num_pollers' => 32, + 'pipeline_size' => 100000, + 'pool' => [ + 'command' => '', + 'num_workers' => 10, + 'max_jobs' => 0, + 'allocate_timeout' => '60s', + 'destroy_timeout' => '60s' + ], + 'pipelines' => [ + 'test-local' => [ + 'driver' => 'memory', + 'config' => [ + 'priority' => 10, + 'prefetch' => 10000 + ] + ], + 'test-local-1' => [ + 'driver' => 'boltdb', + 'config' => [ + 'file' => 'path/to/rr.db', + 'priority' => 10, + 'prefetch' => 10000 + ] + ], + 'test-local-2' => [ + 'driver' => 'amqp', + 'config' => [ + 'prefetch' => 10, + 'priority' => 1, + 'durable' => false, + 'delete_queue_on_stop' => false, + 'queue' => 'test-1-queue', + 'exchange' => 'default', + 'exchange_type' => 'direct', + 'routing_key' => 'test', + 'exclusive' => false, + 'multiple_ack' => false, + 'requeue_on_fail' => false + ] + ], + 'test-local-3' => [ + 'driver' => 'beanstalk', + 'config' => [ + 'priority' => 11, + 'tube_priority' => 1, + 'tube' => 'default-1', + 'reserve_timeout' => '10s' + ] + ], + 'test-local-4' => [ + 'driver' => 'sqs', + 'config' => [ + 'priority' => 10, + 'prefetch' => 10, + 'visibility_timeout' => 0, + 'wait_time_seconds' => 0, + 'queue' => 'default', + 'attributes' => [ + 'DelaySeconds' => 0, + 'MaximumMessageSize' => 262144, + 'MessageRetentionPeriod' => 345600, + 'ReceiveMessageWaitTimeSeconds' => 0, + 'VisibilityTimeout' => 30 + ], + 'tags' => [ + 'test' => 'tag' + ] + ] + ], + 'test-local-5' => [ + 'driver' => 'nats', + 'config' => [ + 'priority' => 2, + 'prefetch' => 100, + 'subject' => 'default', + 'stream' => 'foo', + 'deliver_new' => true, + 'rate_limit' => 100, + 'delete_stream_on_stop' => false, + 'delete_after_ack' => false + ] + ] + ], + 'consume' => [ + 'test-local', + 'test-local-1', + 'test-local-2', + 'test-local-3', + 'test-local-4', + 'test-local-5' + ] + ] + ]; + } + + public function getRequired(): array + { + return [ + Server::class + ]; + } + + public static function getShortName(): string + { + return self::NAME; + } +} diff --git a/src/Configuration/Section/Kv.php b/src/Configuration/Section/Kv.php new file mode 100644 index 0000000..fda4807 --- /dev/null +++ b/src/Configuration/Section/Kv.php @@ -0,0 +1,73 @@ + [ + 'boltdb-south' => [ + 'driver' => 'boltdb', + 'config' => [ + 'file' => 'rr.db', + 'permissions' => 0777, + 'interval' => 40 + ] + ], + 'us-central-kv' => [ + 'driver' => 'memcached', + 'config' => [ + 'addr' => [ + 'localhost:11211' + ] + ] + ], + 'fast-kv-fr' => [ + 'driver' => 'redis', + 'config' => [ + 'addrs' => [ + 'localhost:6379' + ], + 'master_name' => '', + 'username' => '', + 'password' => '', + 'db' => 0, + 'sentinel_password' => '', + 'route_by_latency' => false, + 'route_randomly' => false, + 'dial_timeout' => 0, + 'max_retries' => 1, + 'min_retry_backoff' => 0, + 'max_retry_backoff' => 0, + 'pool_size' => 0, + 'min_idle_conns' => 0, + 'max_conn_age' => 0, + 'read_timeout' => 0, + 'write_timeout' => 0, + 'pool_timeout' => 0, + 'idle_timeout' => 0, + 'idle_check_freq' => 0, + 'read_only' => false + ] + ], + 'local-memory' => [ + 'driver' => 'memory', + 'config' => [ + 'interval' => 1 + ] + ] + ] + ]; + } + + public static function getShortName(): string + { + return self::NAME; + } +} diff --git a/src/Configuration/Section/Logs.php b/src/Configuration/Section/Logs.php new file mode 100644 index 0000000..24faf4f --- /dev/null +++ b/src/Configuration/Section/Logs.php @@ -0,0 +1,59 @@ + [ + 'mode' => 'development', + 'level' => 'debug', + 'encoding' => 'console', + 'line_ending' => '\n', + 'output' => 'stderr', + 'err_output' => 'stderr', + 'file_logger_options' => [ + 'log_output' => '/tmp/my.log', + 'max_size' => 100, + 'max_age' => 1, + 'max_backups' => 5, + 'compress' => false + ], + 'channels' => [ + 'http' => [ + 'mode' => 'development', + 'level' => 'panic', + 'encoding' => 'console', + 'output' => 'stdout', + 'err_output' => 'stderr' + ], + 'server' => [ + 'mode' => 'production', + 'level' => 'info', + 'encoding' => 'json', + 'output' => 'stdout', + 'err_output' => 'stdout' + ], + 'rpc' => [ + 'mode' => 'raw', + 'level' => 'debug', + 'encoding' => 'console', + 'output' => 'stderr', + 'err_output' => 'stdout' + ] + ] + ] + ]; + } + + public static function getShortName(): string + { + return self::NAME; + } +} diff --git a/src/Configuration/Section/Metrics.php b/src/Configuration/Section/Metrics.php new file mode 100644 index 0000000..de55121 --- /dev/null +++ b/src/Configuration/Section/Metrics.php @@ -0,0 +1,47 @@ + [ + 'address' => '127.0.0.1:2112', + 'collect' => [ + 'app_metric' => [ + 'type' => 'histogram', + 'help' => 'Custom application metric', + 'labels' => [ + 'type' + ], + 'buckets' => [ + 0.1, + 0.2, + 0.3, + 1.0 + ], + 'objectives' => [ + [ + '1.4' => 2.3 + ], + [ + '2.0' => 1.4 + ] + ] + ] + ] + ] + ]; + } + + public static function getShortName(): string + { + return self::NAME; + } +} diff --git a/src/Configuration/Section/Nats.php b/src/Configuration/Section/Nats.php new file mode 100644 index 0000000..a3737cf --- /dev/null +++ b/src/Configuration/Section/Nats.php @@ -0,0 +1,24 @@ + [ + 'addr' => 'demo.nats.io' + ] + ]; + } + + public static function getShortName(): string + { + return self::NAME; + } +} diff --git a/src/Configuration/Section/Redis.php b/src/Configuration/Section/Redis.php new file mode 100644 index 0000000..4300f33 --- /dev/null +++ b/src/Configuration/Section/Redis.php @@ -0,0 +1,46 @@ + [ + 'addrs' => [ + 'localhost:6379' + ], + 'master_name' => '', + 'username' => '', + 'password' => '', + 'db' => 0, + 'sentinel_password' => '', + 'route_by_latency' => false, + 'route_randomly' => false, + 'dial_timeout' => 0, + 'max_retries' => 1, + 'min_retry_backoff' => 0, + 'max_retry_backoff' => 0, + 'pool_size' => 0, + 'min_idle_conns' => 0, + 'max_conn_age' => 0, + 'read_timeout' => 0, + 'write_timeout' => 0, + 'pool_timeout' => 0, + 'idle_timeout' => 0, + 'idle_check_freq' => 0, + 'read_only' => false + ] + ]; + } + + public static function getShortName(): string + { + return self::NAME; + } +} diff --git a/src/Configuration/Section/Reload.php b/src/Configuration/Section/Reload.php new file mode 100644 index 0000000..b607816 --- /dev/null +++ b/src/Configuration/Section/Reload.php @@ -0,0 +1,43 @@ + [ + 'interval' => '1s', + 'patterns' => [ + '.php' + ], + 'services' => [ + 'http' => [ + 'dirs' => [ + '.' + ], + 'recursive' => true, + 'ignore' => [ + 'vendor' + ], + 'patterns' => [ + '.php', + '.go', + '.md' + ] + ] + ] + ] + ]; + } + + public static function getShortName(): string + { + return self::NAME; + } +} diff --git a/src/Configuration/Section/Rpc.php b/src/Configuration/Section/Rpc.php new file mode 100644 index 0000000..c25cb97 --- /dev/null +++ b/src/Configuration/Section/Rpc.php @@ -0,0 +1,24 @@ + [ + 'listen' => 'tcp://127.0.0.1:6001' + ] + ]; + } + + public static function getShortName(): string + { + return self::NAME; + } +} diff --git a/src/Configuration/Section/SectionInterface.php b/src/Configuration/Section/SectionInterface.php new file mode 100644 index 0000000..d9d5608 --- /dev/null +++ b/src/Configuration/Section/SectionInterface.php @@ -0,0 +1,14 @@ + [ + 'on_init' => [ + 'command' => 'any php or script here', + 'exec_timeout' => '20s', + ], + 'command' => 'php psr-worker.php', + 'user' => '', + 'group' => '', + 'relay' => 'pipes', + 'relay_timeout' => '60s' + ] + ]; + } + + public static function getShortName(): string + { + return self::NAME; + } +} diff --git a/src/Configuration/Section/Service.php b/src/Configuration/Section/Service.php new file mode 100644 index 0000000..6011d1c --- /dev/null +++ b/src/Configuration/Section/Service.php @@ -0,0 +1,45 @@ + [ + 'some_service_1' => [ + 'command' => 'php tests/plugins/service/test_files/loop.php', + 'env' => [ + 'foo' => 'BAR', + 'foo2' => 'BAR2' + ], + 'process_num' => 1, + 'exec_timeout' => 0, + 'remain_after_exit' => true, + 'restart_sec' => 1 + ], + 'some_service_2' => [ + 'command' => 'binary', + 'env' => [ + 'foo' => 'BAR', + 'foo2' => 'BAR2' + ], + 'process_num' => 1, + 'exec_timeout' => 0, + 'remain_after_exit' => true, + 'restart_sec' => 1 + ] + ] + ]; + } + + public static function getShortName(): string + { + return self::NAME; + } +} diff --git a/src/Configuration/Section/Sqs.php b/src/Configuration/Section/Sqs.php new file mode 100644 index 0000000..ee4dc3d --- /dev/null +++ b/src/Configuration/Section/Sqs.php @@ -0,0 +1,28 @@ + [ + 'key' => 'api-key', + 'secret' => 'api-secret', + 'region' => 'us-west-1', + 'session_token' => 'test', + 'endpoint' => 'http://127.0.0.1:9324' + ] + ]; + } + + public static function getShortName(): string + { + return self::NAME; + } +} diff --git a/src/Configuration/Section/Status.php b/src/Configuration/Section/Status.php new file mode 100644 index 0000000..78d5d02 --- /dev/null +++ b/src/Configuration/Section/Status.php @@ -0,0 +1,25 @@ + [ + 'address' => '127.0.0.1:2114', + 'unavailable_status_code' => 503 + ] + ]; + } + + public static function getShortName(): string + { + return self::NAME; + } +} diff --git a/src/Configuration/Section/Tcp.php b/src/Configuration/Section/Tcp.php new file mode 100644 index 0000000..c122a21 --- /dev/null +++ b/src/Configuration/Section/Tcp.php @@ -0,0 +1,53 @@ + [ + 'servers' => [ + 'server1' => [ + 'addr' => '127.0.0.1:7778', + 'delimiter' => '\r\n', + 'read_buf_size' => 1 + ], + 'server2' => [ + 'addr' => '127.0.0.1:8811', + 'read_buf_size' => 10 + ], + 'server3' => [ + 'addr' => '127.0.0.1:8812', + 'delimiter' => '\r\n', + 'read_buf_size' => 1 + ] + ], + 'pool' => [ + 'command' => '', + 'num_workers' => 5, + 'max_jobs' => 0, + 'allocate_timeout' => '60s', + 'destroy_timeout' => '60s' + ] + ] + ]; + } + + public function getRequired(): array + { + return [ + Server::class + ]; + } + + public static function getShortName(): string + { + return self::NAME; + } +} diff --git a/src/Configuration/Section/Temporal.php b/src/Configuration/Section/Temporal.php new file mode 100644 index 0000000..f98dcc6 --- /dev/null +++ b/src/Configuration/Section/Temporal.php @@ -0,0 +1,48 @@ + [ + 'address' => '127.0.0.1:7233', + 'cache_size' => 10000, + 'namespace' => 'default', + 'codec' => 'proto', + 'debug_level' => 2, + 'metrics' => [ + 'address' => '127.0.0.1:9091', + 'type' => 'summary', + 'prefix' => 'foobar' + ], + 'activities' => [ + 'debug' => false, + 'command' => 'php my-super-app.php', + 'num_workers' => 0, + 'max_jobs' => 64, + 'allocate_timeout' => '60s', + 'destroy_timeout' => '60s', + 'supervisor' => [ + 'watch_tick' => '1s', + 'ttl' => '0s', + 'idle_ttl' => '10s', + 'max_worker_memory' => 128, + 'exec_ttl' => '60s' + ] + ] + ] + ]; + } + + public static function getShortName(): string + { + return self::NAME; + } +} diff --git a/src/Configuration/Section/Version.php b/src/Configuration/Section/Version.php new file mode 100644 index 0000000..5a8f309 --- /dev/null +++ b/src/Configuration/Section/Version.php @@ -0,0 +1,23 @@ + self::CONFIG_VERSION + ]; + } + + public static function getShortName(): string + { + return self::NAME; + } +} diff --git a/src/Configuration/Section/Websockets.php b/src/Configuration/Section/Websockets.php new file mode 100644 index 0000000..80fbed1 --- /dev/null +++ b/src/Configuration/Section/Websockets.php @@ -0,0 +1,26 @@ + [ + 'broker' => 'default-redis', + 'allowed_origin' => '*', + 'path' => '/ws' + ] + ]; + } + + public static function getShortName(): string + { + return self::NAME; + } +} diff --git a/src/GetBinaryCommand.php b/src/GetBinaryCommand.php index a8cb641..782a6ed 100644 --- a/src/GetBinaryCommand.php +++ b/src/GetBinaryCommand.php @@ -18,12 +18,15 @@ use Spiral\RoadRunner\Console\Command\OperatingSystemOption; use Spiral\RoadRunner\Console\Command\StabilityOption; use Spiral\RoadRunner\Console\Command\VersionFilterOption; +use Spiral\RoadRunner\Console\Configuration\Generator; +use Spiral\RoadRunner\Console\Configuration\Plugins; use Spiral\RoadRunner\Console\Repository\AssetInterface; use Spiral\RoadRunner\Console\Repository\ReleaseInterface; use Spiral\RoadRunner\Console\Repository\ReleasesCollection; use Spiral\RoadRunner\Console\Repository\RepositoryInterface; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\StyleInterface; @@ -75,6 +78,23 @@ public function __construct(string $name = null) $this->stability = new StabilityOption($this); } + protected function configure(): void + { + $this->addOption( + 'plugin', + 'p', + InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, + 'Generate configuration with selected plugins.' + ); + + $this->addOption( + 'preset', + null, + InputOption::VALUE_OPTIONAL, + 'Generate configuration with plugins in a selected preset.' + ); + } + /** * {@inheritDoc} */ @@ -126,7 +146,7 @@ public function execute(InputInterface $input, OutputInterface $output): int // Install rr binary $file = $this->installBinary($target, $release, $asset, $io, $output); - $this->installConfig($target, $release, $input, $io); + $this->installConfig($target, $input, $io); // Success if ($file === null) { @@ -199,14 +219,7 @@ private function installBinary( return $file; } - /** - * @param string $to - * @param ReleaseInterface $from - * @param InputInterface $in - * @param StyleInterface $io - * @return bool - */ - private function installConfig(string $to, ReleaseInterface $from, InputInterface $in, StyleInterface $io): bool + private function installConfig(string $to, InputInterface $in, StyleInterface $io): bool { $to .= '/.rr.yaml'; @@ -218,7 +231,18 @@ private function installConfig(string $to, ReleaseInterface $from, InputInterfac return false; } - \file_put_contents($to, $from->getConfig()); + $generator = new Generator(); + $plugins = $in->getOption('preset') ? + Plugins::fromPreset($in->getOption('preset')) : + Plugins::fromPlugins($in->getOption('plugin')); + + try { + $config = $generator->generate($plugins); + } catch (\Throwable $e) { + $io->error($e->getMessage()); + } + + \file_put_contents($to, $config); return true; }