Skip to content

Commit

Permalink
do not try to start client process when command is empty
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexeyBond committed Dec 19, 2023
1 parent f3146a7 commit 9c3fb1e
Showing 1 changed file with 36 additions and 30 deletions.
66 changes: 36 additions & 30 deletions plugin/core/transports.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,13 @@ def start_subprocess() -> subprocess.Popen:

if config.listener_socket:
assert isinstance(config.tcp_port, int) and config.tcp_port > 0
process, sock, reader, writer = _await_tcp_connection(
config.name, config.tcp_port, config.listener_socket, start_subprocess)
if config.command:
process, sock, reader, writer = _start_client_process_and_await_connection(
config.listener_socket,
start_subprocess
)
else:
sock, reader, writer = _await_client_connection(config.listener_socket)
else:
if config.command:
process = start_subprocess()
Expand Down Expand Up @@ -337,39 +342,40 @@ def _start_subprocess(
return process


class _SubprocessData:
def __init__(self) -> None:
self.process = None # type: Optional[subprocess.Popen]


def _await_tcp_connection(
name: str,
tcp_port: int,
listener_socket: socket.socket,
subprocess_starter: Callable[[], subprocess.Popen]
) -> Tuple[subprocess.Popen, socket.socket, IO[bytes], IO[bytes]]:

# After we have accepted one client connection, we can close the listener socket.
def _await_client_connection(listener_socket: socket.socket) -> Tuple[socket.socket, IO[bytes], IO[bytes]]:
with closing(listener_socket):

# We need to be able to start the process while also awaiting a client connection.
def start_in_background(d: _SubprocessData) -> None:
# Sleep for one second, because the listener socket needs to be in the "accept" state before starting the
# subprocess. This is hacky, and will get better when we can use asyncio.
time.sleep(1)
process = subprocess_starter()
d.process = process

data = _SubprocessData()
thread = threading.Thread(target=lambda: start_in_background(data))
thread.start()
# Await one client connection (blocking!)
sock, _ = listener_socket.accept()
thread.join()

reader = sock.makefile('rwb') # type: ignore
writer = reader
assert data.process
return data.process, sock, reader, writer # type: ignore
return sock, reader, writer # type: ignore


def _start_client_process_and_await_connection(
listener_socket: socket.socket,
subprocess_starter: Callable[[], subprocess.Popen]
) -> Tuple[subprocess.Popen, socket.socket, IO[bytes], IO[bytes]]:
process = None

# We need to be able to start the process while also awaiting a client connection.
def start_in_background() -> None:
# Sleep for one second, because the listener socket needs to be in the "accept" state before starting the
# subprocess. This is hacky, and will get better when we can use asyncio.
time.sleep(1)

nonlocal process
process = subprocess_starter()

thread = threading.Thread(target=start_in_background)
thread.start()

sock, reader, writer = _await_client_connection(listener_socket)

thread.join()

assert process is not None
return process, sock, reader, writer # type: ignore


def _connect_tcp(port: int) -> Optional[socket.socket]:
Expand Down

0 comments on commit 9c3fb1e

Please sign in to comment.