1
0
mirror of https://github.com/laravel/valet.git synced 2026-02-04 16:10:08 +01:00

Merge branch 'cloudflared' of https://github.com/rcknr/valet into rcknr-cloudflared

This commit is contained in:
Matt Stauffer
2024-08-24 15:49:01 -05:00
4 changed files with 135 additions and 107 deletions

55
cli/Valet/Cloudflared.php Normal file
View File

@@ -0,0 +1,55 @@
<?php
namespace Valet;
use GuzzleHttp\Client;
class Cloudflared
{
public function __construct(public CommandLine $cli, public Brew $brew)
{
}
public function currentTunnelUrl(?string $domain = null)
{
$urls = [];
$processes = array_filter(explode("\n", $this->cli->run('pgrep -fl cloudflared')));
// Every cloudflare process will start a metrics web server
// where Quick Tunnel URL is mentioned under /metrics endpoint
foreach ($processes as $process) {
preg_match('/(?<pid>\d+)\s.+--http-host-header\s(?<domain>[^\s]+).*/', $process, $matches);
if (array_key_exists('domain', $matches) && array_key_exists('pid', $matches)) {
$local_domain = $matches['domain'];
$lsof = $this->cli->run("lsof -iTCP -P -a -p {$matches['pid']}");
preg_match('/TCP\s(?<server>[^\s]+:\d+)\s\(LISTEN\)/', $lsof, $matches);
if (array_key_exists('server', $matches)) {
try {
$body = (new Client())->get("http://{$matches['server']}/metrics")->getBody();
preg_match('/userHostname="(?<url>.+)"/', $body->getContents(), $matches);
} catch (\Exception $e) {}
$urls[$local_domain] = array_key_exists('url', $matches) ? $matches['url'] : false;
}
}
}
return array_key_exists($domain, $urls) ? $urls[$domain] : false;
}
/**
* Return whether cloudflared is installed.
*/
public function installed(): bool
{
return $this->brew->installed('cloudflared');
}
/**
* Make sure cloudflared is installed.
*/
public function ensureInstalled(): void
{
$this->brew->ensureInstalled('cloudflared');
}
}

View File

