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.
 
 

144 lines
4.1 KiB

import logging
import gevent
from eventemitter import EventEmitter
from steam.enums.emsg import EMsg
from steam.enums import EResult
from steam.core.msg import MsgProto
from steam.core.cm import CMClient
from steam import SteamID
from steam.client.jobs import JobManager
logger = logging.getLogger("SteamClient")
class SteamClient(EventEmitter):
def __init__(self):
self.cm = CMClient()
self.job = JobManager(self)
# re-emit all events from CMClient
self.cm.on(None, self.emit)
# register listners
self.on(EMsg.ClientLogOnResponse, self._handle_logon)
self.on("disconnected", self._handle_disconnect)
self.logged_on = False
def __repr__(self):
return "<%s() %s>" % (self.__class__.__name__,
'online' if self.connected else 'offline',
)
def emit(self, event, *args):
if event is not None:
logger.debug("Emit event: %s" % repr(event))
super(SteamClient, self).emit(event, *args)
@property
def steam_id(self):
return self.cm.steam_id
@property
def connected(self):
return self.cm.connected
def connect(self):
self.cm.connect()
def disconnect(self):
self.cm.disconnect()
def _handle_disconnect(self):
self.logged_on = False
def _handle_logon(self, msg):
result = EResult(msg.body.eresult)
if result == EResult.OK:
self.logged_on = True
self.emit("logged_on")
return
# CM kills the connection on error anyway
self.disconnect()
if result in (EResult.AccountLogonDenied,
EResult.AccountLoginDeniedNeedTwoFactor,
EResult.TwoFactorCodeMismatch,
):
self.emit("auth_code_required", result)
else:
self.emit("error", result)
def send(self, message):
if not self.connected:
raise RuntimeError("Cannot send message while not connected")
self.cm.send_message(message)
def _pre_login(self):
if self.logged_on:
logger.debug("Trying to login while logged on???")
raise RuntimeError("Already logged on")
if not self.connected:
self.connect()
if not self.cm.channel_secured:
self.wait_event("channel_secured")
def anonymous_login(self):
logger.debug("Attempting Anonymous login")
self._pre_login()
message = MsgProto(EMsg.ClientLogon)
message.header.steamid = SteamID(type='AnonUser', universe='Public')
message.body.protocol_version = 65575
self.send(message)
def login(self, username, password, auth_code=None, two_factor_code=None, remember=False):
logger.debug("Attempting login")
self._pre_login()
message = MsgProto(EMsg.ClientLogon)
message.header.steamid = SteamID(type='Individual', universe='Public')
message.body.protocol_version = 65575
message.body.client_package_version = 1771
message.body.client_os_type = 13
message.body.client_language = "english"
message.body.account_name = username
message.body.password = password
if auth_code:
message.body.auth_code = auth_code
if two_factor_code:
message.body.two_factor_code = two_factor_code
self.send(message)
def logout(self):
if self.logged_on:
self.logged_on = False
self.send(MsgProto(EMsg.ClientLogOff))
self.wait_event('disconnected')
def run_forever(self):
while True:
gevent.sleep(300)
def games_played(self, app_ids):
if not isinstance(app_ids, list):
raise ValueError("Expected app_ids to be of type list")
app_ids = map(int, app_ids)
message = MsgProto(EMsg.ClientGamesPlayed)
GamePlayed = message.body.GamePlayed
message.body.games_played.extend(map(lambda x: GamePlayed(game_id=x), app_ids))
self.send(message)