Пример #1
0
 def get_protocol_command_for(self, msg: bytes) -> protocol.Command:
     """Return the Command corresponding to the cmd_id encoded in the given msg."""
     cmd_id = get_devp2p_cmd_id(msg)
     self.logger.trace("Got msg with cmd_id: %s", cmd_id)
     if cmd_id < self.base_protocol.cmd_length:
         return self.base_protocol.cmd_by_id[cmd_id]
     elif cmd_id < self.sub_proto.cmd_id_offset + self.sub_proto.cmd_length:
         return self.sub_proto.cmd_by_id[cmd_id]
     else:
         raise UnknownProtocolCommand(f"No protocol found for cmd_id {cmd_id}")
Пример #2
0
 def get_protocol_command_for(self, msg: bytes) -> protocol.Command:
     """Return the Command corresponding to the cmd_id encoded in the given msg."""
     cmd_id = get_devp2p_cmd_id(msg)
     self.logger.debug("Got msg with cmd_id: %s", cmd_id)
     if cmd_id < self.base_protocol.cmd_length:
         proto = self.base_protocol
     elif cmd_id < self.sub_proto.cmd_id_offset + self.sub_proto.cmd_length:
         proto = self.sub_proto  # type: ignore
     else:
         raise UnknownProtocolCommand("No protocol found for cmd_id {}".format(cmd_id))
     return proto.cmd_by_id[cmd_id]
Пример #3
0
async def stream_transport_messages(transport: TransportAPI,
                                    base_protocol: BaseP2PProtocol,
                                    *protocols: ProtocolAPI,
                                    ) -> AsyncIterator[Tuple[ProtocolAPI, CommandAPI[Any]]]:
    """
    Streams 2-tuples of (Protocol, Command) over the provided `Transport`
    """
    # A cache for looking up the proper protocol instance for a given command
    # id.
    command_id_cache: Dict[int, ProtocolAPI] = {}

    while not transport.is_closing:
        try:
            msg = await transport.recv()
        except PeerConnectionLost:
            return

        command_id = msg.command_id

        if msg.command_id not in command_id_cache:
            if command_id < base_protocol.command_length:
                command_id_cache[command_id] = base_protocol
            else:
                for protocol in protocols:
                    if command_id < protocol.command_id_offset + protocol.command_length:
                        command_id_cache[command_id] = protocol
                        break
                else:
                    protocol_infos = '  '.join(tuple(
                        (
                            f"{proto.name}@{proto.version}"
                            f"[offset={proto.command_id_offset},"
                            f"command_length={proto.command_length}]"
                        )
                        for proto in cons(base_protocol, protocols)
                    ))
                    raise UnknownProtocolCommand(
                        f"No protocol found for command_id {command_id}: Available "
                        f"protocol/offsets are: {protocol_infos}"
                    )

        msg_proto = command_id_cache[command_id]
        command_type = msg_proto.get_command_type_for_command_id(command_id)

        try:
            cmd = command_type.decode(msg, msg_proto.snappy_support)
        except (rlp.exceptions.DeserializationError, snappy_CompressedLengthError) as err:
            raise MalformedMessage(f"Failed to decode {msg} for {command_type}") from err

        yield msg_proto, cmd

        # yield to the event loop for a moment to allow `transport.is_closing`
        # a chance to update.
        await asyncio.sleep(0)
Пример #4
0
 def add_command_handler(
     self,
     command_type: Type[CommandAPI[Any]],
     handler_fn: HandlerFn,
 ) -> SubscriptionAPI:
     for protocol in self._multiplexer.get_protocols():
         if protocol.supports_command(command_type):
             self._command_handlers[command_type].add(handler_fn)
             cancel_fn = functools.partial(
                 self._command_handlers[command_type].remove,
                 handler_fn,
             )
             return Subscription(cancel_fn)
     else:
         raise UnknownProtocolCommand(
             f"Command {command_type} was not found in the connected "
             f"protocols: {self._multiplexer.get_protocols()}")
Пример #5
0
async def stream_transport_messages(transport: TransportAPI,
                                    base_protocol: BaseP2PProtocol,
                                    *protocols: ProtocolAPI,
                                    token: CancelToken = None,
                                    ) -> AsyncIterator[Tuple[ProtocolAPI, CommandAPI, Payload]]:
    """
    Streams 3-tuples of (Protocol, Command, Payload) over the provided `Transport`
    """
    # A cache for looking up the proper protocol instance for a given command
    # id.
    cmd_id_cache: Dict[int, ProtocolAPI] = {}

    while not transport.is_closing:
        raw_msg = await transport.recv(token)

        cmd_id = get_devp2p_cmd_id(raw_msg)

        if cmd_id not in cmd_id_cache:
            if cmd_id < base_protocol.cmd_length:
                cmd_id_cache[cmd_id] = base_protocol
            else:
                for protocol in protocols:
                    if cmd_id < protocol.cmd_id_offset + protocol.cmd_length:
                        cmd_id_cache[cmd_id] = protocol
                        break
                else:
                    protocol_infos = '  '.join(tuple(
                        f"{proto.name}@{proto.version}[offset={proto.cmd_id_offset},cmd_length={proto.cmd_length}]"  # noqa: E501
                        for proto in cons(base_protocol, protocols)
                    ))
                    raise UnknownProtocolCommand(
                        f"No protocol found for cmd_id {cmd_id}: Available "
                        f"protocol/offsets are: {protocol_infos}"
                    )

        msg_proto = cmd_id_cache[cmd_id]
        cmd = msg_proto.cmd_by_id[cmd_id]
        msg = cmd.decode(raw_msg)

        yield msg_proto, cmd, msg

        # yield to the event loop for a moment to allow `transport.is_closing`
        # a chance to update.
        await asyncio.sleep(0)
