mirror of
https://github.com/laravel/valet.git
synced 2026-02-06 16:50:09 +01:00
Merge branch 'rcknr-cloudflared'
This commit is contained in:
70
cli/Valet/Cloudflared.php
Normal file
70
cli/Valet/Cloudflared.php
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Valet;
|
||||||
|
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
|
||||||
|
class Cloudflared
|
||||||
|
{
|
||||||
|
public function __construct(public CommandLine $cli, public Brew $brew)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function currentTunnelUrl(string $domain): ?string
|
||||||
|
{
|
||||||
|
// Every cloudflared process will start a "metrics" web server where the
|
||||||
|
// Quick Tunnel URL will be mentioned under the /metrics endpoint; there
|
||||||
|
// can potentially be more than one process that matches, but the lsof
|
||||||
|
// command will show which one is actually functionally running
|
||||||
|
foreach (array_filter(explode(PHP_EOL, $this->cli->run('pgrep -fl cloudflared'))) as $process) {
|
||||||
|
// Get the URL shared in this process
|
||||||
|
preg_match('/(?<pid>\d+)\s.+--http-host-header\s(?<domain>[^\s]+).*/', $process, $pgrepMatches);
|
||||||
|
|
||||||
|
if (! array_key_exists('domain', $pgrepMatches) || ! array_key_exists('pid', $pgrepMatches)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($pgrepMatches['domain'] !== $domain) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the localhost URL for the metrics server
|
||||||
|
$lsof = $this->cli->run("lsof -iTCP -P -a -p {$pgrepMatches['pid']}");
|
||||||
|
preg_match('/TCP\s(?<server>[^\s]+:\d+)\s\(LISTEN\)/', $lsof, $lsofMatches);
|
||||||
|
|
||||||
|
if (! array_key_exists('server', $lsofMatches)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Get the cloudflared share URL from the metrics server output
|
||||||
|
$body = (new Client())->get("http://{$lsofMatches['server']}/metrics")->getBody();
|
||||||
|
preg_match('/userHostname="(?<url>.+)"/', $body->getContents(), $userHostnameMatches);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('url', $userHostnameMatches)) {
|
||||||
|
return $userHostnameMatches['url'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 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');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@ class Expose
|
|||||||
{
|
{
|
||||||
public function __construct(public Composer $composer, public CommandLine $cli) {}
|
public function __construct(public Composer $composer, public CommandLine $cli) {}
|
||||||
|
|
||||||
public function currentTunnelUrl(?string $domain = null): ?string
|
public function currentTunnelUrl(string $domain): ?string
|
||||||
{
|
{
|
||||||
$endpoint = 'http://127.0.0.1:4040/api/tunnels';
|
$endpoint = 'http://127.0.0.1:4040/api/tunnels';
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public function __construct(public CommandLine $cli, public Brew $brew) {}
|
|||||||
/**
|
/**
|
||||||
* Get the current tunnel URL from the Ngrok API.
|
* Get the current tunnel URL from the Ngrok API.
|
||||||
*/
|
*/
|
||||||
public function currentTunnelUrl(?string $domain = null): string
|
public function currentTunnelUrl(string $domain): string
|
||||||
{
|
{
|
||||||
// wait a second for ngrok to start before attempting to find available tunnels
|
// wait a second for ngrok to start before attempting to find available tunnels
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
|||||||
73
cli/app.php
73
cli/app.php
@@ -47,6 +47,12 @@ function (ConsoleCommandEvent $event) {
|
|||||||
|
|
||||||
Upgrader::onEveryRun();
|
Upgrader::onEveryRun();
|
||||||
|
|
||||||
|
$share_tools = [
|
||||||
|
'cloudflared',
|
||||||
|
'expose',
|
||||||
|
'ngrok'
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Install Valet and any required services.
|
* Install Valet and any required services.
|
||||||
*/
|
*/
|
||||||
@@ -378,83 +384,60 @@ function (ConsoleCommandEvent $event) {
|
|||||||
/**
|
/**
|
||||||
* Echo the currently tunneled URL.
|
* 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;
|
$tool = Configuration::read()['share-tool'] ?? null;
|
||||||
|
|
||||||
switch ($tool) {
|
if ($tool && in_array($tool, $share_tools) && class_exists($tool)) {
|
||||||
case 'expose':
|
|
||||||
if ($url = Expose::currentTunnelUrl($domain ?: Site::host(getcwd()))) {
|
|
||||||
output($url);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'ngrok':
|
|
||||||
try {
|
try {
|
||||||
output(Ngrok::currentTunnelUrl(Site::domain($domain)));
|
output($tool::currentTunnelUrl(Site::domain($domain)));
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
warning($e->getMessage());
|
warning($e->getMessage());
|
||||||
}
|
}
|
||||||
break;
|
} else {
|
||||||
default:
|
info('Please set your share tool with `valet share-tool`.');
|
||||||
info('Please set your share tool with `valet share-tool expose` or `valet share-tool ngrok`.');
|
|
||||||
|
|
||||||
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").
|
* 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) {
|
if ($tool === null) {
|
||||||
return output(Configuration::read()['share-tool'] ?? '(not set)');
|
return output(Configuration::read()['share-tool'] ?? '(not set)');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($tool !== 'expose' && $tool !== 'ngrok') {
|
$share_tools_list = preg_replace('/,\s([^,]+)$/', ' or $1',
|
||||||
warning($tool.' is not a valid share tool. Please use `ngrok` or `expose`.');
|
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;
|
return Command::FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Configuration::updateKey('share-tool', $tool);
|
Configuration::updateKey('share-tool', $tool);
|
||||||
info('Share tool set to '.$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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (! $tool::installed()) {
|
||||||
$helper = $this->getHelperSet()->get('question');
|
$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) {
|
if ($helper->ask($input, $output, $question) === false) {
|
||||||
info('Proceeding without installing Expose.');
|
info('Proceeding without installing '.ucfirst($tool).'.');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expose::ensureInstalled();
|
$tool::ensureInstalled();
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! Ngrok::installed()) {
|
return Command::SUCCESS;
|
||||||
info("\nIn order to share with ngrok, you'll need a version\nof ngrok installed and managed by Homebrew.");
|
})->descriptions('Get the name of the current share tool.');
|
||||||
$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).');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the ngrok auth token.
|
* Set the ngrok auth token.
|
||||||
|
|||||||
@@ -38,3 +38,4 @@ class Site extends Facade {}
|
|||||||
class Status extends Facade {}
|
class Status extends Facade {}
|
||||||
class Upgrader extends Facade {}
|
class Upgrader extends Facade {}
|
||||||
class Valet extends Facade {}
|
class Valet extends Facade {}
|
||||||
|
class Cloudflared extends Facade {}
|
||||||
|
|||||||
89
valet
89
valet
@@ -41,29 +41,18 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# If the command is the "share" command we will need to resolve out any
|
# If the command is the "share" command we will need to resolve out any
|
||||||
# symbolic links for the site. Before starting Ngrok, we will fire a
|
# symbolic links for the site. Before starting the share tool, we will fire a
|
||||||
# process to retrieve the live Ngrok tunnel URL in the background.
|
# process to retrieve the live the share tool tunnel URL in the background.
|
||||||
if [[ "$1" = "share" ]]
|
if [[ "$1" = "share" ]]
|
||||||
then
|
then
|
||||||
SHARETOOL="$("$PHP" "$DIR/cli/valet.php" share-tool)"
|
SHARETOOL="$("$PHP" "$DIR/cli/valet.php" share-tool)"
|
||||||
|
|
||||||
if [[ $SHARETOOL = "ngrok" ]]
|
# Check for parameters to pass through to share tool (these will start with '-' or '--')
|
||||||
then
|
|
||||||
# ngrok
|
|
||||||
# Check to make sure ngrok is configured correctly
|
|
||||||
BREW_PREFIX=$(brew --prefix)
|
|
||||||
$($BREW_PREFIX/bin/ngrok config check >/dev/null 2>&1)
|
|
||||||
|
|
||||||
if [[ $? -ne 0 ]]; then
|
|
||||||
echo "Please sign up for a free ngrok account and then run valet set-ngrok-token {yourTokenHere}."
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check for parameters to pass through to ngrok (these will start with '-' or '--')
|
|
||||||
PARAMS=(${@:2})
|
PARAMS=(${@:2})
|
||||||
|
|
||||||
for PARAM in ${PARAMS[@]}
|
for PARAM in ${PARAMS[@]}
|
||||||
do
|
do
|
||||||
if [[ ${PARAM:0:1} != '-' ]]; then
|
if [[ ${PARAM:0:1} == '-' ]]; then
|
||||||
PARAMS=("${PARAMS[@]/$PARAM}") # Quotes when working with strings
|
PARAMS=("${PARAMS[@]/$PARAM}") # Quotes when working with strings
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@@ -81,19 +70,31 @@ then
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Lowercase the host to match how the rest of our domains are looked up
|
||||||
|
HOST=$(echo "$HOST" | tr '[:upper:]' '[:lower:]')
|
||||||
TLD=$("$PHP" "$DIR/cli/valet.php" tld)
|
TLD=$("$PHP" "$DIR/cli/valet.php" tld)
|
||||||
|
$(grep --quiet --no-messages 443 ~/.config/valet/Nginx/$HOST*)
|
||||||
|
SECURED=$?
|
||||||
|
|
||||||
|
if [[ $SHARETOOL = "ngrok" ]]
|
||||||
|
then
|
||||||
|
# ngrok
|
||||||
|
# Check to make sure ngrok is configured correctly
|
||||||
|
BREW_PREFIX=$(brew --prefix)
|
||||||
|
$($BREW_PREFIX/bin/ngrok config check >/dev/null 2>&1)
|
||||||
|
|
||||||
|
if [[ $? -ne 0 ]]; then
|
||||||
|
echo "Please sign up for a free ngrok account and then run valet set-ngrok-token {yourTokenHere}."
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
# Decide the correct PORT: uses 60 for secure, else 80
|
# Decide the correct PORT: uses 60 for secure, else 80
|
||||||
if grep --quiet --no-messages 443 ~/.config/valet/Nginx/$HOST*
|
if [[ $SECURED -eq 0 ]]; then
|
||||||
then
|
|
||||||
PORT=60
|
PORT=60
|
||||||
else
|
else
|
||||||
PORT=80
|
PORT=80
|
||||||
fi
|
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
|
sudo -u "$USER" "$BREW_PREFIX/bin/ngrok" http "$HOST.$TLD:$PORT" --host-header=rewrite $PARAMS
|
||||||
|
|
||||||
exit
|
exit
|
||||||
@@ -102,48 +103,34 @@ then
|
|||||||
then
|
then
|
||||||
|
|
||||||
# expose
|
# 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
|
# Decide the correct PORT: uses 443 for secure, else 80
|
||||||
if grep --quiet --no-messages 443 ~/.config/valet/Nginx/$HOST*
|
if [[ $SECURED -eq 0 ]]; then
|
||||||
then
|
|
||||||
PORT=443
|
PORT=443
|
||||||
else
|
else
|
||||||
PORT=80
|
PORT=80
|
||||||
fi
|
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
|
sudo -u "$USER" expose share "$HOST.$TLD:$PORT" $PARAMS
|
||||||
|
|
||||||
exit
|
exit
|
||||||
|
|
||||||
|
elif [[ $SHARETOOL = "cloudflared" ]]
|
||||||
|
then
|
||||||
|
# cloudflared
|
||||||
|
if [[ $SECURED -eq 0 ]]; 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
|
else
|
||||||
echo ''
|
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."
|
echo "to set your preferred share tool."
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user