Open::handle()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 28
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 16
dl 0
loc 28
ccs 17
cts 17
cp 1
rs 9.7333
c 1
b 0
f 0
cc 3
nc 3
nop 0
crap 3
1
<?php
2
3
namespace App\Commands\Ngrok;
4
5
use App\Commands\BaseCommand;
6
use App\Models\Site;
7
use App\Support\Mechanics\Exceptions\UnableToRetrieveIP;
8
9
class Open extends BaseCommand
10
{
11
    /**
12
     * The signature of the command.
13
     *
14
     * @var string
15
     */
16
    protected $signature = 'ngrok {site?} {--region=eu} {--no-inspection}';
17
18
    /**
19
     * The description of the command.
20
     *
21
     * @var string
22
     */
23
    protected $description = 'Open ngrok connection to forward your dev environment to an external url';
24
25
    /**
26
     * Was the site secure at the start of the command?
27
     *
28
     * @var bool
29
     */
30
    protected $wasSecure = false;
31
32
    /**
33
     * Execute the console command.
34
     *
35
     * @return void
36
     */
37 4
    public function handle(): void
38
    {
39 4
        $site = Site::resolveFromPathOrCurrentWorkingDirectory((string) $this->argument('site'));
40
41 4
        if (!$site) {
42 1
            $this->error('No site at this location, and no site path provided.');
43
44 1
            return;
45
        }
46
47 3
        if (!$this->checkItWillResolveProperly()) {
48 1
            return;
49
        }
50
51 2
        $this->removeSSLIfNeeded($site);
52
53 2
        $this->porter->stop('ngrok');
54
55 2
        $this->dockerCompose
56 2
            ->runContainer('ngrok')
57 2
            ->append($this->constructNgrokCommand($site))
58 2
            ->interactive()
59 2
            ->doNotTimeout()
60 2
            ->perform();
61
62 2
        $this->restoreSSLIfNeeded($site);
63
64 2
        $this->porter->stop('ngrok');
65
    }
66
67
    /**
68
     * Checking that Porter is using the dns:set-host IP. If we don't ngrok
69
     * requests will only resolve to 127.0.0.1 which is internal to the
70
     * ngrok container, and results in a useless 502 error.
71
     *
72
     * @return bool
73
     */
74 3
    public function checkItWillResolveProperly()
75
    {
76
        try {
77 3
            if ($this->porterLibrary->getMechanic()->isUsingStandardLoopback()) {
78 1
                $this->info('You need to use an alternative loopback address.');
79 1
                $this->info('Please run porter dns:set-host and review the documentation here: https://github.com/konsulting/porter#dns');
80
81 3
                return false;
82
            }
83
        } catch (UnableToRetrieveIP $e) {
84
            $this->info('Please run porter dns:flush and try again. You may need to give it a little while.');
85
86
            return false;
87
        }
88
89 2
        return true;
90
    }
91
92
    /**
93
     * Remove SSL from the site if it was secured.
94
     *
95
     * @param Site $site
96
     */
97 2
    protected function removeSSLIfNeeded(Site $site): void
98
    {
99 2
        if (!$site->secure) {
100 1
            return;
101
        }
102
103 1
        $this->info('Removing SSL for site (required for free ngrok version)');
104 1
        $this->wasSecure = true;
105 1
        $site->unsecure();
106
    }
107
108
    /**
109
     * Add SSL back to the site if it was previously secured.
110
     *
111
     * @param Site $site
112
     */
113 2
    protected function restoreSSLIfNeeded(Site $site): void
114
    {
115 2
        if (!$this->wasSecure) {
116 1
            return;
117
        }
118
119 1
        $this->info('Restoring SSL for site');
120 1
        $site->secure();
121
    }
122
123
    /**
124
     * Construct the ngrok command.
125
     *
126
     * @param Site $site
127
     *
128
     * @return string
129
     */
130 2
    protected function constructNgrokCommand(Site $site): string
131
    {
132 2
        $tls = ' -bind-tls='.($this->wasSecure ? 'true' : 'false');
133 2
        $region = ' -region='.$this->option('region');
134 2
        $inspect = ' -inspect='.($this->option('no-inspection') ? 'false' : 'true');
135
136 2
        return "ngrok http -host-header=rewrite{$region}{$tls}{$inspect} {$site->url}:80";
137
    }
138
}
139