Skip to content

Commit

Permalink
Add SMTP Frame->Event mapper
Browse files Browse the repository at this point in the history
  • Loading branch information
roxblnfk committed Dec 16, 2023
1 parent 35a4785 commit 5e0bc1b
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 8 deletions.
1 change: 1 addition & 0 deletions src/Handler/Router/Router.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ private static function collectRoutes(string $class): array
*/
public function match(Method $method, string $path): ?callable
{
$path = \trim($path, '/');
foreach ($this->routes[$method->value] as $route) {
$match = match ($route->route::class) {
Attribute\StaticRoute::class => $path === (string)$route->route->path,

Check failure on line 130 in src/Handler/Router/Router.php

View workflow job for this annotation

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

UndefinedPropertyFetch

src/Handler/Router/Router.php:130:67: UndefinedPropertyFetch: Instance property Buggregator\Trap\Handler\Router\Attribute\Route::$path is not defined (see https://psalm.dev/039)
Expand Down
3 changes: 3 additions & 0 deletions src/Sender/Frontend/Event.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
use ArrayAccess;
use Buggregator\Trap\Sender\Frontend\Event\Asset;

/**
* @internal
*/
final class Event implements \JsonSerializable
{
/**
Expand Down
1 change: 1 addition & 0 deletions src/Sender/Frontend/FrameMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public function map(Frame $frame): Event
return match ($frame::class) {
Frame\VarDumper::class => (new Mapper\VarDump())->map($frame),
Frame\Http::class => (new Mapper\HttpRequest())->map($frame),
Frame\Smtp::class => (new Mapper\Smtp())->map($frame),
default => throw new \InvalidArgumentException('Unknown frame type ' . $frame::class),
};
}
Expand Down
51 changes: 44 additions & 7 deletions src/Sender/Frontend/Http/EventAssets.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
namespace Buggregator\Trap\Sender\Frontend\Http;

use Buggregator\Trap\Handler\Http\Middleware;
use Buggregator\Trap\Handler\Router\Attribute\RegexpRoute;
use Buggregator\Trap\Handler\Router\Method;
use Buggregator\Trap\Handler\Router\Router as CommonRouter;
use Buggregator\Trap\Logger;
use Buggregator\Trap\Sender\Frontend\Event\AttachedFile;
use Buggregator\Trap\Sender\Frontend\EventsStorage;
Expand All @@ -18,33 +21,67 @@
*/
final class EventAssets implements Middleware
{
private readonly CommonRouter $router;

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

public function handle(ServerRequestInterface $request, callable $next): ResponseInterface
{
$path = $request->getUri()->getPath();
if (\preg_match('#^/api/smtp/([^/]++)/attachment/([^/]++)#', $path, $matches) !== 1) {
$method = $request->getMethod();

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

if ($handler === null) {
return $next($request);
}

return $handler() ?? new Response(404);
}

#[RegexpRoute(Method::Get, '#^api/smtp/(?<eventId>[a-f0-9-]++)/html#')]
public function smtpHtml(string $eventId): ?Response
{
// Find event
$event = $this->eventsStorage->get($eventId);

if ($event === null) {
$this->logger->debug('Get HTML for event `%s`. Event not found.', $eventId);
return null;
}

return new Response(
200,
[
'Content-Type' => 'text/html',
'Cache-Control' => 'no-cache',
],
$event->payload['html'] ?? '',
);
}

#[RegexpRoute(Method::Get, '#^api/smtp/(?<eventId>[a-f0-9-]++)/attachment/(?<attachId>[a-f0-9-]++)#')]
public function attachment(string $eventId, string $attachId): ?Response
{
// Find event
$event = $this->eventsStorage->get($matches[1]);
$event = $this->eventsStorage->get($eventId);

if ($event === null) {
$this->logger->debug('Get attachment %s for event %s. Event not found.', $matches[2], $matches[1]);
return new Response(404);
$this->logger->debug('Get attachment `%s` for event `%s`. Event not found.', $attachId, $eventId);
return null;
}

// Find attachment
$attachment = $event->assets[$matches[2]] ?? null;
$attachment = $event->assets[$attachId] ?? null;

if (!$attachment instanceof AttachedFile) {
$this->logger->debug('Get attachment %s for event %s. Attached file not found.', $matches[2], $matches[1]);
return new Response(404);
$this->logger->debug('Get attachment `%s` for event `%s`. Attached file not found.', $attachId, $eventId);
return null;
}

return new Response(
Expand Down
2 changes: 1 addition & 1 deletion src/Sender/Frontend/Http/Router.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public function __construct(
public function handle(ServerRequestInterface $request, callable $next): ResponseInterface
{
try {
$path = \trim($request->getUri()->getPath(), '/');
$path = $request->getUri()->getPath();
$method = $request->getMethod();

$handler = $this->router->match(Method::fromString($method), $path);
Expand Down
62 changes: 62 additions & 0 deletions src/Sender/Frontend/Mapper/Smtp.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

declare(strict_types=1);

namespace Buggregator\Trap\Sender\Frontend\Mapper;

use ArrayObject;
use Buggregator\Trap\Proto\Frame\Smtp as SmtpFrame;
use Buggregator\Trap\Sender\Frontend\Event;
use Buggregator\Trap\Support\Uuid;
use Buggregator\Trap\Traffic\Message\Multipart\File;
use Buggregator\Trap\Traffic\Message\Smtp\MessageFormat;

/**
* @internal
*/
final class Smtp
{
public function map(SmtpFrame $frame): Event
{
$message = $frame->message;

$assets = new ArrayObject();

return new Event(
uuid: $uuid = Uuid::uuid4(),
type: 'smtp',
payload: [
'from' => $message->getSender(),
'reply_to' => $message->getReplyTo(),
'subject' => $message->getSubject(),
'to' => $message->getTo(),
'cc' => $message->getCc(),
'bcc' => $message->getBcc(),
'text' => $message->getMessage(MessageFormat::Plain)?->getValue() ?? '',
'html' => $message->getMessage(MessageFormat::Html)?->getValue() ?? '',
'raw' => (string)$message->getBody(),
'attachments' => \array_map(
static function (File $attachment) use ($assets, $uuid): array {
$asset = new Event\AttachedFile(
id: Uuid::uuid4(),
file: $attachment,
);
$uri = $uuid . '/' . $asset->uuid;
$assets->offsetSet($asset->uuid, $asset);

return [
'id' => $asset->uuid,
'name' => $attachment->getClientFilename(),
'uri' => $uri,
'size' => $attachment->getSize(),
'mime' => $attachment->getClientMediaType(),
];
},
$message->getAttachments(),
),
],
timestamp: (float)$frame->time->format('U.u'),
assets: $assets,
);
}
}
3 changes: 3 additions & 0 deletions src/Sender/Frontend/Message/EventCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

use Buggregator\Trap\Sender\Frontend\Event;

/**
* @internal
*/
final class EventCollection implements \JsonSerializable
{
/**
Expand Down

0 comments on commit 5e0bc1b

Please sign in to comment.