Completed
Pull Request — master (#27)
by Andrew
02:47
created

DaemonRunCommand::flagShutdown()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 8
rs 9.4285
cc 2
eloc 4
nc 2
nop 0
1
<?php
2
3
namespace PHPFastCGI\FastCGIDaemon\Command;
4
5
use PHPFastCGI\FastCGIDaemon\DaemonInterface;
6
use PHPFastCGI\FastCGIDaemon\DaemonOptions;
7
use PHPFastCGI\FastCGIDaemon\Driver\DriverContainerInterface;
8
use PHPFastCGI\FastCGIDaemon\KernelInterface;
9
use Symfony\Component\Console\Command\Command;
10
use Symfony\Component\Console\Input\InputInterface;
11
use Symfony\Component\Console\Input\InputOption;
12
use Symfony\Component\Console\Output\OutputInterface;
13
use Symfony\Component\Console\Logger\ConsoleLogger;
14
15
class DaemonRunCommand extends Command
16
{
17
    const DEFAULT_NAME        = 'run';
18
    const DEFAULT_DESCRIPTION = 'Run the FastCGI daemon';
19
20
    /**
21
     * @var KernelInterface
22
     */
23
    private $kernel;
24
25
    /**
26
     * @var DriverContainerInterface
27
     */
28
    private $driverContainer;
29
30
    /**
31
     * @var DaemonInterface
32
     */
33
    private $daemon;
34
35
    /**
36
     * Constructor.
37
     *
38
     * @param KernelInterface          $kernel          The kernel to be given to the daemon
39
     * @param DriverContainerInterface $driverContainer The driver container
40
     * @param string                   $name            The name of the daemon run command
41
     * @param string                   $description     The description of the daemon run command
42
     */
43
    public function __construct(KernelInterface $kernel, DriverContainerInterface $driverContainer, $name = null, $description = null)
44
    {
45
        $this->kernel          = $kernel;
46
        $this->driverContainer = $driverContainer;
47
        $this->daemon          = null;
48
49
        $name        = $name        ?: self::DEFAULT_NAME;
50
        $description = $description ?: self::DEFAULT_DESCRIPTION;
51
52
        parent::__construct($name);
53
54
        $this
55
            ->setDescription($description)
56
            ->addOption('port',          null, InputOption::VALUE_OPTIONAL, 'TCP port to listen on (if not present, daemon will listen on FCGI_LISTENSOCK_FILENO)')
57
            ->addOption('host',          null, InputOption::VALUE_OPTIONAL, 'TCP host to listen on')
58
            ->addOption('fd',            null, InputOption::VALUE_OPTIONAL, 'File descriptor to listen on - defaults to FCGI_LISTENSOCK_FILENO', DaemonInterface::FCGI_LISTENSOCK_FILENO)
59
            ->addOption('request-limit', null, InputOption::VALUE_OPTIONAL, 'The maximum number of requests to handle before shutting down')
60
            ->addOption('memory-limit',  null, InputOption::VALUE_OPTIONAL, 'The memory limit on the daemon instance before shutting down')
61
            ->addOption('time-limit',    null, InputOption::VALUE_OPTIONAL, 'The time limit on the daemon in seconds before shutting down')
62
            ->addOption('driver',        null, InputOption::VALUE_OPTIONAL, 'The implementation of the FastCGI protocol to use', 'userland');
63
    }
64
65
    /**
66
     * Creates a daemon configuration object from the Symfony command input and
67
     * output objects.
68
     *
69
     * @param InputInterface  $input  The  Symfony command input
70
     * @param OutputInterface $output The Symfony command output
71
     *
72
     * @return DaemonOptions The daemon configuration
73
     */
74
    private function getDaemonOptions(InputInterface $input, OutputInterface $output)
75
    {
76
        $logger = new ConsoleLogger($output);
77
78
        $requestLimit = $input->getOption('request-limit') ?: DaemonOptions::NO_LIMIT;
79
        $memoryLimit  = $input->getOption('memory-limit')  ?: DaemonOptions::NO_LIMIT;
80
        $timeLimit    = $input->getOption('time-limit')    ?: DaemonOptions::NO_LIMIT;
81
82
        return new DaemonOptions([
83
            DaemonOptions::LOGGER        => $logger,
84
            DaemonOptions::REQUEST_LIMIT => $requestLimit,
85
            DaemonOptions::MEMORY_LIMIT  => $memoryLimit,
86
            DaemonOptions::TIME_LIMIT    => $timeLimit,
87
        ]);
88
    }
89
90
    /**
91
     * {@inheritdoc}
92
     */
93
    protected function execute(InputInterface $input, OutputInterface $output)
94
    {
95
        $port = $input->getOption('port');
96
        $host = $input->getOption('host');
97
        $fd = $input->getOption('fd');
98
99
        $daemonOptions = $this->getDaemonOptions($input, $output);
100
101
        $driver        = $input->getOption('driver');
102
        $daemonFactory = $this->driverContainer->getFactory($driver);
103
104
        if (null !== $port) {
105
            // If we have the port, create a TCP daemon
106
            $this->daemon = $daemonFactory->createTcpDaemon($this->kernel, $daemonOptions, $host ?: 'localhost', $port);
107
        } elseif (null !== $host) {
108
            // If we have the host but not the port, we cant create a TCP daemon - throw exception
109
            throw new \InvalidArgumentException('TCP port option must be set if host option is set');
110
        } else {
111
            // With no host or port, listen on FCGI_LISTENSOCK_FILENO (default)
112
            $this->daemon = $daemonFactory->createDaemon($this->kernel, $daemonOptions, $fd);
113
        }
114
115
        $this->daemon->run();
116
    }
117
118
    /**
119
     * Flag the daemon for shutdown.
120
     */
121
    public function flagShutdown()
122
    {
123
        if (null === $this->daemon) {
124
            throw new \RuntimeException('There is no daemon running');
125
        }
126
127
        $this->daemon->flagShutdown();
128
    }
129
}
130