def handle(self, connection_id, message_content): request = validator_pb2.Message() request.ParseFromString(message_content) return dispatch.HandlerResult( dispatch.HandlerStatus.RETURN, message_out=validator_pb2.Message( correlation_id=request.correlation_id, ), message_type=validator_pb2.Message.DEFAULT)
def _determine_next(self, message_id, future): if future.result().status == HandlerStatus.DROP: del self._message_information[message_id] elif future.result().status == HandlerStatus.PASS: self._process(message_id) elif future.result().status == HandlerStatus.RETURN_AND_PASS: connection, connection_id, \ original_message, _ = self._message_information[message_id] message = validator_pb2.Message( content=future.result().message_out.SerializeToString(), correlation_id=original_message.correlation_id, message_type=future.result().message_type) try: self._send_message[connection](msg=message, connection_id=connection_id) except KeyError: LOGGER.info( "Can't send message %s back to " "%s because connection %s not in dispatcher", get_enum_name(message.message_type), connection_id, connection) self._process(message_id) elif future.result().status == HandlerStatus.RETURN: connection, connection_id, \ original_message, _ = self._message_information[message_id] del self._message_information[message_id] message = validator_pb2.Message( content=future.result().message_out.SerializeToString(), correlation_id=original_message.correlation_id, message_type=future.result().message_type) try: self._send_message[connection](msg=message, connection_id=connection_id) except KeyError: LOGGER.info( "Can't send message %s back to " "%s because connection %s not in dispatcher", get_enum_name(message.message_type), connection_id, connection) with self._condition: if len(self._message_information) == 0: self._condition.notify()
def send(self, message_type, data, connection_id, callback=None): """ Send a message of message_type :param connection_id: the identity for the connection to send to :param message_type: validator_pb2.Message.* enum value :param data: bytes serialized protobuf :return: future.Future """ if connection_id not in self._connections: raise ValueError("Unknown connection id: %s", connection_id) connection_info = self._connections.get(connection_id) if connection_info.connection_type == \ ConnectionType.ZMQ_IDENTITY: message = validator_pb2.Message(correlation_id=_generate_id(), content=data, message_type=message_type) fut = future.Future( message.correlation_id, message.content, has_callback=True if callback is not None else False) if callback is not None: fut.add_callback(callback) self._futures.put(fut) self._send_receive_thread.send_message(msg=message, connection_id=connection_id) return fut else: return connection_info.connection.send(message_type, data, callback=callback)
def handle(self, message, responder): request = client_pb2.ClientBlockGetRequest() resp_proto = client_pb2.ClientBlockGetResponse status = resp_proto.OK try: request.ParseFromString(message.content) block = self._block_store[request.block_id].block.get_block() except DecodeError: LOGGER.info("Expected protobuf of class %s failed to " "deserialize", request) status = resp_proto.ERROR except KeyError as e: status = client_pb2.ClientStateListResponse.NORESOURCE LOGGER.info(e) if status != resp_proto.OK: response = resp_proto(status=status) else: response = resp_proto(status=status, block=block) responder.send(validator_pb2.Message( sender=message.sender, message_type=validator_pb2.Message.CLIENT_BLOCK_LIST_RESPONSE, correlation_id=message.correlation_id, content=response.SerializeToString()))
def handle(self, message, responder): request = client_pb2.ClientStateListRequest() resp_proto = client_pb2.ClientStateListResponse status = resp_proto.OK try: request.ParseFromString(message.content) self._tree.set_merkle_root(request.merkle_root) except KeyError as e: status = resp_proto.NORESOURCE LOGGER.debug(e) except DecodeError: status = resp_proto.ERROR LOGGER.info("Expected protobuf of class %s failed to " "deserialize", request) if status != resp_proto.OK: response = resp_proto(status=status) else: prefix = request.prefix leaves = self._tree.leaves(prefix) if len(leaves) == 0: status = resp_proto.NORESOURCE response = resp_proto(status=status) else: entries = [Entry(address=a, data=v) for a, v in leaves.items()] response = resp_proto(status=status, entries=entries) responder.send(validator_pb2.Message( sender=message.sender, message_type=validator_pb2.Message.CLIENT_STATE_LIST_RESPONSE, correlation_id=message.correlation_id, content=response.SerializeToString()))
def send(self, message_type, data, callback=None): """Sends a message of message_type Args: message_type (validator_pb2.Message): enum value data (bytes): serialized protobuf callback (function): a callback function to call when a response to this message is received Returns: future.Future """ message = validator_pb2.Message(correlation_id=_generate_id(), content=data, message_type=message_type) fut = future.Future( message.correlation_id, message.content, has_callback=True if callback is not None else False) if callback is not None: fut.add_callback(callback) self._futures.put(fut) self._send_receive_thread.send_message(message) return fut
def _receive_message(self): """ Internal coroutine for receiving messages """ with self._condition: self._condition.wait_for(lambda: self._socket is not None) while True: if self._socket.getsockopt(zmq.TYPE) == zmq.ROUTER: identity, msg_bytes = yield from self._socket.recv_multipart() else: msg_bytes = yield from self._socket.recv() message = validator_pb2.Message() message.ParseFromString(msg_bytes) LOGGER.debug("receiving %s message", get_enum_name(message.message_type)) try: self._futures.set_result( message.correlation_id, future.FutureResult(message_type=message.message_type, content=message.content)) except future.FutureCollectionKeyError: if self._socket.getsockopt(zmq.TYPE) == zmq.ROUTER: self._dispatcher.dispatch(identity, message) else: LOGGER.info( "received a first message on the zmq dealer.") else: my_future = self._futures.get(message.correlation_id) LOGGER.debug("message round " "trip: %s %s", get_enum_name(message.message_type), my_future.get_duration()) self._futures.remove(message.correlation_id)
def test_signature_thread(self): try: self.verifier.start() blocks = self._create_blocks(1, 1) message = GossipMessage(content_type="Block", content=blocks[0].SerializeToString()) content = message.SerializeToString() msg = validator_pb2.Message( message_type=validator_pb2.Message.GOSSIP_MESSAGE, correlation_id=self._generate_id(), content=content) with self._in_condition: self._in.put_nowait(msg) self._in_condition.notify_all() to = TimeOut(2) while self._out.qsize() == 0: if to.is_timed_out(): break self.assertEqual(self._out.qsize(), 1) finally: with self._in_condition: self.verifier.stop() self._in_condition.notify_all()
def _receive_message(self): """ Internal coroutine for receiving messages from the zmq processor DEALER interface """ with self._condition: self._condition.wait_for(lambda: self._proc_sock is not None) while True: msg_bytes = yield from self._proc_sock.recv() LOGGER.debug("Client received message: %s", msg_bytes) message = validator_pb2.Message() message.ParseFromString(msg_bytes) try: self._futures.set_result( message.correlation_id, future.FutureResult(message_type=message.message_type, content=message.content)) except future.FutureCollectionKeyError: # if we are getting an initial message, not a response if message.message_type in self._handlers: handler = self._handlers[message.message_type] else: handler = self._handlers[validator_pb2.Message.DEFAULT] handler.handle(message, _Responder(self.send_message)) self._recv_queue.put_nowait(message) else: my_future = self._futures.get(message.correlation_id) LOGGER.debug("Message round " "trip: %s", my_future.get_duration())
def _receive_message(self): """ Internal coroutine for receiving messages from the zmq processor ROUTER interface """ with self._condition: self._condition.wait_for(lambda: self._proc_sock is not None) while True: ident, result = yield from self._proc_sock.recv_multipart() LOGGER.debug("Server received message " "from %s: %s", ident, result) message = validator_pb2.Message() message.ParseFromString(result) message.sender = ident try: # if there is a future, then we are getting a response self._futures.set_result( message.correlation_id, future.FutureResult(content=message.content, message_type=message.message_type)) except future.FutureCollectionKeyError: # if there isn't a future, we are getting an initial message if message.message_type in self._handlers: handler = self._handlers[message.message_type] else: handler = self._handlers[validator_pb2.Message.DEFAULT] handler.handle(message, _Responder(self.send_message))
def _receive_message(self): """ Internal coroutine for receiving messages """ zmq_identity = None while True: try: if self._socket.getsockopt(zmq.TYPE) == zmq.ROUTER: zmq_identity, msg_bytes = \ yield from self._socket.recv_multipart() self._received_from_identity(zmq_identity) else: msg_bytes = yield from self._socket.recv() self._last_message_time = time.time() message = validator_pb2.Message() message.ParseFromString(msg_bytes) LOGGER.debug("%s receiving %s message: %s bytes", self._connection, get_enum_name(message.message_type), sys.getsizeof(msg_bytes)) tag = get_enum_name(message.message_type) self._get_received_message_counter(tag).inc() if zmq_identity is not None: connection_id = \ self._identity_to_connection_id(zmq_identity) else: connection_id = \ self._identity_to_connection_id( self._connection.encode()) try: self._futures.set_result( message.correlation_id, future.FutureResult(message_type=message.message_type, content=message.content, connection_id=connection_id)) except future.FutureCollectionKeyError: self._dispatcher.dispatch(self._connection, message, connection_id) else: my_future = self._futures.get(message.correlation_id) LOGGER.debug("message round " "trip: %s %s", get_enum_name(message.message_type), my_future.get_duration()) my_future.timer_stop() self._futures.remove(message.correlation_id) except CancelledError: # The concurrent.futures.CancelledError is caught by asyncio # when the Task associated with the coroutine is cancelled. # The raise is required to stop this component. raise except Exception as e: # pylint: disable=broad-except LOGGER.exception( "Received a message on address %s that " "caused an error: %s", self._address, e)
def handle(self, message, responder): error = False current_root = None try: client_pb2.ClientStateCurrentRequest().ParseFromString( message.content) current_root = self._current_root_func() except DecodeError: LOGGER.info( "Expected protobuf of class %s failed to " "deserialize.", client_pb2.ClientStateCurrentRequest()) error = True if error: response = client_pb2.ClientStateCurrentResponse( status=client_pb2.ClientStateCurrentResponse.ERROR) else: response = client_pb2.ClientStateCurrentResponse( status=client_pb2.ClientStateCurrentResponse.OK, merkle_root=current_root) responder.send( validator_pb2.Message(sender=message.sender, message_type=validator_pb2.Message. CLIENT_STATE_CURRENT_RESPONSE, correlation_id=message.correlation_id, content=response.SerializeToString()))
def send(self, message_type, data, connection_id, callback=None): """ Send a message of message_type :param connection_id: the identity for the connection to send to :param message_type: validator_pb2.Message.* enum value :param data: bytes serialized protobuf :return: future.Future """ if connection_id not in self._connections: raise ValueError("Unknown connection id: %s", connection_id) connection_info = self._connections.get(connection_id) if connection_info.connection_type == \ ConnectionType.ZMQ_IDENTITY: message = validator_pb2.Message(correlation_id=_generate_id(), content=data, message_type=message_type) timer_tag = get_enum_name(message.message_type) timer_ctx = self._get_send_response_timer(timer_tag).time() fut = future.Future(message.correlation_id, message.content, callback, timer_ctx=timer_ctx) self._futures.put(fut) self._send_receive_thread.send_message(msg=message, connection_id=connection_id) return fut return connection_info.connection.send(message_type, data, callback=callback)
def handle(self, message, responder): self._network.load(message.content) responder.send(validator_pb2.Message( sender=message.sender, message_type="system/load-response", correlation_id=message.correlation_id, content="{ 'status': 'SUCCESS' }".encode()))
def _do_heartbeat(self): ping = PingRequest() while True: try: if self._socket.getsockopt(zmq.TYPE) == zmq.ROUTER: expired = \ [ident for ident in self._last_message_times if time.time() - self._last_message_times[ident] > self._heartbeat_interval] for zmq_identity in expired: if self._is_connection_lost( self._last_message_times[zmq_identity]): LOGGER.debug( "No response from %s in %s seconds" " - removing connection.", zmq_identity, self._connection_timeout) self.remove_connected_identity(zmq_identity) else: message = validator_pb2.Message( correlation_id=_generate_id(), content=ping.SerializeToString(), message_type=validator_pb2.Message.PING_REQUEST ) fut = future.Future( message.correlation_id, message.content, ) self._futures.put(fut) message_frame = [ bytes(zmq_identity), message.SerializeToString() ] yield from self._send_message_frame(message_frame) elif self._socket.getsockopt(zmq.TYPE) == zmq.DEALER: if self._last_message_time and \ self._is_connection_lost(self._last_message_time): LOGGER.debug( "No response from %s in %s seconds" " - removing connection.", self._connection, self._connection_timeout) connection_id = hashlib.sha512( self.connection.encode()).hexdigest() if connection_id in self._connections: del self._connections[connection_id] yield from self._stop() yield from asyncio.sleep(self._heartbeat_interval) except CancelledError: # The concurrent.futures.CancelledError is caught by asyncio # when the Task associated with the coroutine is cancelled. # The raise is required to stop this component. raise except Exception as e: # pylint: disable=broad-except LOGGER.exception( "An error occurred while sending heartbeat: %s", e)
def send(self, message_type, content): LOGGER.debug("Client sending %s: %s", message_type, content) message = validator_pb2.Message(message_type=message_type, correlation_id=_generate_id(), content=content) my_future = future.Future(message.correlation_id) self._futures.put(my_future) self._send_receive_thread.send_message(message) return my_future
def handle(self, message, responder): self._network.load(message.content) responder.send(validator_pb2.Message( sender=message.sender, message_type=validator_pb2.Message.CLIENT_BATCH_SUBMIT_RESPONSE, correlation_id=message.correlation_id, content=client_pb2.ClientBatchSubmitResponse( status=client_pb2.ClientBatchSubmitResponse.OK ).SerializeToString()))
def do_next(result): message_info = self._message_information[message_id] LOGGER.debug("do_next: result %s",str(result)) try: # check for a None result if result is None: LOGGER.error( "%s preprocessor returned None result for messsage %s", preprocessor, message_id) return LOGGER.debug("do_next: status %s",str(result.status)) # check for result status if result.status == HandlerStatus.DROP: del self._message_information[message_id] return if result.status == HandlerStatus.RETURN: del self._message_information[message_id] message = validator_pb2.Message( content=result.message_out.SerializeToString(), correlation_id=message_info.correlation_id, message_type=result.message_type) try: self._send_message[message_info.connection]( msg=message, connection_id=message_info.connection_id) except KeyError: LOGGER.warning( "Can't send message %s back to " "%s because connection %s not in dispatcher", get_enum_name(message.message_type), message_info.connection_id, message_info.connection) return # store the preprocessor result self._message_information[message_id] = \ _MessageInformation( connection=message_info.connection, connection_id=message_info.connection_id, content=result.content, correlation_id=message_info.correlation_id, collection=message_info.collection, message_type=message_info.message_type) self._process_next(message_id) except Exception: # pylint: disable=broad-except LOGGER.exception( "Unhandled exception after preprocessing")
def setUp(self): self._dispatcher = dispatch.Dispatcher() thread_pool = ThreadPoolExecutor() self._dispatcher.add_handler( validator_pb2.Message.DEFAULT, MockHandler1(), thread_pool) self._dispatcher.add_handler( validator_pb2.Message.DEFAULT, MockHandler2(), thread_pool) self.mock_send_message = MockSendMessage() self._dispatcher.set_send_message(self.mock_send_message.send_message) self._message_ids = [str(i) for i in range(10)] self._identities = [str(i) for i in range(10)] self._messages = [validator_pb2.Message(content=validator_pb2.Message(correlation_id=m_id).SerializeToString(), message_type=validator_pb2.Message.DEFAULT) for m_id in self._message_ids]
def _determine_next(self, message_id, future): if future.result().status == HandlerStatus.DROP: with self._condition: del self._message_information[message_id] elif future.result().status == HandlerStatus.PASS: self._process(message_id) elif future.result().status == HandlerStatus.RETURN_AND_PASS: with self._condition: ident, original_message, _ = self._message_information[ message_id] message = validator_pb2.Message( content=future.result().message_out.SerializeToString(), correlation_id=original_message.correlation_id, message_type=future.result().message_type) self._send_message(msg=message, identity=ident) self._process(message_id) elif future.result().status == HandlerStatus.RETURN: with self._condition: ident, original_message, _ = self._message_information[ message_id] del self._message_information[message_id] message = validator_pb2.Message( content=future.result().message_out.SerializeToString(), correlation_id=original_message.correlation_id, message_type=future.result().message_type) self._send_message(msg=message, identity=ident) with self._condition: if len(self._message_information) == 0: self._condition.notify()
def handle(self, message, responder): set_request = state_context_pb2.TpStateSetRequest() set_request.ParseFromString(message.content) set_values_list = [{e.address: e.data} for e in set_request.entries] return_value = self._context_manager.set(set_request.context_id, set_values_list) response = state_context_pb2.TpStateSetResponse() if return_value is True: address_list = [e.address for e in set_request.entries] response.addresses.extend(address_list) responder.send(message=validator_pb2.Message( sender=message.sender, correlation_id=message.correlation_id, message_type=Message.TP_STATE_SET_RESPONSE, content=response.SerializeToString())) else: response.addresses.extend([]) responder.send(message=validator_pb2.Message( sender=message.sender, correlation_id=message.correlation_id, message_type=Message.TP_STATE_SET_RESPONSE, content=response.SerializeToString()))
def __init__(self, identity, endpoint, peer_list, dispatcher): LOGGER.debug("Initializing Network service") self._identity = identity self._dispatcher = dispatcher self._handlers = {} self._peered_with_us = {} self.inbound_queue = queue.Queue() self._futures = future.FutureCollection() self._send_receive_thread = _ServerSendReceiveThread(endpoint, self._handlers, self._futures) self._send_receive_thread.daemon = True self.add_handler('default', DefaultHandler()) self.add_handler('gossip/register', PeerRegisterHandler(self)) self.add_handler('gossip/unregister', PeerUnregisterHandler(self)) self.add_handler('gossip/msg', GossipMessageHandler(self)) self.start() if peer_list is not None: for peer in peer_list: self._send_receive_thread.add_connection(self._identity, peer) LOGGER.info("Sleeping 5 seconds and then broadcasting messages " "to connected peers") time.sleep(5) content = GossipMessage(content=bytes( str("This is a gossip payload"), 'UTF-8')).SerializeToString() for _ in range(1000): message = validator_pb2.Message( message_type=b'gossip/msg', correlation_id=_generate_id(), content=content) self.broadcast_message(message) # If we transmit as fast as possible, we populate the # buffers and get faster throughput but worse avg. message # latency. If we sleep here or otherwise throttle input, # the overall duration is longer, but the per message # latency is low. The process is CPU bound on Vagrant VM # core at ~0.001-0.01 duration sleeps. time.sleep(0.01)
def _receive_message(self): """ Internal coroutine for receiving messages """ zmq_identity = None with self._condition: self._condition.wait_for(lambda: self._socket is not None) while True: if self._socket.getsockopt(zmq.TYPE) == zmq.ROUTER: zmq_identity, msg_bytes = \ yield from self._socket.recv_multipart() self._received_from_identity(zmq_identity) else: msg_bytes = yield from self._socket.recv() self._last_message_time = time.time() message = validator_pb2.Message() message.ParseFromString(msg_bytes) LOGGER.debug("%s receiving %s message: %s bytes", self._connection, get_enum_name(message.message_type), sys.getsizeof(msg_bytes)) try: self._futures.set_result( message.correlation_id, future.FutureResult(message_type=message.message_type, content=message.content)) except future.FutureCollectionKeyError: if zmq_identity is not None: connection_id = \ self._identity_to_connection_id(zmq_identity) else: connection_id = \ self._identity_to_connection_id( self._connection.encode()) self._dispatcher.dispatch(self._connection, message, connection_id) else: my_future = self._futures.get(message.correlation_id) LOGGER.debug("message round " "trip: %s %s", get_enum_name(message.message_type), my_future.get_duration()) self._futures.remove(message.correlation_id)
def handle(self, message, responder): get_request = state_context_pb2.TpStateGetRequest() get_request.ParseFromString(message.content) return_values = self._context_manager.get(get_request.context_id, get_request.addresses) return_list = return_values if return_values is not None else [] LOGGER.debug("GET: %s", return_list) entry_list = [ state_context_pb2.Entry(address=a, data=d) for a, d in return_list ] responder.send(message=validator_pb2.Message( sender=message.sender, correlation_id=message.correlation_id, message_type=Message.TP_STATE_GET_RESPONSE, content=state_context_pb2.TpStateGetResponse( entries=entry_list).SerializeToString()))
def handle(self, message, peer): LOGGER.debug("PingHandler message: %s", message) request = PingRequest() request.ParseFromString(message.content) LOGGER.debug("Got ping message %s " "from %s. sending ack", message.content, message.sender) ack = NetworkAcknowledgement() ack.status = ack.OK peer.send( validator_pb2.Message(sender=message.sender, message_type='gossip/ack', correlation_id=message.correlation_id, content=ack.SerializeToString()))
def send(self, message_type, data): """ Send a message of message_type :param message_type: validator_pb2.Message.* enum value :param data: bytes serialized protobuf :return: future.Future """ message = validator_pb2.Message(correlation_id=_generate_id(), content=data, message_type=message_type) fut = future.Future(message.correlation_id, message.content) self._futures.put(fut) self._send_receive_thread.send_message(message) return fut
def handle(self, message, peer): LOGGER.debug("GossipMessageHandler message: %s", message.sender) LOGGER.debug("Got gossip message %s " "from %s. sending ack", message.content, message.sender) self._ingest_message(message) ack = NetworkAcknowledgement() ack.status = ack.OK peer.send( validator_pb2.Message( sender=message.sender, message_type=validator_pb2.Message.GOSSIP_ACK, correlation_id=message.correlation_id, content=ack.SerializeToString()))
def handle(self, message, peer): request = PeerUnregisterRequest() request.ParseFromString(message.content) self._service.unregister_peer(message.sender, request.identity) LOGGER.debug("Got peer unregister message " "from %s. Sending ack", message.sender) ack = NetworkAcknowledgement() ack.status = ack.OK peer.send( validator_pb2.Message(sender=message.sender, message_type='gossip/ack', correlation_id=message.correlation_id, content=ack.SerializeToString()))
def send_message(self, data): if isinstance(data, str): msg = GossipMessage(content_type="BlockRequest", content=data.encode("utf-8")) elif isinstance(data, block_pb2.Block): msg = GossipMessage(content_type="Block", content=data.SerializeToString()) elif isinstance(data, batch_pb2.Batch): msg = GossipMessage(content_type="Batch", content=data.SerializeToString()) content = msg.SerializeToString() message = validator_pb2.Message( message_type=validator_pb2.Message.GOSSIP_MESSAGE, correlation_id=_generate_id(), content=content) self._put_on_inbound(message)
def _receive_message(self): """ Internal coroutine for receiving messages """ with self._condition: self._condition.wait_for(lambda: self._socket is not None) while True: if self._socket.getsockopt(zmq.TYPE) == zmq.ROUTER: identity, msg_bytes = yield from self._socket.recv_multipart() else: msg_bytes = yield from self._socket.recv() message = validator_pb2.Message() message.ParseFromString(msg_bytes) LOGGER.debug("%s receiving %s message: %s bytes", self._connection, get_enum_name(message.message_type), sys.getsizeof(msg_bytes)) try: self._futures.set_result( message.correlation_id, future.FutureResult(message_type=message.message_type, content=message.content)) except future.FutureCollectionKeyError: if self._socket.getsockopt(zmq.TYPE) == zmq.ROUTER: self._dispatcher.dispatch(self._connection, message, identity=identity) else: # Because this is a zmq.DEALER socket, there is no # outbound identity self._dispatcher.dispatch(self._connection, message) else: my_future = self._futures.get(message.correlation_id) LOGGER.debug("message round " "trip: %s %s", get_enum_name(message.message_type), my_future.get_duration()) self._futures.remove(message.correlation_id)