* * @author Kyrian Obikwelu */ class StdioTransport implements TransportInterface { /** @var callable(string, ?Uuid): void */ private $messageListener; /** @var callable(Uuid): void */ private $sessionEndListener; private ?Uuid $sessionId = null; /** * @param resource $input * @param resource $output */ public function __construct( private $input = \STDIN, private $output = \STDOUT, private readonly LoggerInterface $logger = new NullLogger(), ) { } public function initialize(): void { } public function onMessage(callable $listener): void { $this->messageListener = $listener; } public function send(string $data, array $context): void { $this->logger->debug('Sending data to client via StdioTransport.', ['data' => $data]); if (isset($context['session_id'])) { $this->sessionId = $context['session_id']; } fwrite($this->output, $data.\PHP_EOL); } public function listen(): int { $this->logger->info('StdioTransport is listening for messages on STDIN...'); $status = 0; while (!feof($this->input)) { $line = fgets($this->input); if (false === $line) { if (!feof($this->input)) { $status = 1; } break; } $trimmedLine = trim($line); if (!empty($trimmedLine)) { $this->logger->debug('Received message on StdioTransport.', ['line' => $trimmedLine]); if (\is_callable($this->messageListener)) { \call_user_func($this->messageListener, $trimmedLine, $this->sessionId); } } } $this->logger->info('StdioTransport finished listening.'); if (\is_callable($this->sessionEndListener) && null !== $this->sessionId) { \call_user_func($this->sessionEndListener, $this->sessionId); $this->sessionId = null; } return $status; } public function onSessionEnd(callable $listener): void { $this->sessionEndListener = $listener; } public function close(): void { if (\is_callable($this->sessionEndListener) && null !== $this->sessionId) { \call_user_func($this->sessionEndListener, $this->sessionId); $this->sessionId = null; } if (\is_resource($this->input)) { fclose($this->input); } if (\is_resource($this->output)) { fclose($this->output); } } }