Receive a newline-delimited JSON message. Returns None on timeout/error.
(self, timeout: float = SOCKET_TIMEOUT)
| 275 | self.receive_buffer = b"" |
| 276 | |
| 277 | def recv_message(self, timeout: float = SOCKET_TIMEOUT) -> Optional[dict]: |
| 278 | """Receive a newline-delimited JSON message. Returns None on timeout/error.""" |
| 279 | if not self.socket: |
| 280 | return None |
| 281 | |
| 282 | try: |
| 283 | end_time = time.time() + timeout |
| 284 | while True: |
| 285 | newline_pos = self.receive_buffer.find(b"\n") |
| 286 | if newline_pos != -1: |
| 287 | line = self.receive_buffer[:newline_pos] |
| 288 | self.receive_buffer = self.receive_buffer[newline_pos + 1 :] |
| 289 | |
| 290 | if line.strip(): |
| 291 | if self.verbose: |
| 292 | print(f"[RECV] {line.decode('utf-8', errors='replace')}") |
| 293 | return json.loads(line.decode("utf-8")) |
| 294 | continue |
| 295 | |
| 296 | remaining_time = end_time - time.time() |
| 297 | if remaining_time <= 0: |
| 298 | return None |
| 299 | |
| 300 | ready = select.select([self.socket], [], [], min(remaining_time, 0.1)) |
| 301 | if ready[0]: |
| 302 | chunk = self.socket.recv(RECV_BUFFER_SIZE) |
| 303 | if not chunk: |
| 304 | return None |
| 305 | self.receive_buffer += chunk |
| 306 | except Exception as e: |
| 307 | if self.verbose: |
| 308 | print(f"[ERROR] recv_message: {e}") |
| 309 | return None |
| 310 | |
| 311 | def send_raw( |
| 312 | self, |
no test coverage detected