Completed
Push — master ( 10f5da...bebbc2 )
by Biao
03:04
created

Portal::execute()   B

Complexity

Conditions 7
Paths 13

Size

Total Lines 54
Code Lines 48

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 48
nc 13
nop 2
dl 0
loc 54
rs 8.2012
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Hhxsv5\LaravelS\Console;
4
5
use Hhxsv5\LaravelS\LaravelS;
6
use Hhxsv5\LaravelS\Swoole\Traits\LogTrait;
7
use Swoole\Process;
8
use Symfony\Component\Console\Command\Command;
9
use Symfony\Component\Console\Input\InputArgument;
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\Style\SymfonyStyle;
14
15
class Portal extends Command
16
{
17
    use LogTrait;
18
19
    protected $basePath;
20
21
    /**
22
     * @var InputInterface $input
23
     */
24
    protected $input;
25
26
    /**
27
     * @var OutputInterface $output
28
     */
29
    protected $output;
30
31
    public function __construct($basePath)
32
    {
33
        parent::__construct('laravels');
34
        $this->basePath = $basePath;
35
    }
36
37
    protected function configure()
38
    {
39
        $this->setDescription('LaravelS console tool');
40
        $this->setHelp('LaravelS console tool');
41
42
        $this->addArgument('action', InputArgument::OPTIONAL, 'start|stop|restart|reload|info|help', 'help');
43
        $this->addOption('env', 'e', InputOption::VALUE_OPTIONAL, 'The environment the command should run under, this feature requires Laravel 5.2+');
44
        $this->addOption('daemonize', 'd', InputOption::VALUE_NONE, 'Whether run as a daemon for "start & restart"');
45
        $this->addOption('ignore', 'i', InputOption::VALUE_NONE, 'Whether ignore checking process pid for "start & restart"');
46
    }
47
48
    protected function execute(InputInterface $input, OutputInterface $output)
49
    {
50
        $this->input = $input;
51
        $this->output = $output;
52
        LaravelS::setOutputStyle(new SymfonyStyle($this->input, $this->output));
53
54
        try {
55
            $action = $input->getArgument('action');
56
            switch ($action) {
57
                case 'start':
58
                    $this->start();
59
                    break;
60
                case 'stop':
61
                    $this->stop();
62
                    break;
63
                case 'restart':
64
                    $this->restart();
65
                    break;
66
                case 'reload':
67
                    $this->reload();
68
                    break;
69
                case 'info':
70
                    $this->showInfo();
71
                    break;
72
                default:
73
                    $help = <<<EOS
74
75
Usage: 
76
  [%s] ./bin/laravels [options] <action>
77
78
Arguments:
79
  action                start|stop|restart|reload|info|help
80
81
Options:
82
  -e, --env             The environment the command should run under, this feature requires Laravel 5.2+
83
  -d, --daemonize       Whether run as a daemon for "start & restart"
84
  -i, --ignore          Whether ignore checking process pid for "start & restart"
85
EOS;
86
87
                    $this->info(sprintf($help, PHP_BINARY));
88
                    break;
89
            }
90
        } catch (\Exception $e) {
91
            $error = sprintf(
92
                'Uncaught exception "%s"([%d]%s) at %s:%s, %s%s',
93
                get_class($e),
94
                $e->getCode(),
95
                $e->getMessage(),
96
                $e->getFile(),
97
                $e->getLine(),
98
                PHP_EOL,
99
                $e->getTraceAsString()
100
            );
101
            $this->error($error);
102
        }
103
    }
104
105
    public function start()
106
    {
107
        // Initialize configuration config/laravels.json
108
        $options = $this->input->getOptions();
109
        unset($options['env']);
110
        $options = array_filter($options);
111
        $optionStr = '';
112
        foreach ($options as $key => $value) {
113
            $optionStr .= sprintf('--%s%s ', $key, is_bool($value) ? '' : ('=' . $value));
114
        }
115
        $cmd = trim('laravels config ' . $optionStr);
116
        $this->runArtisanCommand($cmd);
117
118
        $this->showInfo();
119
120
        // Here we go...
121
        $config = $this->getConfig();
122
123
        if (!$config['server']['ignore_check_pid'] && file_exists($config['server']['swoole']['pid_file'])) {
124
            $pid = (int)file_get_contents($config['server']['swoole']['pid_file']);
125
            if ($pid > 0 && self::kill($pid, 0)) {
126
                $this->warning(sprintf('Swoole[PID=%d] is already running.', $pid));
127
                return 1;
128
            }
129
        }
130
131
        if ($config['server']['swoole']['daemonize']) {
132
            $this->trace('Swoole is running in daemon mode, see "ps -ef|grep laravels".');
133
        } else {
134
            $this->trace('Swoole is running, press Ctrl+C to quit.');
135
        }
136
137
        (new LaravelS($config['server'], $config['laravel']))->run();
138
139
        return 0;
140
    }
141
142
    public function stop()
143
    {
144
        $config = $this->getConfig();
145
        $pidFile = $config['server']['swoole']['pid_file'];
146
        if (!file_exists($pidFile)) {
147
            $this->warning('It seems that Swoole is not running.');
148
            return 0;
149
        }
150
151
        $pid = file_get_contents($pidFile);
152
        if (self::kill($pid, 0)) {
153
            if (self::kill($pid, SIGTERM)) {
154
                // Make sure that master process quit
155
                $time = 1;
156
                $waitTime = isset($config['server']['swoole']['max_wait_time']) ? $config['server']['swoole']['max_wait_time'] : 60;
157
                $this->info("The max time of waiting to forcibly stop is {$waitTime}s.");
158
                while (self::kill($pid, 0)) {
159
                    if ($time > $waitTime) {
160
                        $this->warning("Swoole [PID={$pid}] cannot be stopped gracefully in {$waitTime}s, will be stopped forced right now.");
161
                        return 1;
162
                    }
163
                    $this->info("Waiting Swoole[PID={$pid}] to stop. [{$time}]");
164
                    sleep(1);
165
                    $time++;
166
                }
167
                if (file_exists($pidFile)) {
168
                    unlink($pidFile);
169
                }
170
                $this->info("Swoole [PID={$pid}] is stopped.");
171
                return 0;
172
            } else {
173
                $this->error("Swoole [PID={$pid}] is stopped failed.");
174
                return 1;
175
            }
176
        } else {
177
            $this->warning("Swoole [PID={$pid}] does not exist, or permission denied.");
178
            return 0;
179
        }
180
    }
181
182
    public function restart()
183
    {
184
        $code = $this->stop();
185
        if ($code !== 0) {
186
            return $code;
187
        }
188
        return $this->start();
189
    }
190
191
    public function reload()
192
    {
193
        $config = $this->getConfig();
194
        $pidFile = $config['server']['swoole']['pid_file'];
195
        if (!file_exists($pidFile)) {
196
            $this->error('It seems that Swoole is not running.');
197
            return;
198
        }
199
200
        $pid = file_get_contents($pidFile);
201
        if (!$pid || !self::kill($pid, 0)) {
202
            $this->error("Swoole [PID={$pid}] does not exist, or permission denied.");
203
            return;
204
        }
205
206
        if (self::kill($pid, SIGUSR1)) {
207
            $now = date('Y-m-d H:i:s');
208
            $this->info("Swoole [PID={$pid}] is reloaded at {$now}.");
209
        } else {
210
            $this->error("Swoole [PID={$pid}] is reloaded failed.");
211
        }
212
    }
213
214
    public function showInfo()
215
    {
216
        $this->runArtisanCommand('laravels info');
217
    }
218
219
    public function artisanCmd($subCmd)
220
    {
221
        $phpCmd = sprintf('%s -c "%s"', PHP_BINARY, php_ini_loaded_file());
222
        $env = $this->input->getOption('env');
223
        $envs = $env ? "APP_ENV={$env}" : '';
224
        $artisanCmd = trim(sprintf('%s %s %s/artisan %s', $envs, $phpCmd, $this->basePath, $subCmd));
225
        return $artisanCmd;
226
    }
227
228
    public function runArtisanCommand($cmd)
229
    {
230
        $cmd = $this->artisanCmd($cmd);
231
        self::runCommand($cmd);
232
    }
233
234
    public function getConfig()
235
    {
236
        $json = file_get_contents($this->basePath . '/storage/laravels.json');
237
        return (array)json_decode($json, true);
238
    }
239
240
    public static function runCommand($cmd, $input = null)
241
    {
242
        $fp = popen($cmd, 'w');
243
        if ($fp === false) {
244
            return false;
245
        }
246
        if ($input !== null) {
247
            fwrite($fp, $input);
248
        }
249
        pclose($fp);
250
        return true;
251
    }
252
253
    public static function kill($pid, $sig)
254
    {
255
        try {
256
            return Process::kill($pid, $sig);
257
        } catch (\Exception $e) {
258
            return false;
259
        }
260
    }
261
}
262