Passed
Push — master ( 1a2918...dbab80 )
by Biao
09:27
created

Server::__construct()   C

Complexity

Conditions 12
Paths 272

Size

Total Lines 35
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 12
eloc 24
c 2
b 1
f 0
nc 272
nop 1
dl 0
loc 35
rs 5.2333

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
0 ignored issues
show
Coding Style introduced by
Missing file doc comment
Loading history...
3
namespace Hhxsv5\LaravelS\Swoole;
4
5
use Hhxsv5\LaravelS\Illuminate\LogTrait;
6
use Hhxsv5\LaravelS\Swoole\Process\ProcessTitleTrait;
7
use Hhxsv5\LaravelS\Swoole\Socket\PortInterface;
8
use Hhxsv5\LaravelS\Swoole\Task\BaseTask;
9
use Hhxsv5\LaravelS\Swoole\Task\Event;
10
use Hhxsv5\LaravelS\Swoole\Task\Listener;
11
use Hhxsv5\LaravelS\Swoole\Task\Task;
12
use Swoole\Http\Request as SwooleRequest;
13
use Swoole\Http\Response as SwooleResponse;
14
use Swoole\Http\Server as HttpServer;
15
use Swoole\Server\Port;
16
use Swoole\Table;
17
use Swoole\WebSocket\Server as WebSocketServer;
18
19
class Server
0 ignored issues
show
Coding Style introduced by
Missing doc comment for class Server
Loading history...
20
{
21
    use LogTrait;
22
    use ProcessTitleTrait;
23
24
    /**@var array */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
25
    protected $conf;
26
27
    /**@var HttpServer|WebSocketServer */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
28
    protected $swoole;
29
30
    /**@var bool */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
31
    protected $enableWebSocket = false;
32
33
    /**@var array */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
34
    protected $attachedSockets = [];
35
36
    protected function __construct(array $conf)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __construct()
Loading history...
37
    {
38
        $this->conf = $conf;
39
        $this->enableWebSocket = !empty($this->conf['websocket']['enable']);
40
        $this->attachedSockets = empty($this->conf['sockets']) ? [] : $this->conf['sockets'];
41
42
        $ip = isset($conf['listen_ip']) ? $conf['listen_ip'] : '127.0.0.1';
43
        $port = isset($conf['listen_port']) ? $conf['listen_port'] : 5200;
44
        $socketType = isset($conf['socket_type']) ? (int)$conf['socket_type'] : SWOOLE_SOCK_TCP;
45
46
        if ($socketType === SWOOLE_SOCK_UNIX_STREAM) {
47
            $socketDir = dirname($ip);
48
            if (!file_exists($socketDir) && !mkdir($socketDir) && !is_dir($socketDir)) {
49
                throw new \RuntimeException(sprintf('Directory "%s" was not created', $socketDir));
50
            }
51
        }
52
53
        $settings = isset($conf['swoole']) ? $conf['swoole'] : [];
54
        $settings['enable_static_handler'] = !empty($conf['handle_static']);
55
56
        $serverClass = $this->enableWebSocket ? WebSocketServer::class : HttpServer::class;
57
        if (isset($settings['ssl_cert_file'], $settings['ssl_key_file'])) {
58
            $this->swoole = new $serverClass($ip, $port, SWOOLE_PROCESS, $socketType | SWOOLE_SSL);
59
        } else {
60
            $this->swoole = new $serverClass($ip, $port, SWOOLE_PROCESS, $socketType);
61
        }
62
63
        $this->swoole->set($settings);
64
65
        $this->bindBaseEvent();
66
        $this->bindHttpEvent();
67
        $this->bindTaskEvent();
68
        $this->bindWebSocketEvent();
69
        $this->bindAttachedSockets();
70
        $this->bindSwooleTables();
71
    }
72
73
    protected function bindBaseEvent()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function bindBaseEvent()
Loading history...
74
    {
75
        $this->swoole->on('Start', [$this, 'onStart']);
76
        $this->swoole->on('Shutdown', [$this, 'onShutdown']);
77
        $this->swoole->on('ManagerStart', [$this, 'onManagerStart']);
78
        $this->swoole->on('ManagerStop', [$this, 'onManagerStop']);
79
        $this->swoole->on('WorkerStart', [$this, 'onWorkerStart']);
80
        $this->swoole->on('WorkerStop', [$this, 'onWorkerStop']);
81
        $this->swoole->on('WorkerError', [$this, 'onWorkerError']);
82
        $this->swoole->on('PipeMessage', [$this, 'onPipeMessage']);
83
    }
84
85
    protected function bindHttpEvent()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function bindHttpEvent()
Loading history...
86
    {
87
        $this->swoole->on('Request', [$this, 'onRequest']);
88
    }
89
90
    protected function bindTaskEvent()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function bindTaskEvent()
Loading history...
91
    {
92
        if (!empty($this->conf['swoole']['task_worker_num'])) {
93
            $this->swoole->on('Task', [$this, 'onTask']);
94
            $this->swoole->on('Finish', [$this, 'onFinish']);
95
        }
96
    }
97
98
    protected function bindWebSocketEvent()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function bindWebSocketEvent()
Loading history...
99
    {
100
        if ($this->enableWebSocket) {
101
            $eventHandler = function ($method, array $params) {
102
                $this->callWithCatchException(function () use ($method, $params) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
103
                    call_user_func_array([$this->getWebSocketHandler(), $method], $params);
104
                });
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
105
            };
106
107
            $this->swoole->on('Open', function () use ($eventHandler) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
108
                $eventHandler('onOpen', func_get_args());
109
            });
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
110
111
            $this->swoole->on('Message', function () use ($eventHandler) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
112
                $eventHandler('onMessage', func_get_args());
113
            });
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
114
115
            $this->swoole->on('Close', function (WebSocketServer $server, $fd, $reactorId) use ($eventHandler) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
116
                $clientInfo = $server->getClientInfo($fd);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $clientInfo is correct as $server->getClientInfo($fd) targeting Swoole\Server::getClientInfo() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
117
                if (isset($clientInfo['websocket_status']) && $clientInfo['websocket_status'] === \WEBSOCKET_STATUS_FRAME) {
118
                    $eventHandler('onClose', func_get_args());
119
                }
120
                // else ignore the close event for http server
121
            });
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
122
        }
