From fd01fc646dc4c83fd131ea75547a453014c0aa35 Mon Sep 17 00:00:00 2001 From: 0xfMissingNo <0xfmissingno@protonmail.com> Date: Wed, 22 Sep 2021 19:50:14 -0700 Subject: [PATCH] adds TorClient class and _RequestManager base class --- dydx3/__init__.py | 2 +- dydx3/dydx_client.py | 26 +++++++++++++++-- dydx3/helpers/requests.py | 56 ++++++++++++++++++++++--------------- dydx3/modules/api_keys.py | 6 ++-- dydx3/modules/onboarding.py | 6 ++-- dydx3/modules/private.py | 6 ++-- dydx3/modules/public.py | 8 +++--- 7 files changed, 71 insertions(+), 39 deletions(-) diff --git a/dydx3/__init__.py b/dydx3/__init__.py index e4d990d..5a6e168 100644 --- a/dydx3/__init__.py +++ b/dydx3/__init__.py @@ -1,4 +1,4 @@ -from dydx3.dydx_client import Client +from dydx3.dydx_client import Client, TorClient from dydx3.errors import DydxError from dydx3.errors import DydxApiError from dydx3.errors import TransactionReverted diff --git a/dydx3/dydx_client.py b/dydx3/dydx_client.py index 204146d..45b580b 100644 --- a/dydx3/dydx_client.py +++ b/dydx3/dydx_client.py @@ -3,6 +3,7 @@ from dydx3.constants import NETWORK_ID_MAINNET from dydx3.eth_signing import SignWithWeb3 from dydx3.eth_signing import SignWithKey +from dydx3.helpers.requests import _RequestManager from dydx3.modules.api_keys import ApiKeys from dydx3.modules.eth import Eth from dydx3.modules.private import Private @@ -14,12 +15,12 @@ ) -class Client(object): +class Client(_RequestManager): def __init__( self, host, - api_timeout=3000, # TODO: Actually use this. + api_timeout=3000, default_ethereum_address=None, eth_private_key=None, eth_send_options=None, @@ -73,7 +74,12 @@ def __init__( # Initialize the public module. Other modules are initialized on # demand, if the necessary configuration options were provided. + + self._set_session() + self._public = Public(host) + self._public._session = self._session + self._public.api_timeout = self.api_timeout self._private = None self._api_keys = None self._eth = None @@ -140,6 +146,8 @@ def private(self): default_address=self.default_address, api_key_credentials=self.api_key_credentials, ) + self._private._session = self._session + self._private.api_timeout = self.api_timeout else: raise Exception( 'Private endpoints not supported ' + @@ -161,6 +169,8 @@ def api_keys(self): network_id=self.network_id, default_address=self.default_address, ) + self._api_keys._session = self._session + self._api_keys.api_timeout = self.api_timeout else: raise Exception( 'API keys module is not supported since no Ethereum ' + @@ -187,6 +197,8 @@ def onboarding(self): self.stark_public_key_y_coordinate ), ) + self._onboarding._session = self._session + self._onboarding.api_timeout = self.api_timeout else: raise Exception( 'Onboarding is not supported since no Ethereum ' + @@ -218,3 +230,13 @@ def eth(self): 'eth_private_key nor web3_account was provided', ) return self._eth + + +class TorClient(Client): + + def _set_session(self): + super()._set_session() + self._session.proxies = { + 'http': 'socks5://127.0.0.1:9050', + 'https': 'socks5://127.0.0.1:9050' + } diff --git a/dydx3/helpers/requests.py b/dydx3/helpers/requests.py index bca9e07..66d88a4 100644 --- a/dydx3/helpers/requests.py +++ b/dydx3/helpers/requests.py @@ -5,28 +5,38 @@ from dydx3.errors import DydxApiError from dydx3.helpers.request_helpers import remove_nones -# TODO: Use a separate session per client instance. -session = requests.session() -session.headers.update({ - 'Accept': 'application/json', - 'Content-Type': 'application/json', - 'User-Agent': 'dydx/python', -}) - - -def request(uri, method, headers=None, data_values={}): - response = send_request( - uri, - method, - headers, - data=json.dumps( - remove_nones(data_values) - ) - ) - if not str(response.status_code).startswith('2'): - raise DydxApiError(response) - return response.json() if response.content else '{}' +requests.get + +class _RequestManager: + + _session = None + api_timeout = None + def _set_session(self): + self._session = requests.session() + self._session.headers.update({ + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'User-Agent': 'dydx/python', + }) + + def request(self, uri, method, headers=None, data_values={}): + response = self.send_request( + uri, + method, + headers, + data=json.dumps( + remove_nones(data_values) + ), + timeout=self.api_timeout + ) + if not str(response.status_code).startswith('2'): + raise DydxApiError(response) + if response.content: + return response.json() + return '{}' -def send_request(uri, method, headers=None, **kwargs): - return getattr(session, method)(uri, headers=headers, **kwargs) + def send_request(self, uri, method, headers=None, **kwargs): + if not _RequestManager._session: + self._set_session() + return getattr(self._session, method)(uri, headers=headers, **kwargs) diff --git a/dydx3/modules/api_keys.py b/dydx3/modules/api_keys.py index eb9d2cf..2c65d59 100644 --- a/dydx3/modules/api_keys.py +++ b/dydx3/modules/api_keys.py @@ -2,10 +2,10 @@ from dydx3.helpers.request_helpers import generate_query_path from dydx3.helpers.request_helpers import json_stringify from dydx3.eth_signing import SignApiKeyAction -from dydx3.helpers.requests import request +from dydx3.helpers.requests import _RequestManager -class ApiKeys(object): +class ApiKeys(_RequestManager): """Module for adding, querying, and deleting API keys.""" def __init__( @@ -41,7 +41,7 @@ def _request( timestamp=timestamp, ) - return request( + return self.request( self.host + request_path, method, { diff --git a/dydx3/modules/onboarding.py b/dydx3/modules/onboarding.py index f0de0a2..468af29 100644 --- a/dydx3/modules/onboarding.py +++ b/dydx3/modules/onboarding.py @@ -5,10 +5,10 @@ from dydx3.constants import OFF_CHAIN_ONBOARDING_ACTION from dydx3.constants import OFF_CHAIN_KEY_DERIVATION_ACTION from dydx3.eth_signing import SignOnboardingAction -from dydx3.helpers.requests import request +from dydx3.helpers.requests import _RequestManager -class Onboarding(object): +class Onboarding(_RequestManager): def __init__( self, @@ -42,7 +42,7 @@ def _post( ) request_path = '/'.join(['/v3', endpoint]) - return request( + return self.request( self.host + request_path, 'post', { diff --git a/dydx3/modules/private.py b/dydx3/modules/private.py index fecb00b..8a128f7 100644 --- a/dydx3/modules/private.py +++ b/dydx3/modules/private.py @@ -15,7 +15,7 @@ from dydx3.helpers.request_helpers import iso_to_epoch_seconds from dydx3.helpers.request_helpers import json_stringify from dydx3.helpers.request_helpers import remove_nones -from dydx3.helpers.requests import request +from dydx3.helpers.requests import _RequestManager from dydx3.starkex.helpers import get_transfer_erc20_fact from dydx3.starkex.helpers import nonce_from_client_id from dydx3.starkex.order import SignableOrder @@ -23,7 +23,7 @@ from dydx3.starkex.conditional_transfer import SignableConditionalTransfer -class Private(object): +class Private(_RequestManager): def __init__( self, @@ -61,7 +61,7 @@ def _private_request( 'DYDX-TIMESTAMP': now_iso_string, 'DYDX-PASSPHRASE': self.api_key_credentials['passphrase'], } - return request( + return self.request( self.host + request_path, method, headers, diff --git a/dydx3/modules/public.py b/dydx3/modules/public.py index 35d9842..54c99e3 100644 --- a/dydx3/modules/public.py +++ b/dydx3/modules/public.py @@ -1,8 +1,8 @@ from dydx3.helpers.request_helpers import generate_query_path -from dydx3.helpers.requests import request +from dydx3.helpers.requests import _RequestManager -class Public(object): +class Public(_RequestManager): def __init__( self, @@ -13,13 +13,13 @@ def __init__( # ============ Request Helpers ============ def _get(self, request_path, params={}): - return request( + return self.request( generate_query_path(self.host + request_path, params), 'get', ) def _put(self, endpoint, data): - return request( + return self.request( self.host + '/v3/' + endpoint, 'put', {},