66# Copyright © 2019- Sanjay-B(Sanjay Bhadra). All rights reserved.
77#
88
9- import asyncio
10- import requests_async as requests
11- import json
9+ import httpx
10+
11+ class HttpError (Exception ):
12+ """
13+ Base class that represents an HTTP Error in the form of an exception.
14+ """
15+ def __init__ (self , kind = "Generic" , message = "Generic Error" , url = "Somewhere" ):
16+ """
17+ Creates an exception with specified message.
18+ If not message is provided, it defaults to "Generic Error".
19+
20+ @param kind: str. Represents the the kind of exception.
21+ @param message: str. Represents the error message of the exception.
22+ @param url: str. Represents the url the error occured at.
23+ """
24+ self .kind = kind
25+ self .message = message
26+ self .url = url
27+ super ().__init__ (self .message )
1228
1329
1430class Req :
15-
16- token = None
17-
18- '''
19- @method
20- request(t=String,url=String,*args,**kwargs)
21-
22- @params
23- t = Type of Request(GET or POST)
24- url = URL
25-
26- @optionals
27-
28- payload = Dictionary Payload
29- header = Request Headers
30- cookies = cookie
31-
32- @result
33- Returns request response wholesale as a tuple
34-
35- @example 1:
31+ """
32+ Base class that holds HTTP request and response mechanisms.
33+ """
34+
35+ async def request (self , t : str , url : str , payload = None , header = {}, cookies = {}):
36+ """
37+ Creates, executes and returns a request in the form of a response.
38+ Throws an exception if conditions are not met.
39+
40+ @param t: Str. Type of request. ie. GET, POST, PATCH, DELETE or DEL.
41+ Can also be lowercase, snakecase, etc.
42+ @param url: Str. URL to send the request.
43+ @param payload: Dict or None. Represents the payload or data to send
44+ the request with.
45+ @param header: Dict. Represents the headers to send the request with.
46+ @param cookies: Dict. Represents the cookies to send the request with.
47+
48+ @return: Tuple.
49+
50+ @example:
3651
3752 # GET Request
3853 response = Req.request(t="GET",url="http://httpbin.org/get")
@@ -42,9 +57,8 @@ class Req:
4257
4358 # And so on... its a tuple so this also works as a shorthand:
4459 response = Req.request(t="GET",url="http://httpbin.org/get")[0]
45-
46-
47- @example 2:
60+
61+ @example:
4862
4963 # POST Request
5064 data = {"Username":"JohnDoe","Password":"JaneDoe"}
@@ -57,30 +71,56 @@ class Req:
5771
5872 # Once again, this works as a shorthand:
5973 response = Req.request(t="POST",url"http://httpbin.org/post",payload=data)[0]
60- '''
61-
62- async def request (t = str ,url = str ,* args ,** kwargs ):
63- payload = kwargs .get ('payload' ,None )
64- header = kwargs .get ('header' ,{})
65- cookies = kwargs .get ('cookies' ,{})
66-
67- if t == "GET" or "POST" or "PATCH" or "DEL" :
68- method = t .replace ('DEL' , 'delete' )
69- response = await requests .request ("POST" , "https://www.roblox.com/authentication/signoutfromallsessionsandreauthenticate" , data = None , headers = header , cookies = cookies or {})
70- header ['X-CSRF-TOKEN' ] = response .headers ['X-CSRF-TOKEN' ]
71- request = await requests .request (method , str (url ), data = payload or None , headers = header , cookies = cookies )
72- statusCode = request .status_code
73- content = request .content
74- headers = request .headers
75- encoding = request .encoding
76- json = request .json ()
77-
78- # resend request with xcsrf token
79- if statusCode == 403 and 'X-CSRF-TOKEN' in headers :
80- kwargs ['headers' ]['X-CSRF-TOKEN' ] = headers ['X-CSRF-TOKEN' ]
81- return await request (t = t , url = url , * args , ** kwargs )
82-
83- if statusCode == 200 :
84- return statusCode , content , headers , encoding , json
85- else :
86- return statusCode , content , headers , encoding , json ["errors" ][0 ]
74+ """
75+ async with httpx .AsyncClient (cookies = cookies ) as client :
76+
77+ # TODO: Backwards Compatibility (will be renamed to this later)
78+ kind = t .upper ()
79+ headers = header
80+
81+ # Obtain our initial token (fresh)
82+ response = await client .post (url = "https://www.roblox.com/authentication/signoutfromallsessionsandreauthenticate" , data = None , headers = headers )
83+ csrf_token = response .headers .get ("X-CSRF-TOKEN" )
84+ if not csrf_token :
85+ raise HttpError ("POST Request" , "Initial X-CSRF-TOKEN was not found in headers, aborted" , url )
86+
87+ # Perform actual request
88+ headers ["X-CSRF-TOKEN" ] = csrf_token
89+ if kind == "GET" :
90+ response = await client .get (url , headers = headers )
91+ elif kind == "POST" :
92+ if not cookies :
93+ raise HttpError ("POST Request" , "Endpoint requires account cookie / authentication" , url )
94+ elif not payload :
95+ raise HttpError ("POST Request" , "Endpoint requires payload / request body" , url )
96+ response = await client .post (url = url , data = payload , headers = headers )
97+ elif kind == "PATCH" :
98+ if not cookies :
99+ raise HttpError ("PATCH Request" , "Endpoint requires account cookie / authentication" , url )
100+ elif not payload :
101+ raise HttpError ("PATCH Request" , "Endpoint requires payload / request body" , url )
102+ response = await client .patch (url = url , data = payload , headers = headers )
103+ elif kind == ("DEL" or "DELETE" ):
104+ if not cookies :
105+ raise HttpError ("DELETE Request" , "Endpoint requires account cookie / authentication" , url )
106+ response = await client .delete (url = url , payload = payload , headers = headers )
107+ return self .parse_response (response )
108+
109+ def parse_response (self , response ):
110+ """
111+ Parses respone into expected tuple format.
112+
113+ @param response: Response. The response object from the request that has been performed.
114+
115+ @return: tuple. If the status code is 200, the return is Tuple(status_code, content, headers, encoding, json).
116+ If the status code is not 200, the return is Tuple(status_code, content, headers, encoding, json["errors"][0]).
117+ Note that a status code of 200 means the request is successful. Otherwise, an error has occured.
118+ """
119+ status_code = response .status_code
120+ content = response .content
121+ headers = response .headers
122+ encoding = response .encoding
123+ json = response .json ()
124+ if status_code == 200 :
125+ return status_code , content , headers , encoding , json
126+ return status_code , content , headers , encoding , json ["errors" ][0 ]
0 commit comments