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

src/Command.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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 = 'localhost';
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
        $this->handleArguments();
45
46
        $server = new Server($this->host, $this->port);
47
        $server->setApplication(require $this->bootstrap);
48
49
        $server->options($this->serverOptions)->run();
50
    }
51
52
    /**
53
     * @param array $argv
54
     *
55
     * @return bool
56
     */
57
    public function handleAction($argv)
58
    {
59
        if (count($argv) < 2) {
60
            return false;
61
        }
62
63
        if (in_array($argv[1], ['stop', 'reload', 'restart'])) {
64
            call_user_func([$this, $argv[1]]);
65
66
            return true;
67
        }
68
69
        return false;
70
    }
71
72
    public function handleArguments()
73
    {
74
        $serverOptions = array_map(function ($option) {
75
            return "$option:";
76
        }, Server::$validServerOptions);
77
78
        $longOptions = array_merge(['host:', 'port:', 'help'], $serverOptions);
79
80
        $options = getopt('dp:h::s:', $longOptions);
81
82
        foreach ($options as $option => $value) {
83
            switch ($option) {
84
                case 'h':
85
                case 'host':
86
                    if ($value) {
87
                        $this->host = $value;
88
                    } else {
89
                        $this->usage();
90
                    }
91
                    break;
92
93
                case 'help':
94
                    $this->usage();
95
                    break;
96
97
                case 'p':
98
                case 'port':
99
                    if ($value) {
100
                        $this->port = (int) $value;
101
                    }
102
                    break;
103
104
                case 's':
105
                    if ($value) {
106
                        $this->bootstrap = $value;
107
                    }
108
                    break;
109
110
                case 'd':
111
                    $this->serverOptions['daemonize'] = true;
112
                    break;
113
114
                default:
115
                    if (in_array($option, Server::$validServerOptions) && $value) {
116
                        $this->serverOptions[$option] = $value;
117
                    }
118
                    break;
119
            }
120
        }
121
122
        return $options;
123
    }
124
125
    /**
126
     * Show usage.
127
     */
128
    public function usage()
129
    {
130
        exit("Usage: ./vendor/bin/lumen-swoole {stop|restart|reload}\r\n");
0 ignored issues
show
Coding Style Compatibility introduced by
The method usage() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
131
    }
132
133
    /**
134
     * Stop the server.
135
     *
136
     * @throws \Exception
137
     *
138
     * @return void
139
     */
140
    public function stop()
141
    {
142
        $pid = $this->getPid();
143
144
        echo "Server is stopping...\r\n";
145
146
        posix_kill($pid, SIGTERM);
147
148
        usleep(500);
149
150
        posix_kill($pid, SIGKILL);
151
152
        unlink($this->pidFile);
153
    }
154
155
    /**
156
     * Reload the server.
157
     *
158
     * @throws \Exception
159
     *
160
     * @return void
161
     */
162
    public function reload()
163
    {
164
        posix_kill($this->getPid(), SIGUSR1);
165
    }
166
167
    /**
168
     * Restart the server.
169
     *
170
     * @return void
171
     */
172
    public function restart()
173
    {
174
        $cmd = exec('ps -eo args | grep lumen-swoole | grep -v grep | head -n 1');
175
176
        $this->stop();
177
178
        usleep(2000);
179
180
        echo "Server is starting...\r\n";
181
182
        exec($cmd);
183
    }
184
185
    /**
186
     * Get process identifier of this server.
187
     *
188
     * @throws \Exception
189
     *
190
     * @return bool|string
191
     */
192
    protected function getPid()
193
    {
194
        $this->pidFile = __DIR__.'/../../../../storage/lumen-swoole.pid';
195
196
        if (!file_exists($this->pidFile)) {
197
            throw new \Exception('The Server is not running.');
198
        }
199
200
        $pid = file_get_contents($this->pidFile);
201
202
        if (posix_getpgid($pid)) {
203
            return $pid;
204
        }
205
206
        unlink($this->pidFile);
207
208
        return false;
209
    }
210
211
    /**
212
     * Set the error handling for the application.
213
     *
214
     * @return void
215
     */
216
    protected function registerErrorHandling()
217
    {
218
        error_reporting(-1);
219
220
        set_error_handler(function ($level, $message, $file = '', $line = 0) {
221
            if (error_reporting() & $level) {
222
                throw new ErrorException($message, 0, $level, $file, $line);
223
            }
224
        });
225
226
        set_exception_handler(function ($e) {
227
            $this->handleUncaughtException($e);
228
        });
229
230
        register_shutdown_function(function () {
231
            $this->handleShutdown();
232
        });
233
    }
234
235
    /**
236
     * Handle an uncaught exception instance.
237
     *
238
     * @param \Throwable $e
239
     *
240
     * @return void
241
     */
242
    protected function handleUncaughtException($e)
243
    {
244
        if ($e instanceof Error) {
245
            $e = new FatalThrowableError($e);
246
        }
247
248
        (new Handler())->renderForConsole(new ConsoleOutput(), $e);
249
    }
250
251
    /**
252
     * Handle the application shutdown routine.
253
     *
254
     * @return void
255
     */
256
    protected function handleShutdown()
257
    {
258
        if (!is_null($error = error_get_last()) && $this->isFatalError($error['type'])) {
259
            $this->handleUncaughtException(new FatalErrorException(
0 ignored issues
show
new \Symfony\Component\D...file'], $error['line']) is of type object<Symfony\Component...on\FatalErrorException>, 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...
260
                $error['message'],
261
                $error['type'],
262
                0,
263
                $error['file'],
264
                $error['line']
265
            ));
266
        }
267
    }
268
269
    /**
270
     * Determine if the error type is fatal.
271
     *
272
     * @param int $type
273
     *
274
     * @return bool
275
     */
276
    protected function isFatalError($type)
277
    {
278
        $errorCodes = [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE];
279
280
        if (defined('FATAL_ERROR')) {
281
            $errorCodes[] = FATAL_ERROR;
282
        }
283
284
        return in_array($type, $errorCodes);
285
    }
286
}
287