diff --git a/steam/client/__init__.py b/steam/client/__init__.py index 3142295..d97a920 100644 --- a/steam/client/__init__.py +++ b/steam/client/__init__.py @@ -109,10 +109,15 @@ class SteamClient(CMClient, BuiltinBase): jobid = msg.header.targetJobID if jobid not in (-1, 18446744073709551615): - self.emit("job_%d" % jobid, msg) + jobid = "job_%d" % jobid + if msg.body is None and self.count_listeners(jobid): + msg.parse() + self.emit(jobid, msg) # emit UMs - if emsg in (EMsg.ServiceMethodResponse, EMsg.ServiceMethodSendToClient): + if emsg in (EMsg.ServiceMethod, EMsg.ServiceMethodResponse, EMsg.ServiceMethodSendToClient): + if msg.body is None and self.count_listeners(msg.header.target_job_name): + msg.parse() self.emit(msg.header.target_job_name, msg) def _bootstrap_cm_list_from_file(self): diff --git a/steam/core/cm.py b/steam/core/cm.py index 2102c6f..57d0ff2 100644 --- a/steam/core/cm.py +++ b/steam/core/cm.py @@ -247,6 +247,10 @@ class CMClient(EventEmitter): emsg = EMsg(clear_proto_bit(emsg_id)) if not self.connected and emsg != EMsg.ClientLogOnResponse: + self._LOG.debug("Dropped unexpected message: %s (is_proto: %s)", + repr(emsg), + is_proto(emsg_id), + ) return if emsg in (EMsg.ChannelEncryptRequest, @@ -254,13 +258,13 @@ class CMClient(EventEmitter): EMsg.ChannelEncryptResult, ): - msg = Msg(emsg, message) + msg = Msg(emsg, message, parse=False) else: try: if is_proto(emsg_id): - msg = MsgProto(emsg, message) + msg = MsgProto(emsg, message, parse=False) else: - msg = Msg(emsg, message, extended=True) + msg = Msg(emsg, message, extended=True, parse=False) except Exception as e: self._LOG.fatal("Failed to deserialize message: %s (is_proto: %s)", repr(emsg), @@ -269,6 +273,9 @@ class CMClient(EventEmitter): self._LOG.exception(e) return + if self.count_listeners(emsg) or self.verbose_debug: + msg.parse() + if self.verbose_debug: self._LOG.debug("Incoming: %s\n%s" % (repr(msg), str(msg))) else: diff --git a/steam/core/msg/__init__.py b/steam/core/msg/__init__.py index c68a79a..d1eaab3 100644 --- a/steam/core/msg/__init__.py +++ b/steam/core/msg/__init__.py @@ -62,23 +62,30 @@ def get_cmsg(emsg): class Msg(object): proto = False - body = '!!! Unknown message body !!!' #: message instance + body = None #: message instance payload = None #: Will contain body payload, if we fail to find correct message class - def __init__(self, msg, data=None, extended=False): + def __init__(self, msg, data=None, extended=False, parse=True): self.extended = extended self.header = ExtendedMsgHdr(data) if extended else MsgHdr(data) self.msg = msg if data: - data = data[self.header._size:] + self.payload = data[self.header._size:] - deserializer = get_struct(msg) + if parse: + self.parse() - if deserializer: - self.body = deserializer(data) - else: - self.payload = data + def parse(self): + """Parses :attr:`payload` into :attr:`body` instance""" + if self.body is None: + deserializer = get_struct(self.msg) + + if deserializer: + self.body = deserializer(self.payload) + self.payload = None + else: + self.body = '!!! Failed to resolve message !!!' @property def msg(self): @@ -116,7 +123,10 @@ class Msg(object): self.header.sessionID = value def __repr__(self): - return "" % repr(self.msg) + return "" % ( + repr(self.msg), + ' (No Body)' if isinstance(self.body, str) else '', + ) def __str__(self): rows = ["Msg"] @@ -138,32 +148,36 @@ class Msg(object): class MsgProto(object): proto = True - body = '!!! Unknown message body !!!' #: protobuf message instance + body = None #: protobuf message instance payload = None #: Will contain body payload, if we fail to find correct proto message - def __init__(self, msg, data=None): + def __init__(self, msg, data=None, parse=True): self._header = MsgHdrProtoBuf(data) self.header = self._header.proto self.msg = msg - if msg in (EMsg.ServiceMethodResponse, EMsg.ServiceMethodSendToClient): - proto = get_um(self.header.target_job_name, response=True) - if proto: - self.body = proto() - else: - self.body = '!! Failed to resolve UM: %s !!' % repr(self.header.target_job_name) - else: - proto = get_cmsg(msg) + if data: + self.payload = data[self._header._fullsize:] - if proto: - self.body = proto() + if parse: + self.parse() + + def parse(self): + """Parses :attr:`payload` into :attr:`body` instance""" + if self.body is None: + if self.msg in (EMsg.ServiceMethod, EMsg.ServiceMethodResponse, EMsg.ServiceMethodSendToClient): + is_resp = False if self.msg == EMsg.ServiceMethod else True + proto = get_um(self.header.target_job_name, response=is_resp) + else: + proto = get_cmsg(self.msg) - if data: - data = data[self._header._fullsize:] if proto: - self.body.ParseFromString(data) + self.body = proto() + if self.payload: + self.body.ParseFromString(self.payload) + self.payload = None else: - self.payload = data + self.body = '!!! Failed to resolve message !!!' @property def msg(self): @@ -193,7 +207,10 @@ class MsgProto(object): self.header.client_sessionid = value def __repr__(self): - return "" % repr(self.msg) + return "" % ( + repr(self.msg), + ' (No Body)' if isinstance(self.body, str) else '', + ) def __str__(self): rows = ["MsgProto %s" % repr(self.msg)]