Completed
Push — master ( 5d9a17...2628ea )
by Dawid
9s
created

Server::getServerStats()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
ccs 2
cts 2
cp 1
crap 1
1
<?php declare(strict_types=1);
2
3
namespace Igni\Http;
4
5
use Igni\Exception\RuntimeException;
6
use Igni\Http\Server\ClientStats;
7
use Igni\Http\Server\OnConnect;
8
use Igni\Http\Server\OnShutdown;
9
use Igni\Http\Server\OnStart;
10
use Igni\Http\Server\ServerStats;
11
use Igni\Http\Server\HttpConfiguration;
12
use Igni\Http\Server\Listener;
13
use Igni\Http\Server\OnClose;
14
use Igni\Http\Server\OnRequest;
15
use Swoole;
0 ignored issues
show
Bug introduced by
The type Swoole was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
17
/**
18
 * Http server implementation based on swoole extension.
19
 *
20
 * @package Igni\Http
21
 */
22
class Server
23
{
24
    private const SWOOLE_EXT_NAME = 'swoole';
25
26
    /**
27
     * @var Swoole\Server|null
0 ignored issues
show
Bug introduced by
The type Swoole\Server was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
28
     */
29
    private $handler;
30
31
    /**
32
     * @var HttpConfiguration
33
     */
34
    private $settings;
35
36
    /**
37
     * @var Listener[]
38
     */
39
    private $listeners = [];
40
41 7
    public function __construct(HttpConfiguration $settings = null)
42
    {
43 7
        if (!extension_loaded(self::SWOOLE_EXT_NAME)) {
44
            throw new RuntimeException('Could not run server without swoole extension.');
45
        }
46
47 7
        if ($settings === null) {
48 5
            $settings = new HttpConfiguration();
49
        }
50
51 7
        $this->settings = $settings;
52 7
    }
53
54
    /**
55
     * Return server configuration.
56
     *
57
     * @return HttpConfiguration
58
     */
59
    public function getSettings(): HttpConfiguration
60
    {
61
        return $this->settings;
62
    }
63
64
    /**
65
     * Adds listener that is attached to server once it is run.
66
     *
67
     * @param Listener $listener
68
     */
69 1
    public function addListener(Listener $listener): void
70
    {
71 1
        $this->listeners[] = $listener;
72 1
        if ($this->handler !== null) {
73 1
            $this->attachListener($listener);
74
        }
75 1
    }
76
77
    /**
78
     * Checks if listener exists.
79
     *
80
     * @param Listener $listener
81
     * @return bool
82
     */
83 1
    public function hasListener(Listener $listener): bool
84
    {
85 1
        return in_array($listener, $this->listeners);
86
    }
87
88
    /**
89
     * Returns information about client.
90
     *
91
     * @param int $clientId
92
     * @return ClientStats
93
     */
94 1
    public function getClientStats(int $clientId): ClientStats
95
    {
96 1
        return new ClientStats($this->handler->getClientInfo($clientId));
0 ignored issues
show
Bug introduced by
The method getClientInfo() does not exist on null. ( Ignorable by Annotation )

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

96
        return new ClientStats($this->handler->/** @scrutinizer ignore-call */ getClientInfo($clientId));

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...
97
    }
98
99
    /**
100
     * Returns information about server.
101
     *
102
     * @return ServerStats
103
     */
104 1
    public function getServerStats(): ServerStats
105
    {
106 1
        return new ServerStats($this->handler->stats());
107
    }
108
109
    /**
110
     * Starts the server.
111
     */
112 2
    public function start(): void
113
    {
114 2
        $flags = SWOOLE_SOCK_TCP;
0 ignored issues
show
Bug introduced by
The constant Igni\Http\SWOOLE_SOCK_TCP was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
115 2
        if ($this->settings->isSslEnabled()) {
116 1
            $flags |= SWOOLE_SSL;
117
        }
118
119 2
        $settings = $this->settings->getSettings();
120
121 2
        if (!defined('IS_TEST') || IS_TEST !== true) {
122
            $this->handler = new Swoole\Http\Server($settings['address'], $settings['port'], SWOOLE_PROCESS, $flags);
0 ignored issues
show
Bug introduced by
The constant Igni\Http\SWOOLE_PROCESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The type Swoole\Http\Server was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
123
        }
124 2
        $this->handler->set($settings);
125
126
        // Attach listeners.
127 2
        foreach ($this->listeners as $listener) {
128 1
            $this->attachListener($listener);
129
        }
130
131
        // Start the server.
132 2
        $this->handler->start();
133 2
    }
134
135
    /**
136
     * Stops the server.
137
     */
138 1
    public function stop(): void
139
    {
140 1
        if ($this->handler !== null) {
141 1
            $this->handler->shutdown();
142 1
            $this->handler = null;
143
        }
144 1
    }
145
146 1
    private function attachListener(Listener $listener): void
147
    {
148 1
        if ($listener instanceof OnRequest) {
149 1
            $this->attachOnRequestListener($listener);
150
        }
151
152 1
        if ($listener instanceof OnConnect) {
153 1
            $this->attachOnConnectListener($listener);
154
        }
155
156 1
        if ($listener instanceof OnClose) {
157
            $this->attachOnCloseListener($listener);
158
        }
159
160 1
        if ($listener instanceof OnShutdown) {
161 1
            $this->attachOnShutdownListener($listener);
162
        }
163
164 1
        if ($listener instanceof OnStart) {
165 1
            $this->attachOnStartListener($listener);
166
        }
167 1
    }
168
169 1
    private function attachOnRequestListener(OnRequest $listener): void
170
    {
171
        $this->handler->on('Request', function($request, $response) use ($listener) {
172
            $this->normalizeOnRequestListener($request, $response, $listener);
173 1
        });
174 1
    }
175
176 1
    private function attachOnConnectListener(OnConnect $listener): void
177
    {
178
        $this->handler->on('Connect', function($handler, $clientId) use ($listener) {
179
            $listener->onConnect($this, $clientId);
180 1
        });
181 1
    }
182
183
    private function attachOnCloseListener(OnClose $listener): void
184
    {
185
        $this->handler->on('Close', function($handler, $clientId) use ($listener) {
186
            $listener->onClose($this, $clientId);
187
        });
188
    }
189
190 1
    private function attachOnShutdownListener(OnShutdown $listener): void
191
    {
192
        $this->handler->on('Shutdown', function() use ($listener) {
193
            $listener->onShutdown($this);
194 1
        });
195 1
    }
196
197 1
    private function attachOnStartListener(OnStart $listener): void
198
    {
199
        $this->handler->on('Start', function() use ($listener) {
200
            $listener->onStart($this);
201 1
        });
202 1
    }
203
204 1
    private function normalizeOnRequestListener(
205
        Swoole\Http\Request $request,
0 ignored issues
show
Bug introduced by
The type Swoole\Http\Request was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
206
        Swoole\Http\Response $response,
0 ignored issues
show
Bug introduced by
The type Swoole\Http\Response was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
207
        OnRequest $listener
208
    ): void {
209 1
        $psrRequest = ServerRequest::fromSwooleRequest($request);
210 1
        $psrResponse = $listener->onRequest($psrRequest);
211
212
        // Set headers
213 1
        foreach ($psrResponse->getHeaders() as $name => $values) {
214
            foreach ($values as $value) {
215
                $response->header($name, $value);
216
            }
217
        }
218
219
        // Response body.
220 1
        $body = $psrResponse->getBody()->getContents();
221
222
        // Status code
223 1
        $response->status($psrResponse->getStatusCode());
224
225
        // Protect server software header.
226 1
        $response->header('software-server', '');
227 1
        $response->header('server', '');
228
229
        // Support gzip/deflate encoding.
230 1
        if ($psrRequest->hasHeader('accept-encoding')) {
231 1
            $encoding = explode(',', strtolower(implode(',', $psrRequest->getHeader('accept-encoding'))));
232
233 1
            if (in_array('gzip', $encoding, true)) {
234 1
                $response->gzip(1);
235
            } elseif (in_array('deflate', $encoding, true)) {
236
                $response->header('content-encoding', 'deflate');
237
                $body = gzdeflate($body);
238
            }
239
        }
240
241 1
        $response->end($body);
242 1
    }
243
}
244