Skip to content

Commit db085bd

Browse files
committed
feat: add new Share class to setup the supported share tools and communicate with the share tool classes.
Added: - Add new `Share` class which holds various methods to set and get the share tools (eg. ngrok), and create the share tool class instance to be able to chain their methods. - Add new `ShareTool` abstract class in the new `ShareTools` directory, with the namespace `Valet\ShareTools`. It acts as the base/parent class that all other share tool classes will extend. It declares abstract methods that requires the child classes to implement, like `start`, `run`, and `getConfig`. The class also holds shared methods like `currentTunnelUrl` and `findHttpTunnelUrl` that don't need to be implemented by the child classes because the code doesn't need to be changed. - Add the new `Share` class to the facades.php. Changed: - Move `Ngrok` class into the `ShareTools` directory, and changing it's namespace and it extends the new `ShareTool` class. - Move the `currentTunnelUrl` and `findHttpTunnelUrl` methods from Ngrok to the parent `ShareTool` class. - Change `getNgrokConfig` method name to the new `getConfig`. Also change all references to the method. - Change the `Facade` class to check if the class called is `Ngrok`, and append the `ShareTools` string to the default `Valet` namespace to create the ShareTools namespace. This is so that we can call Ngrok methods statically in the main valet.php file. Like `Ngrok::run` for the `ngrok` command.
1 parent e5530aa commit db085bd

File tree

4 files changed

+297
-97
lines changed

4 files changed

+297
-97
lines changed

cli/Valet/Share.php

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?php
2+
3+
namespace Valet;
4+
5+
use DomainException;
6+
use GuzzleHttp\Client;
7+
8+
class Share {
9+
/**
10+
* @var CommandLine
11+
*/
12+
protected $cli;
13+
14+
/**
15+
* @var Configuration
16+
*/
17+
protected $config;
18+
19+
/**
20+
* @var Filesystem
21+
*/
22+
protected $files;
23+
24+
/**
25+
* The supported share tools.
26+
* @var string[]
27+
*/
28+
protected $share_tools;
29+
30+
/**
31+
* @var object
32+
*/
33+
protected $current_tool_instance;
34+
35+
36+
/**
37+
* Create a new Nginx instance.
38+
*
39+
* @param CommandLine $cli
40+
* @param Configuration $config
41+
* @return void
42+
*/
43+
public function __construct(CommandLine $cli, Configuration $config, Filesystem $files) {
44+
$this->cli = $cli;
45+
$this->config = $config;
46+
$this->files = $files;
47+
48+
/**
49+
* Define the supported share tools.
50+
*/
51+
$this->share_tools = [
52+
"ngrok"
53+
];
54+
}
55+
56+
/**
57+
* Main method to use which returns the share tool's class instance
58+
* to be able to access the methods in a chainable way.
59+
*
60+
* @return object
61+
*/
62+
public function shareTool() {
63+
$this->createShareToolInstance();
64+
65+
return $this->getShareToolInstance();
66+
}
67+
68+
/**
69+
* Create the share tool class namespace using the current tool
70+
* and create the child class instance.
71+
*
72+
* @return void
73+
*/
74+
private function createShareToolInstance() {
75+
$tool = $this->getCurrentShareTool();
76+
if ($tool && !isset($this->current_tool_instance)) {
77+
// Construct the share tool's class namespace.
78+
$tool_class = "Valet\\ShareTools\\$tool";
79+
80+
// Create the share tool's child class instance via a dynamic class namespace.
81+
$this->current_tool_instance = new $tool_class($this->cli, $this->files);
82+
}
83+
}
84+
85+
/**
86+
* Get the share tool child class instance.
87+
* @return object
88+
*/
89+
public function getShareToolInstance() {
90+
return $this->current_tool_instance;
91+
}
92+
93+
/**
94+
* Get the share tools as a string.
95+
*
96+
* @return string
97+
*/
98+
public function getShareTools() {
99+
return preg_replace('/,\s([^,]+)$/',
100+
' or $1',
101+
implode(', ', array_map(fn ($t) => "`$t`", $this->share_tools))
102+
);
103+
}
104+
105+
/**
106+
* Check if the specified tool is valid.
107+
*
108+
* @param string $tool
109+
* @return bool
110+
*/
111+
public function isToolValid($tool) {
112+
return (in_array($tool, $this->share_tools) && class_exists($tool));
113+
}
114+
115+
/**
116+
* Get the current share tool from the config.
117+
*
118+
* @return string|null
119+
*/
120+
public function getCurrentShareTool() {
121+
return $this->config->get("share-tool") ?? null;
122+
}
123+
}

cli/Valet/Ngrok.php renamed to cli/Valet/ShareTools/Ngrok.php

Lines changed: 38 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,25 @@
11
<?php
22

3-
namespace Valet;
3+
namespace Valet\ShareTools;
44

5-
use DomainException;
6-
use GuzzleHttp\Client;
7-
use Illuminate\Support\Collection;
5+
use Valet\Valet;
86
use Symfony\Component\Yaml\Yaml;
97

