Completed
Push — master ( 4a85c2...e72a9a )
by Song
05:32
created

Command::printVersionString()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace Encore\LumenSwoole;
4
5
use Error;
6
use ErrorException;
7
use Laravel\Lumen\Exceptions\Handler;
8
use Symfony\Component\Console\Output\ConsoleOutput;
9
use Symfony\Component\Debug\Exception\FatalErrorException;
10
use Symfony\Component\Debug\Exception\FatalThrowableError;
11
12
class Command
13
{
14
    protected $pidFile;
15
16
    protected $options = [];
17
18
    protected $host = '127.0.0.1';
19
20
    protected $port = 8083;
21
22
    protected $bootstrap = 'bootstrap/app.php';
23
24
    protected $serverOptions = [];
25
26
    public function __construct()
27
    {
28
        $this->registerErrorHandling();
29
    }
30
31
    public static function main($argv)
32
    {
33
        $command = new static();
34
35
        return $command->run($argv);
36
    }
37
38
    public function run($argv)
39
    {
40
        if ($this->handleAction($argv)) {
41
            return;
42
        }
43
44
        if (!$this->handleArguments()) {
45
            return;
46
        }
47
48
        $server = new Server($this->host, $this->port);
49
        $server->setApplication(require $this->bootstrap);
50
51
        $server->options($this->serverOptions)->run();
52
    }
53
54
    /**
55
     * @param array $argv
56
     *
57
     * @return bool
58
     */
59
    public function handleAction($argv)
60
    {
61
        if (count($argv) < 2) {
62
            return false;
63
        }
64
65
        if (in_array($argv[1], ['stop', 'reload', 'restart'])) {
66
            call_user_func([$this, $argv[1]]);
67
68
            return true;
69
        }
70
71
        return false;
72
    }
73
74
    public function handleArguments()
75
    {
76
        $serverOptions = array_map(function ($option) {
77
            return "$option:";
78
        }, Server::$validServerOptions);
79
80
        $longOptions = array_merge(['host:', 'port:', 'help', 'version'], $serverOptions);
81
82
        $options = getopt('dvp:h::s:', $longOptions);
83
84
        foreach ($options as $option => $value) {
85
            switch ($option) {
86
                case 'h':
87
                case 'host':
88
                    if ($value) {
89
                        $this->host = $value;
90
                    } else {
91
                        $this->usage();
92
93
                        return false;
94
                    }
95
                    break;
96
97
                case 'help':
98
                    $this->usage();
99
100
                    return false;
101
102
                case 'p':
103
                case 'port':
104
                    if ($value) {
105
                        $this->port = (int) $value;
106
                    }
107
                    break;
108
109
                case 's':
110
                    if ($value) {
111
                        $this->bootstrap = $value;
112
                    }
113
                    break;
114
115
                case 'd':
116
                    $this->serverOptions['daemonize'] = true;
117
                    break;
118
119
                case 'v':
120
                case 'version':
121
                    echo Server::VERSION, "\r\n";
122
123
                    return false;
124
125
                default:
126
                    if (in_array($option, Server::$validServerOptions) && $value) {
127
                        $this->serverOptions[$option] = $value;
128
                    }
129
                    break;
130
            }
131
        }
132
133
        return true;
134
    }
135
136
    /**
137
     * Show usage.
138
     */
139
    public function usage()
140
    {
141
        $this->printVersionString();
142
143
        print <<<EOT
144
145
Usage: vendor/bin/lumen-swoole {stop|restart|reload}
146
147
  -h <hostname>      Server hostname (default: 127.0.0.1).
148
  -p <port>          Server port (default: 6379).
149
  -s <script>        Application script.
150
  -d <daemon>        Run server in daemon mode.
151
  -v <version>       Output version and exit.
152
153
  --host             Server hostname (default: 127.0.0.1).
154
  --port             Server port (default: 6379).
155
  --help             Output this help and exit.
156
  --version          Output version and exit.
157
158
Examples:
159
  vendor/bin/lumen-swoole -d
160
  vendor/bin/lumen-swoole -h 127.0.0.1 -p 80 -d
161
  vendor/bin/lumen-swoole -h 127.0.0.1 -p 80 -d
162
  vendor/bin/lumen-swoole -s path/to/bootstrap/script.php
163
164
  vendor/bin/lumen-swoole restart
165
  vendor/bin/lumen-swoole reload
166
  vendor/bin/lumen-swoole restart
167
168
Other options please see http://wiki.swoole.com/wiki/page/274.html.
169
170
EOT;
171
    }
172
173
    public function printVersionString()
174
    {
175
        echo Server::VERSION, "\r\n";
176
    }
177
178
    /**
179
     * Stop the server.
180
     *
181
     * @throws \Exception
182
     *
183
     * @return void
184
     */
185
    public function stop()
186
    {
187
        $pid = $this->getPid();
188
189
        echo "Server is stopping...\r\n";
190
191
        posix_kill($pid, SIGTERM);
192
193
        usleep(500);
194
195
        posix_kill($pid, SIGKILL);
196
197
        unlink($this->pidFile);
198
    }
199
200
    /**
201
     * Reload the server.
202
     *
203
     * @throws \Exception
204
     *
205
     * @return void
206
     */
207
    public function reload()
208
    {
209
        posix_kill($this->getPid(), SIGUSR1);
210
    }
211
212
    /**
213
     * Restart the server.
214
     *
215
     * @return void
216
     */
217
    public function restart()
218
    {
219
        $pid = $this->getPid();
220
221
        $cmd = exec("ps -p $pid -o args | grep lumen-swoole");
222
223
        if (empty($cmd)) {
224
            throw new \Exception('Cannot find server process.');
225
        }
226
227
        $this->stop();
228
229
        usleep(2000);
230
231
        echo "Server is starting...\r\n";
232
233
        exec($cmd);
234
    }
235
236
    /**
237
     * Get process identifier of this server.
238
     *
239
     * @throws \Exception
240
     *
241
     * @return string|false
242
     */
243
    protected function getPid()
244
    {
245
        $app = require $this->bootstrap;
246
247
        $this->pidFile = $app->storagePath('lumen-swoole.pid');
248
249
        if (!file_exists($this->pidFile)) {
250
            throw new \Exception('The Server is not running.');
251
        }
252
253
        $pid = file_get_contents($this->pidFile);
254
255
        if (posix_getpgid($pid)) {
256
            return $pid;
257
        }
258
259
        unlink($this->pidFile);
260
261
        return false;
262
    }
263
264
    /**
265
     * Set the error handling for the application.
266
     *
267
     * @return void
268
     */
269
    protected function registerErrorHandling()
270
    {
271
        error_reporting(-1);
272
273
        set_error_handler(function ($level, $message, $file = '', $line = 0) {
274
            if (error_reporting() & $level) {
275
                throw new ErrorException($message, 0, $level, $file, $line);
276
            }
277
        });
278
279
        set_exception_handler(function ($e) {
280
            $this->handleUncaughtException($e);
281
        });
282
283
        register_shutdown_function(function () {
284
            $this->handleShutdown();
285
        });
286
    }
287
288
    /**
289
     * Handle an uncaught exception instance.
290
     *
291
     * @param \Exception $e
292
     *
293
     * @return void
294
     */
295
    protected function handleUncaughtException($e)
296
    {
297
        if ($e instanceof Error) {
298
            $e = new FatalThrowableError($e);
0 ignored issues
show
Documentation introduced by
$e is of type object<Error>, but the function expects a object<Throwable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
299
        }
300
301
        (new Handler())->renderForConsole(new ConsoleOutput(), $e);
302
    }
303
304
    /**
305
     * Handle the application shutdown routine.
306
     *
307
     * @return void
308
     */
309
    protected function handleShutdown()
310
    {
311
        if (!is_null($error = error_get_last()) && $this->isFatalError($error['type'])) {
312
            $this->handleUncaughtException(new FatalErrorException(
313
                $error['message'],
314
                $error['type'],
315
                0,
316
                $error['file'],
317
                $error['line']
318
            ));
319
        }
320
    }
321
322
    /**
323
     * Determine if the error type is fatal.
324
     *
325
     * @param int $type
326
     *
327
     * @return bool
328
     */
329
    protected function isFatalError($type)
330
    {
331
        $errorCodes = [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE];
332
333
        if (defined('FATAL_ERROR')) {
334
            $errorCodes[] = FATAL_ERROR;
335
        }
336
337
        return in_array($type, $errorCodes);
338
    }
339
}
340