2 from struct import Struct
8 HEADER = b"\xFF\xFF\xFF\xFF"
11 @attr.s(auto_attribs=True, frozen=True, slots=True)
12 class CLGetServersExt(Writable):
16 def encode(self) -> bytes:
17 return HEADER + f"getserversExt {self.game} {self.protocol} empty full".encode(UTF_8)
20 @attr.s(auto_attribs=True, frozen=True, slots=True)
21 class SVGetServersExtResponse(Readable):
22 @attr.s(auto_attribs=True, frozen=True, slots=True)
31 def decode(cls) -> Generator[Optional["SVGetServersExtResponse"], bytes, None]:
32 end = SVGetServersExtResponse.Server("", 0)
34 ipv6 = Struct(">16sH")
36 def servers() -> Iterator[SVGetServersExtResponse.Server]:
39 h = buf[offset:offset + 1]
48 assert False, f"unknown record type: {h}"
50 it = record.unpack_from(buf, offset)
53 if addr == b"EOT\x00" and port == 0:
56 addr = ipaddress.IPv4Address(addr)
57 yield SVGetServersExtResponse.Server(addr=addr, port=port)
60 addr = ipaddress.IPv6Address(addr)
61 yield SVGetServersExtResponse.Server(addr=addr, port=port)
64 chunks: List[List[SVGetServersExtResponse.Server]] = []
65 ret: Optional[SVGetServersExtResponse] = None
72 chunk = list(servers())
76 ret = SVGetServersExtResponse(servers=[x for l in chunks for x in l])
80 SVMessage = Union[SVGetServersExtResponse]
84 def sv_parse() -> Generator[Optional[SVMessage], bytes, None]:
85 getservers_ext_response = b"getserversExtResponse"
86 getservers_ext_gen: Optional[Generator[Optional[SVGetServersExtResponse], bytes, None]] = None
87 ret: Optional[SVMessage] = None
92 if buf.startswith(HEADER):
93 buf = buf[len(HEADER):]
94 if buf.startswith(getservers_ext_response):
95 buf = buf[len(getservers_ext_response):]
96 if not getservers_ext_gen:
97 getservers_ext_gen = SVGetServersExtResponse.decode()
98 assert getservers_ext_gen
99 ret = getservers_ext_gen.send(buf)
101 getservers_ext_gen = None