This commit is contained in:
Marcel Pociot
2020-04-25 11:42:40 +02:00
parent c89f6b38ea
commit 28c4009dff
16 changed files with 81 additions and 74 deletions

1
.gitignore vendored
View File

@@ -6,3 +6,4 @@
.phpunit.result.cache
expose.php
database/expose.db
.expose.php

View File

@@ -41,7 +41,9 @@ class Client
{
$token = config('expose.auth_token');
connect("ws://{$this->configuration->host()}:{$this->configuration->port()}/__expose_control__?authToken={$token}", [], [
$protocol = $this->configuration->port() === 443 ? "wss" : "ws";
connect($protocol."://{$this->configuration->host()}:{$this->configuration->port()}/__expose_control__?authToken={$token}", [], [
'X-Expose-Control' => 'enabled',
], $this->loop)
->then(function (WebSocket $clientConnection) use ($sharedUrl, $subdomain) {
@@ -65,8 +67,10 @@ class Client
static::$subdomains[] = "$data->subdomain.{$this->configuration->host()}:{$this->configuration->port()}";
});
}, function ($e) {
echo "Could not connect: {$e->getMessage()}\n";
}, function (\Exception $e) {
$this->logger->error("Could not connect to the server.");
$this->logger->error($e->getMessage());
exit(1);
});
}
}

View File

@@ -34,6 +34,6 @@ class Configuration
public function port(): int
{
return $this->port;
return intval($this->port);
}
}

View File

