Completed
Pull Request — master (#6)
by Tomáš
04:54
created

HttpServer::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 16
ccs 0
cts 10
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 7
nc 1
nop 3
crap 2
1
<?php
2
3
/*
4
 * This file is a part of Sculpin.
5
 *
6
 * (c) Dragonfly Development Inc.
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Symplify\PHP7_Sculpin\Bundle\SculpinBundle\HttpServer;
13
14
use Dflydev\ApacheMimeTypes\PhpRepository;
15
use React\EventLoop\StreamSelectLoop;
16
use React\Http\Request;
17
use React\Http\Response;
18
use React\Http\Server as ReactHttpServer;
19
use React\Socket\Server as ReactSocketServer;
20
use Symplify\PHP7_Sculpin\Core\Io\ConsoleIo;
21
22
final class HttpServer
23
{
24
    /**
25
     * @var ConsoleIo
26
     */
27
    private $consoleIo;
28
29
    /**
30
     * @var string
31
     */
32
    private $outputDirectory;
33
34
    /**
35
     * @var PhpRepository
36
     */
37
    private $phpRepository;
38
39
    /**
40
     * @var StreamSelectLoop
41
     */
42
    private $streamSelectLoop;
43
44
    /**
45
     * @var ReactHttpServer
46
     */
47
    private $reactHttpServer;
48
49
    /**
50
     * @var int
51
     */
52
    private $port;
53
54
    /**
55
     * @var ReactSocketServer
56
     */
57
    private $reactSocketServer;
58
59
    public function __construct(
60
        string $outputDirectory,
61
        ConsoleIo $consoleIo,
62
        PhpRepository $phpRepository
63
//        StreamSelectLoop $streamSelectLoop,
64
//        ReactSocketServer $reactSocketServer,
65
//        ReactHttpServer $reactHttpServer
66
)
67
    {
68
        $this->outputDirectory = $outputDirectory;
69
        $this->consoleIo = $consoleIo;
70
        $this->phpRepository = $phpRepository;
71
//        $this->streamSelectLoop = $streamSelectLoop;
0 ignored issues
show
Unused Code Comprehensibility introduced by
42% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
72
//        $this->socketServer = $reactSocketServer;
73
//        $this->reactHttpServer = $reactHttpServer;
74
    }
75
76
    public function init(int $port = 8000)
77
    {
78
        $this->setupDependencies();
79
80
        $this->port = $port;
81
82
        $this->reactHttpServer->on('request', function (Request $request, Response $response) {
83
            $path = $this->outputDirectory.'/'.ltrim(rawurldecode($request->getPath()), '/');
84
            if (is_dir($path)) {
85
                $path .= '/index.html';
86
            }
87
88
            if (!file_exists($path)) {
89
                $this->logRequest(404, $request);
90
                $response->writeHead(404, [
91
                    'Content-Type' => 'text/html',
92
                ]);
93
94
                return $response->end(
95
                    '<h1>404</h1>'.
96
                    '<h2>Not Found</h2>'.
97
                    '<p>'.
98
                    'The embedded <a href="https://sculpin.io">Sculpin</a> web server could not find the requested resource.'.
99
                    '</p>'
100
                );
101
            }
102
103
            $type = 'application/octet-stream';
104
105
            if ('' !== $extension = pathinfo($path, PATHINFO_EXTENSION)) {
106
                if ($guessedType = $this->phpRepository->findType($extension)) {
107
                    $type = $guessedType;
108
                }
109
            }
110
111
            $this->logRequest(200, $request);
112
113
            $response->writeHead(200, [
114
                'Content-Type' => $type,
115
            ]);
116
            $response->end(file_get_contents($path));
117
        });
118
119
        $this->reactSocketServer->listen($this->port, '0.0.0.0');
120
    }
121
122
    public function addPeriodicTimer(int $interval, callable $callback)
123
    {
124
        $this->streamSelectLoop->addPeriodicTimer($interval, $callback);
125
    }
126
127
    public function run()
128
    {
129
        $this->consoleIo->write('Starting Sculpin server.');
130
        $this->consoleIo->write(sprintf(
131
            'Server is running at <info>http://%s:%s</info>',
132
            'localhost',
133
            $this->port
134
        ));
135
        $this->consoleIo->write('Quit the server with CONTROL-C.');
136
137
        $this->streamSelectLoop->run();
138
    }
139
140
    private function setupDependencies()
141
    {
142
        $this->streamSelectLoop = new StreamSelectLoop();
143
        $this->reactSocketServer = new ReactSocketServer($this->streamSelectLoop);
144
        $this->reactHttpServer = new ReactHttpServer($this->reactSocketServer);
145
    }
146
147
    private function logRequest(string $responseCode, Request $request)
148
    {
149
        $wrapOpen = '';
150
        $wrapClose = '';
151
        if ($responseCode >= 400) {
152
            $wrapOpen = '<comment>';
153
            $wrapClose = '</comment>';
154
        }
155
156
        $message = sprintf(
157
            '[%s] "%s %s HTTP/%s" %s',
158
            date('d/M/Y H:i:s'),
159
            $request->getMethod(),
160
            $request->getPath(),
161
            $request->getHttpVersion(),
162
            $responseCode
163
        );
164
165
        $this->consoleIo->write($wrapOpen.$message.$wrapClose);
166
    }
167
}
168