Resulable besim handof so recompiling model does not give second besim window
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from PySide6.QtCore import QObject, Signal
|
||||
from PySide6.QtNetwork import QLocalServer, QLocalSocket
|
||||
|
||||
from bedit_gui.simulation_models import CompiledModel
|
||||
|
||||
SERVER_NAME = "bedit-besim-handoff-v1"
|
||||
|
||||
|
||||
def send_simulation_handoff(path: str | Path, compiled_model: CompiledModel, *, server_name: str = SERVER_NAME, timeout_ms: int = 500) -> bool:
|
||||
socket = QLocalSocket()
|
||||
socket.connectToServer(server_name)
|
||||
if not socket.waitForConnected(timeout_ms):
|
||||
return False
|
||||
payload = json.dumps({"path": str(Path(path).resolve()), "compiled_model": compiled_model.to_data()}, separators=(",", ":")).encode("utf-8") + b"\n"
|
||||
if socket.write(payload) != len(payload) or not socket.waitForBytesWritten(timeout_ms):
|
||||
socket.abort()
|
||||
return False
|
||||
socket.disconnectFromServer()
|
||||
return True
|
||||
|
||||
|
||||
class SimulationHandoffServer(QObject):
|
||||
handoff_received = Signal(object, object)
|
||||
|
||||
def __init__(self, parent: QObject | None = None, *, server_name: str = SERVER_NAME) -> None:
|
||||
super().__init__(parent)
|
||||
self.server = QLocalServer(self)
|
||||
self._buffers: dict[QLocalSocket, bytearray] = {}
|
||||
self.server.newConnection.connect(self._accept_connections)
|
||||
if not self.server.listen(server_name):
|
||||
probe = QLocalSocket()
|
||||
probe.connectToServer(server_name)
|
||||
if probe.waitForConnected(200):
|
||||
probe.disconnectFromServer()
|
||||
return
|
||||
QLocalServer.removeServer(server_name)
|
||||
if not self.server.listen(server_name):
|
||||
raise RuntimeError(f"could not listen for BEsim handoffs: {self.server.errorString()}")
|
||||
|
||||
def _accept_connections(self) -> None:
|
||||
while self.server.hasPendingConnections():
|
||||
socket = self.server.nextPendingConnection()
|
||||
if socket is None:
|
||||
continue
|
||||
self._buffers[socket] = bytearray()
|
||||
socket.readyRead.connect(lambda active=socket: self._read(active))
|
||||
socket.disconnected.connect(lambda active=socket: self._discard(active))
|
||||
self._read(socket)
|
||||
|
||||
def _read(self, socket: QLocalSocket) -> None:
|
||||
buffer = self._buffers.get(socket)
|
||||
if buffer is None:
|
||||
return
|
||||
buffer.extend(socket.readAll().data())
|
||||
while b"\n" in buffer:
|
||||
raw_message, _, remaining = buffer.partition(b"\n")
|
||||
buffer[:] = remaining
|
||||
try:
|
||||
message = json.loads(raw_message.decode("utf-8"))
|
||||
path = Path(str(message["path"]))
|
||||
compiled_model = CompiledModel.from_data(message["compiled_model"])
|
||||
except (KeyError, TypeError, ValueError, json.JSONDecodeError, UnicodeDecodeError):
|
||||
continue
|
||||
self.handoff_received.emit(path, compiled_model)
|
||||
|
||||
def _discard(self, socket: QLocalSocket) -> None:
|
||||
self._buffers.pop(socket, None)
|
||||
Reference in New Issue
Block a user