Completed
Push — master ( af2fe6...d24982 )
by Song
03:24
created

Command::usage()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 36
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 36
rs 8.8571
cc 1
eloc 5
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
                        return false;
93
                    }
94
                    break;
95
96
                case 'help':
97
                    $this->usage();
98
                    return false;
99
100
                case 'p':
101
                case 'port':
102
                    if ($value) {
103
                        $this->port = (int) $value;
104
                    }
105
                    break;
106
107
                case 's':
108
                    if ($value) {
109
                        $this->bootstrap = $value;
110
                    }
111
                    break;
112
113
                case 'd':
114
                    $this->serverOptions['daemonize'] = true;
115
                    break;
116
117
                case 'v':
118
                case 'version':
119
                    echo Server::VERSION, "\r\n";
120
                    return false;
121
122
                default:
123
                    if (in_array($option, Server::$validServerOptions) && $value) {
124
                        $this->serverOptions[$option] = $value;
125
                    }
126
                    break;
127
            }
128
        }
129
130
        return true;
131
    }
132
133
    /**
134
     * Show usage.
135
     */
136
    public function usage()
137
    {
138
        $version = Server::VERSION;
139
140
        echo <<<TYPEOTHER
141
$version
142
143
Usage: vendor/bin/lumen-swoole {stop|restart|reload}
144
145
  -h <hostname>      Server hostname (default: 127.0.0.1).
146
  -p <port>          Server port (default: 6379).
147
  -s <script>        Application script.
148
  -d <daemon>        Run server in daemon mode.
149
  -v <version>       Output version and exit.
150
151
  --host             Server hostname (default: 127.0.0.1).
152
  --port             Server port (default: 6379).
153
  --help             Output this help and exit.
154
  --version          Output version and exit.
155
156
Examples:
157
  vendor/bin/lumen-swoole -d
158
  vendor/bin/lumen-swoole -h 127.0.0.1 -p 80 -d
159
  vendor/bin/lumen-swoole -h 127.0.0.1 -p 80 -d
160
  vendor/bin/lumen-swoole -s path/to/bootstrap/script.php
161
162
  vendor/bin/lumen-swoole restart
163
  vendor/bin/lumen-swoole reload
164
  vendor/bin/lumen-swoole restart
165
166
Other options please see http://wiki.swoole.com/wiki/page/274.html.
167
168
169
TYPEOTHER;
170
171
    }
172
173
    /**
174
     * Stop the server.
175
     *
176
     * @throws \Exception
177
     *
178
     * @return void
179
     */
180
    public function stop()
181
    {
182
        $pid = $this->getPid();
183
184
        echo "Server is stopping...\r\n";
185
186
        posix_kill($pid, SIGTERM);
187
188
        usleep(500);
189
190
        posix_kill($pid, SIGKILL);
191
192
        unlink($this->pidFile);
193
    }
194
195
    /**
196
     * Reload the server.
197
     *
198
     * @throws \Exception
199
     *
200
     * @return void
201
     */
202
    public function reload()
203
    {
204
        posix_kill($this->getPid(), SIGUSR1);
205
    }
206
207
    /**
208
     * Restart the server.
209
     *
210
     * @return void
211
     */
212
    public function restart()
213
    {
214
        $pid = $this->getPid();
215
216
        $cmd = exec("ps -p $pid -o args | grep lumen-swoole");
217
218
        if (empty($cmd)) {
219
            throw new \Exception('Cannot find server process.');
220
        }
221
222
        $this->stop();
223
224
        usleep(2000);
225
226
        echo "Server is starting...\r\n";
227
228
        exec($cmd);
229
    }
230
231
    /**
232
     * Get process identifier of this server.
233
     *
234
     * @throws \Exception
235
     *
236
     * @return bool|string
237
     */
238
    protected function getPid()
239
    {
240
        $this->pidFile = __DIR__.'/../../../../storage/lumen-swoole.pid';
241
242
        if (!file_exists($this->pidFile)) {
243
            throw new \Exception('The Server is not running.');
244
        }
245
246
        $pid = file_get_contents($this->pidFile);
247
248
        if (posix_getpgid($pid)) {
249
            return $pid;
250
        }
251
252
        unlink($this->pidFile);
253
254
        return false;
255
    }
256
257
    /**
258
     * Set the error handling for the application.
259
     *
260
     * @return void
261
     */
262
    protected function registerErrorHandling()
263
    {
264
        error_reporting(-1);
265
266
        set_error_handler(function ($level, $message, $file = '', $line = 0) {
267
            if (error_reporting() & $level) {
268
                throw new ErrorException($message, 0, $level, $file, $line);
269
            }
270
        });
271
272
        set_exception_handler(function ($e) {
273
            $this->handleUncaughtException($e);
274
        });
275
276
        register_shutdown_function(function () {
277
            $this->handleShutdown();
278
        });
279
    }
280
281
    /**
282
     * Handle an uncaught exception instance.
283
     *
284
     * @param \Exception $e
285
     *
286
     * @return void
287
     */
288
    protected function handleUncaughtException($e)
289
    {
290
        if ($e instanceof Error) {
291
            $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...
292
        }
293
294
        (new Handler())->renderForConsole(new ConsoleOutput(), $e);
295
    }
296
297
    /**
298
     * Handle the application shutdown routine.
299
     *
300
     * @return void
301
     */
302
    protected function handleShutdown()
303
    {
304
        if (!is_null($error = error_get_last()) && $this->isFatalError($error['type'])) {
305
            $this->handleUncaughtException(new FatalErrorException(
306
                $error['message'],
307
                $error['type'],
308
                0,
309
                $error['file'],
310
                $error['line']
311
            ));
312
        }
313
    }
314
315
    /**
316
     * Determine if the error type is fatal.
317
     *
318
     * @param int $type
319
     *
320
     * @return bool
321
     */
322
    protected function isFatalError($type)
323
    {
324
        $errorCodes = [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE];
325
326
        if (defined('FATAL_ERROR')) {
327
            $errorCodes[] = FATAL_ERROR;
328
        }
329
330
        return in_array($type, $errorCodes);
331
    }
332
}
333