refactor: use custom imap client

Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
2026-05-08 00:16:43 -04:00
parent a728aeb11c
commit a8764747fd
179 changed files with 6782 additions and 5907 deletions

View File

@@ -0,0 +1,86 @@
<?php
declare(strict_types=1);
namespace KTXM\ProviderImap\Client\Protocol;
use Generator;
use KTXM\ProviderImap\Client\Command\CommandInterface;
use KTXM\ProviderImap\Client\ImapException;
use KTXM\ProviderImap\Client\Protocol\Response\TaggedResponse;
use KTXM\ProviderImap\Client\Protocol\Response\UntaggedResponse;
use KTXM\ProviderImap\Client\SessionContext;
use KTXM\ProviderImap\Client\SessionState;
use Psr\Log\LoggerInterface;
final class CommandExecutor
{
public function __construct(
private readonly ProtocolReader $reader,
private readonly ProtocolWriter $writer,
private readonly TagGenerator $tags = new TagGenerator(),
private readonly ?LoggerInterface $logger = null,
) {}
/**
* @template TResult
* @param CommandInterface<TResult> $command
* @return TResult
*/
public function perform(CommandInterface $command, SessionContext $context): mixed
{
$this->assertState($command->allowedStates(), $context->state(), $command->name());
$this->logger?->debug('IMAP command execution started: {command} (state={state})', [
'command' => $command->name(),
'state' => $context->state()->value,
]);
$tag = $this->tags->next();
$frame = $command->encode($tag, $context);
$this->writer->write($tag, $frame);
return $command->handle(new ResponseStream(function () use ($tag, $context): Generator {
yield from $this->responsesUntilCompletion($tag, $context);
}), $context);
}
/**
* @param list<SessionState> $allowedStates
*/
private function assertState(array $allowedStates, SessionState $currentState, string $commandName): void
{
foreach ($allowedStates as $allowedState) {
if ($allowedState === $currentState) {
return;
}
}
throw new ImapException(sprintf(
'Command %s is not allowed while session is in state %s.',
$commandName,
$currentState->value,
));
}
private function responsesUntilCompletion(string $tag, SessionContext $context): Generator
{
while (true) {
$response = $this->reader->readResponse();
if ($response instanceof UntaggedResponse && $response->label() === 'CAPABILITY') {
$context->replaceCapabilities(...$response->payloadTokens());
}
yield $response;
if ($response instanceof TaggedResponse && $response->tag() === $tag) {
$this->logger?->debug('IMAP command execution completed: tag={tag} status={status}', [
'tag' => $tag,
'status' => $response->status(),
]);
return;
}
}
}
}