@@ -47,6 +47,12 @@ function (ConsoleCommandEvent $event) {
Upgrader::onEveryRun();
$share_tools = [
'cloudflared',
'expose',
'ngrok'
];
/**
* Install Valet and any required services.
*/
@@ -378,83 +384,60 @@ function (ConsoleCommandEvent $event) {
/**
* Echo the currently tunneled URL.
*/
$app->command('fetch-share-url [domain]', function ($domain = null) {
$app->command('fetch-share-url [domain]', function ($domain = null) use ($share_tools) {
$tool = Configuration::read()['share-tool'] ?? null;
switch ($tool) {
case 'expose':
if ($url = Expose::currentTunnelUrl($domain ?: Site::host(getcwd()))) {
output($url);
}
break;
case 'ngrok':
try {
output(Ngrok::currentTunnelUrl(Site::domain($domain)));
} catch (\Throwable $e) {
warning($e->getMessage());
}
break;
default:
info('Please set your share tool with `valet share-tool expose` or `valet share-tool ngrok`.');
if ($tool && in_array($tool, $share_tools) && class_exists($tool)) {
try {
output($tool::currentTunnelUrl(Site::domain($domain)));
} catch (\Throwable $e) {
warning($e->getMessage());
}
} else {
info('Please set your share tool with `valet share-tool`.');
return Command::FAILURE;
return Command::FAILURE;
}
})->descriptions('Get the URL to the current share tunnel (for Expose or ngrok)');
})->descriptions('Get the URL to the current share tunnel');
/**
* Echo or set the name of the currently-selected share tool (either "ngrok" or "expose").
*/
$app->command('share-tool [tool]', function (InputInterface $input, OutputInterface $output, $tool = null) {
$app->command('share-tool [tool]', function (InputInterface $input, OutputInterface $output, $tool = null)
use ($share_tools) {
if ($tool === null) {
return output(Configuration::read()['share-tool'] ?? '(not set)');
}
if ($tool !== 'expose' && $tool !== 'ngrok') {
warning($tool.' is not a valid share tool. Please use `ngrok` or `expose`.');
$share_tools_list = preg_replace('/,\s([^,]+)$/', ' or $1',
join(', ', array_map(fn($t) => "`$t`", $share_tools)));
if (! in_array($tool, $share_tools) || ! class_exists($tool)) {
warning("$tool is not a valid share tool. Please use $share_tools_list.");
return Command::FAILURE;
}
Configuration::updateKey('share-tool', $tool);
info('Share tool set to '.$tool.'.');
if ($tool === 'expose') {
if (Expose::installed()) {
// @todo: Check it's the right version (has /api/tunnels/)
// E.g. if (Expose::installedVersion)
// if (version_compare(Expose::installedVersion(), $minimumExposeVersion) < 0) {
// prompt them to upgrade
return;
}
info("Share tool set to $tool.");
if (! $tool::installed()) {
$helper = $this->getHelperSet()->get('question');
$question = new ConfirmationQuestion('Would you like to install Expose now? [y/N] ', false);
$question = new ConfirmationQuestion(
'Would you like to install '.ucfirst($tool).' now? [y/N] ',
false);
if ($helper->ask($input, $output, $question) === false) {
info('Proceeding without installing Expose.');
info('Proceeding without installing '.ucfirst($tool).'.');
return;
}
Expose::ensureInstalled();
return;
$tool::ensureInstalled();
}
if (! Ngrok::installed()) {
info("\nIn order to share with ngrok, you'll need a version\nof ngrok installed and managed by Homebrew.");
$helper = $this->getHelperSet()->get('question');
$question = new ConfirmationQuestion('Would you like to install ngrok via Homebrew now? [y/N] ', false);
if ($helper->ask($input, $output, $question) === false) {
info('Proceeding without installing ngrok.');
return;
}
Ngrok::ensureInstalled();
}
})->descriptions('Get the name of the current share tool (Expose or ngrok).');
return Command::SUCCESS;
})->descriptions('Get the name of the current share tool.');
/**
* Set the ngrok auth token.

View File

@@ -38,3 +38,4 @@ class Site extends Facade {}
class Status extends Facade {}
class Upgrader extends Facade {}
class Valet extends Facade {}
class Cloudflared extends Facade {}

103
valet
View File

@@ -47,6 +47,34 @@ if [[ "$1" = "share" ]]
then
SHARETOOL="$("$PHP" "$DIR/cli/valet.php" share-tool)"
# Check for parameters to pass through to share tool (these will start with '-' or '--')
PARAMS=(${@:2})
for PARAM in ${PARAMS[@]}
do
if [[ ${PARAM:0:1} == '-' ]]; then
PARAMS=("${PARAMS[@]/$PARAM}") # Quotes when working with strings
fi
done
PARAMS=${PARAMS[@]}
HOST="${PWD##*/}"
# Find the first linked site for the current dir, if one exists
for linkname in ~/.config/valet/Sites/*; do
if [[ "$(readlink $linkname)" = "$PWD" ]]
then
HOST="${linkname##*/}"
break
fi
done
# Lowercase the host to match the rest of our domains are looked up
HOST=$(echo "$HOST" | tr '[:upper:]' '[:lower:]')
TLD=$("$PHP" "$DIR/cli/valet.php" tld)
SECURED=$(grep --quiet --no-messages 443 ~/.config/valet/Nginx/$HOST*)
if [[ $SHARETOOL = "ngrok" ]]
then
# ngrok
@@ -59,41 +87,14 @@ then
exit
fi
# Check for parameters to pass through to ngrok (these will start with '-' or '--')
PARAMS=(${@:2})
for PARAM in ${PARAMS[@]}
do
if [[ ${PARAM:0:1} != '-' ]]; then
PARAMS=("${PARAMS[@]/$PARAM}") # Quotes when working with strings
fi
done
PARAMS=${PARAMS[@]}
HOST="${PWD##*/}"
# Find the first linked site for the current dir, if one exists
for linkname in ~/.config/valet/Sites/*; do
if [[ "$(readlink $linkname)" = "$PWD" ]]
then
HOST="${linkname##*/}"
break
fi
done
TLD=$("$PHP" "$DIR/cli/valet.php" tld)
# Decide the correct PORT: uses 60 for secure, else 80
if grep --quiet --no-messages 443 ~/.config/valet/Nginx/$HOST*
if $SECURED
then
PORT=60
else
PORT=80
fi
# Lowercase the host to match how the rest of our domains are looked up
HOST=$(echo "$HOST" | tr '[:upper:]' '[:lower:]')
sudo -u "$USER" "$BREW_PREFIX/bin/ngrok" http "$HOST.$TLD:$PORT" --host-header=rewrite $PARAMS
exit
@@ -102,48 +103,36 @@ then
then
# expose
# Check for parameters to pass through to Expose (these will start with '-' or '--')
PARAMS=(${@:2})
for PARAM in ${PARAMS[@]}
do
if [[ ${PARAM:0:1} != '-' ]]; then
PARAMS=("${PARAMS[@]/$PARAM}") #Quotes when working with strings
fi
done
PARAMS=${PARAMS[@]}
HOST="${PWD##*/}"
# Find the first linked site for the current dir, if one exists
for linkname in ~/.config/valet/Sites/*; do
if [[ "$(readlink $linkname)" = "$PWD" ]]
then
HOST="${linkname##*/}"
break
fi
done
TLD=$("$PHP" "$DIR/cli/valet.php" tld)
# Decide the correct PORT: uses 443 for secure, else 80
if grep --quiet --no-messages 443 ~/.config/valet/Nginx/$HOST*
if $SECURED
then
PORT=443
else
PORT=80
fi
# Lowercase the host to match how the rest of our domains are looked up
HOST=$(echo "$HOST" | tr '[:upper:]' '[:lower:]')
sudo -u "$USER" expose share "$HOST.$TLD:$PORT" $PARAMS
exit
elif [[ $SHARETOOL = "cloudflared" ]]
then
# cloudflared
if $SECURED
then
SCHEME="https"
else
SCHEME="http"
fi
sudo -u "$USER" cloudflared tunnel --no-tls-verify --url "$SCHEME://localhost" \
--http-host-header "$HOST.$TLD" $PARAMS
exit
else
echo ''
echo "Please use 'valet share-tool ngrok' or 'valet share-tool expose'"
echo "Please use 'valet share-tool cloudflared', 'valet share-tool expose' or 'valet share-tool ngrok'"
echo "to set your preferred share tool."
exit
fi