mirror of
https://github.com/bitinflow/expose.git
synced 2026-03-13 13:35:54 +00:00
wip
This commit is contained in:
98
app/Server/Http/Controllers/ControlMessageController.php
Normal file
98
app/Server/Http/Controllers/ControlMessageController.php
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace App\Server\Http\Controllers;
|
||||
|
||||
use App\Contracts\ConnectionManager;
|
||||
use stdClass;
|
||||
use Ratchet\ConnectionInterface;
|
||||
use Ratchet\MessageComponentInterface;
|
||||
|
||||
class ControlMessageController implements MessageComponentInterface
|
||||
{
|
||||
|
||||
/** @var ConnectionManager */
|
||||
protected $connectionManager;
|
||||
|
||||
public function __construct(ConnectionManager $connectionManager)
|
||||
{
|
||||
$this->connectionManager = $connectionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
function onClose(ConnectionInterface $connection)
|
||||
{
|
||||
if (isset($connection->request_id)) {
|
||||
$httpConnection = $this->connectionManager->getHttpConnectionForRequestId($connection->request_id);
|
||||
$httpConnection->close();
|
||||
}
|
||||
|
||||
$this->connectionManager->removeControlConnection($connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
function onMessage(ConnectionInterface $connection, $msg)
|
||||
{
|
||||
if (isset($connection->request_id)) {
|
||||
return $this->sendRequestToHttpConnection($connection->request_id, $msg);
|
||||
}
|
||||
|
||||
try {
|
||||
$payload = json_decode($msg);
|
||||
$eventName = $payload->event;
|
||||
|
||||
if (method_exists($this, $eventName)) {
|
||||
return call_user_func([$this, $eventName], $connection, $payload->data ?? new stdClass());
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
protected function sendRequestToHttpConnection(string $requestId, $request)
|
||||
{
|
||||
$httpConnection = $this->connectionManager->getHttpConnectionForRequestId($requestId);
|
||||
$httpConnection->send($request);
|
||||
}
|
||||
|
||||
protected function authenticate(ConnectionInterface $connection, $data)
|
||||
{
|
||||
$connectionInfo = $this->connectionManager->storeConnection($data->host, $data->subdomain, $connection);
|
||||
|
||||
$connection->send(json_encode([
|
||||
'event' => 'authenticated',
|
||||
'subdomain' => $connectionInfo->subdomain,
|
||||
'client_id' => $connectionInfo->client_id
|
||||
]));
|
||||
}
|
||||
|
||||
protected function registerProxy(ConnectionInterface $connection, $data)
|
||||
{
|
||||
$connection->request_id = $data->request_id;
|
||||
|
||||
$connectionInfo = $this->connectionManager->findControlConnectionForClientId($data->client_id);
|
||||
|
||||
$connectionInfo->emit('proxy_ready_' . $data->request_id, [
|
||||
$connection,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
function onOpen(ConnectionInterface $conn)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
function onError(ConnectionInterface $conn, \Exception $e)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
91
app/Server/Http/Controllers/TunnelMessageController.php
Normal file
91
app/Server/Http/Controllers/TunnelMessageController.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace App\Server\Http\Controllers;
|
||||
|
||||
use App\Contracts\ConnectionManager;
|
||||
use App\HttpServer\Controllers\PostController;
|
||||
use App\Server\Configuration;
|
||||
use App\Server\Connections\ControlConnection;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Pipeline\Pipeline;
|
||||
use Nyholm\Psr7\Factory\Psr17Factory;
|
||||
use Ratchet\ConnectionInterface;
|
||||
use Ratchet\RFC6455\Messaging\Frame;
|
||||
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
|
||||
use function GuzzleHttp\Psr7\str;
|
||||
|
||||
class TunnelMessageController extends PostController
|
||||
{
|
||||
/** @var ConnectionManager */
|
||||
protected $connectionManager;
|
||||
|
||||
/** @var Configuration */
|
||||
private $configuration;
|
||||
|
||||
protected $keepConnectionOpen = true;
|
||||
|
||||
protected $middleware = [
|
||||
|
||||
];
|
||||
|
||||
public function __construct(ConnectionManager $connectionManager, Configuration $configuration)
|
||||
{
|
||||
$this->connectionManager = $connectionManager;
|
||||
$this->configuration = $configuration;
|
||||
}
|
||||
|
||||
public function handle(Request $request, ConnectionInterface $httpConnection)
|
||||
{
|
||||
$controlConnection = $this->connectionManager->findControlConnectionForSubdomain($this->detectSubdomain($request));
|
||||
|
||||
if (is_null($controlConnection)) {
|
||||
$httpConnection->send(str(new Response(404, [], 'Not found')));
|
||||
$httpConnection->close();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->sendRequestToClient($request, $controlConnection, $httpConnection);
|
||||
}
|
||||
|
||||
protected function detectSubdomain(Request $request): ?string
|
||||
{
|
||||
$domainParts = explode('.', $request->getHost());
|
||||
|
||||
return trim($domainParts[0]);
|
||||
}
|
||||
|
||||
protected function sendRequestToClient(Request $request, ControlConnection $controlConnection, ConnectionInterface $httpConnection)
|
||||
{
|
||||
(new Pipeline(app()))
|
||||
->send($this->prepareRequest($request, $controlConnection))
|
||||
->through($this->middleware)
|
||||
->then(function ($request) use ($controlConnection, $httpConnection) {
|
||||
$requestId = $request->header('X-Expose-Request-ID');
|
||||
|
||||
$this->connectionManager->storeHttpConnection($httpConnection, $requestId);
|
||||
|
||||
$controlConnection->once('proxy_ready_' . $requestId, function (ConnectionInterface $proxy) use ($request) {
|
||||
// Convert the Laravel request into a PSR7 request
|
||||
$psr17Factory = new Psr17Factory();
|
||||
$psrHttpFactory = new PsrHttpFactory($psr17Factory, $psr17Factory, $psr17Factory, $psr17Factory);
|
||||
$request = $psrHttpFactory->createRequest($request);
|
||||
|
||||
$binaryMsg = new Frame(str($request), true, Frame::OP_BINARY);
|
||||
$proxy->send($binaryMsg);
|
||||
});
|
||||
|
||||
$controlConnection->registerProxy($requestId);
|
||||
});
|
||||
}
|
||||
|
||||
protected function prepareRequest(Request $request, ControlConnection $controlConnection): Request
|
||||
{
|
||||
$request->headers->set('Host', $controlConnection->host);
|
||||
$request->headers->set('X-Expose-Request-ID', uniqid());
|
||||
$request->headers->set('X-Exposed-By', config('app.name') . ' '. config('app.version'));
|
||||
$request->headers->set('X-Original-Host', "{$controlConnection->subdomain}.{$this->configuration->hostname()}:{$this->configuration->port()}");
|
||||
|
||||
return $request;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user