Read a single JSON-RPC message with a Content-Length header (blocking). Returns: Parsed JSON message, or None if the connection is closed.
(self)
| 327 | return b"".join(chunks) |
| 328 | |
| 329 | def _read_message(self) -> dict | None: |
| 330 | """ |
| 331 | Read a single JSON-RPC message with a Content-Length header (blocking). |
| 332 | |
| 333 | Returns: |
| 334 | Parsed JSON message, or None if the connection is closed. |
| 335 | """ |
| 336 | # Read header line |
| 337 | header_line = self.process.stdout.readline() |
| 338 | if not header_line: |
| 339 | return None |
| 340 | |
| 341 | # Parse Content-Length |
| 342 | header = header_line.decode("utf-8").strip() |
| 343 | if not header.startswith("Content-Length:"): |
| 344 | return None |
| 345 | |
| 346 | content_length = int(header.split(":")[1].strip()) |
| 347 | |
| 348 | # Read empty line |
| 349 | self.process.stdout.readline() |
| 350 | |
| 351 | # Read exact content using loop to handle short reads |
| 352 | content_bytes = self._read_exact(content_length) |
| 353 | content = content_bytes.decode("utf-8") |
| 354 | |
| 355 | return json.loads(content) |
| 356 | |
| 357 | def _handle_message(self, message: dict): |
| 358 | """Handle an incoming message (response or notification)""" |