Skip to content

Commit 81efb8e

Browse files
committed
Merge branch 'cloudflared' of https://github.com/rcknr/valet into rcknr-cloudflared
2 parents fc1b23b + dce6b3c commit 81efb8e

File tree

4 files changed

+135
-107
lines changed

4 files changed

+135
-107
lines changed

cli/Valet/Cloudflared.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
namespace Valet;
4+
5+
use GuzzleHttp\Client;
6+
7+
class Cloudflared
8+
{
9+
public function __construct(public CommandLine $cli, public Brew $brew)
10+
{
11+
}
12+
13+
public function currentTunnelUrl(?string $domain = null)
14+
{
15+
$urls = [];
16+
$processes = array_filter(explode("\n", $this->cli->run('pgrep -fl cloudflared')));
17+
18+
// Every cloudflare process will start a metrics web server
19+
// where Quick Tunnel URL is mentioned under /metrics endpoint
20+
foreach ($processes as $process) {
21+
preg_match('/(?<pid>\d+)\s.+--http-host-header\s(?<domain>[^\s]+).*/', $process, $matches);
22+
if (array_key_exists('domain', $matches) && array_key_exists('pid', $matches)) {
23+
$local_domain = $matches['domain'];
24+
$lsof = $this->cli->run("lsof -iTCP -P -a -p {$matches['pid']}");
25+
preg_match('/TCP\s(?<server>[^\s]+:\d+)\s\(LISTEN\)/', $lsof, $matches);
26+
if (array_key_exists('server', $matches)) {
27+
try {
28+
$body = (new Client())->get("http://{$matches['server']}/metrics")->getBody();
29+
preg_match('/userHostname="(?<url>.+)"/', $body->getContents(), $matches);
30+
} catch (\Exception $e) {}
31+
32+
$urls[$local_domain] = array_key_exists('url', $matches) ? $matches['url'] : false;
33+
}
34+
}
35+
}
36+
37+
return array_key_exists($domain, $urls) ? $urls[$domain] : false;
38+
}
39+
40+
/**
41+
* Return whether cloudflared is installed.
42+
*/
43+
public function installed(): bool
44+
{
45+
return $this->brew->installed('cloudflared');
46+
}
47+
48+
/**
49+
* Make sure cloudflared is installed.
50+
*/
51+
public function ensureInstalled(): void
52+
{
53+
$this->brew->ensureInstalled('cloudflared');
54+
}
55+
}

cli/app.php

