76 def __init__(self, helper_path, env):
86 cmd_in_r, cmd_in_w = os.pipe()
87 cmd_out_r, cmd_out_w = os.pipe()
89 if sys.platform ==
"win32":
90 cmd_in_handle = msvcrt.get_osfhandle(cmd_in_r)
91 cmd_out_handle = msvcrt.get_osfhandle(cmd_out_w)
92 os.set_handle_inheritable(cmd_in_handle,
True)
93 os.set_handle_inheritable(cmd_out_handle,
True)
94 cmd_in_arg = f
"--cmdInFd={cmd_in_handle:x}"
95 cmd_out_arg = f
"--cmdOutFd={cmd_out_handle:x}"
100 popen_kwargs = {
"close_fds":
False}
102 cmd_in_arg = f
"--cmdInFd=P{cmd_in_r:x}"
103 cmd_out_arg = f
"--cmdOutFd=P{cmd_out_w:x}"
104 popen_kwargs = {
"close_fds":
True,
"pass_fds": (cmd_in_r, cmd_out_w)}
106 self.proc = subprocess.Popen(
107 [helper_path, cmd_in_arg, cmd_out_arg],
108 stdin=subprocess.DEVNULL,
116 self._in = os.fdopen(cmd_in_w,
"w", buffering=1)
117 self._out = os.fdopen(cmd_out_r,
"r")
118 self._lines = queue.Queue()
119 self._reader = threading.Thread(target=self._read_loop, daemon=
True)
123 def _read_loop(self):
124 for line
in self._out:
127 self._lines.put(line)
129 def request(self, method, params=None, timeout=REQUEST_TIMEOUT):
131 req_id = self._next_id
132 msg = {
"jsonrpc":
"2.0",
"id": req_id,
"method": method}
133 if params
is not None:
134 msg[
"params"] = params
135 self._in.write(json.dumps(msg) +
"\n")
138 deadline = time.monotonic() + timeout
140 remaining = deadline - time.monotonic()
144 line = self._lines.get(timeout=remaining)
147 reply = json.loads(line)
148 if reply.get(
"id") == req_id:
151 raise TimeoutError(f
"no reply to {method!r} within {timeout}s")
153 def notify(self, method, params=None):
154 msg = {
"jsonrpc":
"2.0",
"method": method}
155 if params
is not None:
156 msg[
"params"] = params
157 self._in.write(json.dumps(msg) +
"\n")
160 def wait(self, timeout=10):
161 return self.proc.wait(timeout=timeout)