Skip to content

Commit

Permalink
Merge pull request #123: Add ability to process HTTP events and UI on…
Browse files Browse the repository at this point in the history
… the same port
  • Loading branch information
roxblnfk committed Jun 20, 2024
2 parents 02e283e + 35dc4cf commit bb2bbc2
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 39 deletions.
13 changes: 3 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ And that's it. Trap is [ready to go](#usage).
Buggregator Trap provides a toolkit for use in your code. Firstly, just having Buggregator Trap in your
package enhances the capabilities of Symfony Var-Dumper.

If you've already worked with google/protobuf, you probably know how unpleasant it can be.
If you've already worked with `google/protobuf`, you probably know how unpleasant it can be.
Now let's compare the dumps of protobuf-message: on the left (with trap) and on the right (without trap).

![trap-proto-diff](https://github.com/buggregator/trap/assets/4152481/30662429-809e-422a-83c6-61d7d2788b18)
Expand Down Expand Up @@ -171,18 +171,11 @@ function handle($input) {

Trap automatically recognizes the type of traffic.
Therefore, there is no need to open separate ports for different protocols.
By default, it operates on port `9912`.
By default, it operates on the same ports as the Buggregator Server: `9912`, `9913`, `1025`, and `8000`.
However, if you wish to utilize a different port, you can easily make this adjustment using the `-p` option:

```bash
vendor/bin/trap -p8000
```

Sometimes, it's convenient to run Trap on the same ports that [Buggregator](https://github.com/buggregator/server)
uses by default. Well, that's also possible:

```bash
vendor/bin/trap -p1025 -p9912 -p9913 -p8000 --ui=8080
vendor/bin/trap -p9912 --ui=8000
```

Environment variables can also be used to set endpoints:
Expand Down
5 changes: 5 additions & 0 deletions psalm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
<issueHandlers>
<RedundantConditionGivenDocblockType errorLevel="suppress"/>
<RedundantCastGivenDocblockType errorLevel="suppress"/>
<PropertyNotSetInConstructor errorLevel="suppress">
<errorLevel type="suppress">
<directory name="src/Command"/>
</errorLevel>
</PropertyNotSetInConstructor>
</issueHandlers>
<projectFiles>
<directory name="src"/>
Expand Down
62 changes: 46 additions & 16 deletions src/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,16 @@ public function __construct(
$this->buffer = new Buffer(bufferSize: 10485760, timer: 0.1);
$this->container->set($this->buffer);

$inspector = $container->make(Inspector::class, [
// Frontend
$feConfig = $this->container->get(FrontendConfig::class);
$feSeparated = !\in_array(
$feConfig->port,
\array_map(static fn(SocketServer $item): ?int => $item->type === 'tcp' ? $item->port : null, $map, ),
true,
);
$withFrontend and $this->configureFrontend($feSeparated);

$inspectorWithFrontend = $inspector = $container->make(Inspector::class, [
// new Traffic\Dispatcher\WebSocket(),
new Traffic\Dispatcher\VarDumper(),
new Traffic\Dispatcher\Http(
Expand All @@ -71,11 +80,33 @@ public function __construct(
]);
$this->processors[] = $inspector;

$withFrontend and $this->configureFrontend(8000);

if ($withFrontend && !$feSeparated) {
$inspectorWithFrontend = $container->make(Inspector::class, [
new Traffic\Dispatcher\VarDumper(),
new Traffic\Dispatcher\Http(
[
$this->container->get(Sender\Frontend\Http\Pipeline::class),
$this->container->get(Middleware\Resources::class),
$this->container->get(Middleware\DebugPage::class),
$this->container->get(Middleware\RayRequestDump::class),
$this->container->get(Middleware\SentryTrap::class),
$this->container->get(Middleware\XHProfTrap::class),
],
[$this->container->get(Sender\Frontend\Http\RequestHandler::class)],
),
new Traffic\Dispatcher\Smtp(),
new Traffic\Dispatcher\Monolog(),
]);
$this->processors[] = $inspectorWithFrontend;
}

$this->configureFileObserver();

foreach ($map as $config) {
$this->prepareServerFiber($config, $inspector, $this->logger);
$withFrontend && !$feSeparated && $config->type === 'tcp' && $config->port === $feConfig->port
? $this->prepareServerFiber($config, $inspectorWithFrontend, $this->logger)
: $this->prepareServerFiber($config, $inspector, $this->logger);
}
}

Expand Down Expand Up @@ -175,27 +206,26 @@ public function prepareServerFiber(SocketServer $config, Inspector $inspector, L
});
}

/**
* @param int<1, 65535> $port
*/
public function configureFrontend(int $port): void
public function configureFrontend(bool $separated): void
{
$this->senders[] = $wsSender = Sender\FrontendSender::create($this->logger);
$this->processors[] = $this->senders[] = $wsSender = Sender\FrontendSender::create($this->logger);
$this->container->set($wsSender);
$this->container->set($wsSender->getEventStorage());
$this->container->set($wsSender->getConnectionPool());

if (!$separated) {
return;
}

// Separated port
$inspector = $this->container->make(Inspector::class, [
new Traffic\Dispatcher\Http(
[
new Sender\Frontend\Http\Cors(),
new Sender\Frontend\Http\StaticFiles(),
new Sender\Frontend\Http\EventAssets($this->logger, $wsSender->getEventStorage()),
new Sender\Frontend\Http\Router($this->logger, $wsSender->getEventStorage()),
],
[new Sender\Frontend\Http\RequestHandler($wsSender->getConnectionPool())],
[$this->container->get(Sender\Frontend\Http\Pipeline::class)],
[$this->container->get(Sender\Frontend\Http\RequestHandler::class)],
silentMode: true,
),
]);
$this->processors[] = $inspector;
$this->processors[] = $wsSender;
$config = $this->container->get(FrontendConfig::class);
$this->prepareServerFiber(new SocketServer(port: $config->port), $inspector, $this->logger);
}
Expand Down
20 changes: 8 additions & 12 deletions src/Command/Run.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ final class Run extends Command implements SignalableCommandInterface
{
private ?Application $app = null;

private Logger $logger;

private bool $cancelled = false;

public function configure(): void
Expand Down Expand Up @@ -61,7 +63,7 @@ public function getServers(Container $container): array
$config = $container->get(TcpPorts::class);

$servers = [];
$ports = $config->ports ?: [9912];
$ports = $config->ports ?: [1025, 8000, 9912, 9913];
/** @var scalar $port */
foreach ($ports as $port) {
\is_numeric($port) or throw new \InvalidArgumentException(
Expand Down Expand Up @@ -129,6 +131,7 @@ protected function execute(
InputInterface $input,
OutputInterface $output,
): int {
$this->logger = new Logger($output);
try {
// Print intro
$output->writeln(\sprintf('<fg=yellow;options=bold>%s</> <info>v%s</>', Info::NAME, Info::version()));
Expand All @@ -147,7 +150,7 @@ protected function execute(
)->finish();
$container->set($registry);
$container->set($input, InputInterface::class);
$container->set(new Logger($output));
$container->set($this->logger);
$this->app = $container->get(Application::class, [
'map' => $this->getServers($container),
'senders' => $registry->getSenders($senders),
Expand All @@ -157,16 +160,9 @@ protected function execute(

$this->app->run();
} catch (\Throwable $e) {
if ($output->isVerbose()) {
// Write colorful exception (title, message, stacktrace)
$output->writeln(\sprintf("<fg=red;options=bold>%s</>", $e::class));
}

$output->writeln(\sprintf("<fg=red>%s</>", $e->getMessage()));

if ($output->isDebug()) {
$output->writeln(\sprintf("<fg=gray>%s</>", $e->getTraceAsString()));
}
do {
$this->logger->exception($e);
} while ($e = $e->getPrevious());
}

return Command::SUCCESS;
Expand Down
7 changes: 7 additions & 0 deletions src/Handler/Http/Handler/Fallback.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Buggregator\Trap\Handler\Http\RequestHandler;
use Buggregator\Trap\Handler\Pipeline;
use Buggregator\Trap\Proto\Frame;
use Buggregator\Trap\Sender\Frontend\Http\Pipeline as FrontendPipeline;
use Buggregator\Trap\Traffic\StreamClient;
use Nyholm\Psr7\Response;
use Psr\Http\Message\ResponseInterface;
Expand Down Expand Up @@ -81,6 +82,12 @@ public function handle(StreamClient $streamClient, ServerRequestInterface $reque
$streamClient->disconnect();
}

/** @var mixed $response */
$response ??= null;
if ($response instanceof ResponseInterface && $response->hasHeader(FrontendPipeline::FRONTEND_HEADER)) {
return;
}

if (!$gotFrame) {
yield new Frame\Http(
$request,
Expand Down
57 changes: 57 additions & 0 deletions src/Sender/Frontend/Http/Pipeline.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

declare(strict_types=1);

namespace Buggregator\Trap\Sender\Frontend\Http;

use Buggregator\Trap\Handler\Http\Middleware;
use Buggregator\Trap\Handler\Pipeline as MiddlewaresPipeline;
use Buggregator\Trap\Info;
use Buggregator\Trap\Logger;
use Nyholm\Psr7\Response;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

/**
* Full Frontend HTTP pipeline as single middleware.
*
* @internal
* @psalm-internal Buggregator\Trap
*/
final class Pipeline implements Middleware
{
public const FRONTEND_HEADER = 'X-Trap-Frontend';

/** @var MiddlewaresPipeline<Middleware, ResponseInterface> */
private MiddlewaresPipeline $pipeline;

public function __construct(
Logger $logger,
\Buggregator\Trap\Sender\FrontendSender $wsSender,
) {
// Build pipeline of handlers.
/** @var MiddlewaresPipeline<Middleware, ResponseInterface> */
$this->pipeline = MiddlewaresPipeline::build(
[
new Cors(),
new StaticFiles(),
new EventAssets($logger, $wsSender->getEventStorage()),
new Router($logger, $wsSender->getEventStorage()),
],
/** @see Middleware::handle() */
'handle',
static fn(): ResponseInterface => new Response(404),
ResponseInterface::class,
);
}

public function handle(ServerRequestInterface $request, callable $next): ResponseInterface
{
/** @var ResponseInterface $response */
$response = ($this->pipeline)($request);

return $response->getStatusCode() === 404
? $next($request)
: $response->withHeader(self::FRONTEND_HEADER, Info::version());
}
}
2 changes: 1 addition & 1 deletion src/Service/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public function make(string $class, array $arguments = []): object
try {
$result = $this->injector->make($class, \array_merge((array) $binding, $arguments));
} catch (\Throwable $e) {
throw new class("Unable to create object of class $class.", previous: $e, ) extends \RuntimeException implements NotFoundExceptionInterface {};
throw new class("Unable to create object of class $class.", previous: $e) extends \RuntimeException implements NotFoundExceptionInterface {};
}
}

Expand Down

0 comments on commit bb2bbc2

Please sign in to comment.