py-near 1.1.43__py3-none-any.whl → 1.1.47__py3-none-any.whl
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.
py_near/providers.py
CHANGED
@@ -5,8 +5,7 @@ import json
|
|
5
5
|
from collections import Counter
|
6
6
|
from typing import Optional
|
7
7
|
|
8
|
-
import
|
9
|
-
from aiohttp import ClientResponseError, ClientConnectorError, ServerDisconnectedError
|
8
|
+
import httpx
|
10
9
|
from loguru import logger
|
11
10
|
|
12
11
|
from py_near.constants import TIMEOUT_WAIT_RPC
|
@@ -61,10 +60,10 @@ class JsonProvider(object):
|
|
61
60
|
self._last_rpc_addr_check = 0
|
62
61
|
self.allow_broadcast = allow_broadcast
|
63
62
|
self._timeout = timeout
|
64
|
-
self.
|
63
|
+
self._client: httpx.AsyncClient = httpx.AsyncClient()
|
65
64
|
|
66
65
|
async def shutdown(self):
|
67
|
-
|
66
|
+
pass
|
68
67
|
|
69
68
|
async def check_available_rpcs(self):
|
70
69
|
if (
|
@@ -81,7 +80,8 @@ class JsonProvider(object):
|
|
81
80
|
await asyncio.sleep(3)
|
82
81
|
|
83
82
|
if not self._available_rpcs:
|
84
|
-
|
83
|
+
self._available_rpcs = self._rpc_addresses.copy()
|
84
|
+
logger.error("All RPCs are async, reset to default list")
|
85
85
|
|
86
86
|
async def _check_available_rpcs(self):
|
87
87
|
available_rpcs = []
|
@@ -93,32 +93,46 @@ class JsonProvider(object):
|
|
93
93
|
"params": {"finality": "final"},
|
94
94
|
"id": 1,
|
95
95
|
}
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
)
|
96
|
+
auth_key = "py-near"
|
97
|
+
rpc_addr_url = rpc_addr
|
98
|
+
if "@" in rpc_addr:
|
99
|
+
auth_key = rpc_addr_url.split("//")[1].split("@")[0]
|
100
|
+
rpc_addr_url = rpc_addr_url.replace(auth_key + "@", "")
|
101
|
+
|
102
|
+
r = await self._client.post(
|
103
|
+
rpc_addr_url,
|
104
|
+
json=data,
|
105
|
+
headers={
|
106
|
+
"Referer": "https://tgapp.herewallet.app",
|
107
|
+
"Authorization": f"Bearer {auth_key}",
|
108
|
+
},
|
109
|
+
)
|
110
|
+
if r.status_code == 200:
|
111
|
+
data = json.loads(r.text)["result"]
|
112
|
+
diff = 0
|
113
|
+
if data["sync_info"]["syncing"]:
|
114
|
+
last_block_ts = datetime.datetime.fromisoformat(
|
115
|
+
data["sync_info"]["latest_block_time"]
|
116
|
+
)
|
117
|
+
diff = (
|
118
|
+
datetime.datetime.utcnow().timestamp()
|
119
|
+
- last_block_ts.timestamp()
|
120
|
+
)
|
121
|
+
is_syncing = diff > 60
|
122
|
+
else:
|
123
|
+
is_syncing = False
|
124
|
+
if is_syncing:
|
125
|
+
logger.error(f"Remove async RPC : {rpc_addr} ({diff})")
|
126
|
+
continue
|
127
|
+
available_rpcs.append(rpc_addr)
|
128
|
+
else:
|
129
|
+
logger.error(
|
130
|
+
f"Remove rpc because of error {r.status_code}: {rpc_addr}"
|
131
|
+
)
|
119
132
|
except Exception as e:
|
120
133
|
if rpc_addr in self._available_rpcs:
|
121
134
|
logger.error(f"Remove rpc: {e}")
|
135
|
+
logger.error(f"Rpc check error: {e}")
|
122
136
|
self._available_rpcs = available_rpcs
|
123
137
|
|
124
138
|
@staticmethod
|
@@ -138,24 +152,26 @@ class JsonProvider(object):
|
|
138
152
|
if "@" in rpc_call_addr:
|
139
153
|
auth_key = rpc_call_addr.split("//")[1].split("@")[0]
|
140
154
|
rpc_call_addr = rpc_call_addr.replace(auth_key + "@", "")
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
"
|
155
|
-
"
|
156
|
-
"
|
157
|
-
}
|
155
|
+
r = await self._client.post(
|
156
|
+
rpc_call_addr,
|
157
|
+
json=j,
|
158
|
+
timeout=self._timeout,
|
159
|
+
headers={
|
160
|
+
"Referer": "https://tgapp.herewallet.app",
|
161
|
+
"Authorization": f"Bearer {auth_key}",
|
162
|
+
},
|
163
|
+
)
|
164
|
+
if r.status_code == 200:
|
165
|
+
return json.loads(r.text)
|
166
|
+
return {
|
167
|
+
"error": {
|
168
|
+
"cause": {
|
169
|
+
"name": "RPC_ERROR",
|
170
|
+
"message": f"Status: {r.status_code}",
|
171
|
+
},
|
172
|
+
"data": r.text,
|
158
173
|
}
|
174
|
+
}
|
159
175
|
|
160
176
|
if broadcast or threshold:
|
161
177
|
pending = [
|
@@ -163,6 +179,9 @@ class JsonProvider(object):
|
|
163
179
|
]
|
164
180
|
|
165
181
|
responses = []
|
182
|
+
correct_responses = []
|
183
|
+
result = None
|
184
|
+
|
166
185
|
while pending and len(pending):
|
167
186
|
done, pending = await asyncio.wait(
|
168
187
|
pending, return_when=asyncio.FIRST_COMPLETED
|
@@ -175,17 +194,25 @@ class JsonProvider(object):
|
|
175
194
|
responses.append(result)
|
176
195
|
except Exception as e:
|
177
196
|
logger.warning(e)
|
178
|
-
if responses:
|
197
|
+
if responses and threshold:
|
179
198
|
array = [hash(json.dumps(x)) for x in responses]
|
180
199
|
most_frequent_element = self.most_frequent_by_hash(array)
|
181
200
|
correct_responses = [
|
182
|
-
x
|
201
|
+
x
|
202
|
+
for x in responses
|
203
|
+
if hash(json.dumps(x)) == most_frequent_element
|
183
204
|
]
|
184
205
|
if len(correct_responses) >= threshold:
|
185
206
|
for task in pending:
|
186
207
|
task.cancel()
|
187
|
-
return
|
208
|
+
return correct_responses[0]
|
209
|
+
if threshold and threshold > 0:
|
210
|
+
raise RpcEmptyResponse(
|
211
|
+
f"Threshold not reached: {len(correct_responses)}/{threshold}"
|
212
|
+
)
|
213
|
+
return result
|
188
214
|
else:
|
215
|
+
res = None
|
189
216
|
for rpc_addr in self._available_rpcs:
|
190
217
|
try:
|
191
218
|
res = await f(rpc_addr)
|
@@ -194,7 +221,7 @@ class JsonProvider(object):
|
|
194
221
|
except Exception as e:
|
195
222
|
logger.error(f"Rpc error: {e}")
|
196
223
|
continue
|
197
|
-
|
224
|
+
return res
|
198
225
|
|
199
226
|
@staticmethod
|
200
227
|
def get_error_from_response(content: dict):
|
@@ -299,7 +326,7 @@ class JsonProvider(object):
|
|
299
326
|
|
300
327
|
async def get_status(self):
|
301
328
|
await self.check_available_rpcs()
|
302
|
-
for rpc_addr in self._available_rpcs:
|
329
|
+
for rpc_addr in self._available_rpcs.copy():
|
303
330
|
try:
|
304
331
|
data = {
|
305
332
|
"jsonrpc": "2.0",
|
@@ -307,16 +334,19 @@ class JsonProvider(object):
|
|
307
334
|
"params": {"finality": "final"},
|
308
335
|
"id": 1,
|
309
336
|
}
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
337
|
+
headers = {
|
338
|
+
"Referer": "https://tgapp.herewallet.app",
|
339
|
+
}
|
340
|
+
if "@" in rpc_addr:
|
341
|
+
auth_key = rpc_addr.split("//")[1].split("@")[0]
|
342
|
+
rpc_addr = rpc_addr.replace(auth_key + "@", "")
|
343
|
+
headers = {
|
344
|
+
"Authorization": f"Bearer {auth_key}"
|
345
|
+
}
|
346
|
+
r = await self._client.post(rpc_addr, json=data, headers=headers)
|
347
|
+
if r.status_code == 200:
|
348
|
+
return json.loads(r.text)["result"]
|
349
|
+
except ConnectionError as e:
|
320
350
|
logger.error(f"Rpc get status error: {e}")
|
321
351
|
except Exception as e:
|
322
352
|
logger.error(e)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: py-near
|
3
|
-
Version: 1.1.
|
3
|
+
Version: 1.1.47
|
4
4
|
Summary: Pretty simple and fully asynchronous framework for working with NEAR blockchain
|
5
5
|
Author: pvolnov
|
6
6
|
Author-email: petr@herewallet.app
|
@@ -12,9 +12,9 @@ Classifier: Programming Language :: Python :: 3.9
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.10
|
13
13
|
Classifier: Programming Language :: Python :: 3.11
|
14
14
|
Classifier: Programming Language :: Python :: 3.12
|
15
|
-
Requires-Dist:
|
16
|
-
Requires-Dist:
|
17
|
-
Requires-Dist: py-near-primitives (
|
15
|
+
Requires-Dist: ed25519 (==1.5)
|
16
|
+
Requires-Dist: httpx (==0.27.0)
|
17
|
+
Requires-Dist: py-near-primitives (==0.2.3)
|
18
18
|
Description-Content-Type: text/markdown
|
19
19
|
|
20
20
|
# py-near
|
@@ -20,10 +20,10 @@ py_near/exceptions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
|
|
20
20
|
py_near/exceptions/exceptions.py,sha256=DEFipaAHm0y7oCuN2QKzHsiQvUTUQVl-Ce36Ag7n7hs,5509
|
21
21
|
py_near/exceptions/provider.py,sha256=K-wexgjPJ8sw42JePwaP7R5dJEIn9DoFJRvVcURsx6s,7718
|
22
22
|
py_near/models.py,sha256=GZQD1TKGWlwqsJsKRXrVNBjCdAIpk7GQypU-QOtAPFs,11533
|
23
|
-
py_near/providers.py,sha256=
|
23
|
+
py_near/providers.py,sha256=1eg9MFIYIKA09bZyTdSZ2Umrh0kX1SUFEhY_tN8Cqz4,16722
|
24
24
|
py_near/transactions.py,sha256=QAXegv2JpKISk92NaChtIH6-QPHrcWbrwdKH_lH4TsU,3186
|
25
25
|
py_near/utils.py,sha256=FirRH93ydH1cwjn0-sNrZeIn3BRD6QHedrP2VkAdJ6g,126
|
26
|
-
py_near-1.1.
|
27
|
-
py_near-1.1.
|
28
|
-
py_near-1.1.
|
29
|
-
py_near-1.1.
|
26
|
+
py_near-1.1.47.dist-info/LICENSE,sha256=I_GOA9xJ35FiL-KnYXZJdATkbO2KcV2dK2enRGVxzKM,1023
|
27
|
+
py_near-1.1.47.dist-info/METADATA,sha256=Nd8CpvwjXiIyN9WK4JdCs46PgRUExpRNnSXTW6javYE,4693
|
28
|
+
py_near-1.1.47.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
29
|
+
py_near-1.1.47.dist-info/RECORD,,
|
File without changes
|
File without changes
|