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.
 
 

232 lines
7.9 KiB

import logging
from six import itervalues
from eventemitter import EventEmitter
from steam.steamid import SteamID, intBase
from steam.enums import EResult, EFriendRelationship
from steam.enums.emsg import EMsg
from steam.core.msg import MsgProto
from steam.client.user import SteamUser
class Friends(object):
def __init__(self, *args, **kwargs):
super(Friends, self).__init__(*args, **kwargs)
#: :class:`.SteamFriendlist` instance
self.friends = SteamFriendlist(self, logger_name="%s.friends" % self.__class__.__name__)
class SteamFriendlist(EventEmitter):
"""SteamFriendlist is an object that keeps state of user's friend list.
It's essentially a :class:`list` of :class:`.SteamUser`.
You can iterate over it, check if it contains a particular ``steam id``,
or get :class:`.SteamUser` for a ``steam id``.
"""
EVENT_READY = 'ready'
"""Friend list is ready for use
"""
EVENT_FRIEND_INVITE = 'friend_invite'
"""New or existing friend invite
:param user: steam user instance
:type user: :class:`.SteamUser`
"""
EVENT_FRIEND_NEW = 'friend_new'
"""Friendship established (after being accepted, or accepting)
:param user: steam user instance
:type user: :class:`.SteamUser`
"""
EVENT_FRIEND_REMOVED = 'friend_removed'
"""No longer a friend (removed by either side)
:param user: steam user instance
:type user: :class:`.SteamUser`
"""
EVENT_FRIEND_ADD_RESULT = 'friend_add_result'
"""Result response after adding a friend
:param eresult: result
:type eresult: :class:`.EResult`
:param steam_id: steam id
:type steam_id: :class:`.SteamID`
"""
ready = False #: indicates whether friend list is ready for use
def __init__(self, client, logger_name='SteamFriendList'):
self._LOG = logging.getLogger(logger_name)
self._fr = {}
self._steam = client
self._steam.on(EMsg.ClientAddFriendResponse, self._handle_add_friend_result)
self._steam.on(EMsg.ClientFriendsList, self._handle_friends_list)
self._steam.on(self._steam.EVENT_DISCONNECTED, self._handle_disconnect)
def emit(self, event, *args):
if event is not None:
self._LOG.debug("Emit event: %s" % repr(event))
EventEmitter.emit(self, event, *args)
def _handle_disconnect(self):
self.ready = False
self._fr.clear()
def _handle_add_friend_result(self, message):
eresult = EResult(message.body.eresult)
steam_id = SteamID(message.body.steam_id_added)
self.emit(self.EVENT_FRIEND_ADD_RESULT, eresult, steam_id)
def _handle_friends_list(self, message):
incremental = message.body.bincremental
if incremental == False:
self._fr.clear()
steamids_to_check = set()
# update internal friends list
for friend in message.body.friends:
steamid = SteamID(friend.ulfriendid)
if steamid.type != steamid.EType.Individual:
continue
suser = self._steam.get_user(steamid, False)
rel = EFriendRelationship(friend.efriendrelationship)
if steamid not in self._fr and rel != EFriendRelationship.NONE: # 0
self._fr[steamid] = suser
suser.relationship = rel
steamids_to_check.add(steamid)
if rel in (2,4): # RequestRecipient = 2, RequestInitiator = 4
if rel == EFriendRelationship.RequestRecipient:
self.emit(self.EVENT_FRIEND_INVITE, suser)
else:
oldrel, suser.relationship = suser.relationship, rel
if rel == EFriendRelationship.NONE:
suser = self._fr.pop(steamid, None)
if suser and oldrel not in (EFriendRelationship.Ignored, 0):
self.emit(self.EVENT_FRIEND_REMOVED, suser)
elif oldrel in (2,4) and rel == EFriendRelationship.Friend:
self.emit(self.EVENT_FRIEND_NEW, suser)
# request persona state for any new entries
if steamids_to_check:
self._steam.request_persona_state(steamids_to_check)
if not self.ready:
self.ready = True
self.emit(self.EVENT_READY)
def __repr__(self):
return "<%s %d users>" % (
self.__class__.__name__,
len(self._fr),
)
def __len__(self):
return len(self._fr)
def __iter__(self):
return itervalues(self._fr)
def __list__(self):
return list(iter(self))
def __getitem__(self, key):
if isinstance(key, SteamUser):
key = key.steam_id
return self._fr[key]
def __contains__(self, friend):
if isinstance(friend, SteamUser):
friend = friend.steam_id
return friend in self._fr
def add(self, steamid_or_accountname_or_email):
"""
Add/Accept a steam user to be your friend.
When someone sends you an invite, use this method to accept it.
:param steamid_or_accountname_or_email: steamid, account name, or email
:type steamid_or_accountname_or_email: :class:`int`, :class:`.SteamID`, :class:`.SteamUser`, :class:`str`
.. note::
Adding by email doesn't not work. It's only mentioned for the sake of completeness.
"""
m = MsgProto(EMsg.ClientAddFriend)
if isinstance(steamid_or_accountname_or_email, (intBase, int)):
m.body.steamid_to_add = steamid_or_accountname_or_email
elif isinstance(steamid_or_accountname_or_email, SteamUser):
m.body.steamid_to_add = steamid_or_accountname_or_email.steam_id
else:
m.body.accountname_or_email_to_add = steamid_or_accountname_or_email
self._steam.send_job(m)
def remove(self, steamid):
"""
Remove a friend
:param steamid: their steamid
:type steamid: :class:`int`, :class:`.SteamID`, :class:`.SteamUser`
"""
if isinstance(steamid, SteamUser):
steamid = steamid.steam_id
self._steam.send(MsgProto(EMsg.ClientRemoveFriend), {'friendid': steamid})
def block(self, steamid):
"""
Block Steam user
:param steamid: their steamid
:type steamid: :class:`int`, :class:`.SteamID`, :class:`.SteamUser`
:return: result
:rtype: :class:`EResult`
"""
if isinstance(steamid, SteamUser):
steamid = steamid.steam_id
elif not isinstance(steamid, SteamID):
steamid = SteamID(steamid)
resp = self._steam.send_um_and_wait("Player.IgnoreFriend#1",
{"steamid": steamid},
timeout=10)
if not resp:
return EResult.Timeout
elif resp.header.eresult == EResult.OK:
if steamid not in self._fr:
self._fr[steamid] = self._steam.get_user(steamid, False)
self._fr[steamid].relationship = EFriendRelationship(resp.body.friend_relationship)
return resp.header.eresult
def unblock(self, steamid):
"""
Unblock Steam user
:param steamid: their steamid
:type steamid: :class:`int`, :class:`.SteamID`, :class:`.SteamUser`
:return: result
:rtype: :class:`EResult`
"""
if isinstance(steamid, SteamUser):
steamid = steamid.steam_id
elif not isinstance(steamid, SteamID):
steamid = SteamID(steamid)
resp = self._steam.send_um_and_wait("Player.IgnoreFriend#1",
{"steamid": steamid, "unignore": True},
timeout=10)
if not resp:
return EResult.Timeout
elif resp.header.eresult == EResult.OK:
if steamid in self._fr:
self._fr[steamid].relationship = EFriendRelationship(resp.body.friend_relationship)
return resp.header.eresult