Passed
Push — master ( 23bbf0...48eab7 )
by Keoghan
05:16
created

Open::handle()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 27
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 15
c 1
b 0
f 0
dl 0
loc 27
ccs 16
cts 16
cp 1
rs 9.7666
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($this->argument('site'));
0 ignored issues
show
Bug introduced by
It seems like $this->argument('site') can also be of type array; however, parameter $path of App\Models\Site::resolve...rrentWorkingDirectory() does only seem to accept null|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

39
        $site = Site::resolveFromPathOrCurrentWorkingDirectory(/** @scrutinizer ignore-type */ $this->argument('site'));
Loading history...
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
            ->perform();
60
61 2
        $this->restoreSSLIfNeeded($site);
62
63 2
        $this->porter->stop('ngrok');
64 2
    }
65
66
    /**
67
     * Checking that Porter is using the dns:set-host IP. If we don't ngrok
68
     * requests will only resolve to 127.0.0.1 which is internal to the
69
     * ngrok container, and results in a useless 502 error.
70
     *
71
     * @return bool
72
     */
73 3
    public function checkItWillResolveProperly()
74
    {
75
        try {
76 3
            if ($this->porterLibrary->getMechanic()->isUsingStandardLoopback()) {
77 1
                $this->info('You need to use an alternative loopback address.');
78 1
                $this->info('Please run porter dns:set-host and review the documentation here: https://github.com/konsulting/porter#dns');
79
80 3
                return false;
81
            }
82
        } catch (UnableToRetrieveIP $e) {
83
            $this->info('Please run porter dns:flush and try again. You may need to give it a little while.');
84
85
            return false;
86
        }
87
88 2
        return true;
89
    }
90
91
    /**
92
     * Remove SSL from the site if it was secured.
93
     *
94
     * @param Site $site
95
     */
96 2
    protected function removeSSLIfNeeded(Site $site): void
97
    {
98 2
        if (!$site->secure) {
99 1
            return;
100
        }
101
102 1
        $this->info('Removing SSL for site (required for free ngrok version)');
103 1
        $this->wasSecure = true;
104 1
        $site->unsecure();
105 1
    }
106
107
    /**
108
     * Add SSL back to the site if it was previously secured.
109
     *
110
     * @param Site $site
111
     */
112 2
    protected function restoreSSLIfNeeded(Site $site): void
113
    {
114 2
        if (!$this->wasSecure) {
115 1
            return;
116
        }
117
118 1
        $this->info('Restoring SSL for site');
119 1
        $site->secure();
120 1
    }
121
122
    /**
123
     * Construct the ngrok command.
124
     *
125
     * @param Site $site
126
     *
127
     * @return string
128
     */
129 2
    protected function constructNgrokCommand(Site $site): string
130
    {
131 2
        $tls = ' -bind-tls='.($this->wasSecure ? 'true' : 'false');
132 2
        $region = ' -region='.$this->option('region');
133 2
        $inspect = ' -inspect='.($this->option('no-inspection') ? 'false' : 'true');
134
135 2
        return "ngrok http -host-header=rewrite{$region}{$tls}{$inspect} {$site->url}:80";
136
    }
137
}
138