| 29 | |
| 30 | |
| 31 | class JupyterKernelWebSocket(BaseModel): |
| 32 | model_config = ConfigDict(arbitrary_types_allowed=True) |
| 33 | |
| 34 | url: str |
| 35 | |
| 36 | _cells: Dict[str, Cell] = {} |
| 37 | _waiting_for_replies: Dict[str, DeferredFuture] = PrivateAttr(default_factory=dict) |
| 38 | _queue_in: Queue = PrivateAttr(default_factory=Queue) |
| 39 | _queue_out: Queue = PrivateAttr(default_factory=Queue) |
| 40 | _process_cleanup: List[Callable[[], Any]] = PrivateAttr(default_factory=list) |
| 41 | _closed: bool = PrivateAttr(default=False) |
| 42 | |
| 43 | def process_messages(self): |
| 44 | while True: |
| 45 | data = self._queue_out.get() |
| 46 | |
| 47 | # logger.debug(f"WebSocket received message: {data}".strip()) |
| 48 | self._receive_message(json.loads(data)) |
| 49 | self._queue_out.task_done() |
| 50 | |
| 51 | def connect(self, timeout: float = TIMEOUT): |
| 52 | started = threading.Event() |
| 53 | stopped = threading.Event() |
| 54 | self._process_cleanup.append(stopped.set) |
| 55 | |
| 56 | threading.Thread( |
| 57 | target=self.process_messages, daemon=True, name="e2b-process-messages" |
| 58 | ).start() |
| 59 | |
| 60 | threading.Thread( |
| 61 | target=WebSocket( |
| 62 | url=self.url, |
| 63 | queue_in=self._queue_in, |
| 64 | queue_out=self._queue_out, |
| 65 | started=started, |
| 66 | stopped=stopped, |
| 67 | ).run, |
| 68 | daemon=True, |
| 69 | name="e2b-code-interpreter-websocket", |
| 70 | ).start() |
| 71 | |
| 72 | # logger.info("WebSocket waiting to start") |
| 73 | |
| 74 | try: |
| 75 | start_time = time.time() |
| 76 | while ( |
| 77 | not started.is_set() |
| 78 | and time.time() - start_time < timeout |
| 79 | and not self._closed |
| 80 | ): |
| 81 | time.sleep(0.1) |
| 82 | |
| 83 | if not started.is_set(): |
| 84 | # logger.error("WebSocket failed to start") |
| 85 | raise TimeoutException("WebSocket failed to start") |
| 86 | except BaseException as e: |
| 87 | self.close() |
| 88 | raise Exception(f"WebSocket failed to start: {e}") from e |
no outgoing calls
no test coverage detected
searching dependent graphs…