You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

198 lines
5.6 KiB

import fnmatch
from steam.core.msg_unified import get_um
from steam.core.msg_structs import get_struct
from steam.core.msg_headers import MsgHdr, ExtendedMsgHdr, MsgHdrProtoBuf, GCMsgHdr, GCMsgHdrProto
from steam.enums.emsg import EMsg
from steam.protobufs import steammessages_base_pb2
from steam.protobufs import steammessages_clientserver_pb2
from steam.protobufs import steammessages_clientserver_2_pb2
cmsg_lookup = None
cmsg_lookup2 = None
cmsg_lookup_predefined = {
EMsg.Multi: steammessages_base_pb2.CMsgMulti,
EMsg.ClientToGC: steammessages_clientserver_2_pb2.CMsgGCClient,
EMsg.ClientFromGC: steammessages_clientserver_2_pb2.CMsgGCClient,
EMsg.ServiceMethod: steammessages_clientserver_2_pb2.CMsgClientServiceMethod,
EMsg.ServiceMethodResponse: steammessages_clientserver_2_pb2.CMsgClientServiceMethodResponse,
EMsg.ClientGetNumberOfCurrentPlayersDP: steammessages_clientserver_2_pb2.CMsgDPGetNumberOfCurrentPlayers,
EMsg.ClientGetNumberOfCurrentPlayersDPResponse: steammessages_clientserver_2_pb2.CMsgDPGetNumberOfCurrentPlayersResponse,
}
def get_cmsg(emsg):
"""Get protobuf for a given EMsg
:param emsg: EMsg
:type emsg: :class:`steam.enums.emsg.EMsg`, :class:`int`
:return: protobuf message
"""
global cmsg_lookup, cmsg_lookup2
if not isinstance(emsg, EMsg):
emsg = EMsg(emsg)
if emsg in cmsg_lookup_predefined:
return cmsg_lookup_predefined[emsg]
else:
enum_name = emsg.name.lower()
if enum_name.startswith("econ"): # special case for 'EconTrading_'
enum_name = enum_name[4:]
cmsg_name = "cmsg" + enum_name
if not cmsg_lookup:
cmsg_list = steammessages_clientserver_pb2.__dict__
cmsg_list = fnmatch.filter(cmsg_list, 'CMsg*')
cmsg_lookup = dict(zip(map(lambda x: x.lower(), cmsg_list), cmsg_list))
name = cmsg_lookup.get(cmsg_name, None)
if name:
return getattr(steammessages_clientserver_pb2, name)
if not cmsg_lookup2:
cmsg_list = steammessages_clientserver_2_pb2.__dict__
cmsg_list = fnmatch.filter(cmsg_list, 'CMsg*')
cmsg_lookup2 = dict(zip(map(lambda x: x.lower(), cmsg_list), cmsg_list))
name = cmsg_lookup2.get(cmsg_name, None)
if name:
return getattr(steammessages_clientserver_2_pb2, name)
return None
class Msg(object):
proto = False
body = '!!! NO BODY !!!'
def __init__(self, msg, data=None, extended=False):
self.extended = extended
self.header = ExtendedMsgHdr(data) if extended else MsgHdr(data)
self.header.msg = msg
self.msg = msg
if data:
data = data[self.header._size:]
deserializer = get_struct(msg)
if deserializer:
self.body = deserializer(data)
def serialize(self):
return self.header.serialize() + self.body.serialize()
@property
def steamID(self):
return (self.header.steamID
if isinstance(self.header, ExtendedMsgHdr)
else None
)
@steamID.setter
def steamID(self, value):
if isinstance(self.header, ExtendedMsgHdr):
self.header.steamID = value
@property
def sessionID(self):
return (self.header.sessionID
if isinstance(self.header, ExtendedMsgHdr)
else None
)
@sessionID.setter
def sessionID(self, value):
if isinstance(self.header, ExtendedMsgHdr):
self.header.sessionID = value
def __repr__(self):
return "<Msg %s>" % repr(self.msg)
def __str__(self):
rows = ["Msg"]
header = str(self.header)
if header:
rows.append("-------------- header --")
rows.append(header)
body = str(self.body)
if body:
rows.append("---------------- body --")
rows.append(body)
if len(rows) == 1:
rows[0] += " (empty)"
return '\n'.join(rows)
class MsgProto(object):
proto = True
body = "!!! NO BODY !!!"
def __init__(self, msg, data=None):
self._header = MsgHdrProtoBuf(data)
self.msg = self._header.msg = msg
self.header = self._header.proto
if msg == EMsg.ServiceMethod:
proto = get_um(self.header.target_job_name)
if proto:
self.body = proto()
else:
self.body = '!! Can\'t resolve ServiceMethod: %s !!' % repr(self.header.target_job_name)
else:
proto = get_cmsg(msg)
if proto:
self.body = proto()
if data:
data = data[self._header._fullsize:]
self.body.ParseFromString(data)
def serialize(self):
return self._header.serialize() + self.body.SerializeToString()
@property
def steamID(self):
return self.header.steamid
@steamID.setter
def steamID(self, value):
self.header.steamid = value
@property
def sessionID(self):
return self.header.client_sessionid
@sessionID.setter
def sessionID(self, value):
self.header.client_sessionid = value
def __repr__(self):
return "<MsgProto %s>" % repr(self.msg)
def __str__(self):
rows = ["MsgProto"]
header = str(self.header).rstrip()
if header:
rows.append("-------------- header --")
rows.append(header)
body = str(self.body).rstrip()
if body:
rows.append("---------------- body --")
rows.append(body)
if len(rows) == 1:
rows[0] += " (empty)"
return '\n'.join(rows)