123
    }
124
125
    protected function bindAttachedSockets()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function bindAttachedSockets()
Loading history...
126
    {
127
        foreach ($this->attachedSockets as $socket) {
128
            if (isset($socket['enable']) && !$socket['enable']) {
129
                continue;
130
            }
131
132
            $port = $this->swoole->addListener($socket['host'], $socket['port'], $socket['type']);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $port is correct as $this->swoole->addListen...ort'], $socket['type']) targeting Swoole\Server::addlistener() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
133
            if (!($port instanceof Port)) {
134
                $errno = method_exists($this->swoole, 'getLastError') ? $this->swoole->getLastError() : 'unknown';
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->swoole->getLastError() targeting Swoole\Server::getLastError() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
135
                $errstr = sprintf('listen %s:%s failed: errno=%s', $socket['host'], $socket['port'], $errno);
136
                $this->error($errstr);
137
                continue;
138
            }
139
140
            $port->set(empty($socket['settings']) ? [] : $socket['settings']);
141
142
            $handlerClass = $socket['handler'];
143
            $eventHandler = function ($method, array $params) use ($port, $handlerClass) {
144
                $handler = $this->getSocketHandler($port, $handlerClass);
145
                if (method_exists($handler, $method)) {
146
                    $this->callWithCatchException(function () use ($handler, $method, $params) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
147
                        call_user_func_array([$handler, $method], $params);
148
                    });
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
149
                }
150
            };
151
            static $events = [
152
                'Open',
153
                'Request',
154
                'Message',
155
                'Connect',
156
                'Close',
157
                'Receive',
158
                'Packet',
159
                'BufferFull',
160
                'BufferEmpty',
161
            ];
162
            foreach ($events as $event) {
163
                $port->on($event, function () use ($event, $eventHandler) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
164
                    $eventHandler('on' . $event, func_get_args());
165
                });
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
166
            }
