Source code for mcstatus._protocol.legacy_client
from time import perf_counter
from typing import ClassVar, final
from mcstatus._protocol.io.base_io import StructFormat
from mcstatus._protocol.io.connection import BaseAsyncConnection, BaseSyncConnection
from mcstatus.responses import LegacyStatusResponse
__all__ = ["AsyncLegacyClient", "LegacyClient"]
class _BaseLegacyClient:
request_status_data: ClassVar[bytes] = bytes.fromhex(
# see https://minecraft.wiki/w/Java_Edition_protocol/Server_List_Ping#Client_to_server
"fe01fa"
)
@staticmethod
def parse_response(data: bytes, latency: float) -> LegacyStatusResponse:
decoded_data: list[str] = data.decode("UTF-16BE").split("\0")
if decoded_data[0] != "§1":
# kick packets before 1.4 (12w42a) did not start with §1 and did
# not included information about server and protocol version
decoded_data = ["§1", "-1", "<1.4", *decoded_data[0].split("§")]
if len(decoded_data) != 6:
raise OSError("Received invalid kick packet reason")
return LegacyStatusResponse.build(decoded_data[1:], latency)
[docs]
@final
class LegacyClient(_BaseLegacyClient):
def __init__(self, connection: BaseSyncConnection) -> None:
self.connection = connection
[docs]
def read_status(self) -> LegacyStatusResponse:
"""Send the status request and read the response."""
start = perf_counter()
self.connection.write(self.request_status_data)
id = self.connection.read(1)
if id != b"\xff":
raise OSError("Received invalid packet ID")
length = self.connection.read_value(StructFormat.USHORT)
data = self.connection.read(length * 2)
end = perf_counter()
return self.parse_response(data, (end - start) * 1000)
[docs]
@final
class AsyncLegacyClient(_BaseLegacyClient):
def __init__(self, connection: BaseAsyncConnection) -> None:
self.connection = connection
[docs]
async def read_status(self) -> LegacyStatusResponse:
"""Send the status request and read the response."""
start = perf_counter()
await self.connection.write(self.request_status_data)
id = await self.connection.read(1)
if id != b"\xff":
raise OSError("Received invalid packet ID")
length = await self.connection.read_value(StructFormat.USHORT)
data = await self.connection.read(length * 2)
end = perf_counter()
return self.parse_response(data, (end - start) * 1000)