Skip to content
This repository has been archived by the owner on Jan 17, 2022. It is now read-only.

Commit

Permalink
feat(swoole): Add ability to customize server
Browse files Browse the repository at this point in the history
- Lazy Server construction via dedicated factory
- Handle more options
- Fix setting random port (when port=0)
  • Loading branch information
k911 committed Sep 23, 2018
1 parent ec92f23 commit 3534ed0
Show file tree
Hide file tree
Showing 8 changed files with 237 additions and 93 deletions.
32 changes: 20 additions & 12 deletions Command/ServerProfileCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ public function __construct(KernelInterface $kernel, HttpServer $server, HttpSer
protected function configure(): void
{
$this->setName('swoole:server:profile')
->setDescription('Handles specified amount of requests to a local swoole server. Useful for debug or benchmarking.')
->setDescription('Handles specified amount of requests to a local swoole server. Useful for profiling.')
->addArgument('requests', InputArgument::REQUIRED, 'Number of requests to handle by the server')
->addOption('host', null, InputOption::VALUE_OPTIONAL, 'Host of the server')
->addOption('port', null, InputOption::VALUE_OPTIONAL, 'Port of the server')
->addOption('host', null, InputOption::VALUE_REQUIRED, 'Host name to listen to.')
->addOption('port', null, InputOption::VALUE_REQUIRED, 'Range 0-65535. When 0 random available port is chosen.')
->addOption('enable-static', null, InputOption::VALUE_NONE, 'Enables static files serving');
}

Expand All @@ -73,13 +73,15 @@ protected function execute(InputInterface $input, OutputInterface $output): void

$io = new SymfonyStyle($input, $output);

$host = (string) ($input->getOption('host') ?? $this->configuration->getHost());
$port = (int) ($input->getOption('port') ?? $this->configuration->getPort());
$this->configuration->changeSocket(
(string) ($input->getOption('host') ?? $this->configuration->getHost()),
(int) ($input->getOption('port') ?? $this->configuration->getPort())
);

$this->configuration->changeSocket($host, $port);

if ((bool) $input->getOption('enable-static')) {
$this->configuration->enableServingStaticFiles(\dirname($this->kernel->getRootDir()).'/public');
if (\filter_var($input->getOption('enable-static'), FILTER_VALIDATE_BOOLEAN)) {
$this->configuration->enableServingStaticFiles(
$this->configuration->hasPublicDir() ? $this->configuration->getPublicDir() : \dirname($this->kernel->getRootDir()).'/public'
);
}

$requestLimit = (int) $input->getArgument('requests');
Expand All @@ -89,13 +91,16 @@ protected function execute(InputInterface $input, OutputInterface $output): void

$trustedHosts = ServerUtils::decodeStringAsSet($_SERVER['APP_TRUSTED_HOSTS']);
$trustedProxies = ServerUtils::decodeStringAsSet($_SERVER['APP_TRUSTED_PROXIES']);

$this->driver->boot([
'symfonyStyle' => $io,
'requestLimit' => $requestLimit,
'trustedHosts' => $trustedHosts,
'trustedProxies' => $trustedProxies,
]);

$this->server->setup($this->configuration);

$rows = [
['env', $this->kernel->getEnvironment()],
['debug', \var_export($this->kernel->isDebug(), true)],
Expand All @@ -110,15 +115,18 @@ protected function execute(InputInterface $input, OutputInterface $output): void
$rows[] = ['public_dir', $this->configuration->getPublicDir()];
}

$io->success(\sprintf('Swoole HTTP Server started on http://%s:%d', $host, $port));
$io->success(\sprintf('Swoole HTTP Server started on http://%s:%d', $this->configuration->getHost(), $this->configuration->getPort()));
$io->table(['Configuration', 'Values'], $rows);

if ($this->kernel->isDebug()) {
dump($this->configuration);
dump($this->configuration->getSwooleSettings());
}

$this->server->setSymfonyStyle($io);
$this->server->start($this->driver, $this->configuration);
if ($this->server->start($this->driver)) {
$io->success('Swoole HTTP Server has been successfully shutdown.');
} else {
$io->error('Failure during starting Swoole HTTP Server.');
}
}
}
33 changes: 20 additions & 13 deletions Command/ServerRunCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ public function __construct(KernelInterface $kernel, HttpServer $server, HttpSer
protected function configure(): void
{
$this->setName('swoole:server:run')
->setDescription('Runs a local swoole server')
->addOption('host', null, InputOption::VALUE_OPTIONAL, 'Host of the server')
->addOption('port', null, InputOption::VALUE_OPTIONAL, 'Port of the server')
->addOption('enable-static', null, InputOption::VALUE_NONE, 'Enables static files serving');
->setDescription('Runs a local swoole http server')
->addOption('host', null, InputOption::VALUE_REQUIRED, 'Host name to listen to.')
->addOption('port', null, InputOption::VALUE_REQUIRED, 'Range 0-65535. When 0 random available port is chosen.')
->addOption('enable-static', null, InputOption::VALUE_NONE, 'Enables static files serving. Uses configured public directory or symfony default one.');
}

/**
Expand All @@ -69,20 +69,24 @@ protected function execute(InputInterface $input, OutputInterface $output): void

$io = new SymfonyStyle($input, $output);

$host = (string) ($input->getOption('host') ?? $this->configuration->getHost());
$port = (int) ($input->getOption('port') ?? $this->configuration->getPort());
$this->configuration->changeSocket(
(string) ($input->getOption('host') ?? $this->configuration->getHost()),
(int) ($input->getOption('port') ?? $this->configuration->getPort())
);

$this->configuration->changeSocket($host, $port);

if ((bool) $input->getOption('enable-static')) {
$this->configuration->enableServingStaticFiles(\dirname($this->kernel->getRootDir()).'/public');
if (\filter_var($input->getOption('enable-static'), FILTER_VALIDATE_BOOLEAN)) {
$this->configuration->enableServingStaticFiles(
$this->configuration->hasPublicDir() ? $this->configuration->getPublicDir() : \dirname($this->kernel->getRootDir()).'/public'
);
}

$this->driver->boot([
'trustedHosts' => ServerUtils::decodeStringAsSet($_SERVER['APP_TRUSTED_HOSTS']),
'trustedProxies' => ServerUtils::decodeStringAsSet($_SERVER['APP_TRUSTED_PROXIES']),
]);

$this->server->setup($this->configuration);

$rows = [
['env', $this->kernel->getEnvironment()],
['debug', \var_export($this->kernel->isDebug(), true)],
Expand All @@ -94,10 +98,13 @@ protected function execute(InputInterface $input, OutputInterface $output): void
$rows[] = ['public_dir', $this->configuration->getPublicDir()];
}

$io->success(\sprintf('Swoole HTTP Server started on http://%s:%d', $host, $port));
$io->success(\sprintf('Swoole HTTP Server started on http://%s:%d', $this->configuration->getHost(), $this->configuration->getPort()));
$io->table(['Configuration', 'Values'], $rows);

$this->server->setSymfonyStyle($io);
$this->server->start($this->driver, $this->configuration);
if ($this->server->start($this->driver)) {
$io->success('Swoole HTTP Server has been successfully shutdown.');
} else {
$io->error('Failure during starting Swoole HTTP Server.');
}
}
}
15 changes: 15 additions & 0 deletions DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,28 @@ public function getConfigTreeBuilder(): TreeBuilder
->arrayNode('http_server')
->children()
->scalarNode('host')
->cannotBeEmpty()
->defaultValue('127.0.0.1')
->end()
->integerNode('port')
->min(0)
->max(65535)
->defaultValue(9501)
->end()
->enumNode('runningMode')
->defaultValue('process')
->values(['process', 'reactor'])
->cannotBeEmpty()
->end()
->enumNode('socketType')
->cannotBeEmpty()
->defaultValue('sock_tcp_ipv4')
->values(['sock_tcp_ipv4', 'sock_tcp_ipv6', 'sock_udp_ipv4', 'sock_udp_ipv6', 'unix_dgram', 'unix_stream'])
->end()
->booleanNode('sslEnabled')
->defaultFalse()
->treatNullLike(false)
->end()
->arrayNode('static')
->addDefaultsIfNotSet()
->children()
Expand Down
12 changes: 6 additions & 6 deletions DependencyInjection/SwooleExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,6 @@ public function load(array $configs, ContainerBuilder $container): void
*/
private function registerHttpServer(array $config, ContainerBuilder $container): void
{
$container->getDefinition('app.swoole.server.http_server.server_instance')
->addArgument($config['host'])
->addArgument($config['port'])
->addArgument(SWOOLE_BASE)
->addArgument(SWOOLE_TCP);

if (!empty($config['services'])) {
$this->registerHttpServerServices($config['services'], $container);
}
Expand All @@ -73,6 +67,9 @@ private function registerHttpServerConfiguration(array $config, ContainerBuilder
'static' => $static,
'host' => $host,
'port' => $port,
'runningMode' => $runningMode,
'socketType' => $socketType,
'sslEnabled' => $sslEnabled,
'settings' => $settings,
] = $config;

Expand Down Expand Up @@ -101,6 +98,9 @@ private function registerHttpServerConfiguration(array $config, ContainerBuilder
$container->getDefinition(HttpServerConfiguration::class)
->addArgument($host)
->addArgument($port)
->addArgument($runningMode)
->addArgument($socketType)
->addArgument($sslEnabled)
->addArgument($settings);
}

Expand Down
7 changes: 3 additions & 4 deletions Resources/config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,11 @@ services:

'App\Bundle\SwooleBundle\Server\HttpServerConfiguration':

'app.swoole.server.http_server.server_instance':
class: Swoole\Http\Server
lazy: true
'app.swoole.server.http_server.factory':
class: App\Bundle\SwooleBundle\Server\HttpServerFactory

'App\Bundle\SwooleBundle\Server\HttpServer':
arguments: ['@app.swoole.server.http_server.server_instance']
arguments: ['@app.swoole.server.http_server.factory']

'App\Bundle\SwooleBundle\Command\ServerRunCommand':
tags: ['console.command']
Expand Down
76 changes: 39 additions & 37 deletions Server/HttpServer.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,66 +4,68 @@

namespace App\Bundle\SwooleBundle\Server;

use RuntimeException;
use Assert\Assertion;
use Swoole\Http\Server;
use Symfony\Component\Console\Style\SymfonyStyle;

final class HttpServer
{
/**
* @var Server|null
*/
private $server;

/**
* @var SymfonyStyle|null
* @var HttpServerFactory
*/
private $symfonyStyle;
private $serverFactory;

public function __construct(Server $server)
public function __construct(HttpServerFactory $serverFactory)
{
$this->server = $server;
$this->serverFactory = $serverFactory;
}

public function setSymfonyStyle(SymfonyStyle $symfonyStyle): void
/**
* @param HttpServerConfiguration $configuration
*
* @throws \Assert\AssertionFailedException
*/
public function setup(HttpServerConfiguration $configuration): void
{
$this->symfonyStyle = $symfonyStyle;
}
Assertion::null($this->server, 'Cannot setup swoole http server multiple times.');
$server = $this->serverFactory->make($configuration);

public function start(RequestHandlerInterface $driver, HttpServerConfiguration $configuration): void
{
$this->server->port = $configuration->getPort();
$this->server->host = $configuration->getHost();
$this->server->on('request', [$driver, 'handle']);
$this->server->set($configuration->getSwooleSettings());
$server->set($configuration->getSwooleSettings());

if (0 === $configuration->getPort()) {
$configuration->changePort($server->port);
}

$this->havingSymfonyStyle(function (SymfonyStyle $io): void {
if (!$this->server->start()) {
$io->error('Failure during starting Swoole HTTP Server.');
} else {
$io->success('Swoole HTTP Server has been successfully shutdown.');
}
}, function (): void {
if (!$this->server->start()) {
throw new RuntimeException('Failure during starting Swoole HTTP Server.');
}
});
$this->server = $server;
}

public function shutdown(): void
/**
* @param RequestHandlerInterface $driver
*
* @throws \Assert\AssertionFailedException
*
* @return bool
*/
public function start(RequestHandlerInterface $driver): bool
{
$this->server->shutdown();
Assertion::isInstanceOf($this->server, Server::class, 'Swoole HTTP Server has not been setup yet. Please use setup() method.');

$this->server->on('request', [$driver, 'handle']);

return $this->server->start();
}

/**
* @param callable $having executes function if symfony style is available
* @param callable $notHaving executes function if symfony style is unavailable
*
* @return mixed
* @throws \Assert\AssertionFailedException
*/
private function havingSymfonyStyle(callable $having, callable $notHaving)
public function shutdown(): void
{
if ($this->symfonyStyle instanceof SymfonyStyle) {
return $having($this->symfonyStyle);
}
Assertion::isInstanceOf($this->server, Server::class, 'Swoole HTTP Server has not been setup yet. Please use setup() method.');

return $notHaving();
$this->server->shutdown();
}
}
Loading

0 comments on commit 3534ed0

Please sign in to comment.