Пример #6
0
async def stream_transport_messages(
    transport: TransportAPI,
    base_protocol: BaseP2PProtocol,
    *protocols: ProtocolAPI,
    token: CancelToken = None,
) -> AsyncIterator[Tuple[ProtocolAPI, CommandAPI[Any]]]:
    """
    Streams 2-tuples of (Protocol, Command) over the provided `Transport`
    """
    # A cache for looking up the proper protocol instance for a given command
    # id.
    command_id_cache: Dict[int, ProtocolAPI] = {}

    while not transport.is_closing:
        msg = await transport.recv(token)
        command_id = msg.command_id

        if msg.command_id not in command_id_cache:
            if command_id < base_protocol.command_length:
                command_id_cache[command_id] = base_protocol
            else:
                for protocol in protocols:
                    if command_id < protocol.command_id_offset + protocol.command_length:
                        command_id_cache[command_id] = protocol
                        break
                else:
                    protocol_infos = '  '.join(
                        tuple((f"{proto.name}@{proto.version}"
                               f"[offset={proto.command_id_offset},"
                               f"command_length={proto.command_length}]")
                              for proto in cons(base_protocol, protocols)))
                    raise UnknownProtocolCommand(
                        f"No protocol found for command_id {command_id}: Available "
                        f"protocol/offsets are: {protocol_infos}")

        msg_proto = command_id_cache[command_id]
        command_type = msg_proto.get_command_type_for_command_id(command_id)
        cmd = command_type.decode(msg, msg_proto.snappy_support)

        yield msg_proto, cmd

        # yield to the event loop for a moment to allow `transport.is_closing`
        # a chance to update.
        await asyncio.sleep(0)
Пример #7
0
async def stream_transport_messages(transport: TransportAPI,
                                    base_protocol: BaseP2PProtocol,
                                    *protocols: ProtocolAPI,
                                    ) -> AsyncIterator[Tuple[ProtocolAPI, CommandAPI[Any]]]:
    """
    Streams 2-tuples of (Protocol, Command) over the provided `Transport`

    Raises a TimeoutError if nothing is received in constants.CONN_IDLE_TIMEOUT seconds.
    """
    # A cache for looking up the proper protocol instance for a given command
    # id.
    command_id_cache: Dict[int, ProtocolAPI] = {}
    loop = asyncio.get_event_loop()

    while not transport.is_closing:
        try:
            msg = await transport.recv()
        except PeerConnectionLost:
            transport.logger.debug(
                "Lost connection to %s, leaving stream_transport_messages()", transport.remote)
            return

        command_id = msg.command_id

        if msg.command_id not in command_id_cache:
            if command_id < base_protocol.command_length:
                command_id_cache[command_id] = base_protocol
            else:
                for protocol in protocols:
                    if command_id < protocol.command_id_offset + protocol.command_length:
                        command_id_cache[command_id] = protocol
                        break
                else:
                    protocol_infos = '  '.join(tuple(
                        (
                            f"{proto.name}@{proto.version}"
                            f"[offset={proto.command_id_offset},"
                            f"command_length={proto.command_length}]"
                        )
                        for proto in cons(base_protocol, protocols)
                    ))
                    raise UnknownProtocolCommand(
                        f"No protocol found for command_id {command_id}: Available "
                        f"protocol/offsets are: {protocol_infos}"
                    )

        msg_proto = command_id_cache[command_id]
        command_type = msg_proto.get_command_type_for_command_id(command_id)

        try:
            if len(msg.body) > MAX_IN_LOOP_DECODE_SIZE:
                cmd = await loop.run_in_executor(
                    None,
                    command_type.decode,
                    msg,
                    msg_proto.snappy_support,
                )
            else:
                cmd = command_type.decode(msg, msg_proto.snappy_support)

        except (rlp.exceptions.DeserializationError, snappy_CompressedLengthError) as err:
            raise MalformedMessage(f"Failed to decode {msg} for {command_type}") from err

        yield msg_proto, cmd

        # yield to the event loop for a moment to allow `transport.is_closing`
        # a chance to update.
        await asyncio.sleep(0)