From 4cc07bedad5435490e9720405d4b4811c305aa6d Mon Sep 17 00:00:00 2001 From: Rossen Georgiev Date: Sat, 10 Nov 2018 14:16:49 +0000 Subject: [PATCH] tweak UM and update guard and gameservers --- steam/client/builtins/__init__.py | 2 +- steam/client/builtins/gameservers.py | 94 +++++++++++++++-------- steam/client/builtins/unified_messages.py | 21 +++-- steam/guard.py | 9 ++- 4 files changed, 77 insertions(+), 49 deletions(-) diff --git a/steam/client/builtins/__init__.py b/steam/client/builtins/__init__.py index 2e0f2f5..22d682b 100644 --- a/steam/client/builtins/__init__.py +++ b/steam/client/builtins/__init__.py @@ -10,7 +10,7 @@ from steam.client.builtins.gameservers import GameServers from steam.client.builtins.friends import Friends from steam.client.builtins.apps import Apps -class BuiltinBase(Account, User, Web, UnifiedMessages, Leaderboards, GameServers, Friends, Apps): +class BuiltinBase(GameServers, UnifiedMessages, Account, User, Web, Leaderboards, Friends, Apps): """ This object is used as base to implement all high level functionality. The features are separated into submodules. diff --git a/steam/client/builtins/gameservers.py b/steam/client/builtins/gameservers.py index 93a8b28..d0fcaec 100644 --- a/steam/client/builtins/gameservers.py +++ b/steam/client/builtins/gameservers.py @@ -49,9 +49,10 @@ class GameServers(object): class SteamGameServers(object): def __init__(self, steam): - self.steam = steam + self._s = steam + self._um = steam.unified_messages - def query(self, filter_text, max_servers=10, **kwargs): + def query(self, filter_text, max_servers=10, timeout=30, **kw): r""" Query game servers @@ -62,13 +63,15 @@ class SteamGameServers(object): as literal characters (e.g. ``query(r'\appid\730\white\1')``) :param filter_text: filter for servers - :type filter_text: str + :type filter_text: str :param max_servers: (optional) number of servers to return - :type max_servers: int + :type max_servers: int + :param timeout: (optional) timeout for request in seconds + :type timeout: int :param app_id: (optional) app id - :type app_id: int + :type app_id: int :param geo_location_ip: (optional) ip (e.g. '1.2.3.4') - :type geo_location_ip: str + :type geo_location_ip: str :returns: list of servers, see below. (``None`` is returned steam doesn't respond) :rtype: :class:`list`, :class:`None` @@ -81,15 +84,19 @@ class SteamGameServers(object): ... ] """ - if 'geo_location_ip' in kwargs: - kwargs['geo_location_ip'] = ip_to_int(kwargs['geo_location_ip']) + if 'geo_location_ip' in kw: + kw['geo_location_ip'] = ip_to_int(kw['geo_location_ip']) - kwargs['filter_text'] = filter_text - kwargs['max_servers'] = max_servers + kw['filter_text'] = filter_text + kw['max_servers'] = max_servers - resp = self.steam.send_job_and_wait(MsgProto(EMsg.ClientGMSServerQuery), kwargs, timeout=30) + resp = self._s.send_job_and_wait(MsgProto(EMsg.ClientGMSServerQuery), + kw, + timeout=timeout, + ) - if resp is None: return None + if resp is None: + return None resp = proto_to_dict(resp) @@ -98,16 +105,19 @@ class SteamGameServers(object): return resp['servers'] - def get_server_list(self, filter_text, max_servers=10): + def get_server_list(self, filter_text, max_servers=10, timeout=20): """ Get list of servers. Works similiarly to :meth:`query`, but the response has more details. :param filter_text: filter for servers - :type filter_text: str + :type filter_text: str :param max_servers: (optional) number of servers to return - :type max_servers: int + :type max_servers: int + :param timeout: (optional) timeout for request in seconds + :type timeout: int :returns: list of servers, see below. (``None`` is returned steam doesn't respond) :rtype: :class:`list`, :class:`None` + :raises: :class:`.UnifiedMessageError` Sample response: @@ -133,11 +143,16 @@ class SteamGameServers(object): 'version': '1.35.4.0'} ] """ - resp = self.steam.unified_messages.send_and_wait("GameServers.GetServerList#1", { - "filter": filter_text, - "limit": max_servers, - }, timeout=20) - + resp, error = self._um.send_and_wait("GameServers.GetServerList#1", + { + "filter": filter_text, + "limit": max_servers, + }, + timeout=20, + ) + + if error: + raise error if resp is None: return None @@ -151,13 +166,16 @@ class SteamGameServers(object): return resp['servers'] - def get_ips_from_steamid(self, server_steam_ids): + def get_ips_from_steamids(self, server_steam_ids, timeout=30): """Resolve IPs from SteamIDs :param server_steam_ids: a list of steamids - :type server_steam_ids: list + :type server_steam_ids: list + :param timeout: (optional) timeout for request in seconds + :type timeout: int :return: map of ips to steamids :rtype: dict + :raises: :class:`.UnifiedMessageError` Sample response: @@ -165,21 +183,27 @@ class SteamGameServers(object): {SteamID(id=123456, type='AnonGameServer', universe='Public', instance=1234): '1.2.3.4:27060'} """ - resp = self.steam.unified_messages.send_and_wait("GameServers.GetServerIPsBySteamID#1", { - "server_steamids": server_steam_ids, - }, timeout=30) - - if resp is None: return None + resp, error = self._um.send_and_wait("GameServers.GetServerIPsBySteamID#1", + {"server_steamids": server_steam_ids}, + timeout=timeout, + ) + if error: + raise error + if resp is None: + return None return {SteamID(server.steamid): server.addr for server in resp.servers} - def get_steamids_from_ip(self, server_ips): + def get_steamids_from_ips(self, server_ips, timeout=30): """Resolve SteamIDs from IPs :param steam_ids: a list of ips (e.g. ``['1.2.3.4:27015',...]``) - :type steam_ids: list + :type steam_ids: list + :param timeout: (optional) timeout for request in seconds + :type timeout: int :return: map of steamids to ips :rtype: dict + :raises: :class:`.UnifiedMessageError` Sample response: @@ -187,10 +211,14 @@ class SteamGameServers(object): {'1.2.3.4:27060': SteamID(id=123456, type='AnonGameServer', universe='Public', instance=1234)} """ - resp = self.steam.unified_messages.send_and_wait("GameServers.GetServerSteamIDsByIP#1", { - "server_ips": server_ips, - }, timeout=30) + resp, error = self._um.send_and_wait("GameServers.GetServerSteamIDsByIP#1", + {"server_ips": server_ips}, + timeout=timeout, + ) - if resp is None: return None + if error: + raise error + if resp is None: + return None return {server.addr: SteamID(server.steamid) for server in resp.servers} diff --git a/steam/client/builtins/unified_messages.py b/steam/client/builtins/unified_messages.py index 3508bd8..af20dec 100644 --- a/steam/client/builtins/unified_messages.py +++ b/steam/client/builtins/unified_messages.py @@ -36,8 +36,8 @@ class UnifiedMessages(object): self.unified_messages = SteamUnifiedMessages(self, name) #: instance of :class:`SteamUnifiedMessages` -class UnifiedMessageError(object): - def __init__(self, eresult, message): +class UnifiedMessageError(Exception): + def __init__(self, message, eresult=EResult.Invalid): self.eresult = eresult self.message = message @@ -45,7 +45,8 @@ class UnifiedMessageError(object): return "%s(%s, %s)" % (self.__class__.__name__, self.eresult, repr(self.message)) def __str__(self): - return self.message + return "(%s) %s" % (self.eresult, self.message) + class SteamUnifiedMessages(EventEmitter): @@ -80,10 +81,9 @@ class SteamUnifiedMessages(EventEmitter): error = None if message.header.eresult != EResult.OK: - self._LOG.error("%s (%s): %s" % (method_name, repr(EResult(message.header.eresult)), - message.header.error_message)) - error = UnifiedMessageError(EResult(message.header.eresult), - message.header.error_message) + error = UnifiedMessageError(message.header.error_message, + EResult(message.header.eresult), + ) resp = proto() resp.ParseFromString(message.body.serialized_method_response) @@ -139,7 +139,7 @@ class SteamUnifiedMessages(EventEmitter): return self._steam.send_job(capsule) - def send_and_wait(self, message, params=None, timeout=None, raises=False): + def send_and_wait(self, message, params=None, timeout=10, raises=False): """Send service method request and wait for response :param message: @@ -158,7 +158,4 @@ class SteamUnifiedMessages(EventEmitter): """ job_id = self.send(message, params) resp = self.wait_event(job_id, timeout, raises=raises) - if resp is None and not raises: - return None - else: - return resp + return (None, None) if resp is None else resp diff --git a/steam/guard.py b/steam/guard.py index 123e349..cbcfbb0 100644 --- a/steam/guard.py +++ b/steam/guard.py @@ -132,10 +132,13 @@ class SteamAuthenticator(object): if not medium.logged_on: raise SteamAuthenticatorError("SteamClient instance not logged in") - resp = medium.unified_messages.send_and_wait("TwoFactor.%s#1" % action, - params, timeout=10) + resp, error = medium.unified_messages.send_and_wait("TwoFactor.%s#1" % action, + params, timeout=10) + + if error: + raise SteamAuthenticatorError("Failed: %s" % str(error)) if resp is None: - raise SteamAuthenticatorError("Failed to add authenticator. Request timeout") + raise SteamAuthenticatorError("Failed. Request timeout") resp = proto_to_dict(resp)