Fix blocking pipe connection

The console application could be run forever in case of connection errors
This commit is contained in:
Benedek Racz 2020-04-18 12:45:51 +02:00
parent 290ceebc2d
commit c8977d8460
3 changed files with 34 additions and 7 deletions

View File

@ -11,7 +11,7 @@ This project fixes these limitations, with example codes, tests, and pypi integr
Refactor
^^^^^^^^
The original wexpect was a monolite, one-file code, with several structural weaknesses. This leads
The original wexpect was a monolith, one-file code, with several structural weaknesses. This leads
me to rewrite the whole code. The first variant of the new structure is delivered with
`v3.2.0 <https://pypi.org/project/wexpect/3.2.0/>`_. (The default is the old variant
(:code:`legacy_wexpect`) in v3.2.0. :code:`WEXPECT_SPAWN_CLASS` environment variable can choose the
@ -26,7 +26,7 @@ Generally, wexpect (both old and new) has three processes:
- *host* is our original python script/program, which want to launch the child.
- *console* is a process which started by the host, and launches the child. (This is a python script)
- *child* is the process which want to be launced.
- *child* is the process which want to be launched.
The child and the console has a common Windows console, distict from the host.

View File

@ -27,6 +27,7 @@ import socket
from .wexpect_util import init_logger
from .wexpect_util import EOF_CHAR
from .wexpect_util import SIGNAL_CHARS
from .wexpect_util import TIMEOUT
#
# System-wide constants
@ -74,6 +75,8 @@ class ConsoleReaderBase:
self.child_process = None
self.child_pid = None
self.enable_signal_chars = True
self.timeout = 30
self.child_exitstatus = None
logger.info(f'ConsoleReader started. location {os.path.abspath(__file__)}')
@ -504,17 +507,32 @@ class ConsoleReaderSocket(ConsoleReaderBase):
class ConsoleReaderPipe(ConsoleReaderBase):
def create_connection(self, **kwargs):
def create_connection(self, timeout=-1, **kwargs):
if timeout == -1:
timeout = self.timeout
if timeout is None:
end_time = float('inf')
else:
end_time = time.time() + timeout
pipe_name = 'wexpect_{}'.format(self.console_pid)
pipe_full_path = r'\\.\pipe\{}'.format(pipe_name)
logger.info('Start pipe server: %s', pipe_full_path)
self.pipe = win32pipe.CreateNamedPipe(
pipe_full_path,
win32pipe.PIPE_ACCESS_DUPLEX,
win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_READMODE_MESSAGE | win32pipe.PIPE_WAIT,
1, 65536, 65536, 0, None)
win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_READMODE_MESSAGE | win32pipe.PIPE_NOWAIT,
1, 65536, 65536, 10000, None)
logger.info("waiting for client")
win32pipe.ConnectNamedPipe(self.pipe, None)
while True:
if end_time < time.time():
raise TIMEOUT('Connect to child has been timed out.')
try:
win32pipe.ConnectNamedPipe(self.pipe, None)
break
except Exception as e:
logger.debug(e)
time.sleep(0.2)
logger.info('got client')
def close_connection(self):

View File

@ -881,11 +881,20 @@ class SpawnPipe(SpawnBase):
# seconds.
self.delayafterterminate = 2
def connect_to_child(self):
def connect_to_child(self, timeout=-1):
if timeout == -1:
timeout = self.timeout
if timeout is None:
end_time = float('inf')
else:
end_time = time.time() + timeout
pipe_name = 'wexpect_{}'.format(self.console_pid)
pipe_full_path = r'\\.\pipe\{}'.format(pipe_name)
logger.debug(f'Trying to connect to pipe: {pipe_full_path}')
while True:
if end_time < time.time():
raise TIMEOUT('Connect to child has been timed out.')
try:
self.pipe = win32file.CreateFile(
pipe_full_path,