Completed
Push — master ( d42705...573ee7 )
by Tomáš
05:03 queued 02:39
created

HttpServer::send200Response()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 0
cts 4
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 3
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of Symplify
7
 * Copyright (c) 2016 Tomas Votruba (http://tomasvotruba.cz).
8
 */
9
10
namespace Symplify\PHP7_Sculpin\HttpServer;
11
12
use React\EventLoop\StreamSelectLoop;
13
use React\Http\Request;
14
use React\Http\Response;
15
use React\Http\Server as ReactHttpServer;
16
use React\Socket\Server as ReactSocketServer;
17
use Symfony\Component\Console\Output\OutputInterface;
18
19
final class HttpServer
20
{
21
    /**
22
     * @var string
23
     */
24
    private $outputDirectory;
25
26
    /**
27
     * @var StreamSelectLoop
28
     */
29
    private $streamSelectLoop;
30
31
    /**
32
     * @var ReactHttpServer
33
     */
34
    private $reactHttpServer;
35
36
    /**
37
     * @var int
38
     */
39
    private $port;
40
41
    /**
42
     * @var ReactSocketServer
43
     */
44
    private $reactSocketServer;
45
46
    /**
47
     * @var OutputInterface
48
     */
49
    private $output;
50
51 1
    public function __construct(string $outputDirectory, OutputInterface $output)
52
    {
53 1
        $this->outputuDirectory = $outputDirectory;
0 ignored issues
show
Bug introduced by
The property outputuDirectory does not seem to exist. Did you mean output?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
54 1
        $this->output = $output;
55 1
    }
56
57 1
    public function init(int $port = 8000)
58
    {
59 1
        $this->setupDependencies();
60
61 1
        $this->port = $port;
62
63 1
        $this->reactHttpServer->on('request', function (Request $request, Response $response) {
64
            $path = $this->outputDirectory.'/'.ltrim(rawurldecode($request->getPath()), '/');
65
            if (is_dir($path)) {
66
                $path .= '/index.html';
67
            }
68
69
            if (!file_exists($path)) {
70
                $this->send404Response($request, $response);
71
            } else {
72
                $this->send200Response($request, $response, $path);
73
            }
74 1
        });
75
76 1
        $this->reactSocketServer->listen($this->port, '0.0.0.0');
77 1
    }
78
79 1
    public function addPeriodicTimer(int $interval, callable $callback)
80
    {
81 1
        $this->streamSelectLoop->addPeriodicTimer($interval, $callback);
82 1
    }
83
84
    public function run()
85
    {
86
        $this->output->write(sprintf(
87
            'Starting Sculpin at <info>http://localhost:%s</info>',
88
            $this->port
89
        ));
90
        $this->output->write('Quit the server with <info>CONTROL-C</info>.');
91
92
        $this->streamSelectLoop->run();
93
    }
94
95 1
    private function setupDependencies()
96
    {
97 1
        $this->streamSelectLoop = new StreamSelectLoop();
98 1
        $this->reactSocketServer = new ReactSocketServer($this->streamSelectLoop);
99 1
        $this->reactHttpServer = new ReactHttpServer($this->reactSocketServer);
100 1
    }
101
102
    private function send404Response(Request $request, Response $response)
103
    {
104
        $this->logRequest(404, $request);
105
        $response->writeHead(404, [
106
            'Content-Type' => 'text/html',
107
        ]);
108
109
        $response->end(
110
            '<h1>404</h1>'.
111
            '<h2>Not Found</h2>'.
112
            '<p>'.
113
            'The embedded <a href="https://sculpin.io">Sculpin</a> web server could not find the requested resource.'.
114
            '</p>'
115
        );
116
    }
117
118
    private function logRequest(int $responseCode, Request $request)
119
    {
120
        $message = sprintf(
121
            '%s for path: "%s"',
122
            $responseCode,
123
            $request->getPath()
124
        );
125
126
        $this->output->write($this->prepareResponseMessage($responseCode, $message));
127
    }
128
129
    private function send200Response(Request $request, Response $response, string $path)
130
    {
131
        $this->logRequest(200, $request);
132
        $response->end(file_get_contents($path));
133
    }
134
135
    private function prepareResponseMessage(int $responseCode, string $message) : string
136
    {
137
        $wrapOpen = '';
138
        $wrapClose = '';
139
        if ($responseCode >= 400) {
140
            $wrapOpen = '<error>';
141
            $wrapClose = '</error>';
142
        }
143
144
        return $wrapOpen.$message.$wrapClose;
145
    }
146
}
147