Skip to content

Commit

Permalink
Update endpoints; use the same Service for Websockets and HTTP reques…
Browse files Browse the repository at this point in the history
…ts from the Frontend
  • Loading branch information
roxblnfk committed Dec 15, 2023
1 parent 966b704 commit 6aead78
Show file tree
Hide file tree
Showing 13 changed files with 182 additions and 63 deletions.
2 changes: 1 addition & 1 deletion src/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ public function configureFrontend(int $port): void
new Traffic\Dispatcher\Http(
[
new Sender\Frontend\Http\StaticFiles(),
new Sender\Frontend\Http\Events($wsSender->getEventStorage()),
new Sender\Frontend\Http\Router($this->logger, $wsSender->getEventStorage()),
new Sender\Frontend\Http\Version(),
],
[new Sender\Frontend\Http\RequestHandler($wsSender->getConnectionPool())],

Check failure on line 181 in src/Application.php

View workflow job for this annotation

GitHub Actions / Psalm Validation (PHP 8.2, OS ubuntu-latest)

InternalClass

src/Application.php:181:18: InternalClass: Buggregator\Trap\Sender\Frontend\Http\RequestHandler is internal to Buggregator\Trap * Read about Sec-WebSocket-Extensions: but called from Buggregator\Trap\Application (see https://psalm.dev/174)

Check failure on line 181 in src/Application.php

View workflow job for this annotation

GitHub Actions / Psalm Validation (PHP 8.2, OS ubuntu-latest)

InternalMethod

src/Application.php:181:18: InternalMethod: Constructor Buggregator\Trap\Sender\Frontend\Http\RequestHandler::__construct is internal to Buggregator\Trap * Read about Sec-WebSocket-Extensions: but called from Buggregator\Trap\Application::configureFrontend (see https://psalm.dev/175)
Expand Down
2 changes: 1 addition & 1 deletion src/Command/Run.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ protected function execute(
[new SocketServer($port)],
new Logger($output),
senders: $registry->getSenders($senders),
configureUI: $input->getOption('ui') !== false,
withFrontend: $input->getOption('ui') !== false,
);

$app->run();
Expand Down
7 changes: 6 additions & 1 deletion src/Sender/Frontend/EventsStorage.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Buggregator\Trap\Sender\Frontend;

use Buggregator\Trap\Proto\Frame;
use Buggregator\Trap\Sender\Frontend\Message\Event;
use IteratorAggregate;

/**
Expand Down Expand Up @@ -40,4 +40,9 @@ public function delete(string $key): void
{
unset($this->events[$key]);
}

public function get(string $uuid): ?Event
{
return $this->events[$uuid] ?? null;
}
}
1 change: 1 addition & 0 deletions src/Sender/Frontend/FrameMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Buggregator\Trap\Sender\Frontend;

use Buggregator\Trap\Proto\Frame;
use Buggregator\Trap\Sender\Frontend\Message\Event;
use IteratorAggregate;

/**
Expand Down
51 changes: 0 additions & 51 deletions src/Sender/Frontend/Http/Events.php

This file was deleted.

70 changes: 70 additions & 0 deletions src/Sender/Frontend/Http/Router.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?php

declare(strict_types=1);

namespace Buggregator\Trap\Sender\Frontend\Http;

use Buggregator\Trap\Handler\Http\Middleware;
use Buggregator\Trap\Handler\Router\Method;
use Buggregator\Trap\Handler\Router\Router as CommonRouter;
use Buggregator\Trap\Logger;
use Buggregator\Trap\Sender\Frontend\EventsStorage;
use Buggregator\Trap\Sender\Frontend\Service;
use Buggregator\Trap\Support\Json;
use Nyholm\Psr7\Response;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

/**
* @internal
* @psalm-internal Buggregator\Trap
*/
final class Router implements Middleware
{
private readonly CommonRouter $router;

public function __construct(
private readonly Logger $logger,
EventsStorage $eventsStorage,
) {
$service = new Service($logger, $eventsStorage);
$this->router = CommonRouter::new($service);
}

public function handle(ServerRequestInterface $request, callable $next): ResponseInterface
{
try {
$path = \trim($request->getUri()->getPath(), '/');
$method = $request->getMethod();

$handler = $this->router->match(Method::fromString($method), $path);

\trap($path, $method, $handler)->if(Method::fromString($method) === Method::Delete);
if ($handler === null) {
return new Response(404);
}

$message = $handler($request);

return new Response(
200,
[
'Content-Type' => 'application/json',
'Cache-Control' => 'no-cache',
],
Json::encode($message),
);
} catch (\Throwable $e) {
$this->logger->exception($e);

return new Response(
500,
[
'Content-Type' => 'application/json',
'Cache-Control' => 'no-cache',
],
Json::encode(['error' => $e->getMessage()]),
);
}
}
}
2 changes: 1 addition & 1 deletion src/Sender/Frontend/Mapper/VarDump.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace Buggregator\Trap\Sender\Frontend\Mapper;

use Buggregator\Trap\Proto\Frame\VarDumper;
use Buggregator\Trap\Sender\Frontend\Event;
use Buggregator\Trap\Sender\Frontend\Message\Event;
use Buggregator\Trap\Support\Uuid;
use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\Component\VarDumper\Cloner\Stub;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

declare(strict_types=1);

namespace Buggregator\Trap\Sender\Frontend;
namespace Buggregator\Trap\Sender\Frontend\Message;

final class Event
final class Event implements \JsonSerializable
{
/**
* @param non-empty-string $uuid
Expand All @@ -18,4 +18,15 @@ public function __construct(
public readonly ?string $projectId = null,
) {
}

public function jsonSerialize(): array
{
return [
'uuid' => $this->uuid,
'type' => $this->type,
'payload' => $this->payload,
'timestamp' => $this->timestamp,
'projectId' => $this->projectId,
];
}
}
26 changes: 26 additions & 0 deletions src/Sender/Frontend/Message/EventCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace Buggregator\Trap\Sender\Frontend\Message;

final class EventCollection implements \JsonSerializable
{
/**
* @param array<array-key, Event> $events
* @param array<array-key, mixed> $meta
*/
public function __construct(
public readonly array $events,
public readonly array $meta = [],
) {
}

public function jsonSerialize(): array
{
return [
'data' => $this->events,
'meta' => $this->meta + ['grid' => []],
];
}
}
26 changes: 26 additions & 0 deletions src/Sender/Frontend/Message/Version.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace Buggregator\Trap\Sender\Frontend\Message;

use Buggregator\Trap\Info;
use JsonSerializable;

/**
* @internal
*/
final class Version implements JsonSerializable
{
public function __construct(
public readonly string $number = Info::VERSION,
) {
}

public function jsonSerialize(): array
{
return [
'version' => $this->number,
];
}
}
37 changes: 32 additions & 5 deletions src/Sender/Frontend/Service.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
use Buggregator\Trap\Handler\Router\Attribute\StaticRoute;
use Buggregator\Trap\Handler\Router\Method;
use Buggregator\Trap\Logger;
use Buggregator\Trap\Sender\Frontend\Message\Event;
use Buggregator\Trap\Sender\Frontend\Message\EventCollection;
use Buggregator\Trap\Sender\Frontend\Message\Success;
use Buggregator\Trap\Sender\Frontend\Message\Version;

/**
* @internal
Expand All @@ -20,20 +24,43 @@ public function __construct(
) {
}

#[RegexpRoute(Method::Delete, '#^/api/events/(?<uuid>[a-f0-9-]++)#i')]
public function eventDelete(string $uuid): bool
#[StaticRoute(Method::Get, 'api/version')]
public function version(): Version
{
$this->debug('Get version');
return new Version();
}

#[RegexpRoute(Method::Delete, '#^/api/event/(?<uuid>[a-f0-9-]++)#i')]
public function eventDelete(string $uuid): Success
{
$this->debug('Delete event %s', $uuid);
$this->eventsStorage->delete($uuid);
return true;
return new Success();
}

#[RegexpRoute(Method::Get, '#^/api/event/(?<uuid>[a-f0-9-]++)#i')]
public function eventShow(string $uuid): Event|Success
{
$this->debug('Show event %s', $uuid);
$event = $this->eventsStorage->get($uuid);
// todo: verify correct format
return $event ?? new Success(status: false);
}

#[StaticRoute(Method::Delete, 'api/events')]
public function eventsDelete(): bool
public function eventsDelete(): Success
{
$this->debug('Delete all events');
$this->eventsStorage->clear();
return true;
return new Success();
}

#[StaticRoute(Method::Get, 'api/events')]
public function eventsList(): EventCollection
{
$this->debug('List all events');
return new EventCollection(events: \iterator_to_array($this->eventsStorage, false));
}

private function debug(string $pattern, string ...$args): void
Expand Down
2 changes: 1 addition & 1 deletion src/Traffic/Dispatcher/Http.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,6 @@ public function detect(string $data, DateTimeImmutable $createdAt): ?bool
return null;
}

return \preg_match('/^(GET|POST|PUT|HEAD|OPTIONS) \\S++ HTTP\\/1\\.\\d\\r$/m', $data) === 1;
return \preg_match('/^(GET|POST|PUT|HEAD|OPTIONS|DELETE|PATCH|TRACE|CONNECT) \\S++ HTTP\\/1\\.\\d\\r$/m', $data) === 1;
}
}
4 changes: 4 additions & 0 deletions tests/Unit/Traffic/Dispatcher/HttpTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;

/**
* @covers \Buggregator\Trap\Traffic\Dispatcher\Http
*/
class HttpTest extends TestCase
{
public static function detectProvider()
Expand All @@ -17,6 +20,7 @@ public static function detectProvider()
yield ['POST /foo HT', null];
yield ['GET /foo HTTP/1.1', null];
yield ["BUGGREGATOR /foo HTTP/1.1\r\n", false];
yield ["DELETE /foo HTTP/1.1\r\n", true];
yield ["GET HTTP/1.1\r\n", false];
yield [<<<HTTP
GET /_nuxt/index.30fc2cdf.js HTTP/1.1\r
Expand Down

0 comments on commit 6aead78

Please sign in to comment.