Completed
Push — master ( 572d20...8347cd )
by Song
04:05
created

Server::serverIsRunning()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 10
rs 9.4285
cc 2
eloc 5
nc 2
nop 0
1
<?php
2
3
namespace Encore\LumenSwoole;
4
5
use Illuminate\Http\Request;
6
use Illuminate\Http\Response;
7
use swoole_http_server as HttpServer;
8
9
class Server
10
{
11
    /**
12
     * @var \Laravel\Lumen\Application
13
     */
14
    protected $app;
15
16
    /**
17
     * @var string
18
     */
19
    protected $host;
20
21
    /**
22
     * @var string
23
     */
24
    protected $port;
25
26
    /**
27
     * @var string
28
     */
29
    protected $pidFile = '';
30
31
    /**
32
     * @var HttpServer
33
     */
34
    protected $httpServer;
35
36
    /**
37
     * Http server options.
38
     *
39
     * @var array
40
     */
41
    protected $options = [];
42
43
    /**
44
     * @var array
45
     */
46
    public static $validServerOptions = [
47
        'reactor_num',
48
        'worker_num',
49
        'max_request',
50
        'max_conn',
51
        'task_worker_num',
52
        'task_ipc_mode',
53
        'task_max_request',
54
        'task_tmpdir',
55
        'dispatch_mode',
56
        'message_queue_key',
57
        'daemonize',
58
        'backlog',
59
        'log_file',
60
        'log_level',
61
        'heartbeat_check_interval',
62
        'heartbeat_idle_time',
63
        'open_eof_check',
64
        'open_eof_split',
65
        'package_eof',
66
        'open_length_check',
67
        'package_length_type',
68
        'package_max_length',
69
        'open_cpu_affinity',
70
        'cpu_affinity_ignore',
71
        'open_tcp_nodelay',
72
        'tcp_defer_accept',
73
        'ssl_cert_file',
74
        'ssl_method',
75
        'user',
76
        'group',
77
        'chroot',
78
        'pipe_buffer_size',
79
        'buffer_output_size',
80
        'socket_buffer_size',
81
        'enable_unsafe_event',
82
        'discard_timeout_request',
83
        'enable_reuse_port',
84
        'ssl_ciphers',
85
        'enable_delay_receive',
86
    ];
87
88
    /**
89
     * Create a new Server instance.
90
     *
91
     * @param string $host
92
     * @param string $port
93
     */
94
    public function __construct($host = 'localhost', $port = '8083')
95
    {
96
        $this->host = $host;
97
        $this->port = $port;
98
    }
99
100
    /**
101
     * Set application.
102
     *
103
     * @param \Laravel\Lumen\Application $app
104
     *
105
     * @return $this
106
     */
107
    public function setApplication($app)
108
    {
109
        $this->app = $app;
110
111
        return $this;
112
    }
113
114
    /**
115
     * Get application.
116
     *
117
     * @return \Laravel\Lumen\Application
118
     */
119
    public function getApplication()
120
    {
121
        $this->resolveApplication();
122
123
        return $this->app;
124
    }
125
126
    /**
127
     * Resolve application.
128
     *
129
     * @return void
130
     */
131
    protected function resolveApplication()
132
    {
133
        if (!$this->app) {
134
            $this->app = require $this->basePath('bootstrap/app.php');
135
        }
136
    }
137
138
    /**
139
     * Get the base path for the application.
140
     *
141
     * @param string|null $path
142
     *
143
     * @return string
144
     */
145
    public function basePath($path = null)
146
    {
147
        return getcwd().($path ? '/'.$path : $path);
148
    }
149
150
    /**
151
     * Initialize the server.
152
     *
153
     * @return $this
154
     */
155
    public function initHttpServer()
156
    {
157
        if ($this->httpServer) {
158
            return $this;
159
        }
160
161
        $this->httpServer = new HttpServer($this->host, $this->port);
162
163
        $this->httpServer->on('Request', [$this, 'onRequest']);
164
        $this->httpServer->on('Start', [$this, 'onStart']);
165
        $this->httpServer->on('Shutdown', [$this, 'onShutdown']);
166
167
        return $this;
168
    }
169
170
    /**
171
     * Start the server.
172
     *
173
     * @return void
174
     */
175
    public function run()
176
    {
177
        $this->initHttpServer();
178
179
        $this->resolveApplication();
180
181
        $this->pidFile = $this->app->storagePath('lumen-swoole.pid');
182
183
        if ($this->serverIsRunning()) {
184
            throw new \Exception('The server is already running.');
185
        }
186
187
        if (!empty($this->options)) {
188
            $this->httpServer->set($this->options);
189
        }
190
191
        $this->httpServer->start();
192
    }
193
194
    /**
195
     * Determine if server is running.
196
     *
197
     * @return bool
198
     */
199
    public function serverIsRunning()
200
    {
201
        if (!file_exists($this->pidFile)) {
202
            return false;
203
        }
204
205
        $pid = file_get_contents($this->pidFile);
206
207
        return (bool) posix_getpgid($pid);
208
    }
209
210
    /**
211
     * Set http server options.
212
     *
213
     * @param array $options
214
     *
215
     * @return $this
216
     */
217
    public function options($options = [])
218
    {
219
        $this->options = array_only($options, static::$validServerOptions);
220
221
        return $this;
222
    }
223
224
    /**
225
     * On request callback.
226
     *
227
     * @param \swoole_http_request  $request
228
     * @param \swoole_http_response $response
229
     */
230
    public function onRequest($request, $response)
0 ignored issues
show
Coding Style introduced by
onRequest uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
onRequest uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
onRequest uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
onRequest uses the super-global variable $_COOKIE which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
onRequest uses the super-global variable $_FILES which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
231
    {
232
        foreach ($request->server as $key => $value) {
233
            $_SERVER[strtoupper($key)] = $value;
234
        }
235
236
        if (property_exists($request, 'get')) {
237
            $_GET = $request->get;
238
        }
239
240
        if (property_exists($request, 'post')) {
241
            $_POST = $request->post;
242
        }
243
244
        if (property_exists($request, 'cookie')) {
245
            $_COOKIE = $request->cookie;
246
        }
247
248
        if (property_exists($request, 'files')) {
249
            $_FILES = $request->files;
250
        }
251
252
        if (property_exists($request, 'header')) {
253
            foreach ($request->header as $key => $value) {
254
                $_SERVER['HTTP_'.strtoupper($key)] = $value;
255
            }
256
        }
257
258
        $this->handleResponse($response, $this->app->dispatch(Request::capture()));
259
    }
260
261
    /**
262
     * Server start event callback.
263
     *
264
     * @param $server
265
     */
266
    public function onStart($server)
267
    {
268
        file_put_contents($this->pidFile, $server->master_pid);
269
    }
270
271
    /**
272
     * Server shutdown event callback.
273
     *
274
     * @param $server
275
     */
276
    public function onShutdown($server)
0 ignored issues
show
Unused Code introduced by
The parameter $server is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
277
    {
278
        unlink($this->pidFile);
279
    }
280
281
    /**
282
     * Response handler.
283
     *
284
     * @param \swoole_http_response $swooleResponse
285
     * @param Response              $response
286
     *
287
     * @return void
288
     */
289
    protected function handleResponse($swooleResponse, Response $response)
290
    {
291
        $swooleResponse->status($response->getStatusCode());
292
293
        foreach ($response->headers->allPreserveCase() as $name => $values) {
294
            foreach ($values as $value) {
295
                $swooleResponse->header($name, $value);
296
            }
297
        }
298
299
        // set cookies
300
        foreach ($response->headers->getCookies() as $cookie) {
301
            $swooleResponse->rawcookie(
302
                $cookie->getName(),
303
                $cookie->getValue(),
304
                $cookie->getExpiresTime(),
305
                $cookie->getPath(),
306
                $cookie->getDomain(),
307
                $cookie->isSecure(),
308
                $cookie->isHttpOnly()
309
            );
310
        }
311
312
        // send content & close
313
        $swooleResponse->end($response->getContent());
314
    }
315
}
316