abstract-solana 0.0.2.81__tar.gz → 0.0.2.83__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of abstract-solana might be problematic. Click here for more details.
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/PKG-INFO +1 -1
- abstract_solana-0.0.2.83/pyproject.toml +3 -0
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/setup.py +34 -34
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana/abstract_rpcs/__init__.py +1 -1
- abstract_solana-0.0.2.83/src/abstract_solana/abstract_rpcs/rate_limiter.py +177 -0
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana/abstract_rpcs/solana_rpc_client.py +14 -7
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana.egg-info/PKG-INFO +1 -1
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana.egg-info/SOURCES.txt +1 -0
- abstract_solana-0.0.2.81/src/abstract_solana/abstract_rpcs/rate_limiter.py +0 -142
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/README.md +0 -0
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/setup.cfg +0 -0
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana/__init__.py +0 -0
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana/abstract_rpcs/db_templates.py +0 -0
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana/abstract_rpcs/get_api_gui.py +0 -0
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana/abstract_rpcs/get_body.py +0 -0
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana/abstract_utils/__init__.py +0 -0
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana/abstract_utils/account_key_utils.py +0 -0
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana/abstract_utils/constants.py +0 -0
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana/abstract_utils/genesis_functions.py +0 -0
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana/abstract_utils/index_utils.py +0 -0
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana/abstract_utils/keypair_utils.py +0 -0
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana/abstract_utils/log_message_functions.py +0 -0
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana/abstract_utils/price_utils.py +0 -0
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana/abstract_utils/pubkey_utils.py +0 -0
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana/abstract_utils/signature_data_parse.py +0 -0
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana/abstract_utils/utils.py +0 -0
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana.egg-info/dependency_links.txt +0 -0
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana.egg-info/requires.txt +0 -0
- {abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana.egg-info/top_level.txt +0 -0
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
from time import time
|
|
2
|
-
import setuptools
|
|
3
|
-
with open("README.md", "r", encoding="utf-8") as fh:
|
|
4
|
-
long_description = fh.read()
|
|
5
|
-
setuptools.setup(
|
|
6
|
-
name='abstract_solana',
|
|
7
|
-
version='0.0.2.
|
|
8
|
-
author='putkoff',
|
|
9
|
-
author_email='partners@abstractendeavors.com',
|
|
10
|
-
description="",
|
|
11
|
-
long_description=long_description,
|
|
12
|
-
long_description_content_type='text/markdown',
|
|
13
|
-
url='https://github.com/AbstractEndeavors/abstract_solana',
|
|
14
|
-
classifiers=[
|
|
15
|
-
'Development Status :: 3 - Alpha',
|
|
16
|
-
'Intended Audience :: Developers',
|
|
17
|
-
'Topic :: Software Development :: Libraries',
|
|
18
|
-
'License :: OSI Approved :: MIT License',
|
|
19
|
-
'Programming Language :: Python :: 3',
|
|
20
|
-
'Programming Language :: Python :: 3.6',
|
|
21
|
-
'Programming Language :: Python :: 3.7',
|
|
22
|
-
'Programming Language :: Python :: 3.8',
|
|
23
|
-
'Programming Language :: Python :: 3.9',
|
|
24
|
-
'Programming Language :: Python :: 3.10',
|
|
25
|
-
'Programming Language :: Python :: 3.11',
|
|
26
|
-
'Programming Language :: Python :: 3.12',
|
|
27
|
-
],
|
|
28
|
-
install_requires=['solders','abstract_solcatcher','abstract_utilities','solana'],
|
|
29
|
-
package_dir={"": "src"},
|
|
30
|
-
packages=setuptools.find_packages(where="src"),
|
|
31
|
-
python_requires=">=3.6",
|
|
32
|
-
# Add this line to include wheel format in your distribution
|
|
33
|
-
setup_requires=['wheel'],
|
|
34
|
-
)
|
|
1
|
+
from time import time
|
|
2
|
+
import setuptools
|
|
3
|
+
with open("README.md", "r", encoding="utf-8") as fh:
|
|
4
|
+
long_description = fh.read()
|
|
5
|
+
setuptools.setup(
|
|
6
|
+
name='abstract_solana',
|
|
7
|
+
version='0.0.2.083',
|
|
8
|
+
author='putkoff',
|
|
9
|
+
author_email='partners@abstractendeavors.com',
|
|
10
|
+
description="",
|
|
11
|
+
long_description=long_description,
|
|
12
|
+
long_description_content_type='text/markdown',
|
|
13
|
+
url='https://github.com/AbstractEndeavors/abstract_solana',
|
|
14
|
+
classifiers=[
|
|
15
|
+
'Development Status :: 3 - Alpha',
|
|
16
|
+
'Intended Audience :: Developers',
|
|
17
|
+
'Topic :: Software Development :: Libraries',
|
|
18
|
+
'License :: OSI Approved :: MIT License',
|
|
19
|
+
'Programming Language :: Python :: 3',
|
|
20
|
+
'Programming Language :: Python :: 3.6',
|
|
21
|
+
'Programming Language :: Python :: 3.7',
|
|
22
|
+
'Programming Language :: Python :: 3.8',
|
|
23
|
+
'Programming Language :: Python :: 3.9',
|
|
24
|
+
'Programming Language :: Python :: 3.10',
|
|
25
|
+
'Programming Language :: Python :: 3.11',
|
|
26
|
+
'Programming Language :: Python :: 3.12',
|
|
27
|
+
],
|
|
28
|
+
install_requires=['solders','abstract_solcatcher','abstract_utilities','solana'],
|
|
29
|
+
package_dir={"": "src"},
|
|
30
|
+
packages=setuptools.find_packages(where="src"),
|
|
31
|
+
python_requires=">=3.6",
|
|
32
|
+
# Add this line to include wheel format in your distribution
|
|
33
|
+
setup_requires=['wheel'],
|
|
34
|
+
)
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import os
|
|
3
|
+
import json
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
|
|
6
|
+
from abstract_utilities import *
|
|
7
|
+
from abstract_security import get_env_value
|
|
8
|
+
def getAbsFile():
|
|
9
|
+
return os.path.abspath(__file__)
|
|
10
|
+
def getAbsDir():
|
|
11
|
+
return os.path.dirname(getAbsFile())
|
|
12
|
+
def getAbsPath(path):
|
|
13
|
+
return os.path.join(getAbsDir(),path)
|
|
14
|
+
def getSaveStatePath():
|
|
15
|
+
return getAbsPath('rate_limiter_state.json')
|
|
16
|
+
def readSaveState(url1,url2,path=None):
|
|
17
|
+
path= path or getSaveStatePath()
|
|
18
|
+
if not os.path.isfile(path):
|
|
19
|
+
state = {'last_method':None,'rate_limits': {url1: [], url2: []},'last_mb': {url1: {}, url2: {}},'cooldown_times': {url1: {}, url2: {}},'last_url':url1}
|
|
20
|
+
safe_dump_to_file(data=state,file_path=path)
|
|
21
|
+
return safe_read_from_json(path)
|
|
22
|
+
def is_time_interval(time_obj, interval):
|
|
23
|
+
return (time.time() - time_obj) < interval-1
|
|
24
|
+
|
|
25
|
+
def get_mb(sum_list, limit, last_mb):
|
|
26
|
+
return (sum_list + last_mb) > limit
|
|
27
|
+
|
|
28
|
+
def datasize(data):
|
|
29
|
+
if isinstance(data, str):
|
|
30
|
+
size = len(data.encode('utf-8'))
|
|
31
|
+
elif isinstance(data, (bytes, bytearray)):
|
|
32
|
+
size = len(data)
|
|
33
|
+
elif isinstance(data, list) or isinstance(data, dict):
|
|
34
|
+
size = len(json.dumps(data).encode('utf-8'))
|
|
35
|
+
else:
|
|
36
|
+
size = len(str(data).encode('utf-8'))
|
|
37
|
+
return size/1000
|
|
38
|
+
class RateLimiter(metaclass=SingletonMeta):
|
|
39
|
+
def __init__(self, rpc_url=None, fallback_rpc_url=None, env_directory=None,save_state_path = None):
|
|
40
|
+
if not hasattr(self, 'initialized'): # Prevent reinitialization
|
|
41
|
+
self.initialized = True
|
|
42
|
+
self.rpc_url = rpc_url or get_env_value(key="solana_primary_rpc_url", path=env_directory) or "https://api.mainnet-beta.solana.com"
|
|
43
|
+
self.fallback_rpc_url = fallback_rpc_url or get_env_value(key="solana_fallback_rpc_url", path=env_directory)
|
|
44
|
+
self.state_file = save_state_path or getSaveStatePath()
|
|
45
|
+
self.url1 = self.rpc_url
|
|
46
|
+
self.url2 = self.fallback_rpc_url
|
|
47
|
+
self.rate_limits = {self.url1: [], self.url2: []} # Separate rate limits for each URL
|
|
48
|
+
self.last_mb = {self.url1: {}, self.url2: {}}
|
|
49
|
+
self.cooldown_times = {self.url1: {}, self.url2: {}} # Separate cooldowns for each URL
|
|
50
|
+
self.last_url = None
|
|
51
|
+
self.last_method = None
|
|
52
|
+
self.load_state()
|
|
53
|
+
|
|
54
|
+
def save_state(self):
|
|
55
|
+
state = {
|
|
56
|
+
'last_method': self.last_method,
|
|
57
|
+
'rate_limits': self.rate_limits,
|
|
58
|
+
'last_mb': self.last_mb,
|
|
59
|
+
'cooldown_times': self.cooldown_times,
|
|
60
|
+
'last_url': self.last_url
|
|
61
|
+
}
|
|
62
|
+
safe_dump_to_file(data=state, file_path=self.state_file)
|
|
63
|
+
|
|
64
|
+
def load_state(self):
|
|
65
|
+
state = readSaveState(self.url1,self.url2)
|
|
66
|
+
self.last_method = state.get('last_method')
|
|
67
|
+
self.rate_limits = state.get('rate_limits', {self.url1: [], self.url2: []})
|
|
68
|
+
self.last_mb = state.get('last_mb', {self.url1: {}, self.url2: {}})
|
|
69
|
+
self.cooldown_times = state.get('cooldown_times', {self.url1: {}, self.url2: {}})
|
|
70
|
+
|
|
71
|
+
def set_cooldown(self, url, method=None, add=False):
|
|
72
|
+
if method:
|
|
73
|
+
if add:
|
|
74
|
+
self.cooldown_times[url][method] = time.time() + add
|
|
75
|
+
if method in self.cooldown_times[url] and time.time() > self.cooldown_times[url][method]:
|
|
76
|
+
del self.cooldown_times[url][method]
|
|
77
|
+
return method in self.cooldown_times[url]
|
|
78
|
+
return False
|
|
79
|
+
|
|
80
|
+
def get_last_rate_limit(self, url):
|
|
81
|
+
if self.rate_limits[url]:
|
|
82
|
+
return self.rate_limits[url][-1]
|
|
83
|
+
return {}
|
|
84
|
+
|
|
85
|
+
def is_all_limit(self, url, method):
|
|
86
|
+
if method not in self.last_mb[url]:
|
|
87
|
+
self.last_mb[url][method] = 0
|
|
88
|
+
|
|
89
|
+
if self.set_cooldown(url, method):
|
|
90
|
+
print(f'set_cooldown for method {method} in {url} hit')
|
|
91
|
+
return True
|
|
92
|
+
|
|
93
|
+
# Clean up expired queries for the current URL
|
|
94
|
+
self.rate_limits[url] = [
|
|
95
|
+
query for query in self.rate_limits[url] if is_time_interval(query.get('time') or 0, 30)
|
|
96
|
+
]
|
|
97
|
+
last_rate_limit = self.get_last_rate_limit(url)
|
|
98
|
+
|
|
99
|
+
# Check data size limits
|
|
100
|
+
total_mb = sum(query.get('data', 0) for query in self.rate_limits[url])
|
|
101
|
+
mb = get_mb(total_mb, 100, self.last_mb[url][method])
|
|
102
|
+
if mb:
|
|
103
|
+
print(f'mb {total_mb} of limit 100 hit')
|
|
104
|
+
return True
|
|
105
|
+
|
|
106
|
+
# Check if the last request for the same method was within 10 seconds
|
|
107
|
+
time_rate = [
|
|
108
|
+
query for query in self.rate_limits[url] if is_time_interval(query.get('time') or 0, 10)
|
|
109
|
+
]
|
|
110
|
+
if len(time_rate) > 100:
|
|
111
|
+
print(f'time_rate {time_rate} of timerate limit 100 hit')
|
|
112
|
+
return True
|
|
113
|
+
|
|
114
|
+
method_specific_time_rate = [
|
|
115
|
+
query for query in time_rate if query['method'] == method
|
|
116
|
+
]
|
|
117
|
+
if len(method_specific_time_rate) > 40:
|
|
118
|
+
print(f'method_specific_time_rate {len(method_specific_time_rate)} of method_specific_time_rate limit 40 hit')
|
|
119
|
+
return True
|
|
120
|
+
|
|
121
|
+
return False
|
|
122
|
+
|
|
123
|
+
def log_response(self, method=None, response=None, retry_after=None):
|
|
124
|
+
method = method or 'default_method'
|
|
125
|
+
response = response or {}
|
|
126
|
+
data_size = datasize(response)
|
|
127
|
+
active_url = self.last_url
|
|
128
|
+
|
|
129
|
+
# Handle Retry-After logic
|
|
130
|
+
if retry_after:
|
|
131
|
+
try:
|
|
132
|
+
wait_time = int(retry_after)
|
|
133
|
+
except ValueError:
|
|
134
|
+
retry_after_date = datetime.strptime(retry_after, '%a, %d %b %Y %H:%M:%S GMT')
|
|
135
|
+
wait_time = (retry_after_date - datetime.utcnow()).total_seconds()
|
|
136
|
+
self.set_cooldown(active_url, method, add=max(wait_time, 0))
|
|
137
|
+
|
|
138
|
+
if active_url == self.url1:
|
|
139
|
+
self.rate_limits[active_url].append({'method': method, 'data': data_size, 'time': time.time()})
|
|
140
|
+
|
|
141
|
+
# Clean up expired entries for the current URL
|
|
142
|
+
self.rate_limits[active_url] = [
|
|
143
|
+
query for query in self.rate_limits[active_url] if is_time_interval(query['time'], 30)
|
|
144
|
+
]
|
|
145
|
+
self.save_state()
|
|
146
|
+
def get_cooldown_for_method(self,url,method):
|
|
147
|
+
wait_time = 0
|
|
148
|
+
if self.set_cooldown(url,method):
|
|
149
|
+
wait_time = int(self.cooldown_times[url][method]) - time.time()
|
|
150
|
+
if wait_time <= 0:
|
|
151
|
+
del self.cooldown_times[url][method]
|
|
152
|
+
|
|
153
|
+
else:
|
|
154
|
+
return wait_time
|
|
155
|
+
return False
|
|
156
|
+
def get_url(self, method=None):
|
|
157
|
+
method = method or 'default_method'
|
|
158
|
+
wait_time = self.get_cooldown_for_method(self.url1,method)
|
|
159
|
+
|
|
160
|
+
if wait_time:
|
|
161
|
+
wait_time = int(self.cooldown_times[self.url1][method]) - time.time()
|
|
162
|
+
if wait_time > 0:
|
|
163
|
+
self.last_url = self.url2
|
|
164
|
+
#retry_after_date = datetime.strptime(str(int(self.cooldown_times[method])), '%a, %d %b %Y %H:%M:%S GMT')
|
|
165
|
+
print(f"{method} is on cooldown for {wait_time} more seconds")
|
|
166
|
+
if method == 'get_url2':
|
|
167
|
+
self.last_url = self.url2
|
|
168
|
+
return self.last_url
|
|
169
|
+
# If fallback URL is selected, skip all limits
|
|
170
|
+
|
|
171
|
+
is_limit = self.is_all_limit(self.url1, method)
|
|
172
|
+
if not is_limit:
|
|
173
|
+
self.last_method = method
|
|
174
|
+
self.last_url = self.url1
|
|
175
|
+
print([is_limit,self.last_url])
|
|
176
|
+
return self.last_url
|
|
177
|
+
|
|
@@ -2,7 +2,7 @@ from solana.rpc.core import _ClientCore
|
|
|
2
2
|
from typing import Dict, List, Optional, Sequence, Union
|
|
3
3
|
from solana.rpc.commitment import Commitment, Finalized
|
|
4
4
|
from .rate_limiter import RateLimiter
|
|
5
|
-
from ..abstract_utils.
|
|
5
|
+
from ..abstract_utils.pubkey_utils import *
|
|
6
6
|
import inspect,asyncio,json,requests
|
|
7
7
|
from abstract_apis import *
|
|
8
8
|
from abstract_utilities import is_number
|
|
@@ -85,10 +85,17 @@ def get_rpc_dict(endpoint,*args,**kwargs):
|
|
|
85
85
|
kwargs = get_conversions(variables,*args,**kwargs)
|
|
86
86
|
kwargs = json.loads(str(call_function(function,**kwargs)))
|
|
87
87
|
return kwargs
|
|
88
|
-
def
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
88
|
+
def make_call(url,body):
|
|
89
|
+
return postRpcRequest(url=url,**body,retry_after =True,status_code=True, headers=get_headers())
|
|
90
|
+
def abstract_solana_rate_limited_call(method, *args, **kwargs):
|
|
91
|
+
# Build the request body
|
|
92
|
+
body = get_rpc_dict(method, *args, **kwargs)
|
|
93
|
+
body_method = body.get('method')
|
|
94
|
+
url = rate_limiter.get_url(body_method)
|
|
95
|
+
response,status_code,retry_after = make_call(url,body)
|
|
96
|
+
rate_limiter.log_response(body_method, response, retry_after)
|
|
97
|
+
if url == rate_limiter.url1 and status_code == 429:
|
|
98
|
+
url = rate_limiter.get_url('get_url2')
|
|
99
|
+
response,status_code,retry_after = make_call(url,body)
|
|
100
|
+
rate_limiter.log_response(body_method, response)
|
|
94
101
|
return response
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import time,os,json
|
|
2
|
-
from abstract_utilities import *
|
|
3
|
-
from abstract_security import *
|
|
4
|
-
def getAbsFile():
|
|
5
|
-
return os.path.abspath(__file__)
|
|
6
|
-
def getAbsDir():
|
|
7
|
-
return os.path.dirname(getAbsFile())
|
|
8
|
-
def getAbsPath(path):
|
|
9
|
-
return os.path.join(getAbsDir(),path)
|
|
10
|
-
def getSaveStatePath():
|
|
11
|
-
return getAbsPath('rate_limiter_state.json')
|
|
12
|
-
def readSaveState():
|
|
13
|
-
path= getSaveStatePath()
|
|
14
|
-
if not os.path.isfile(path):
|
|
15
|
-
state = {'last_method':None,'rate_limit': [],'last_mb': {},'cooldown_time': False,'last_url':None}
|
|
16
|
-
safe_dump_to_file(data=state,file_path=path)
|
|
17
|
-
return safe_read_from_json(getSaveStatePath())
|
|
18
|
-
def is_time_interval(time_obj, interval):
|
|
19
|
-
return (time.time() - time_obj) < interval-1
|
|
20
|
-
|
|
21
|
-
def get_mb(sum_list, limit, last_mb):
|
|
22
|
-
return (sum_list + last_mb) > limit
|
|
23
|
-
|
|
24
|
-
def datasize(data):
|
|
25
|
-
if isinstance(data, str):
|
|
26
|
-
return len(data.encode('utf-8'))
|
|
27
|
-
elif isinstance(data, (bytes, bytearray)):
|
|
28
|
-
return len(data)
|
|
29
|
-
elif isinstance(data, list) or isinstance(data, dict):
|
|
30
|
-
return len(json.dumps(data).encode('utf-8'))
|
|
31
|
-
else:
|
|
32
|
-
return len(str(data).encode('utf-8'))
|
|
33
|
-
|
|
34
|
-
class RateLimiter(metaclass=SingletonMeta):
|
|
35
|
-
def __init__(self,rpc_url = None,fallback_rpc_url=None,env_directory=None):
|
|
36
|
-
if not hasattr(self, 'initialized'): # Prevent reinitialization
|
|
37
|
-
self.initialized = True
|
|
38
|
-
self.rpc_url = rpc_url or get_env_value(key="solana_primary_rpc_url",path=env_directory) or "https://api.mainnet-beta.solana.com"
|
|
39
|
-
self.fallback_rpc_url = fallback_rpc_url or get_env_value(key="solana_fallback_rpc_url",path=env_directory)
|
|
40
|
-
self.initialized = True
|
|
41
|
-
self.rate_limit = []
|
|
42
|
-
self.last_mb = {}
|
|
43
|
-
self.cooldown_time = False
|
|
44
|
-
self.url1 = self.rpc_url
|
|
45
|
-
self.url2 = self.fallback_rpc_url
|
|
46
|
-
self.state_file = getSaveStatePath()
|
|
47
|
-
self.last_url = None
|
|
48
|
-
self.last_method=None
|
|
49
|
-
self.load_state()
|
|
50
|
-
def get_url_2(self):
|
|
51
|
-
return self.url2
|
|
52
|
-
|
|
53
|
-
def save_state(self):
|
|
54
|
-
state = {
|
|
55
|
-
'last_method':self.last_method,
|
|
56
|
-
'rate_limit': self.rate_limit,
|
|
57
|
-
'last_mb': self.last_mb,
|
|
58
|
-
'cooldown_time': self.cooldown_time,
|
|
59
|
-
'last_url': self.last_url
|
|
60
|
-
}
|
|
61
|
-
safe_dump_to_file(data=state,file_path=self.state_file)
|
|
62
|
-
|
|
63
|
-
def load_state(self):
|
|
64
|
-
state = readSaveState()
|
|
65
|
-
self.last_method = state.get('last_method')
|
|
66
|
-
self.rate_limit = state.get('rate_limit', [])
|
|
67
|
-
self.last_mb = state.get('last_mb', {})
|
|
68
|
-
self.last_url = state.get('last_url')
|
|
69
|
-
self.cooldown_time = state.get('cooldown_time', False)
|
|
70
|
-
|
|
71
|
-
def set_cooldown(self, add=False):
|
|
72
|
-
if add:
|
|
73
|
-
self.cooldown_time = time.time() + add
|
|
74
|
-
if self.cooldown_time and (time.time() > self.cooldown_time):
|
|
75
|
-
self.cooldown_time = False
|
|
76
|
-
return bool(self.cooldown_time)
|
|
77
|
-
|
|
78
|
-
def get_last_rate_limit(self):
|
|
79
|
-
if self.rate_limit:
|
|
80
|
-
return self.rate_limit[-1]
|
|
81
|
-
return {}
|
|
82
|
-
|
|
83
|
-
def is_all_limit(self, method):
|
|
84
|
-
if method not in self.last_mb:
|
|
85
|
-
self.last_mb[method] = 0
|
|
86
|
-
|
|
87
|
-
if self.set_cooldown():
|
|
88
|
-
return True
|
|
89
|
-
|
|
90
|
-
self.rate_limit = [query for query in self.rate_limit if is_time_interval(query.get('time') or 0, 30)]
|
|
91
|
-
last_rate_limit = self.get_last_rate_limit()
|
|
92
|
-
|
|
93
|
-
# Check if data size exceeds limit
|
|
94
|
-
if get_mb(sum(query.get('data', 0) for query in self.rate_limit), 100, self.last_mb[method]):
|
|
95
|
-
return True
|
|
96
|
-
|
|
97
|
-
# Check if the last request for the same method was within 10 seconds
|
|
98
|
-
if self.last_method == method and is_time_interval(last_rate_limit.get('time') or 0, 10):
|
|
99
|
-
return True
|
|
100
|
-
|
|
101
|
-
# Check if more than 100 requests in the last 10 seconds
|
|
102
|
-
time_rate = [query for query in self.rate_limit if is_time_interval(query.get('time') or 0, 10)]
|
|
103
|
-
if len(time_rate) > 100:
|
|
104
|
-
return True
|
|
105
|
-
|
|
106
|
-
# Check if more than 40 requests for the same method in the last 10 seconds
|
|
107
|
-
method_specific_time_rate = [query for query in time_rate if query['method'] == method]
|
|
108
|
-
if len(method_specific_time_rate) > 40:
|
|
109
|
-
return True
|
|
110
|
-
|
|
111
|
-
return False
|
|
112
|
-
|
|
113
|
-
def log_response(self, method=None, response=None):
|
|
114
|
-
method = method or 'default_method'
|
|
115
|
-
response = response or {}
|
|
116
|
-
data_size = datasize(response)
|
|
117
|
-
self.last_mb[method] = data_size
|
|
118
|
-
|
|
119
|
-
if self.last_url == self.url1:
|
|
120
|
-
self.rate_limit.append({'method': method, 'data': data_size, 'time': time.time()})
|
|
121
|
-
|
|
122
|
-
self.rate_limit = [query for query in self.rate_limit if is_time_interval(query['time'], 30)]
|
|
123
|
-
self.save_state()
|
|
124
|
-
|
|
125
|
-
def get_url(self, method=None):
|
|
126
|
-
method = method or 'default_method'
|
|
127
|
-
if self.url2 and method == 'get_url_2':
|
|
128
|
-
self.last_url = self.url2
|
|
129
|
-
return self.url2
|
|
130
|
-
|
|
131
|
-
if not self.is_all_limit(method):
|
|
132
|
-
self.last_method = method
|
|
133
|
-
|
|
134
|
-
self.last_url = self.url1
|
|
135
|
-
elif self.url2:
|
|
136
|
-
self.last_url = self.url2
|
|
137
|
-
else:
|
|
138
|
-
return {"rate_limited":"limit has been reached"}
|
|
139
|
-
return self.last_url
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana/abstract_rpcs/get_body.py
RENAMED
|
File without changes
|
{abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana/abstract_utils/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana/abstract_utils/utils.py
RENAMED
|
File without changes
|
|
File without changes
|
{abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana.egg-info/requires.txt
RENAMED
|
File without changes
|
{abstract_solana-0.0.2.81 → abstract_solana-0.0.2.83}/src/abstract_solana.egg-info/top_level.txt
RENAMED
|
File without changes
|