Esempio n. 1
0
async def handle_packet(stream: Stream):
    packet_length = 0

    # Basically an implementation of Buffer.unpack_varint()
    # except designed to read directly from a a StreamReader
    # and also to handle legacy server list ping packets
    for i in range(5):
        try:
            read = await asyncio.wait_for(stream.read(1), 5)
        except asyncio.TimeoutError:
            logger.debug("Closing due to timeout on read...")
            return False, stream

        if read == b"":
            logger.debug("Closing due to invalid read....")
            return False, stream

        if i == 0 and read == b"\xFE":
            logger.warn("Legacy ping attempted, legacy ping is not supported.")
            return False, stream

        b = struct.unpack("B", read)[0]
        packet_length |= (b & 0x7F) << 7 * i

        if not b & 0x80:
            break

    if packet_length & (1 << 31):
        packet_length -= 1 << 32

    buf = Buffer(await stream.read(packet_length))

    state = STATES.encode(states.get(stream.remote, 0))
    packet = buf.unpack_packet(state, PACKET_MAP)

    logger.debug(
        f"IN : state:{state:<11} | id:0x{packet.id:02X} | packet:{type(packet).__name__}"
    )

    for handler in pymine_api.packet.PACKET_HANDLERS[state][packet.id]:
        resp_value = await handler(stream, packet)

        try:
            continue_, stream = resp_value
        except (
                ValueError,
                TypeError,
        ):
            logger.warn(
                f"Invalid return from packet handler: {handler.__module__}.{handler.__qualname__}"
            )
            continue

        if not continue_:
            return False, stream

    return continue_, stream
Esempio n. 2
0
    async def handle_packet(
        self, stream: Stream
    ):  # Handle / respond to packets, this is called in a loop
        packet_length = 0

        # Basically an implementation of Buffer.unpack_varint()
        # except designed to read directly from a a StreamReader
        # and also to handle legacy server list ping packets
        for i in range(3):
            try:
                read = await asyncio.wait_for(stream.read(1), 30)
            except asyncio.TimeoutError:
                self.console.debug("Closing due to timeout on read...")
                raise StopHandling

            if read == b"":
                self.console.debug("Closing due to invalid read....")
                raise StopHandling

            if i == 0 and read == b"\xFE":
                self.console.warn("Legacy ping attempted, legacy ping is not supported.")
                raise StopHandling

            b = struct.unpack(">B", read)[0]
            packet_length |= (b & 0x7F) << 7 * i

            if not b & 0x80:
                break

        if packet_length & (1 << 31):
            packet_length -= 1 << 32

        buf = Buffer(await stream.read(packet_length))

        state = self.cache.states.get(stream.remote, 0)

        try:
            packet = buf.unpack_packet(state, PACKET_MAP)
        except InvalidPacketID:
            self.console.warn("Invalid packet ID received.")
            return stream

        self.console.debug(
            f"IN : state: {state} | id:0x{packet.id:02X} | packet:{type(packet).__name__}"
        )

        if self.api.register._on_packet[state].get(packet.id) is None:
            self.console.warn(
                f"No packet handler found for packet: 0x{packet.id:02X} {type(packet).__name__}"
            )
            return stream

        for handler in self.api.register._on_packet[state][packet.id].values():
            try:
                res = await handler(stream, packet)

                if isinstance(res, Stream):
                    stream = res
            except StopHandling:
                raise
            except BaseException as e:
                self.console.error(
                    f"Error occurred in {handler.__module__}.{handler.__qualname__}: {self.console.f_traceback(e)}"
                )

        return stream