dispatcher = $dispatcher; } public function run(): void { while (($message = $this->readMessage(STDIN)) !== null) { $response = $this->dispatcher->handleMessage($message); if ($response !== null) { $this->writeMessage($response); } } } /** * @param resource $stream * * @return array|null */ private function readMessage($stream): ?array { $headers = []; while (($line = fgets($stream)) !== false) { $line = rtrim($line, "\r\n"); if ($line === '') { break; } if (!str_contains($line, ':')) { $decoded = json_decode($line, true); return is_array($decoded) ? $decoded : null; } [$name, $value] = explode(':', $line, 2); $headers[strtolower(trim($name))] = trim($value); } if ($line === false && $headers === []) { return null; } $length = isset($headers['content-length']) ? (int) $headers['content-length'] : 0; if ($length <= 0) { return null; } $body = ''; while (strlen($body) < $length && !feof($stream)) { $chunk = fread($stream, $length - strlen($body)); if ($chunk === false || $chunk === '') { break; } $body .= $chunk; } $decoded = json_decode($body, true); return is_array($decoded) ? $decoded : null; } /** * @param array $message */ private function writeMessage(array $message): void { $body = json_encode($message, JSON_UNESCAPED_SLASHES); if ($body === false) { return; } fwrite(STDOUT, 'Content-Length: ' . strlen($body) . "\r\n\r\n" . $body); fflush(STDOUT); } }