75 def __init__(self, helper_path, env):
85 cmd_in_r, cmd_in_w = os.pipe()
86 cmd_out_r, cmd_out_w = os.pipe()
88 if sys.platform ==
"win32":
89 cmd_in_handle = msvcrt.get_osfhandle(cmd_in_r)
90 cmd_out_handle = msvcrt.get_osfhandle(cmd_out_w)
91 os.set_handle_inheritable(cmd_in_handle,
True)
92 os.set_handle_inheritable(cmd_out_handle,
True)
93 cmd_in_arg = f
"--cmdInFd={cmd_in_handle:x}"
94 cmd_out_arg = f
"--cmdOutFd={cmd_out_handle:x}"
99 popen_kwargs = {
"close_fds":
False}
101 cmd_in_arg = f
"--cmdInFd=P{cmd_in_r:x}"
102 cmd_out_arg = f
"--cmdOutFd=P{cmd_out_w:x}"
103 popen_kwargs = {
"close_fds":
True,
"pass_fds": (cmd_in_r, cmd_out_w)}
105 self.proc = subprocess.Popen(
106 [helper_path, cmd_in_arg, cmd_out_arg],
107 stdin=subprocess.DEVNULL,
115 self._in = os.fdopen(cmd_in_w,
"w", buffering=1)
116 self._out = os.fdopen(cmd_out_r,
"r")
117 self._lines = queue.Queue()
118 self._reader = threading.Thread(target=self._read_loop, daemon=
True)
122 def _read_loop(self):
123 for line
in self._out:
126 self._lines.put(line)
128 def request(self, method, params=None, timeout=REQUEST_TIMEOUT):
130 req_id = self._next_id
131 msg = {
"jsonrpc":
"2.0",
"id": req_id,
"method": method}
132 if params
is not None:
133 msg[
"params"] = params
134 self._in.write(json.dumps(msg) +
"\n")
137 deadline = time.monotonic() + timeout
139 remaining = deadline - time.monotonic()
143 line = self._lines.get(timeout=remaining)
146 reply = json.loads(line)
147 if reply.get(
"id") == req_id:
150 raise TimeoutError(f
"no reply to {method!r} within {timeout}s")
152 def notify(self, method, params=None):
153 msg = {
"jsonrpc":
"2.0",
"method": method}
154 if params
is not None:
155 msg[
"params"] = params
156 self._in.write(json.dumps(msg) +
"\n")
159 def wait(self, timeout=10):
160 return self.proc.wait(timeout=timeout)