import struct import binascii import logging import zipfile try: from cStringIO import StringIO except ImportError: from StringIO import StringIO import gevent from gevent import event from gevent import queue from Crypto.Random import random from steam.steamid import SteamID from steam.enums import EResult, EUniverse from steam.enums.emsg import EMsg from steam.client import crypto from steam.client.connection import TCPConnection from steam.client.msg import is_proto, clear_proto_bit from steam.client.msg import Msg, MsgProto server_list = [ ('162.254.196.41', '27020'), ('162.254.196.40', '27021'), ('162.254.196.43', '27019'), ('162.254.196.40', '27018'), ('162.254.196.43', '27020'), ('162.254.196.41', '27019'), ('162.254.196.41', '27018'), ('162.254.196.42', '27020'), ('162.254.196.41', '27017'), ('162.254.196.41', '27021'), ('146.66.152.10', '27017'), ('146.66.152.10', '27018'), ('146.66.152.11', '27019'), ('146.66.152.11', '27020'), ('146.66.152.10', '27019'), ('162.254.197.42', '27018'), ('162.254.197.41', '27019'), ('162.254.197.41', '27017'), ('208.78.164.14', '27017'), ('208.78.164.14', '27019'), ('208.78.164.9', '27019'), ('208.78.164.14', '27018'), ('208.78.164.9', '27018'), ('208.78.164.13', '27017'), ] logger = logging.getLogger("CMClient") class CMClient: TCP = 0 UDP = 1 def __init__(self, protocol=0): self.reconnect = False self._init_attributes() self.registered_callbacks = {} if protocol == CMClient.TCP: self.connection = TCPConnection() # elif protocol == CMClient.UDP: # self.connection = UDPConnection() else: raise ValueError("Only TCP is supported") self.event_connected = event.Event() self.event_ready = event.Event() self.event_disconnected = event.Event() self.register_callback(EMsg.ChannelEncryptRequest, self._handle_encrypt_request), self.register_callback(EMsg.Multi, self._handle_multi), self.register_callback(EMsg.ClientLogOnResponse, self._handle_logon), def connect(self, reconnect=None): if reconnect is not None: self.reconnect = reconnect logger.debug("Connect (reconnect=%s)" % self.reconnect) while True: with gevent.Timeout(15, False): server_addr = random.choice(server_list) self.connection.connect(server_addr) if not self.connection.event_connected.is_set(): if self.reconnect: logger.debug("Failed to connect. Retrying...") continue logger.debug("Failed to connect") return False break logger.debug("Event: Connected") self.event_connected.set() self._recv_loop = gevent.spawn(self._recv_messages) return True def disconnect(self): self.connection.disconnect() self._recv_loop.kill(block=False) self._heartbeat_loop.kill() self._init_attributes() self.event_connected.clear() self.event_ready.clear() self.event_disconnected.set() logger.debug("Event: Disconnected") def _init_attributes(self): self.key = None self.steam_id = None self.session_id = None self.cell_id = None self.webapi_nonce = None self._recv_loop = None self._heartbeat_loop = None def send_message(self, message): if not isinstance(message, (Msg, MsgProto)): raise ValueError("Expected Msg or MsgProto, got %s" % message) data = message.serialize() if self.key: data = crypto.encrypt(data, self.key) logger.debug("Outgoing: %s", repr(message.msg)) self.connection.put_message(data) def _recv_messages(self): while True: try: message = self.connection.get_message(timeout=1) except queue.Empty: if not self.connection.event_connected.is_set(): self.disconnect() if self.reconnect: gevent.spawn(self.connect) return continue if self.key: message = crypto.decrypt(message, self.key) self._parse_message(message) def _parse_message(self, message): emsg_id, = struct.unpack_from(" 0: size, = struct.unpack_from("