Passed
Push — master ( 07faf1...77b801 )
by Caen
04:23 queued 15s
created

Router::handle()   A

Complexity

Conditions 6
Paths 8

Size

Total Lines 25
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 12
c 1
b 0
f 0
nc 8
nop 0
dl 0
loc 25
rs 9.2222
1
<?php
2
3
namespace Hyde\RealtimeCompiler\Routing;
4
5
use Desilva\Microserve\JsonResponse;
6
use Desilva\Microserve\Request;
7
use Desilva\Microserve\Response;
8
use Hyde\RealtimeCompiler\Actions\AssetFileLocator;
9
use Hyde\RealtimeCompiler\Actions\RendersSearchPage;
10
use Hyde\RealtimeCompiler\Concerns\SendsErrorResponses;
11
use Hyde\RealtimeCompiler\Http\HtmlResponse;
12
use Hyde\RealtimeCompiler\Models\FileObject;
13
14
class Router
15
{
16
    use SendsErrorResponses;
17
18
    protected Request $request;
19
20
    public function __construct(Request $request)
21
    {
22
        $this->request = $request;
23
    }
24
25
    public function handle(): Response
26
    {
27
        if ($this->shouldProxy($this->request)) {
28
            return $this->proxyStatic();
29
        }
30
31
        if ($this->shouldRenderSpecial($this->request)) {
32
            if ($this->request->path === '/docs') {
33
                $this->request->path = '/docs/index';
34
            }
35
36
            if ($this->request->path === '/docs/search') {
37
                return new HtmlResponse(200, 'OK', [
38
                    'body' => (new RendersSearchPage())->__invoke(),
39
                ]);
40
            }
41
42
            if ($this->request->path === '/ping') {
43
                return new JsonResponse(200, 'OK', [
44
                    'server' => 'Hyde/RealtimeCompiler',
45
                ]);
46
            }
47
        }
48
49
        return PageRouter::handle($this->request);
50
    }
51
52
    /**
53
     * If the request is not for a web page, we assume it's
54
     * a static asset, which we instead want to proxy.
55
     */
56
    protected function shouldProxy(Request $request): bool
57
    {
58
        // Always proxy media files
59
        if (str_starts_with($request->path, '/media/')) {
60
            return true;
61
        }
62
63
        // Get the requested file extension
64
        $extension = pathinfo($request->path)['extension'] ?? null;
65
66
        // If the extension is not set (pretty url), or is .html,
67
        //we assume it's a web page which we need to compile.
68
        if ($extension === null || $extension === 'html') {
69
            return false;
70
        }
71
72
        // The page is not a web page, so we assume it should be proxied.
73
        return true;
74
    }
75
76
    /**
77
     * Proxy a static file or return a 404.
78
     */
79
    protected function proxyStatic(): Response
80
    {
81
        $path = AssetFileLocator::find($this->request->path);
82
83
        if ($path === null) {
84
            return $this->notFound();
85
        }
86
87
        $file = new FileObject($path);
88
89
        return (new Response(200, 'OK', [
90
            'body' => $file->getStream(),
91
        ]))->withHeaders([
92
            'Content-Type'   => $file->getMimeType(),
93
            'Content-Length' => $file->getContentLength(),
94
        ]);
95
    }
96
97
    /**
98
     * If the request is for a special page, we handle it here.
99
     */
100
    protected function shouldRenderSpecial(Request $request): bool
101
    {
102
        $routes = [
103
            '/ping',
104
            '/docs',
105
            '/docs/search',
106
        ];
107
108
        return in_array($request->path, $routes);
109
    }
110
}
111