Skip to content

Commit f945fa8

Browse files
authored
Merge pull request #419 from carpedm20/remove-client-variables
Clean up `Client` variables
2 parents 70faa86 + bfca20b commit f945fa8

File tree

1 file changed

+74
-85
lines changed

1 file changed

+74
-85
lines changed

fbchat/_client.py

Lines changed: 74 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,14 @@ class Client(object):
3737
"""Verify ssl certificate, set to False to allow debugging with a proxy"""
3838
listening = False
3939
"""Whether the client is listening. Used when creating an external event loop to determine when to stop listening"""
40-
uid = None
41-
"""
42-
The ID of the client.
43-
Can be used as `thread_id`. See :ref:`intro_threads` for more info.
4440

45-
Note: Modifying this results in undefined behaviour
46-
"""
41+
@property
42+
def uid(self):
43+
"""The ID of the client.
44+
45+
Can be used as `thread_id`. See :ref:`intro_threads` for more info.
46+
"""
47+
return self._uid
4748

4849
def __init__(
4950
self,
@@ -67,15 +68,14 @@ def __init__(
6768
:type logging_level: int
6869
:raises: FBchatException on failed login
6970
"""
70-
self.sticky, self.pool = (None, None)
71+
self._sticky, self._pool = (None, None)
7172
self._session = requests.session()
72-
self.req_counter = 1
73-
self.seq = "0"
73+
self._req_counter = 1
74+
self._seq = "0"
7475
# See `createPoll` for the reason for using `OrderedDict` here
75-
self.payloadDefault = OrderedDict()
76-
self.client = "mercury"
77-
self.default_thread_id = None
78-
self.default_thread_type = None
76+
self._payload_default = OrderedDict()
77+
self._default_thread_id = None
78+
self._default_thread_type = None
7979
self.req_url = ReqUrl()
8080
self._markAlive = True
8181
self._buddylist = dict()
@@ -100,9 +100,6 @@ def __init__(
100100
or not self.isLoggedIn()
101101
):
102102
self.login(email, password, max_tries)
103-
else:
104-
self.email = email
105-
self.password = password
106103

107104
"""
108105
INTERNAL REQUEST METHODS
@@ -112,12 +109,12 @@ def _generatePayload(self, query):
112109
"""Adds the following defaults to the payload:
113110
__rev, __user, __a, ttstamp, fb_dtsg, __req
114111
"""
115-
payload = self.payloadDefault.copy()
112+
payload = self._payload_default.copy()
116113
if query:
117114
payload.update(query)
118-
payload["__req"] = str_base(self.req_counter, 36)
119-
payload["seq"] = self.seq
120-
self.req_counter += 1
115+
payload["__req"] = str_base(self._req_counter, 36)
116+
payload["seq"] = self._seq
117+
self._req_counter += 1
121118
return payload
122119

123120
def _fix_fb_errors(self, error_code):
@@ -215,7 +212,7 @@ def _cleanGet(self, url, query=None, timeout=30, allow_redirects=True):
215212
)
216213

217214
def _cleanPost(self, url, query=None, timeout=30):
218-
self.req_counter += 1
215+
self._req_counter += 1
219216
return self._session.post(
220217
url,
221218
headers=self._header,
@@ -299,60 +296,55 @@ def graphql_request(self, query):
299296
"""
300297

301298
def _resetValues(self):
302-
self.payloadDefault = OrderedDict()
299+
self._payload_default = OrderedDict()
303300
self._session = requests.session()
304-
self.req_counter = 1
305-
self.seq = "0"
306-
self.uid = None
301+
self._req_counter = 1
302+
self._seq = "0"
303+
self._uid = None
307304

308305
def _postLogin(self):
309-
self.payloadDefault = OrderedDict()
310-
self.client_id = hex(int(random() * 2147483648))[2:]
311-
self.start_time = now()
312-
self.uid = self._session.cookies.get_dict().get("c_user")
313-
if self.uid is None:
306+
self._payload_default = OrderedDict()
307+
self._client_id = hex(int(random() * 2147483648))[2:]
308+
self._uid = self._session.cookies.get_dict().get("c_user")
309+
if self._uid is None:
314310
raise FBchatException("Could not find c_user cookie")
315-
self.uid = str(self.uid)
316-
self.user_channel = "p_{}".format(self.uid)
317-
self.ttstamp = ""
311+
self._uid = str(self._uid)
318312

319313
r = self._get(self.req_url.BASE)
320314
soup = bs(r.text, "html.parser")
321315

322316
fb_dtsg_element = soup.find("input", {"name": "fb_dtsg"})
323317
if fb_dtsg_element:
324-
self.fb_dtsg = fb_dtsg_element["value"]
318+
fb_dtsg = fb_dtsg_element["value"]
325319
else:
326-
self.fb_dtsg = re.search(r'name="fb_dtsg" value="(.*?)"', r.text).group(1)
320+
fb_dtsg = re.search(r'name="fb_dtsg" value="(.*?)"', r.text).group(1)
327321

328322
fb_h_element = soup.find("input", {"name": "h"})
329323
if fb_h_element:
330-
self.fb_h = fb_h_element["value"]
324+
self._fb_h = fb_h_element["value"]
331325

332-
for i in self.fb_dtsg:
333-
self.ttstamp += str(ord(i))
334-
self.ttstamp += "2"
326+
ttstamp = ""
327+
for i in fb_dtsg:
328+
ttstamp += str(ord(i))
329+
ttstamp += "2"
335330
# Set default payload
336-
self.payloadDefault["__rev"] = int(
331+
self._payload_default["__rev"] = int(
337332
r.text.split('"client_revision":', 1)[1].split(",", 1)[0]
338333
)
339-
self.payloadDefault["__user"] = self.uid
340-
self.payloadDefault["__a"] = "1"
341-
self.payloadDefault["ttstamp"] = self.ttstamp
342-
self.payloadDefault["fb_dtsg"] = self.fb_dtsg
343-
344-
def _login(self):
345-
if not (self.email and self.password):
346-
raise FBchatUserError("Email and password not found.")
334+
self._payload_default["__user"] = self._uid
335+
self._payload_default["__a"] = "1"
336+
self._payload_default["ttstamp"] = ttstamp
337+
self._payload_default["fb_dtsg"] = fb_dtsg
347338

339+
def _login(self, email, password):
348340
soup = bs(self._get(self.req_url.MOBILE).text, "html.parser")
349341
data = dict(
350342
(elem["name"], elem["value"])
351343
for elem in soup.findAll("input")
352344
if elem.has_attr("value") and elem.has_attr("name")
353345
)
354-
data["email"] = self.email
355-
data["pass"] = self.password
346+
data["email"] = email
347+
data["pass"] = password
356348
data["login"] = "Log In"
357349

358350
r = self._cleanPost(self.req_url.LOGIN, data)
@@ -492,11 +484,8 @@ def login(self, email, password, max_tries=5):
492484
if not (email and password):
493485
raise FBchatUserError("Email and password not set")
494486

495-
self.email = email
496-
self.password = password
497-
498487
for i in range(1, max_tries + 1):
499-
login_successful, login_url = self._login()
488+
login_successful, login_url = self._login(email, password)
500489
if not login_successful:
501490
log.warning(
502491
"Attempt #{} failed{}".format(
@@ -522,11 +511,11 @@ def logout(self):
522511
:return: True if the action was successful
523512
:rtype: bool
524513
"""
525-
if not hasattr(self, "fb_h"):
514+
if not hasattr(self, "_fb_h"):
526515
h_r = self._post(self.req_url.MODERN_SETTINGS_MENU, {"pmid": "4"})
527-
self.fb_h = re.search(r'name=\\"h\\" value=\\"(.*?)\\"', h_r.text).group(1)
516+
self._fb_h = re.search(r'name=\\"h\\" value=\\"(.*?)\\"', h_r.text).group(1)
528517

529-
data = {"ref": "mb", "h": self.fb_h}
518+
data = {"ref": "mb", "h": self._fb_h}
530519

531520
r = self._get(self.req_url.LOGOUT, data)
532521

@@ -551,8 +540,8 @@ def _getThread(self, given_thread_id=None, given_thread_type=None):
551540
:rtype: tuple
552541
"""
553542
if given_thread_id is None:
554-
if self.default_thread_id is not None:
555-
return self.default_thread_id, self.default_thread_type
543+
if self._default_thread_id is not None:
544+
return self._default_thread_id, self._default_thread_type
556545
else:
557546
raise ValueError("Thread ID is not set")
558547
else:
@@ -566,8 +555,8 @@ def setDefaultThread(self, thread_id, thread_type):
566555
:param thread_type: See :ref:`intro_threads`
567556
:type thread_type: models.ThreadType
568557
"""
569-
self.default_thread_id = thread_id
570-
self.default_thread_type = thread_type
558+
self._default_thread_id = thread_id
559+
self._default_thread_type = thread_type
571560

572561
def resetDefaultThread(self):
573562
"""Resets default thread"""
@@ -672,7 +661,7 @@ def fetchAllUsers(self):
672661
:rtype: list
673662
:raises: FBchatException if request failed
674663
"""
675-
data = {"viewer": self.uid}
664+
data = {"viewer": self._uid}
676665
j = self._post(
677666
self.req_url.ALL_USERS, query=data, fix_request=True, as_json=True
678667
)
@@ -1260,13 +1249,13 @@ def _getSendData(self, message=None, thread_id=None, thread_type=ThreadType.USER
12601249
messageAndOTID = generateOfflineThreadingID()
12611250
timestamp = now()
12621251
data = {
1263-
"client": self.client,
1264-
"author": "fbid:{}".format(self.uid),
1252+
"client": "mercury",
1253+
"author": "fbid:{}".format(self._uid),
12651254
"timestamp": timestamp,
12661255
"source": "source:chat:web",
12671256
"offline_threading_id": messageAndOTID,
12681257
"message_id": messageAndOTID,
1269-
"threading_id": generateMessageID(self.client_id),
1258+
"threading_id": generateMessageID(self._client_id),
12701259
"ephemeral_ttl_mode:": "0",
12711260
}
12721261

@@ -1331,7 +1320,7 @@ def _doSendRequest(self, data, get_thread_id=False):
13311320
# update JS token if received in response
13321321
fb_dtsg = get_jsmods_require(j, 2)
13331322
if fb_dtsg is not None:
1334-
self.payloadDefault["fb_dtsg"] = fb_dtsg
1323+
self._payload_default["fb_dtsg"] = fb_dtsg
13351324

13361325
try:
13371326
message_ids = [
@@ -1738,7 +1727,7 @@ def createGroup(self, message, user_ids):
17381727
if len(user_ids) < 2:
17391728
raise FBchatUserError("Error when creating group: Not enough participants")
17401729

1741-
for i, user_id in enumerate(user_ids + [self.uid]):
1730+
for i, user_id in enumerate(user_ids + [self._uid]):
17421731
data["specific_to_list[{}]".format(i)] = "fbid:{}".format(user_id)
17431732

17441733
message_id, thread_id = self._doSendRequest(data, get_thread_id=True)
@@ -1766,7 +1755,7 @@ def addUsersToGroup(self, user_ids, thread_id=None):
17661755
user_ids = require_list(user_ids)
17671756

17681757
for i, user_id in enumerate(user_ids):
1769-
if user_id == self.uid:
1758+
if user_id == self._uid:
17701759
raise FBchatUserError(
17711760
"Error when adding users: Cannot add self to group thread"
17721761
)
@@ -1842,7 +1831,7 @@ def _usersApproval(self, user_ids, approve, thread_id=None):
18421831

18431832
data = {
18441833
"client_mutation_id": "0",
1845-
"actor_id": self.uid,
1834+
"actor_id": self._uid,
18461835
"thread_fbid": thread_id,
18471836
"user_ids": user_ids,
18481837
"response": "ACCEPT" if approve else "DENY",
@@ -2001,7 +1990,7 @@ def reactToMessage(self, message_id, reaction):
20011990
data = {
20021991
"action": "ADD_REACTION" if reaction else "REMOVE_REACTION",
20031992
"client_mutation_id": "1",
2004-
"actor_id": self.uid,
1993+
"actor_id": self._uid,
20051994
"message_id": str(message_id),
20061995
"reaction": reaction.value if reaction else None,
20071996
}
@@ -2097,7 +2086,7 @@ def createPoll(self, poll, thread_id=None):
20972086

20982087
# We're using ordered dicts, because the Facebook endpoint that parses the POST
20992088
# parameters is badly implemented, and deals with ordering the options wrongly.
2100-
# This also means we had to change `client.payloadDefault` to an ordered dict,
2089+
# This also means we had to change `client._payload_default` to an ordered dict,
21012090
# since that's being copied in between this point and the `requests` call
21022091
#
21032092
# If you can find a way to fix this for the endpoint, or if you find another
@@ -2405,14 +2394,14 @@ def unmuteThreadMentions(self, thread_id=None):
24052394

24062395
def _ping(self):
24072396
data = {
2408-
"channel": self.user_channel,
2409-
"clientid": self.client_id,
2397+
"channel": "p_" + self._uid,
2398+
"clientid": self._client_id,
24102399
"partition": -2,
24112400
"cap": 0,
2412-
"uid": self.uid,
2413-
"sticky_token": self.sticky,
2414-
"sticky_pool": self.pool,
2415-
"viewer_uid": self.uid,
2401+
"uid": self._uid,
2402+
"sticky_token": self._sticky,
2403+
"sticky_pool": self._pool,
2404+
"viewer_uid": self._uid,
24162405
"state": "active",
24172406
}
24182407
self._get(self.req_url.PING, data, fix_request=True, as_json=False)
@@ -2421,9 +2410,9 @@ def _pullMessage(self):
24212410
"""Call pull api with seq value to get message data."""
24222411
data = {
24232412
"msgs_recv": 0,
2424-
"sticky_token": self.sticky,
2425-
"sticky_pool": self.pool,
2426-
"clientid": self.client_id,
2413+
"sticky_token": self._sticky,
2414+
"sticky_pool": self._pool,
2415+
"clientid": self._client_id,
24272416
"state": "active" if self._markAlive else "offline",
24282417
}
24292418
return self._get(self.req_url.STICKY, data, fix_request=True, as_json=True)
@@ -2976,11 +2965,11 @@ def getThreadIdAndThreadType(msg_metadata):
29762965

29772966
def _parseMessage(self, content):
29782967
"""Get message and author name from content. May contain multiple messages in the content."""
2979-
self.seq = content.get("seq", "0")
2968+
self._seq = content.get("seq", "0")
29802969

29812970
if "lb_info" in content:
2982-
self.sticky = content["lb_info"]["sticky"]
2983-
self.pool = content["lb_info"]["pool"]
2971+
self._sticky = content["lb_info"]["sticky"]
2972+
self._pool = content["lb_info"]["pool"]
29842973

29852974
if "batches" in content:
29862975
for batch in content["batches"]:
@@ -3013,7 +3002,7 @@ def _parseMessage(self, content):
30133002
thread_id = str(thread_id)
30143003
else:
30153004
thread_type = ThreadType.USER
3016-
if author_id == self.uid:
3005+
if author_id == self._uid:
30173006
thread_id = m.get("to")
30183007
else:
30193008
thread_id = author_id
@@ -3126,7 +3115,7 @@ def doOneListen(self, markAlive=None):
31263115
def stopListening(self):
31273116
"""Cleans up the variables from startListening"""
31283117
self.listening = False
3129-
self.sticky, self.pool = (None, None)
3118+
self._sticky, self._pool = (None, None)
31303119

31313120
def listen(self, markAlive=None):
31323121
"""

0 commit comments

Comments
 (0)