Passed
Push — master ( 9ac57c...18281d )
by Biao
03:34
created

Portal::start()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

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