167
        }
168
    }
169
170
    protected function getWebSocketHandler()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function getWebSocketHandler()
Loading history...
171
    {
172
        static $handler = null;
173
        if ($handler !== null) {
174
            return $handler;
175
        }
176
177
        $handlerClass = $this->conf['websocket']['handler'];
178
        $t = new $handlerClass();
179
        if (!($t instanceof WebSocketHandlerInterface)) {
180
            throw new \InvalidArgumentException(sprintf('%s must implement the interface %s', get_class($t), WebSocketHandlerInterface::class));
181
        }
182
        $handler = $t;
183
        return $handler;
184
    }
185
186
    protected function getSocketHandler(Port $port, $handlerClass)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function getSocketHandler()
Loading history...
187
    {
188
        static $handlers = [];
189
        $portHash = spl_object_hash($port);
190
        if (isset($handlers[$portHash])) {
191
            return $handlers[$portHash];
192
        }
193
        $t = new $handlerClass($port);
194
        if (!($t instanceof PortInterface)) {
195
            throw new \InvalidArgumentException(sprintf('%s must extend the abstract class TcpSocket/UdpSocket', get_class($t)));
196
        }
197
        $handlers[$portHash] = $t;
198
        return $handlers[$portHash];
199
    }
200
201
    protected function bindSwooleTables()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function bindSwooleTables()
Loading history...
202
    {
203
        $tables = isset($this->conf['swoole_tables']) ? (array)$this->conf['swoole_tables'] : [];
204
        foreach ($tables as $name => $table) {
205
            $t = new Table($table['size']);
206
            foreach ($table['column'] as $column) {
207
                if (isset($column['size'])) {
208
                    $t->column($column['name'], $column['type'], $column['size']);
209
                } else {
210
                    $t->column($column['name'], $column['type']);
211
                }
212
            }
213
            $t->create();
214
            $name .= 'Table'; // Avoid naming conflicts
215
            $this->swoole->{$name} = $t;
216
        }
217
    }
218
219
    public function onStart(HttpServer $server)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function onStart()
Loading history...
220
    {
221
        $this->setProcessTitle(sprintf('%s laravels: master process', $this->conf['process_prefix']));
222
223
        if (version_compare(swoole_version(), '1.9.5', '<')) {
0 ignored issues
show
Bug introduced by
Are you sure the usage of swoole_version() is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
224
            file_put_contents($this->conf['swoole']['pid_file'], $server->master_pid);
225
        }
226
    }
227
228
    public function onShutdown(HttpServer $server)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function onShutdown()
Loading history...
229
    {
230
    }
231
232
    public function onManagerStart(HttpServer $server)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function onManagerStart()
Loading history...
233
    {
234
        $this->setProcessTitle(sprintf('%s laravels: manager process', $this->conf['process_prefix']));
235
    }
236
237
    public function onManagerStop(HttpServer $server)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function onManagerStop()
Loading history...
238
    {
239
    }
240
241
    public function onWorkerStart(HttpServer $server, $workerId)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function onWorkerStart()
Loading history...
242
    {
243
        if ($workerId >= $server->setting['worker_num']) {
244
            $process = 'task worker';
245
        } else {
246
            $process = 'worker';
247
            if (!empty($this->conf['enable_coroutine_runtime'])) {
248
                \Swoole\Runtime::enableCoroutine();
249
            }
250
        }
251
        $this->setProcessTitle(sprintf('%s laravels: %s process %d', $this->conf['process_prefix'], $process, $workerId));
252
253
        if (function_exists('opcache_reset')) {
254
            opcache_reset();
255
        }
256
        if (function_exists('apc_clear_cache')) {
257
            apc_clear_cache();
258
        }
259
260
        clearstatcache();
261
    }
