def invoke_sync(self, interface, method_name, content, spanctx=None, target_app="", uid="", timeout_ms=None, **headers): """ :param request: :param timeout: if timeout > 0, this specifies the maximum wait time, in seconds if timeout <= 0, the select() call won't block, and will report the currently ready file objects if timeout is None, select() will block until a monitored file object becomes ready :return: serialized response content :raise: TimeoutError """ assert isinstance(timeout_ms, (int, float)) pkg = BoltResponse deadline = time.time() + timeout_ms / 1000 + 1 req_id, c = self._raw_invoke(interface, method_name, content, target_app=target_app, uid=uid, spanctx=spanctx, timeout_ms=timeout_ms, **headers) with DefaultSelector() as sel: sel.register(c, EVENT_READ) total_size = pkg.bolt_header_size() resp_bytes = b'' header = None while len(resp_bytes) < total_size: ready = sel.select(timeout=deadline - time.time()) if not ready: # timeout c.close() raise TimeoutError('Sync call timeout') for key, event in ready: resp_bytes += key.fileobj.recv(total_size - len(resp_bytes)) if not header and len(resp_bytes) >= total_size: header = pkg.bolt_header_from_stream(resp_bytes) body_size = header['class_len'] + header[ 'header_len'] + header['content_len'] total_size += body_size self._get_pool(interface).put_conn(c) resp = pkg.bolt_content_from_stream( resp_bytes[pkg.bolt_header_size():], header) if resp.request_id != req_id: raise ServerError("RequestId not match") if resp.respstatus != RESPSTATUS.SUCCESS: raise ServerError.from_statuscode(resp.respstatus) return resp.content
async def _recv_response(self, reader, writer): """ wait response and put it in response_mapping, than notify the invoke coro :param reader: :return: """ while True: pkg = None try: fixed_header_bs = await reader.readexactly( BoltResponse.bolt_header_size()) header = BoltResponse.bolt_header_from_stream(fixed_header_bs) bs = await reader.readexactly(header['class_len'] + header['header_len'] + header['content_len']) pkg = BoltResponse.bolt_content_from_stream(bs, header) if pkg.class_name != BoltResponse.class_name: raise ServerError("wrong class_name:[{}]".format( pkg.class_name)) if pkg.cmdcode == CMDCODE.HEARTBEAT: continue elif pkg.cmdcode == CMDCODE.REQUEST: # raise error, the connection will be dropped raise ServerError("wrong cmdcode:[{}]".format(pkg.cmdcode)) if pkg.respstatus != RESPSTATUS.SUCCESS: raise ServerError.from_statuscode(pkg.respstatus) if pkg.request_id not in self.request_mapping: continue self.response_mapping[pkg.request_id] = pkg except PyboltError as e: logger.error(e) except (asyncio.CancelledError, EOFError, ConnectionResetError) as e: logger.error(e) writer.close() break except Exception: logger.error(traceback.format_exc()) writer.close() break finally: with suppress(AttributeError, KeyError): # wake up the coro event = self.request_mapping.pop(pkg.request_id) event.set()