Lines changed: 33 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ function (ConsoleCommandEvent $event) {
4747

4848
Upgrader::onEveryRun();
4949

50+
$share_tools = [
51+
'cloudflared',
52+
'expose',
53+
'ngrok'
54+
];
55+
5056
/**
5157
* Install Valet and any required services.
5258
*/
@@ -378,83 +384,60 @@ function (ConsoleCommandEvent $event) {
378384
/**
379385
* Echo the currently tunneled URL.
380386
*/
381-
$app->command('fetch-share-url [domain]', function ($domain = null) {
387+
$app->command('fetch-share-url [domain]', function ($domain = null) use ($share_tools) {
382388
$tool = Configuration::read()['share-tool'] ?? null;
383389

384-
switch ($tool) {
385-
case 'expose':
386-
if ($url = Expose::currentTunnelUrl($domain ?: Site::host(getcwd()))) {
387-
output($url);
388-
}
389-
break;
390-
case 'ngrok':
391-
try {
392-
output(Ngrok::currentTunnelUrl(Site::domain($domain)));
393-
} catch (\Throwable $e) {
394-
warning($e->getMessage());
395-
}
396-
break;
397-
default:
398-
info('Please set your share tool with `valet share-tool expose` or `valet share-tool ngrok`.');
390+
if ($tool && in_array($tool, $share_tools) && class_exists($tool)) {
391+
try {
392+
output($tool::currentTunnelUrl(Site::domain($domain)));
393+
} catch (\Throwable $e) {
394+
warning($e->getMessage());
395+
}
396+
} else {
397+
info('Please set your share tool with `valet share-tool`.');
399398

400-
return Command::FAILURE;
399+
return Command::FAILURE;
401400
}
402-
})->descriptions('Get the URL to the current share tunnel (for Expose or ngrok)');
401+
})->descriptions('Get the URL to the current share tunnel');
403402

404403
/**
405404
* Echo or set the name of the currently-selected share tool (either "ngrok" or "expose").
406405
*/
407-
$app->command('share-tool [tool]', function (InputInterface $input, OutputInterface $output, $tool = null) {
406+
$app->command('share-tool [tool]', function (InputInterface $input, OutputInterface $output, $tool = null)
407+
use ($share_tools) {
408408
if ($tool === null) {
409409
return output(Configuration::read()['share-tool'] ?? '(not set)');
410410
}
411411

412-
if ($tool !== 'expose' && $tool !== 'ngrok') {
413-
warning($tool.' is not a valid share tool. Please use `ngrok` or `expose`.');
412+
$share_tools_list = preg_replace('/,\s([^,]+)$/', ' or $1',
413+
join(', ', array_map(fn($t) => "`$t`", $share_tools)));
414+
415+
if (! in_array($tool, $share_tools) || ! class_exists($tool)) {
416+
warning("$tool is not a valid share tool. Please use $share_tools_list.");
414417

415418
return Command::FAILURE;
416419
}
417420

418421
Configuration::updateKey('share-tool', $tool);
419-
info('Share tool set to '.$tool.'.');
420-
421-
if ($tool === 'expose') {
422-
if (Expose::installed()) {
423-
// @todo: Check it's the right version (has /api/tunnels/)
424-
// E.g. if (Expose::installedVersion)
425-
// if (version_compare(Expose::installedVersion(), $minimumExposeVersion) < 0) {
426-
// prompt them to upgrade
427-
return;
428-
}
422+
info("Share tool set to $tool.");
429423

424+
if (! $tool::installed()) {
430425
$helper = $this->getHelperSet()->get('question');
431-
$question = new ConfirmationQuestion('Would you like to install Expose now? [y/N] ', false);
426+
$question = new ConfirmationQuestion(
427+
'Would you like to install '.ucfirst($tool).' now? [y/N] ',
428+
false);
432429

433430
if ($helper->ask($input, $output, $question) === false) {
434-
info('Proceeding without installing Expose.');
431+
info('Proceeding without installing '.ucfirst($tool).'.');
435432

436433
return;
437434
}
438435

439-
Expose::ensureInstalled();
440-
441-
return;
436+
$tool::ensureInstalled();
442437
}
443438

444-
if (! Ngrok::installed()) {
445-
info("\nIn order to share with ngrok, you'll need a version\nof ngrok installed and managed by Homebrew.");
446-
$helper = $this->getHelperSet()->get('question');
447-
$question = new ConfirmationQuestion('Would you like to install ngrok via Homebrew now? [y/N] ', false);
448-
449-
if ($helper->ask($input, $output, $question) === false) {
450-
info('Proceeding without installing ngrok.');
451-
452-
return;
453-
}
454-
455-
Ngrok::ensureInstalled();
456-
}
457-
})->descriptions('Get the name of the current share tool (Expose or ngrok).');
439+
return Command::SUCCESS;
440+
})->descriptions('Get the name of the current share tool.');
458441

459442
/**
460443
* Set the ngrok auth token.

cli/includes/facades.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,4 @@ class Site extends Facade {}
3838
class Status extends Facade {}
3939
class Upgrader extends Facade {}
4040
class Valet extends Facade {}
41+
class Cloudflared extends Facade {}

valet

Lines changed: 46 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,34 @@ if [[ "$1" = "share" ]]
4747
then
4848
SHARETOOL="$("$PHP" "$DIR/cli/valet.php" share-tool)"
4949

50+
# Check for parameters to pass through to share tool (these will start with '-' or '--')
51+
PARAMS=(${@:2})
52+
53+
for PARAM in ${PARAMS[@]}
54+
do
55+
if [[ ${PARAM:0:1} == '-' ]]; then
56+
PARAMS=("${PARAMS[@]/$PARAM}") # Quotes when working with strings
57+
fi
58+
done
59+
60+
PARAMS=${PARAMS[@]}
61+
62+
HOST="${PWD##*/}"
63+
64+
# Find the first linked site for the current dir, if one exists
65+
for linkname in ~/.config/valet/Sites/*; do
66+
if [[ "$(readlink $linkname)" = "$PWD" ]]
67+
then
68+
HOST="${linkname##*/}"
69+
break
70+
fi
71+
done
72+
73+
# Lowercase the host to match the rest of our domains are looked up
74+
HOST=$(echo "$HOST" | tr '[:upper:]' '[:lower:]')
75+
TLD=$("$PHP" "$DIR/cli/valet.php" tld)
76+
SECURED=$(grep --quiet --no-messages 443 ~/.config/valet/Nginx/$HOST*)
77+
5078
if [[ $SHARETOOL = "ngrok" ]]
5179
then
5280
# ngrok
@@ -59,41 +87,14 @@ then
5987
exit
6088
fi
6189

62-
# Check for parameters to pass through to ngrok (these will start with '-' or '--')
63-
PARAMS=(${@:2})
64-
for PARAM in ${PARAMS[@]}
65-
do
66-
if [[ ${PARAM:0:1} != '-' ]]; then
67-
PARAMS=("${PARAMS[@]/$PARAM}") # Quotes when working with strings
68-
fi
69-
done
70-
71-
PARAMS=${PARAMS[@]}
72-
73-
HOST="${PWD##*/}"
74-
75-
# Find the first linked site for the current dir, if one exists
76-
for linkname in ~/.config/valet/Sites/*; do
77-
if [[ "$(readlink $linkname)" = "$PWD" ]]
78-
then
79-
HOST="${linkname##*/}"
80-
break
81-
fi
82-
done
83-
84-
TLD=$("$PHP" "$DIR/cli/valet.php" tld)
85-
8690
# Decide the correct PORT: uses 60 for secure, else 80
87-
if grep --quiet --no-messages 443 ~/.config/valet/Nginx/$HOST*
91+
if $SECURED
8892
then
8993
PORT=60
9094
else
9195
PORT=80
9296
fi
9397

94-
# Lowercase the host to match how the rest of our domains are looked up
95-
HOST=$(echo "$HOST" | tr '[:upper:]' '[:lower:]')
96-
9798
sudo -u "$USER" "$BREW_PREFIX/bin/ngrok" http "$HOST.$TLD:$PORT" --host-header=rewrite $PARAMS
9899

99100
exit
@@ -102,48 +103,36 @@ then
102103
then
103104

104105
# expose
105-
# Check for parameters to pass through to Expose (these will start with '-' or '--')
106-
PARAMS=(${@:2})
107-
for PARAM in ${PARAMS[@]}
108-
do
109-
if [[ ${PARAM:0:1} != '-' ]]; then
110-
PARAMS=("${PARAMS[@]/$PARAM}") #Quotes when working with strings
111-
fi
112-
done
113-
114-
PARAMS=${PARAMS[@]}
115-
116-
HOST="${PWD##*/}"
117-
118-
# Find the first linked site for the current dir, if one exists
119-
for linkname in ~/.config/valet/Sites/*; do
120-
if [[ "$(readlink $linkname)" = "$PWD" ]]
121-
then
122-
HOST="${linkname##*/}"
123-
break
124-
fi
125-
done
126-
127-
TLD=$("$PHP" "$DIR/cli/valet.php" tld)
128-
129106
# Decide the correct PORT: uses 443 for secure, else 80
130-
if grep --quiet --no-messages 443 ~/.config/valet/Nginx/$HOST*
107+
if $SECURED
131108
then
132109
PORT=443
133110
else
134111
PORT=80
135112
fi
136113

137-
# Lowercase the host to match how the rest of our domains are looked up
138-
HOST=$(echo "$HOST" | tr '[:upper:]' '[:lower:]')
139-
140114
sudo -u "$USER" expose share "$HOST.$TLD:$PORT" $PARAMS
141115

142116
exit
143117

118+
elif [[ $SHARETOOL = "cloudflared" ]]
119+
then
120+
# cloudflared
121+
if $SECURED
122+
then
123+
SCHEME="https"
124+
else
125+
SCHEME="http"
126+
fi
127+
128+
sudo -u "$USER" cloudflared tunnel --no-tls-verify --url "$SCHEME://localhost" \
129+
--http-host-header "$HOST.$TLD" $PARAMS
130+
131+
exit
132+
144133
else
145134
echo ''
146-
echo "Please use 'valet share-tool ngrok' or 'valet share-tool expose'"
135+
echo "Please use 'valet share-tool cloudflared', 'valet share-tool expose' or 'valet share-tool ngrok'"
147136
echo "to set your preferred share tool."
148137
exit
149138
fi

0 commit comments

Comments
 (0)