@@ -24,7 +24,9 @@ class ProxyManager
public function createProxy(string $clientId, $connectionData)
{
connect("ws://{$this->configuration->host()}:{$this->configuration->port()}/__expose_control__", [], [
$protocol = $this->configuration->port() === 443 ? "wss" : "ws";
connect($protocol."://{$this->configuration->host()}:{$this->configuration->port()}/__expose_control__", [], [
'X-Expose-Control' => 'enabled',
], $this->loop)
->then(function (WebSocket $proxyConnection) use ($clientId, $connectionData) {

View File

@@ -30,8 +30,8 @@ class ShareCommand extends Command
(new Factory())
->setLoop(app(LoopInterface::class))
// ->setHost('beyond.sh') // TODO: Read from (local/global) config file
// ->setPort(8080) // TODO: Read from (local/global) config file
->setHost(config('expose.host', 'localhost'))
->setPort(config('expose.port', 8080))
->setAuth($this->option('auth'))
->createClient($this->argument('host'), explode(',', $this->option('subdomain')))
->createHttpServer()

View File

@@ -12,6 +12,8 @@ class ShareCurrentWorkingDirectoryCommand extends ShareCommand
{
$this->input->setArgument('host', basename(getcwd()).'.test');
$this->input->setOption('subdomain', basename(getcwd()));
parent::handle();
}
}

View File

@@ -5,6 +5,9 @@ namespace App\HttpServer\Controllers;
use Exception;
use Ratchet\ConnectionInterface;
use Ratchet\Http\HttpServerInterface;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
use function GuzzleHttp\Psr7\stream_for;
abstract class Controller implements HttpServerInterface
{
@@ -22,4 +25,17 @@ abstract class Controller implements HttpServerInterface
public function onMessage(ConnectionInterface $from, $msg)
{
}
protected function getView(string $view, array $data)
{
$templatePath = implode(DIRECTORY_SEPARATOR, explode('.', $view));
$twig = new Environment(
new ArrayLoader([
'template' => file_get_contents(base_path('resources/views/'.$templatePath.'.twig')),
])
);
return stream_for($twig->render('template', $data));
}
}

View File

@@ -16,19 +16,12 @@ class DashboardController extends Controller
str(new Response(
200,
['Content-Type' => 'text/html'],
$this->getView()
$this->getView('client.dashboard', [
'subdomains' => Client::$subdomains,
])
))
);
$connection->close();
}
protected function getView(): string
{
$view = file_get_contents(base_path('resources/views/index.html'));
$view = str_replace('%subdomains%', implode(' ', Client::$subdomains), $view);
return $view;
}
}

View File

@@ -31,6 +31,14 @@ class AppServiceProvider extends ServiceProvider
protected function loadConfigurationFile()
{
$localConfigFile = getcwd() . DIRECTORY_SEPARATOR . '.expose.php';
if (file_exists($localConfigFile)) {
config()->set('expose', require_once $localConfigFile);
return;
}
$configFile = implode(DIRECTORY_SEPARATOR, [
$_SERVER['HOME'],
'.expose',
@@ -39,12 +47,6 @@ class AppServiceProvider extends ServiceProvider
if (file_exists($configFile)) {
config()->set('expose', require_once $configFile);
return;
}
$localConfigFile = getcwd() . DIRECTORY_SEPARATOR . '.expose.php';
if (file_exists($localConfigFile)) {
config()->set('expose', require_once $localConfigFile);
}
}
}

View File

@@ -80,9 +80,12 @@ class Factory
protected function addExposeRoutes()
{
$wsServer = new WsServer(app(ControlMessageController::class));
$wsServer->enableKeepAlive($this->loop);
$this->routes->add('control',
new Route('/__expose_control__', [
'_controller' => new WsServer(app(ControlMessageController::class))
'_controller' => $wsServer
], [], [], null, [], []
)
);

View File

@@ -27,18 +27,7 @@ class ListSitesController extends PostController
public function handle(Request $request, ConnectionInterface $httpConnection)
{
$httpConnection->send(
respond_html($this->getView(['sites' => $this->connectionManager->getConnections()]))
respond_html($this->getView('server.sites.index', ['sites' => $this->connectionManager->getConnections()]))
);
}
protected function getView(array $data)
{
$twig = new Environment(
new ArrayLoader([
'template' => file_get_contents(base_path('resources/views/admin/sites/index.twig')),
])
);
return stream_for($twig->render('template', $data));
}
}

View File

@@ -29,7 +29,7 @@ class ListUsersController extends PostController
{
$this->database->query('SELECT * FROM users ORDER by created_at DESC')->then(function (Result $result) use ($httpConnection) {
$httpConnection->send(
respond_html($this->getView(['users' => $result->rows]))
respond_html($this->getView('server.users.index', ['users' => $result->rows]))
);
$httpConnection->close();
@@ -39,15 +39,4 @@ class ListUsersController extends PostController
$httpConnection->close();
});
}
protected function getView(array $data)
{
$twig = new Environment(
new ArrayLoader([
'template' => file_get_contents(base_path('resources/views/admin/users/index.twig')),
])
);
return stream_for($twig->render('template', $data));
}
}

View File

@@ -3,11 +3,6 @@
use GuzzleHttp\Psr7\Response;
use function GuzzleHttp\Psr7\str;
function expose_view_path(string $path = '')
{
return base_path('resources/views/' . $path);
}
function respond_json($responseData, int $statusCode = 200)
{
return str(new Response(

View File

@@ -91,8 +91,11 @@
<div class="max-w-screen-xl mx-auto py-3 px-3 sm:px-6 lg:px-8">
<div class="pr-16 sm:text-center sm:px-16">
<p class="font-medium text-white flex justify-center">
<span class="inline-block">Waiting for requests on: <a class="underline" target="_blank"
href="%subdomains%">%subdomains%</a></span>
<span class="inline-block">Waiting for requests on:
{% for subdomain in subdomains %}
<a class="underline" target="_blank" href="http://{{ subdomain }}">{{ subdomain }}</a>
{% endfor %}
</span>
</p>
</div>
</div>
@@ -135,14 +138,14 @@
@click="setLog(log)">
<td class="cursor.pointer px-6 py-4 whitespace-no-wrap border-b border-gray-200 text-sm leading-5 font-medium text-gray-900">
<p>
{{ log.request.method }}
{{ log.request.uri }}
@{ log.request.method }
@{ log.request.uri }
</p>
<span class="text-xs">{{ log.subdomain }}</span>
<span class="text-xs">@{ log.subdomain }</span>
</td>
<td class="cursor.pointer px-6 py-4 whitespace-no-wrap border-b border-gray-200 text-sm leading-5 text-gray-500">
<div v-if="log.response">
{{ log.response.status }} - {{ log.response.reason }}
@{ log.response.status } - @{ log.response.reason }
</div>
<div v-else>
...
@@ -150,7 +153,7 @@
</td>
<td class="cursor.pointer px-6 py-4 whitespace-no-wrap border-b border-gray-200 text-sm leading-5 text-gray-500">
<div v-if="log.response">
{{ log.duration }}ms
@{ log.duration }ms
</div>
</td>
</tr>
@@ -163,7 +166,7 @@
<div v-if="currentLog" class="bg-white shadow overflow-hidden sm:rounded-lg">
<div class="px-4 py-5 border-b border-gray-200 sm:px-6">
<h3 class="text-lg leading-6 font-medium text-gray-900 flex">
{{ currentLog.request.method }} {{ currentLog.request.uri }}
@{ currentLog.request.method } @{ currentLog.request.uri }
<div class="flex-grow"></div>
<span class="inline-flex rounded-md shadow-sm">
<button @click.prevent="replay(currentLog)"
@@ -182,7 +185,7 @@
</span>
</h3>
<p class="mt-1 max-w-2xl text-sm leading-5 text-gray-500">
Status code: {{ currentLog.response?.status}}
Status code: @{ currentLog.response?.status}
</p>
</div>
<div>
@@ -223,10 +226,10 @@
:key="'query_' + name"
class="even:bg-gray-50 odd:bg-gray-50 px-4 py-3 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
<dt class="text-sm leading-5 font-medium text-gray-500">
{{ name }}
@{ name }
</dt>
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
{{ value }}
@{ value }
</dd>
</div>
@@ -239,12 +242,12 @@
:key="'post_' + name"
class="even:bg-gray-50 odd:bg-gray-50 px-4 py-3 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
<dt class="text-sm leading-5 font-medium text-gray-500">
{{ parameter.name }}
@{ parameter.name }
</dt>
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
<span
v-if="parameter.is_file">File: {{ parameter.filename }} ({{ parameter.mime_type }})</span>
<span v-else>{{ parameter.value }}</span>
v-if="parameter.is_file">File: @{ parameter.filename } (@{ parameter.mime_type })</span>
<span v-else>@{ parameter.value }</span>
</dd>
</div>
@@ -257,15 +260,15 @@
:key="header"
class="even:bg-gray-50 odd:bg-gray-50 px-4 py-3 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
<dt class="text-sm leading-5 font-medium text-gray-500">
{{ header }}
@{ header }
</dt>
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
{{ value }}
@{ value }
</dd>
</div>
<div>
<pre class="p-6 prettyprint">{{ currentLog.request.body }}</pre>
<pre class="p-6 prettyprint">@{ currentLog.request.body }</pre>
</div>
</div>
@@ -279,10 +282,10 @@
:key="header"
class="even:bg-gray-50 odd:bg-gray-50 px-4 py-3 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
<dt class="text-sm leading-5 font-medium text-gray-500">
{{ header }}
@{ header }
</dt>
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
{{ value }}
@{ value }
</dd>
</div>
<div v-if="currentLog.request.additional_data.length !== 0">
@@ -295,7 +298,7 @@
:key="'debug'+key"
class="even:bg-gray-50 odd:bg-gray-50 px-4 py-3 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
<dt class="text-sm leading-5 font-medium text-gray-500">
{{ key }}
@{ key }
</dt>
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
<div v-html="value">
@@ -327,13 +330,18 @@
</div>
</div>
<div v-if="activeTab === 'raw'">
<pre class="p-6 text-sm">{{ currentLog.response.body }}</pre>
<pre class="p-6 text-sm">@{ currentLog.response.body }</pre>
</div>
<div v-if="activeTab === 'preview'">
<iframe :srcdoc="currentLog.response.body" style="height: 500px;" class="w-full h-full"></iframe>
</div>
</div>
</div>
<div v-else class="flex-col bg-white shadow overflow-hidden sm:rounded-lg justify-center items-center flex py-4">
<h1 class="text-lg">Waiting for connections...</h1>
<img src="https://chart.googleapis.com/chart?chs=500x500&cht=qr&chl=http://{{ subdomains[0] | url_encode }}&choe=UTF-8" />
<a class="text-sm" href="http://{{ subdomains[0] }}" target="_blank">http://{{ subdomains[0] }}</a>
</div>
</div>
</div>
</div>
@@ -342,6 +350,8 @@
new Vue({
el: '#app',
delimiters: ['@{', '}'],
data: {
search: '',
currentLog: null,
@@ -367,6 +377,7 @@
},
clearLogs: function() {
fetch('/logs/clear');
this.currentLog = null;
},
setLog: function (log) {
this.currentLog = log;