From a5699ece1445123688c81676534993078eafbf6b Mon Sep 17 00:00:00 2001 From: larsyngvelundin <34173819+larsyngvelundin@users.noreply.github.com> Date: Mon, 30 Oct 2023 00:56:03 +0100 Subject: [PATCH] updates to setup --- setup.py | 3 +- src/__init__.py | 0 src/main.py | 147 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 src/__init__.py create mode 100644 src/main.py diff --git a/setup.py b/setup.py index 8decbdf..4870f00 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,8 @@ author='Lars Lundin', author_email='lars.y.lundin@gmail.com', url='https://github.com/larsyngvelundin/web3-balancer/', - py_modules=['main', "__init__"], + packages=['src'], + package_dir={'': 'src'}, install_requires=[ 'web3', 'loguru', diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/main.py b/src/main.py new file mode 100644 index 0000000..febbb25 --- /dev/null +++ b/src/main.py @@ -0,0 +1,147 @@ +from time import sleep +import requests + +from web3 import Web3 +from web3.providers.rpc import HTTPProvider +import web3 +from web3.middleware import geth_poa_middleware +from loguru import logger + + +class Balancer(): + def __init__(self, rpc_list, tor=False, is_contract=False, w3=None, set_net=""): + self.error_count = 0 + self.curr_func = "" + self.is_contract = is_contract + self.net = set_net + self._active_net = set_net + self.rpc_list = rpc_list + self.balancer = {} + for network in self.rpc_list: + self.balancer[network] = 0 + self.tor = tor + self._w3 = w3 + + def get_w3(self, network): + self._active_net = network + self.balancer[network] += 1 + self.balancer[network] = self.balancer[network] % len( + self.rpc_list[network]['links']) + + if (self.tor): + session = get_tor_session() + w3 = Web3(Web3.HTTPProvider( + self.rpc_list[network]['links'][self.balancer[network]], session=session)) + else: + w3 = Web3(Web3.HTTPProvider( + self.rpc_list[network]['links'][self.balancer[network]])) + if (self.is_contract): + self.is_contract = w3.eth.contract( + address=self.is_contract.address, abi=self.is_contract.abi) + + if (network == "matic" or network == "bnb"): + w3.middleware_onion.inject(geth_poa_middleware, layer=0) + + try: + if (self.is_contract): + if (self.is_contract.w3.is_connected()): + logger.debug( + f"W3 connected to {self.rpc_list[network]['links'][self.balancer[network]]}") + self._active_net = network + return w3 + else: + logger.error( + f"Unable to connect to {self.rpc_list[network]['links'][self.balancer[network]]}") + sleep(0.5) + return self.get_w3(network) + + else: + if (w3.is_connected()): + logger.debug( + f"W3 connected to {self.rpc_list[network]['links'][self.balancer[network]]}") + self._active_net = network + else: + logger.error( + f"Unable to connect to {self.rpc_list[network]['links'][self.balancer[network]]}") + logger.debug("Attempting new connection in 0.5s") + sleep(0.5) + return self.get_w3(network) + except AssertionError as error: + logger.error( + f"Unable to connect to {self.rpc_list[network]['links'][self.balancer[network]]}") + sleep(0.5) + return self.get_w3(network) + + return w3 + + def __getattr__(self, name): + self.curr_func += "." + name + return self + + def __call__(self, *args, **kwargs): + func_call = self.curr_func[1:] + if (func_call.find("eth") == 0 and len(args) + len(kwargs) == 0): + pass + else: + arg_str = ', '.join(repr(arg) for arg in args) + kwarg_str = "" + for argument in kwargs: + if argument == "address": + kwarg_str += f",{argument} = '{kwargs[argument]}'" + else: + kwarg_str += f",{argument} = {kwargs[argument]}" + func_call = f"{func_call}({arg_str}{kwarg_str})" + self.curr_func = "" + func_call = func_call.replace("(,", "(") + return self._call_w3_func(func_call) + + def _call_w3_func(self, func): + if (self._w3 == None or self._active_net != self.net): + self._w3 = self.get_w3(self.net) + val = None + try: + if (self.is_contract): + val = eval(f"self.is_contract.{func}") + else: + val = eval(f"self._w3.{func}") + except (requests.exceptions.ConnectionError, requests.exceptions.ReadTimeout, requests.exceptions.HTTPError) as error: + self.error_count += 1 + if (self.error_count > 1): + raise Exception( + f"Failed to get a working web3 connection {self.error_count} times in a row, aborting.") + logger.error(error) + logger.debug(f"Fetching new w3 connection and trying again") + self._w3 = self.get_w3(self.net) + if (self.is_contract): + self.is_contract.w3 = self._w3 + sleep(0.2) + self._call_w3_func(func) + if str(type(val)) == "": + logger.debug("Returning a contract balancer") + contract = Balancer(self.rpc_list, tor=self.tor, + is_contract=val, set_net=self._active_net) + return contract + self.error_count = 0 + return (val) + + +url = "http://ip-api.com/json/" + + +def get_tor_session(): + session = requests.Session() + session.proxies = { + 'http': 'socks5h://localhost:9050', + 'https': 'socks5h://localhost:9050', + } + + adapter = requests.adapters.HTTPAdapter( + pool_connections=20, pool_maxsize=20) + + session.mount('http://', adapter) + session.mount('https://', adapter) + + response = session.get(url) + logger.debug(response.text) + + return session