From f07122d44634cf32b2505c3378a1ee984043c5e4 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 1 Jul 2019 13:30:22 +0200 Subject: [PATCH] Move request payload into State model --- fbchat/_client.py | 30 +++++++++--------------------- fbchat/_state.py | 23 +++++++++++++++++++++++ 2 files changed, 32 insertions(+), 21 deletions(-) create mode 100644 fbchat/_state.py diff --git a/fbchat/_client.py b/fbchat/_client.py index daebf3f..4ea7646 100644 --- a/fbchat/_client.py +++ b/fbchat/_client.py @@ -11,6 +11,7 @@ from collections import OrderedDict from ._util import * from .models import * from ._graphql import graphql_queries_to_json, graphql_response_to_json, GraphQL +from ._state import State import time import json @@ -69,11 +70,7 @@ class Client(object): :raises: FBchatException on failed login """ self._sticky, self._pool = (None, None) - self._session = requests.session() - self._req_counter = 1 - self._seq = "0" - # See `createPoll` for the reason for using `OrderedDict` here - self._payload_default = OrderedDict() + self._resetValues() self._default_thread_id = None self._default_thread_type = None self._pull_channel = 0 @@ -106,14 +103,11 @@ class Client(object): """ def _generatePayload(self, query): - """Adds the following defaults to the payload: - __rev, __user, __a, ttstamp, fb_dtsg, __req - """ if not query: query = {} - query.update(self._payload_default) query["__req"] = str_base(self._req_counter, 36) self._req_counter += 1 + query.update(self._state.get_params()) return query def _fix_fb_errors(self, error_code): @@ -271,14 +265,14 @@ class Client(object): """ def _resetValues(self): - self._payload_default = OrderedDict() + self._state = State() self._session = requests.session() self._req_counter = 1 self._seq = "0" self._uid = None def _postLogin(self): - self._payload_default = OrderedDict() + self._state = State() self._client_id = hex(int(random() * 2147483648))[2:] self._uid = self._session.cookies.get_dict().get("c_user") if self._uid is None: @@ -298,12 +292,9 @@ class Client(object): if fb_h_element: self._fb_h = fb_h_element["value"] - # Set default payload - self._payload_default["__rev"] = int( - r.text.split('"client_revision":', 1)[1].split(",", 1)[0] - ) - self._payload_default["__a"] = "1" - self._payload_default["fb_dtsg"] = fb_dtsg + revision = int(r.text.split('"client_revision":', 1)[1].split(",", 1)[0]) + + self._state = State(fb_dtsg=fb_dtsg, revision=revision) def _login(self, email, password): soup = bs(self._get("https://m.facebook.com/").text, "html.parser") @@ -1299,7 +1290,7 @@ class Client(object): # update JS token if received in response fb_dtsg = get_jsmods_require(j, 2) if fb_dtsg is not None: - self._payload_default["fb_dtsg"] = fb_dtsg + self._state.fb_dtsg = fb_dtsg try: message_ids = [ @@ -2092,9 +2083,6 @@ class Client(object): # We're using ordered dicts, because the Facebook endpoint that parses the POST # parameters is badly implemented, and deals with ordering the options wrongly. - # This also means we had to change `client._payload_default` to an ordered dict, - # since that's being copied in between this point and the `requests` call - # # If you can find a way to fix this for the endpoint, or if you find another # endpoint, please do suggest it ;) data = OrderedDict([("question_text", poll.title), ("target_id", thread_id)]) diff --git a/fbchat/_state.py b/fbchat/_state.py new file mode 100644 index 0000000..a72f558 --- /dev/null +++ b/fbchat/_state.py @@ -0,0 +1,23 @@ +# -*- coding: UTF-8 -*- +from __future__ import unicode_literals + +import attr + +from . import _util + + +@attr.s(slots=True, kw_only=True) +class State(object): + """Stores and manages state required for most Facebook requests.""" + + fb_dtsg = attr.ib(None) + _revision = attr.ib(None) + + def get_params(self): + if self.fb_dtsg is None: + return {} + return { + "__a": 1, + "__rev": self._revision, + "fb_dtsg": self.fb_dtsg, + }