Completed
Push — master ( 50b448...b57b98 )
by Biao
03:45
created

Portal::reload()   C

Complexity

Conditions 13
Paths 34

Size

Total Lines 52
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 33
nc 34
nop 0
dl 0
loc 52
rs 6.6166
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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