crypto-ws-api 2.0.7__tar.gz → 2.0.9__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.
- {crypto-ws-api-2.0.7 → crypto-ws-api-2.0.9}/CHANGELOG.md +8 -0
- {crypto-ws-api-2.0.7 → crypto-ws-api-2.0.9}/PKG-INFO +1 -1
- {crypto-ws-api-2.0.7 → crypto-ws-api-2.0.9}/crypto_ws_api/__init__.py +2 -2
- {crypto-ws-api-2.0.7 → crypto-ws-api-2.0.9}/crypto_ws_api/ws_session.py +28 -18
- {crypto-ws-api-2.0.7 → crypto-ws-api-2.0.9}/.deepsource.toml +0 -0
- {crypto-ws-api-2.0.7 → crypto-ws-api-2.0.9}/LICENSE.md +0 -0
- {crypto-ws-api-2.0.7 → crypto-ws-api-2.0.9}/README.md +0 -0
- {crypto-ws-api-2.0.7 → crypto-ws-api-2.0.9}/crypto_ws_api/demo.py +0 -0
- {crypto-ws-api-2.0.7 → crypto-ws-api-2.0.9}/crypto_ws_api/ws_api.toml.template +0 -0
- {crypto-ws-api-2.0.7 → crypto-ws-api-2.0.9}/pyproject.toml +0 -0
- {crypto-ws-api-2.0.7 → crypto-ws-api-2.0.9}/requirements.txt +0 -0
|
@@ -13,7 +13,7 @@ __maintainer__ = "Jerry Fedorenko"
|
|
|
13
13
|
__contact__ = "https://github.com/DogsTailFarmer"
|
|
14
14
|
__email__ = "jerry.fedorenko@yahoo.com"
|
|
15
15
|
__credits__ = ["https://github.com/DanyaSWorlD"]
|
|
16
|
-
__version__ = "2.0.
|
|
16
|
+
__version__ = "2.0.9"
|
|
17
17
|
|
|
18
18
|
from pathlib import Path
|
|
19
19
|
import shutil
|
|
@@ -21,7 +21,7 @@ from platformdirs import user_config_path
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
TIMEOUT = 5 # sec timeout for WSS initialization and get response
|
|
24
|
-
DELAY = 0.1 # sec delay in
|
|
24
|
+
DELAY = 0.1 # sec delay in keepalive loop
|
|
25
25
|
# Maximum str size for unique query ID
|
|
26
26
|
ID_LEN_LIMIT = {
|
|
27
27
|
"binance": 36,
|
|
@@ -66,7 +66,7 @@ class UserWSS:
|
|
|
66
66
|
"request_limit_reached",
|
|
67
67
|
"in_event",
|
|
68
68
|
"_response_pool",
|
|
69
|
-
"
|
|
69
|
+
"tasks",
|
|
70
70
|
)
|
|
71
71
|
|
|
72
72
|
def __init__(self, method, ws_id, exchange, endpoint, api_key, api_secret, passphrase=None):
|
|
@@ -87,10 +87,17 @@ class UserWSS:
|
|
|
87
87
|
self.order_handling = False
|
|
88
88
|
self.request_limit_reached = False
|
|
89
89
|
self.in_event = asyncio.Event()
|
|
90
|
-
self.
|
|
90
|
+
self.tasks = set()
|
|
91
|
+
|
|
92
|
+
def tasks_manage(self, coro, name=None):
|
|
93
|
+
_t = asyncio.create_task(coro)
|
|
94
|
+
if name:
|
|
95
|
+
_t.set_name(name)
|
|
96
|
+
self.tasks.add(_t)
|
|
97
|
+
_t.add_done_callback(self.tasks.discard)
|
|
91
98
|
|
|
92
99
|
async def _ws_listener(self):
|
|
93
|
-
|
|
100
|
+
self.tasks_manage(self.ws_login())
|
|
94
101
|
async for msg in self._ws:
|
|
95
102
|
# logger.info(f"_ws_listener: msg: {self.ws_id}: {msg}")
|
|
96
103
|
if isinstance(msg, str):
|
|
@@ -104,7 +111,7 @@ class UserWSS:
|
|
|
104
111
|
elif self.exchange in ['okx', 'bitfinex']:
|
|
105
112
|
self._response_pool[res.get('id') or self.ws_id] = res.get('data') or res
|
|
106
113
|
self.in_event.set()
|
|
107
|
-
|
|
114
|
+
await asyncio.sleep(0)
|
|
108
115
|
else:
|
|
109
116
|
logger.warning(f"UserWSS: {self.ws_id}: {msg}")
|
|
110
117
|
await self.stop()
|
|
@@ -119,8 +126,8 @@ class UserWSS:
|
|
|
119
126
|
break
|
|
120
127
|
else:
|
|
121
128
|
self.operational_status = False
|
|
122
|
-
[task.cancel() for task in self.
|
|
123
|
-
self.
|
|
129
|
+
[task.cancel() for task in self.tasks if not task.done()]
|
|
130
|
+
self.tasks.clear()
|
|
124
131
|
logger.warning(f"Restart WSS for {self.ws_id}")
|
|
125
132
|
continue
|
|
126
133
|
except Exception as ex:
|
|
@@ -134,16 +141,12 @@ class UserWSS:
|
|
|
134
141
|
else:
|
|
135
142
|
if self.exchange == 'binance':
|
|
136
143
|
self._listen_key = res.get('listenKey')
|
|
137
|
-
|
|
138
|
-
_t.set_name(f"heartbeat-{self.ws_id}")
|
|
139
|
-
self.tasks_list.append(_t)
|
|
144
|
+
self.tasks_manage(self.heartbeat(), f"heartbeat-{self.ws_id}")
|
|
140
145
|
else:
|
|
141
146
|
self._listen_key = f"{int(time.time() * 1000)}{self.ws_id}"
|
|
142
147
|
self.operational_status = True
|
|
143
148
|
self.order_handling = True
|
|
144
|
-
|
|
145
|
-
_t.set_name(f"keepalive-{self.ws_id}")
|
|
146
|
-
self.tasks_list.append(_t)
|
|
149
|
+
self.tasks_manage(self._keepalive(), f"keepalive-{self.ws_id}")
|
|
147
150
|
logger.info(f"UserWSS: 'logged in' for {self.ws_id}")
|
|
148
151
|
|
|
149
152
|
async def request(self, _method=None, _params=None, _api_key=False, _signed=False):
|
|
@@ -171,9 +174,10 @@ class UserWSS:
|
|
|
171
174
|
await self._ws.send(
|
|
172
175
|
json.dumps(self.compose_request(_id, _api_key, method, params, _signed))
|
|
173
176
|
)
|
|
177
|
+
await asyncio.sleep(0)
|
|
174
178
|
try:
|
|
175
179
|
res = await asyncio.wait_for(self._response_distributor(_id), timeout=TIMEOUT)
|
|
176
|
-
except asyncio.TimeoutError:
|
|
180
|
+
except asyncio.exceptions.TimeoutError:
|
|
177
181
|
logger.warning(f"UserWSS: get response timeout error: {self.ws_id}")
|
|
178
182
|
await self.stop()
|
|
179
183
|
except asyncio.CancelledError:
|
|
@@ -274,8 +278,8 @@ class UserWSS:
|
|
|
274
278
|
self.operational_status = None # Not restart and break all loops
|
|
275
279
|
self.order_handling = False
|
|
276
280
|
self.init = True
|
|
277
|
-
[task.cancel() for task in self.
|
|
278
|
-
self.
|
|
281
|
+
[task.cancel() for task in self.tasks if not task.done()]
|
|
282
|
+
self.tasks.clear()
|
|
279
283
|
if self._ws and not self._ws.closed:
|
|
280
284
|
await self._ws.close(code=4000)
|
|
281
285
|
gc.collect()
|
|
@@ -296,7 +300,7 @@ class UserWSS:
|
|
|
296
300
|
elif self.exchange == 'bitfinex':
|
|
297
301
|
return await self.bitfinex_error_handle(msg)
|
|
298
302
|
|
|
299
|
-
#region BitfinexErrorHandle
|
|
303
|
+
# region BitfinexErrorHandle
|
|
300
304
|
async def bitfinex_error_handle(self, msg):
|
|
301
305
|
if isinstance(msg, dict):
|
|
302
306
|
return await self._handle_dict_message(msg)
|
|
@@ -348,7 +352,7 @@ class UserWSS:
|
|
|
348
352
|
msg[2][7]
|
|
349
353
|
]
|
|
350
354
|
}
|
|
351
|
-
#endregion
|
|
355
|
+
# endregion
|
|
352
356
|
|
|
353
357
|
async def okx_error_handle(self, msg):
|
|
354
358
|
if msg.get('code') == '1':
|
|
@@ -390,6 +394,7 @@ class UserWSSession:
|
|
|
390
394
|
"_api_secret",
|
|
391
395
|
"_passphrase",
|
|
392
396
|
"user_wss",
|
|
397
|
+
"tasks_wss",
|
|
393
398
|
)
|
|
394
399
|
|
|
395
400
|
def __init__(self, exchange, endpoint, api_key, api_secret, passphrase=None):
|
|
@@ -402,6 +407,7 @@ class UserWSSession:
|
|
|
402
407
|
self._api_secret = api_secret
|
|
403
408
|
self._passphrase = passphrase
|
|
404
409
|
self.user_wss = {}
|
|
410
|
+
self.tasks_wss = set()
|
|
405
411
|
|
|
406
412
|
async def handle_request(
|
|
407
413
|
self,
|
|
@@ -428,7 +434,9 @@ class UserWSSession:
|
|
|
428
434
|
if user_wss.init:
|
|
429
435
|
user_wss.init = False
|
|
430
436
|
user_wss.operational_status = False
|
|
431
|
-
asyncio.
|
|
437
|
+
_t = asyncio.create_task(user_wss.start_wss())
|
|
438
|
+
self.tasks_wss.add(_t)
|
|
439
|
+
_t.add_done_callback(self.tasks_wss.discard)
|
|
432
440
|
|
|
433
441
|
duration = 0
|
|
434
442
|
while not (user_wss.operational_status and user_wss.order_handling):
|
|
@@ -450,3 +458,5 @@ class UserWSSession:
|
|
|
450
458
|
for ws in user_wss_copy.values():
|
|
451
459
|
await ws.stop()
|
|
452
460
|
self.user_wss.clear()
|
|
461
|
+
[task.cancel() for task in self.tasks_wss if not task.done()]
|
|
462
|
+
self.tasks_wss.clear()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|