Passed
Push — master ( 318d64...79e67c )
by Biao
04:20
created

LaravelSCommandBAK::publish()   B

Complexity

Conditions 8
Paths 9

Size

Total Lines 40
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 22
nc 9
nop 0
dl 0
loc 40
rs 8.4444
c 0
b 0
f 0
1
<?php
2
3
namespace Hhxsv5\LaravelS\Illuminate;
4
5
use Illuminate\Console\Command;
6
use Illuminate\Filesystem\Filesystem;
7
8
class LaravelSCommandBAK extends Command
9
{
10
    protected $signature = 'laravels';
11
12
    protected $description = 'LaravelS console tool';
13
14
    protected $actions;
15
16
    protected $isLumen = false;
17
18
    public function __construct()
19
    {
20
        $this->actions = ['start', 'stop', 'restart', 'reload', 'publish'];
21
        $actions = implode('|', $this->actions);
22
        $this->signature .= sprintf(
23
            ' {action : %s} {--d|daemonize : Whether run as a daemon for start & restart} {--i|ignore : Whether ignore checking process pid for start & restart}',
24
            $actions
25
        );
26
        $this->description .= ': ' . $actions;
27
28
        parent::__construct();
29
    }
30
31
    public function fire()
32
    {
33
        $this->handle();
34
    }
35
36
    public function handle()
37
    {
38
        $action = (string)$this->argument('action');
39
        if (!in_array($action, $this->actions, true)) {
40
            $this->warn(sprintf(
41
                    'LaravelS: action %s is not available, only support %s',
42
                    $action,
43
                    implode('|', $this->actions)
44
                )
45
            );
46
            return 127;
47
        }
48
49
        $this->isLumen = stripos($this->getApplication()->getVersion(), 'Lumen') !== false;
50
        $this->loadConfigManually();
51
        return $this->{$action}();
52
    }
53
54
    protected function loadConfigManually()
55
    {
56
        // Load configuration laravel.php manually for Lumen
57
        $basePath = config('laravels.laravel_base_path') ?: base_path();
58
        if ($this->isLumen && file_exists($basePath . '/config/laravels.php')) {
59
            $this->getLaravel()->configure('laravels');
0 ignored issues
show
Bug introduced by
The method configure() does not exist on Illuminate\Contracts\Foundation\Application. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

59
            $this->getLaravel()->/** @scrutinizer ignore-call */ configure('laravels');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
60
        }
61
    }
62
63
    protected function outputInfo()
64
    {
65
        static $logo = <<<EOS
66
 _                               _  _____ 
67
| |                             | |/ ____|
68
| |     __ _ _ __ __ ___   _____| | (___  
69
| |    / _` | '__/ _` \ \ / / _ \ |\___ \ 
70
| |___| (_| | | | (_| |\ V /  __/ |____) |
71
|______\__,_|_|  \__,_| \_/ \___|_|_____/ 
72
                                           
73
EOS;
74
        $this->info($logo);
75
        $this->info('Speed up your Laravel/Lumen');
76
        $this->table(['Component', 'Version'], [
77
            ['Component' => 'PHP', 'Version' => phpversion()],
78
            ['Component' => 'Swoole', 'Version' => \swoole_version()],
79
            ['Component' => $this->getApplication()->getName(), 'Version' => $this->getApplication()->getVersion()],
80
        ]);
81
    }
82
83
    protected function preSet(array &$svrConf)
84
    {
85
        if (!isset($svrConf['enable_gzip'])) {
86
            $svrConf['enable_gzip'] = false;
87
        }
88
        if (empty($svrConf['laravel_base_path'])) {
89
            $svrConf['laravel_base_path'] = base_path();
90
        }
91
        if (empty($svrConf['process_prefix'])) {
92
            $svrConf['process_prefix'] = $svrConf['laravel_base_path'];
93
        }
94
        if (empty($svrConf['swoole']['document_root'])) {
95
            $svrConf['swoole']['document_root'] = $svrConf['laravel_base_path'] . '/public';
96
        }
97
        if ($this->option('daemonize')) {
98
            $svrConf['swoole']['daemonize'] = true;
99
        }
100
        if (empty($svrConf['swoole']['pid_file'])) {
101
            $svrConf['swoole']['pid_file'] = storage_path('laravels.pid');
102
        }
103
    }
104
105
    protected function preCheck(array $svrConf)
106
    {
107
        if (!empty($svrConf['enable_gzip']) && version_compare(\swoole_version(), '4.1.0', '>=')) {
108
            $this->error('LaravelS: enable_gzip is DEPRECATED since Swoole 4.1.0, set http_compression of Swoole instead, http_compression is disabled by default.');
109
            $this->info('LaravelS: if there is a proxy server like Nginx, suggest that enable gzip in Nginx and disable gzip in Swoole, to avoid the repeated gzip compression for response.');
110
            return 1;
111
        }
112
        if (!empty($svrConf['events'])) {
113
            if (empty($svrConf['swoole']['task_worker_num']) || $svrConf['swoole']['task_worker_num'] <= 0) {
114
                $this->error('LaravelS: Asynchronous event listening needs to set task_worker_num > 0');
115
                return 1;
116
            }
117
        }
118
        return 0;
119
    }
120
121
    protected function start()
122
    {
123
        $this->outputInfo();
124
125
        $svrConf = config('laravels');
126
127
        $this->preSet($svrConf);
128
129
        $ret = $this->preCheck($svrConf);
130
        if ($ret !== 0) {
131
            return $ret;
132
        }
133
134
        $laravelConf = [
135
            'root_path'          => $svrConf['laravel_base_path'],
136
            'static_path'        => $svrConf['swoole']['document_root'],
137
            'register_providers' => array_unique((array)array_get($svrConf, 'register_providers', [])),
138
            'is_lumen'           => $this->isLumen,
139
            '_SERVER'            => $_SERVER,
140
            '_ENV'               => $_ENV,
141
        ];
142
143
        if (isset($svrConf['socket_type'])
144
            && in_array($svrConf['socket_type'], [\SWOOLE_SOCK_UNIX_DGRAM, \SWOOLE_SOCK_UNIX_STREAM])
145
        ) {
146
            $listenAt = $svrConf['listen_ip'];
147
        } else {
148
            $listenAt = sprintf('%s:%s', $svrConf['listen_ip'], $svrConf['listen_port']);
149
        }
150
151
        if (!$this->option('ignore') && file_exists($svrConf['swoole']['pid_file'])) {
152
            $pid = (int)file_get_contents($svrConf['swoole']['pid_file']);
153
            if ($pid > 0 && $this->killProcess($pid, 0)) {
154
                $this->warn(sprintf('LaravelS: PID[%s] is already running at %s.', $pid, $listenAt));
155
                return 1;
156
            }
157
        }
158
159
        if (!$svrConf['swoole']['daemonize']) {
160
            $this->info(sprintf('LaravelS: Swoole is listening at %s, press Ctrl+C to quit.', $listenAt));
161
        }
162
163
        // Implements gracefully reload, avoid including laravel's files before worker start
164
        $cmd = sprintf('%s -c "%s" %s/../GoLaravelS.php', PHP_BINARY, php_ini_loaded_file(), __DIR__);
165
        $params = json_encode(compact('svrConf', 'laravelConf'));
166
        $ret = $this->popen($cmd, $params);
167
        if ($ret === false) {
168
            $this->error('LaravelS: popen ' . $cmd . ' failed');
169
            return 1;
170
        }
171
172
        $pidFile = $svrConf['swoole']['pid_file'];
173
174
        // Make sure that master process started
175
        $time = 0;
176
        while (!file_exists($pidFile) && $time <= 20) {
177
            usleep(100000);
178
            $time++;
179
        }
180
181
        if (file_exists($pidFile)) {
182
            $this->info(sprintf('LaravelS: PID[%s] is listening at %s.', file_get_contents($pidFile), $listenAt));
183
            return 0;
184
        } else {
185
            $this->error(sprintf('LaravelS: PID file[%s] does not exist.', $pidFile));
186
            return 1;
187
        }
188
    }
189
190
    protected function popen($cmd, $input = null)
191
    {
192
        $fp = popen($cmd, 'w');
193
        if ($fp === false) {
194
            return false;
195
        }
196
        if ($input !== null) {
197
            fwrite($fp, $input);
198
        }
199
        pclose($fp);
200
        return true;
201
    }
202
203
    protected function stop()
204
    {
205
        $pidFile = config('laravels.swoole.pid_file') ?: storage_path('laravels.pid');
206
        if (!file_exists($pidFile)) {
207
            $this->info('LaravelS: already stopped.');
208
            return 0;
209
        }
210
211
        $pid = (int)file_get_contents($pidFile);
212
        if ($this->killProcess($pid, 0)) {
213
            if ($this->killProcess($pid, SIGTERM)) {
214
                // Make sure that master process quit
215
                $time = 1;
216
                $waitTime = config('laravels.swoole.max_wait_time', 60);
217
                while ($this->killProcess($pid, 0)) {
218
                    if ($time > $waitTime) {
219
                        $this->error("LaravelS: PID[{$pid}] cannot be stopped gracefully in {$waitTime}s, will be stopped forced right now.");
220
                        return 1;
221
                    }
222
                    $this->warn("LaravelS: Waiting PID[{$pid}] to stop. [{$time}]");
223
                    sleep(1);
224
                    $time++;
225
                }
226
                if (file_exists($pidFile)) {
227
                    unlink($pidFile);
228
                }
229
                $this->info("LaravelS: PID[{$pid}] is stopped.");
230
                return 0;
231
            } else {
232
                $this->error("LaravelS: PID[{$pid}] is stopped failed.");
233
                return 1;
234
            }
235
        } else {
236
            $this->warn("LaravelS: PID[{$pid}] does not exist, or permission denied.");
237
            if (file_exists($pidFile)) {
238
                unlink($pidFile);
239
            }
240
            return $this->option('ignore') ? 0 : 1;
241
        }
242
    }
243
244
    protected function restart()
245
    {
246
        $exitCode = $this->stop();
247
        if ($exitCode !== 0) {
248
            return $exitCode;
249
        }
250
        return $this->start();
251
    }
252
253
    protected function reload()
254
    {
255
        $pidFile = config('laravels.swoole.pid_file') ?: storage_path('laravels.pid');
256
        if (!file_exists($pidFile)) {
257
            $this->error('LaravelS: it seems that LaravelS is not running.');
258
            return 1;
259
        }
260
261
        $pid = (int)file_get_contents($pidFile);
262
        if (!$this->killProcess($pid, 0)) {
263
            $this->error("LaravelS: PID[{$pid}] does not exist, or permission denied.");
264
            return 1;
265
        }
266
267
        if ($this->killProcess($pid, SIGUSR1)) {
268
            $now = date('Y-m-d H:i:s');
269
            $this->info("LaravelS: PID[{$pid}] is reloaded at {$now}.");
270
            return 0;
271
        } else {
272
            $this->error("LaravelS: PID[{$pid}] is reloaded failed.");
273
            return 1;
274
        }
275
    }
276
277
    protected function publish()
278
    {
279
        $basePath = config('laravels.laravel_base_path') ?: base_path();
280
        $to = $basePath . '/config/laravels.php';
281
        if (file_exists($to)) {
282
            $choice = $this->anticipate($to . ' already exists, do you want to override it ? Y/N', ['Y', 'N'], 'N');
283
            if (!$choice || strtoupper($choice) !== 'Y') {
284
                $this->info('Publishing skipped.');
285
                return 0;
286
            }
287
        }
288
289
        try {
290
            return $this->call('vendor:publish', ['--provider' => LaravelSServiceProvider::class, '--force' => true]);
291
        } catch (\InvalidArgumentException $e) {
292
            // do nothing.
293
        } catch (\Exception $e) {
294
            throw $e;
295
        }
296
297
        $from = __DIR__ . '/../../config/laravels.php';
298
        $toDir = dirname($to);
299
300
        /**
301
         * @var Filesystem $files
302
         */
303
        $files = app(Filesystem::class);
304
305
        if (!$files->isDirectory($toDir)) {
306
            $files->makeDirectory($toDir, 0755, true);
307
        }
308
309
        $files->copy($from, $to);
310
311
        $from = str_replace($basePath, '', realpath($from));
312
313
        $to = str_replace($basePath, '', realpath($to));
314
315
        $this->line('<info>Copied File</info> <comment>[' . $from . ']</comment> <info>To</info> <comment>[' . $to . ']</comment>');
316
        return 0;
317
    }
318
319
    protected function killProcess($pid, $sig)
320
    {
321
        try {
322
            return \swoole_process::kill($pid, $sig);
323
        } catch (\Exception $e) {
324
            return false;
325
        }
326
    }
327
}
328