10-
class Ngrok {
11-
/**
12-
* @var CommandLine
13-
*/
14-
protected $cli;
15-
16-
/**
17-
* @var array
18-
*/
19-
protected $tunnelsEndpoints = [
20-
'http://127.0.0.1:4040/api/tunnels',
21-
'http://127.0.0.1:4041/api/tunnels'
22-
];
8+
use function Valet\output;
9+
use function Valet\info;
10+
use function Valet\info_dump;
11+
use function Valet\error;
12+
use function Valet\valetBinPath;
13+
use function Valet\prefixOptions;
2314

15+
class Ngrok extends ShareTool {
2416
/**
25-
* Create a new Nginx instance.
17+
* Start sharing with ngrok.
2618
*
27-
* @param CommandLine $cli
28-
* @return void
29-
*/
30-
public function __construct(CommandLine $cli) {
31-
$this->cli = $cli;
32-
}
33-
34-
/**
35-
* @param string $command
36-
* @return void
37-
*/
38-
public function run(string $command) {
39-
$ngrok = realpath(valetBinPath() . 'ngrok.exe');
40-
41-
if (trim($command) === "update") {
42-
$command = "$command " . $this->getNgrokConfig();
43-
}
44-
if (trim($command) === "config upgrade") {
45-
$command = "$command " . $this->getNgrokConfig();
46-
}
47-
48-
$this->cli->passthru("\"$ngrok\" $command");
49-
}
50-
51-
/**
5219
* @param string $site The site
5320
* @param int $port The site's port
5421
* @param array $options Options/flags to pass to ngrok
22+
*
5523
* @return void
5624
*/
5725
public function start(string $site, int $port, array $options = []) {
@@ -72,7 +40,7 @@ public function start(string $site, int $port, array $options = []) {
7240

7341
$ngrok = realpath(valetBinPath() . 'ngrok.exe');
7442

75-
$ngrokCommand = "\"$ngrok\" http $site:$port " . $this->getNgrokConfig() . " $options";
43+
$ngrokCommand = "\"$ngrok\" http $site:$port " . $this->getConfig() . " $options";
7644

7745
info("Sharing $site...\n");
7846
info("To output the public URL, please open a new terminal and run `valet fetch-share-url $site`");
@@ -88,6 +56,29 @@ public function start(string $site, int $port, array $options = []) {
8856
}
8957
}
9058

59+
/**
60+
* Run ngrok CLI commands.
61+
*
62+
* @param string $command
63+
*
64+
* @return void
65+
*/
66+
public function run(string $command) {
67+
$ngrok = realpath(valetBinPath() . 'ngrok.exe');
68+
69+
// If command is `update` then append the config flag.
70+
if (trim($command) === "update") {
71+
$command = "$command " . $this->getConfig();
72+
}
73+
74+
// If command is `config upgrade` then append the config flag.
75+
if (trim($command) === "config upgrade") {
76+
$command = "$command " . $this->getConfig();
77+
}
78+
79+
$this->cli->passthru("\"$ngrok\" $command");
80+
}
81+
9182
/**
9283
* Get the ngrok configuration path
9384
*
@@ -102,72 +93,24 @@ public function start(string $site, int $port, array $options = []) {
10293
*
10394
* `C:/Users/Username/.config/valet/Ngrok/ngrok.yml`
10495
*/
105-
public function getNgrokConfig(bool $asCliFlag = true) {
96+
public function getConfig(bool $asCliFlag = true) {
10697
$configPath = Valet::homePath() . "/Ngrok/ngrok.yml";
10798
if ($asCliFlag) {
10899
return "--config $configPath";
109100
}
110101
return $configPath;
111102
}
112103

113-
/**
114-
* Get the current tunnel URL from the ngrok API.
115-
* @param string $site The site
116-
*
117-
* @return string $url The current tunnel URL
118-
*/
119-
public function currentTunnelUrl(string $site) {
120-
// Set a new GuzzleHttp client.
121-
$client = new Client();
122-
123-
// Create a GuzzleHttp get request to the ngrok tunnels API.
124-
$response = $client->get('http://127.0.0.1:4040/api/tunnels');
125-
126-
// Get the contents of the API response.
127-
$response = $response->getBody()->getContents();
128-
// Decode the json response into a properly formed PHP array.
129-
$tunnels = json_decode($response, true);
130-
131-
// Find and get the public URL of the site.
132-
$url = $this->findHttpTunnelUrl($tunnels["tunnels"], $site);
133-
134-
if (!empty($url)) {
135-
// Use | clip to copy the URL to the clipboard.
136-
$this->cli->passthru("echo $url | clip");
137-
return $url;
138-
}
139-
140-
throw new DomainException('Tunnel not established.');
141-
}
142-
143-
/**
144-
* Find the HTTP tunnel URL from the list of tunnels.
145-
*
146-
* @param array $tunnels
147-
* @return string|null
148-
* @return void|string
149-
*/
150-
public function findHttpTunnelUrl(array $tunnels, ?string $site = null) {
151-
// If there are active tunnels on the ngrok instance we will spin through them and
152-
// find the one responding on HTTP. Each tunnel has an HTTP and a HTTPS address
153-
// but for local dev purposes we just desire the plain HTTP URL endpoint.
154-
foreach ($tunnels as $tunnel) {
155-
if (($tunnel["proto"] === 'http' || $tunnel["proto"] === 'https') && strpos($tunnel["config"]["addr"], $site)) {
156-
return $tunnel["public_url"];
157-
}
158-
}
159-
}
160-
161104
/**
162105
* Check if ngrok config exists and the authtoken is set.
163106
*
164107
* @return bool
165108
*/
166109
protected function hasAuthToken(): bool {
167110
// If the config file exists...
168-
if (file_exists($this->getNgrokConfig(false))) {
111+
if (file_exists($this->getConfig(false))) {
169112
// Read and parse the config yml file and convert to an associative array.
170-
$config = Yaml::parseFile($this->getNgrokConfig(false));
113+
$config = Yaml::parseFile($this->getConfig(false));
171114

172115
// If config version is 2...
173116
if ($config["version"] === "2") {

0 commit comments

Comments
 (0)