262
263
    public function onWorkerStop(HttpServer $server, $workerId)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function onWorkerStop()
Loading history...
264
    {
265
    }
266
267
    public function onWorkerError(HttpServer $server, $workerId, $workerPId, $exitCode, $signal)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function onWorkerError()
Loading history...
268
    {
269
        $this->error(sprintf('worker[%d] error: exitCode=%s, signal=%s', $workerId, $exitCode, $signal));
270
    }
271
272
    public function onPipeMessage(HttpServer $server, $srcWorkerId, $message)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function onPipeMessage()
Loading history...
273
    {
274
        if ($message instanceof BaseTask) {
275
            $this->onTask($server, null, $srcWorkerId, $message);
276
        }
277
    }
278
279
    public function onRequest(SwooleRequest $swooleRequest, SwooleResponse $swooleResponse)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function onRequest()
Loading history...
280
    {
281
    }
282
283
    public function onTask(HttpServer $server, $taskId, $srcWorkerId, $data)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function onTask()
Loading history...
284
    {
285
        if ($data instanceof Event) {
286
            $this->handleEvent($data);
287
        } elseif ($data instanceof Task) {
288
            if ($this->handleTask($data) && method_exists($data, 'finish')) {
289
                return $data;
290
            }
291
        }
292
    }
293
294
    public function onFinish(HttpServer $server, $taskId, $data)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function onFinish()
Loading history...
295
    {
296
        if ($data instanceof Task) {
297
            $data->finish();
298
        }
299
    }
300
301
    protected function handleEvent(Event $event)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function handleEvent()
Loading history...
302
    {
303
        $listenerClasses = $event->getListeners();
304
        foreach ($listenerClasses as $listenerClass) {
305
            /**@var Listener $listener */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
306
            $listener = new $listenerClass($event);
307
            if (!($listener instanceof Listener)) {
308
                throw new \InvalidArgumentException(sprintf('%s must extend the abstract class %s', $listenerClass, Listener::class));
309
            }
310
            $this->callWithCatchException(function () use ($listener) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
311
                $listener->handle();
312
            }, [], $event->getTries());
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
313
        }
314
        return true;
315
    }
316
317
    protected function handleTask(Task $task)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function handleTask()
Loading history...
318
    {
319
        return $this->callWithCatchException(function () use ($task) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
320
            $task->handle();
321
            return true;
322
        }, [], $task->getTries());
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
323
    }
324
325
    protected function fireEvent($event, $interface, array $arguments)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function fireEvent()
Loading history...
326
    {
327
        if (isset($this->conf['event_handlers'][$event])) {
328
            $eventHandlers = (array)$this->conf['event_handlers'][$event];
329
            foreach ($eventHandlers as $eventHandler) {
330
                if (!isset(class_implements($eventHandler)[$interface])) {
331
                    throw new \InvalidArgumentException(sprintf(
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
332
                            '%s must implement the interface %s',
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 24 spaces, but found 28.
Loading history...
333
                            $eventHandler,
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 24 spaces, but found 28.
Loading history...
334
                            $interface
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 24 spaces, but found 28.
Loading history...
335
                        )
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 20 spaces, but found 24.
Loading history...
336
                    );
337
                }
338
                $this->callWithCatchException(function () use ($eventHandler, $arguments) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
339
                    call_user_func_array([(new $eventHandler), 'handle'], $arguments);
340
                });
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
341
            }
342
        }
343
    }
344
345
    public function run()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function run()
Loading history...
346
    {
347
        $this->swoole->start();
348
    }
349
}
350