Browse Source

Outsource packet type into Header

While at it, make LoginRequest a subclass of str.
pull/8/head 2.0.5
Richard Neumann 3 years ago
parent
commit
5532de7e6e
  1. 2
      rcon/battleye/client.py
  2. 65
      rcon/battleye/proto.py

2
rcon/battleye/client.py

@ -64,7 +64,7 @@ class Client(BaseClient, socket_type=SOCK_DGRAM):
def login(self, passwd: str) -> bool: def login(self, passwd: str) -> bool:
"""Logs the user in.""" """Logs the user in."""
if not self.communicate(LoginRequest.from_passwd(passwd)).success: if not self.communicate(LoginRequest(passwd)).success:
raise WrongPassword() raise WrongPassword()
return True return True

65
rcon/battleye/proto.py

@ -18,88 +18,82 @@ __all__ = [
PREFIX = 'BE' PREFIX = 'BE'
SUFFIX = 0xff INFIX = 0xff
class Header(NamedTuple): class Header(NamedTuple):
"""Packet header.""" """Packet header."""
prefix: str
crc32: int crc32: int
suffix: int type: int
def __bytes__(self): def __bytes__(self):
return b''.join(( return b''.join((
self.prefix.encode('ascii'), PREFIX.encode('ascii'),
self.crc32.to_bytes(4, 'little'), self.crc32.to_bytes(4, 'little'),
self.suffix.to_bytes(1, 'little') INFIX.to_bytes(1, 'little'),
self.type.to_bytes(1, 'little')
)) ))
@classmethod @classmethod
def from_payload(cls, payload: bytes): def create(cls, typ: int, payload: bytes):
"""Creates a header for the given payload.""" """Creates a header for the given payload."""
return cls( return cls(
PREFIX, crc32(b''.join((
crc32(SUFFIX.to_bytes(1, 'little') + payload), INFIX.to_bytes(1, 'little'),
SUFFIX typ.to_bytes(1, 'little'),
payload
))),
typ
) )
@classmethod @classmethod
def from_bytes(cls, payload: bytes): def from_bytes(cls, payload: bytes):
"""Creates a header from the given bytes.""" """Creates a header from the given bytes."""
if (prefix := payload[:2].decode('ascii')) != PREFIX:
raise ValueError('Invalid prefix', prefix)
if (infix := int.from_bytes(payload[5:6], 'little')) != INFIX:
raise ValueError('Invalid infix', infix)
return cls( return cls(
payload[:2].decode('ascii'),
int.from_bytes(payload[2:5], 'little'), int.from_bytes(payload[2:5], 'little'),
int.from_bytes(payload[5:6], 'little') int.from_bytes(payload[6:7], 'little')
) )
class LoginRequest(NamedTuple): class LoginRequest(str):
"""Login request packet.""" """Login request packet."""
type: int
passwd: str
def __bytes__(self): def __bytes__(self):
return bytes(self.header) + self.payload return bytes(self.header) + self.payload
@property @property
def payload(self) -> bytes: def payload(self) -> bytes:
"""Returns the payload.""" """Returns the payload."""
return self.type.to_bytes(1, 'little') + self.passwd.encode('ascii') return self.encode('ascii')
@property @property
def header(self) -> Header: def header(self) -> Header:
"""Returns the appropriate header.""" """Returns the appropriate header."""
return Header.from_payload(self.payload) return Header.create(0x00, self.payload)
@classmethod
def from_passwd(cls, passwd: str):
"""Creates a login request with the given password."""
return cls(0x00, passwd)
class LoginResponse(NamedTuple): class LoginResponse(NamedTuple):
"""A login response.""" """A login response."""
header: Header header: Header
type: int
success: bool success: bool
@classmethod @classmethod
def from_bytes(cls, header: Header, payload: bytes): def from_bytes(cls, header: Header, payload: bytes):
"""Creates a login response from the given bytes.""" """Creates a login response from the given bytes."""
return cls( return cls(header, bool(int.from_bytes(payload[:1], 'little')))
header,
int.from_bytes(payload[:1], 'little'),
bool(int.from_bytes(payload[2:3], 'little'))
)
class Command(NamedTuple): class Command(NamedTuple):
"""Command packet.""" """Command packet."""
type: int
seq: int seq: int
command: str command: str
@ -110,7 +104,6 @@ class Command(NamedTuple):
def payload(self) -> bytes: def payload(self) -> bytes:
"""Returns the payload.""" """Returns the payload."""
return b''.join(( return b''.join((
self.type.to_bytes(1, 'little'),
self.seq.to_bytes(1, 'little'), self.seq.to_bytes(1, 'little'),
self.command.encode('ascii') self.command.encode('ascii')
)) ))
@ -118,12 +111,12 @@ class Command(NamedTuple):
@property @property
def header(self) -> Header: def header(self) -> Header:
"""Returns the appropriate header.""" """Returns the appropriate header."""
return Header.from_payload(self.payload) return Header.create(0x01, self.payload)
@classmethod @classmethod
def from_string(cls, command: str): def from_string(cls, command: str):
"""Creates a command packet from the given string.""" """Creates a command packet from the given string."""
return cls(0x01, 0x00, command) return cls(0x00, command)
@classmethod @classmethod
def from_command(cls, command: str, *args: str): def from_command(cls, command: str, *args: str):
@ -135,7 +128,6 @@ class CommandResponse(NamedTuple):
"""A command response.""" """A command response."""
header: Header header: Header
type: int
seq: int seq: int
payload: bytes payload: bytes
@ -145,8 +137,7 @@ class CommandResponse(NamedTuple):
return cls( return cls(
header, header,
int.from_bytes(payload[:1], 'little'), int.from_bytes(payload[:1], 'little'),
int.from_bytes(payload[1:2], 'little'), payload[1:]
payload[2:]
) )
@property @property
@ -159,7 +150,6 @@ class ServerMessage(NamedTuple):
"""A message from the server.""" """A message from the server."""
header: Header header: Header
type: int
seq: int seq: int
payload: bytes payload: bytes
@ -169,8 +159,7 @@ class ServerMessage(NamedTuple):
return cls( return cls(
header, header,
int.from_bytes(payload[:1], 'little'), int.from_bytes(payload[:1], 'little'),
int.from_bytes(payload[1:2], 'little'), payload[1:]
payload[2:]
) )
@property @property

Loading…
Cancel
Save