gengineapi 0.1.0__tar.gz → 0.2.1__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.
- {gengineapi-0.1.0 → gengineapi-0.2.1}/PKG-INFO +61 -55
- {gengineapi-0.1.0 → gengineapi-0.2.1}/README.md +59 -52
- {gengineapi-0.1.0 → gengineapi-0.2.1}/pyproject.toml +3 -10
- {gengineapi-0.1.0 → gengineapi-0.2.1}/src/gengineapi/__init__.py +4 -0
- gengineapi-0.2.1/src/gengineapi/farm.py +464 -0
- {gengineapi-0.1.0 → gengineapi-0.2.1}/src/gengineapi.egg-info/PKG-INFO +61 -55
- {gengineapi-0.1.0 → gengineapi-0.2.1}/src/gengineapi.egg-info/SOURCES.txt +1 -0
- {gengineapi-0.1.0 → gengineapi-0.2.1}/src/gengineapi.egg-info/requires.txt +0 -1
- {gengineapi-0.1.0 → gengineapi-0.2.1}/setup.cfg +0 -0
- {gengineapi-0.1.0 → gengineapi-0.2.1}/src/gengineapi/client.py +0 -0
- {gengineapi-0.1.0 → gengineapi-0.2.1}/src/gengineapi/config.py +0 -0
- {gengineapi-0.1.0 → gengineapi-0.2.1}/src/gengineapi/exceptions.py +0 -0
- {gengineapi-0.1.0 → gengineapi-0.2.1}/src/gengineapi/http.py +0 -0
- {gengineapi-0.1.0 → gengineapi-0.2.1}/src/gengineapi/modules/__init__.py +0 -0
- {gengineapi-0.1.0 → gengineapi-0.2.1}/src/gengineapi/modules/auth.py +0 -0
- {gengineapi-0.1.0 → gengineapi-0.2.1}/src/gengineapi/modules/base.py +0 -0
- {gengineapi-0.1.0 → gengineapi-0.2.1}/src/gengineapi/modules/currencies.py +0 -0
- {gengineapi-0.1.0 → gengineapi-0.2.1}/src/gengineapi/modules/finances.py +0 -0
- {gengineapi-0.1.0 → gengineapi-0.2.1}/src/gengineapi/modules/payments.py +0 -0
- {gengineapi-0.1.0 → gengineapi-0.2.1}/src/gengineapi/modules/transactions.py +0 -0
- {gengineapi-0.1.0 → gengineapi-0.2.1}/src/gengineapi/modules/users.py +0 -0
- {gengineapi-0.1.0 → gengineapi-0.2.1}/src/gengineapi.egg-info/dependency_links.txt +0 -0
- {gengineapi-0.1.0 → gengineapi-0.2.1}/src/gengineapi.egg-info/top_level.txt +0 -0
@@ -1,15 +1,14 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: gengineapi
|
3
|
-
Version: 0.1
|
4
|
-
Summary:
|
3
|
+
Version: 0.2.1
|
4
|
+
Summary: G-Engine API Client
|
5
5
|
Requires-Python: >=3.13
|
6
6
|
Description-Content-Type: text/markdown
|
7
7
|
Requires-Dist: aiohttp>=3.8.0
|
8
8
|
Requires-Dist: typing-extensions>=4.0.0
|
9
9
|
Requires-Dist: aiohttp-socks>=0.7.1
|
10
|
-
Requires-Dist: uv-publish
|
11
10
|
|
12
|
-
#
|
11
|
+
# GEngineAPI
|
13
12
|
|
14
13
|
Асинхронный модульный клиент для взаимодействия с API G-Engine.
|
15
14
|
|
@@ -21,6 +20,7 @@ Requires-Dist: uv-publish
|
|
21
20
|
- Автоматические повторные попытки для временных ошибок
|
22
21
|
- Поддержка JWT-аутентификации
|
23
22
|
- Поддержка прокси, включая SOCKS5
|
23
|
+
- Ферма клиентов с балансировкой нагрузки и стратегиями ротации
|
24
24
|
- Подробное логирование
|
25
25
|
- Строгая типизация с помощью аннотаций типов
|
26
26
|
- Класс-конфигурация для централизованной настройки и повторного использования
|
@@ -28,33 +28,13 @@ Requires-Dist: uv-publish
|
|
28
28
|
## Установка
|
29
29
|
|
30
30
|
```bash
|
31
|
-
pip install
|
31
|
+
pip install gengineapi
|
32
32
|
```
|
33
33
|
|
34
|
-
|
34
|
+
Для поддержки SOCKS5 прокси убедитесь, что установлен пакет `aiohttp-socks`:
|
35
35
|
|
36
36
|
```bash
|
37
|
-
pip install
|
38
|
-
```
|
39
|
-
|
40
|
-
## Структура проекта
|
41
|
-
|
42
|
-
```
|
43
|
-
gengine_client/
|
44
|
-
├── __init__.py # Экспорт основных классов
|
45
|
-
├── client.py # Основной класс клиента
|
46
|
-
├── http.py # HTTP клиент с поддержкой аутентификации
|
47
|
-
├── exceptions.py # Иерархия исключений API
|
48
|
-
├── config.py # Класс-конфигурация для настройки параметров
|
49
|
-
└── modules/ # Папка с модулями API
|
50
|
-
├── __init__.py
|
51
|
-
├── base.py # Базовый класс для всех модулей
|
52
|
-
├── payments.py # Модуль для работы с платежами
|
53
|
-
├── finances.py # Модуль для работы с финансами
|
54
|
-
├── auth.py # Модуль для аутентификации
|
55
|
-
├── users.py # Модуль для работы с пользователями
|
56
|
-
├── transactions.py # Модуль для работы с транзакциями
|
57
|
-
└── currencies.py # Модуль для работы с валютами
|
37
|
+
pip install aiohttp-socks
|
58
38
|
```
|
59
39
|
|
60
40
|
## Использование
|
@@ -63,7 +43,7 @@ gengine_client/
|
|
63
43
|
|
64
44
|
```python
|
65
45
|
import asyncio
|
66
|
-
from
|
46
|
+
from gengineapi import GEngineClient
|
67
47
|
|
68
48
|
async def main():
|
69
49
|
# Создаем клиент с существующим токеном
|
@@ -84,7 +64,7 @@ asyncio.run(main())
|
|
84
64
|
|
85
65
|
```python
|
86
66
|
import asyncio
|
87
|
-
from
|
67
|
+
from gengineapi import GEngineClient
|
88
68
|
|
89
69
|
async def main():
|
90
70
|
# Создаем клиент без токена
|
@@ -119,7 +99,7 @@ asyncio.run(main())
|
|
119
99
|
|
120
100
|
```python
|
121
101
|
import asyncio
|
122
|
-
from
|
102
|
+
from gengineapi import GEngineClient
|
123
103
|
|
124
104
|
async def main():
|
125
105
|
# Создаем клиент с использованием SOCKS5 прокси
|
@@ -149,7 +129,7 @@ asyncio.run(main())
|
|
149
129
|
|
150
130
|
```python
|
151
131
|
import asyncio
|
152
|
-
from
|
132
|
+
from gengineapi import GEngineConfig
|
153
133
|
|
154
134
|
async def main():
|
155
135
|
# Настройка параметров клиента
|
@@ -188,32 +168,52 @@ async def main():
|
|
188
168
|
asyncio.run(main())
|
189
169
|
```
|
190
170
|
|
191
|
-
###
|
171
|
+
### Использование фермы клиентов
|
172
|
+
|
173
|
+
Ферма клиентов позволяет управлять множеством клиентов с разными конфигурациями и стратегиями ротации:
|
192
174
|
|
193
175
|
```python
|
194
176
|
import asyncio
|
195
|
-
import
|
196
|
-
from gengine_client import GEngineConfig
|
197
|
-
|
198
|
-
# Установка переменных окружения
|
199
|
-
os.environ["GENGINE_BASE_URL"] = "https://api.example.com/api/v2"
|
200
|
-
os.environ["GENGINE_TOKEN"] = "env_jwt_token"
|
201
|
-
os.environ["GENGINE_TIMEOUT"] = "45"
|
202
|
-
os.environ["GENGINE_MAX_RETRIES"] = "5"
|
203
|
-
os.environ["GENGINE_PROXY"] = "socks5://127.0.0.1:9050" # Опционально - прокси
|
177
|
+
from gengineapi import ClientFarm
|
204
178
|
|
205
179
|
async def main():
|
206
|
-
#
|
207
|
-
|
180
|
+
# Создаем ферму клиентов
|
181
|
+
farm = ClientFarm()
|
208
182
|
|
209
|
-
#
|
210
|
-
|
183
|
+
# Добавляем несколько конфигураций с разными прокси
|
184
|
+
farm.create_config(
|
185
|
+
name="client1",
|
186
|
+
base_url="https://api.example.com/api/v2",
|
187
|
+
jwt_token="token1",
|
188
|
+
proxy="socks5://user1:pass1@host1:port1",
|
189
|
+
tags=["group1", "production"]
|
190
|
+
)
|
211
191
|
|
212
|
-
|
213
|
-
|
192
|
+
farm.create_config(
|
193
|
+
name="client2",
|
194
|
+
base_url="https://api.example.com/api/v2",
|
195
|
+
jwt_token="token2",
|
196
|
+
proxy="socks5://user2:pass2@host2:port2",
|
197
|
+
tags=["group1", "backup"]
|
198
|
+
)
|
214
199
|
|
215
|
-
#
|
216
|
-
|
200
|
+
# Устанавливаем стратегию выбора клиента
|
201
|
+
farm.set_selection_strategy("round_robin") # или "random", "least_errors", "least_recently_used"
|
202
|
+
|
203
|
+
# Получаем клиент по имени
|
204
|
+
client1 = await farm.get_client("client1")
|
205
|
+
await client1.users.get_me()
|
206
|
+
|
207
|
+
# Получаем следующий клиент согласно стратегии
|
208
|
+
client = await farm.get_next_client()
|
209
|
+
await client.currencies.get_rate(source="cb_rf", pair="USD:RUB")
|
210
|
+
|
211
|
+
# Получаем клиент по тегу
|
212
|
+
client = await farm.get_next_client(tag="production")
|
213
|
+
await client.transactions.get_transactions(limit=5)
|
214
|
+
|
215
|
+
# При завершении работы закрываем все клиенты
|
216
|
+
await farm.close_all()
|
217
217
|
|
218
218
|
asyncio.run(main())
|
219
219
|
```
|
@@ -224,7 +224,7 @@ asyncio.run(main())
|
|
224
224
|
import asyncio
|
225
225
|
import uuid
|
226
226
|
from decimal import Decimal
|
227
|
-
from
|
227
|
+
from gengineapi import GEngineClient
|
228
228
|
|
229
229
|
async def main():
|
230
230
|
async with GEngineClient(
|
@@ -255,19 +255,25 @@ async def main():
|
|
255
255
|
asyncio.run(main())
|
256
256
|
```
|
257
257
|
|
258
|
-
##
|
258
|
+
## Доступные модули API
|
259
|
+
|
260
|
+
- `payments` - создание и выполнение платежей
|
261
|
+
- `finances` - работа с финансовыми данными
|
262
|
+
- `auth` - аутентификация и управление токенами
|
263
|
+
- `users` - работа с пользователями и их балансами
|
264
|
+
- `transactions` - работа с транзакциями
|
265
|
+
- `currencies` - работа с курсами валют
|
259
266
|
|
260
|
-
|
267
|
+
## Дополнительная документация
|
261
268
|
|
262
|
-
|
263
|
-
- `old_examples/` - директория с устаревшими примерами
|
269
|
+
Ручки, которые дергаем - https://b2b-api.ggsel.com/api/v2/docs#
|
264
270
|
|
265
271
|
## Зависимости
|
266
272
|
|
267
273
|
- Python 3.7+
|
268
274
|
- aiohttp >= 3.8.0
|
269
275
|
- typing-extensions >= 4.0.0
|
270
|
-
- aiohttp-socks >= 0.7.1 (для поддержки SOCKS5 прокси)
|
276
|
+
- aiohttp-socks >= 0.7.1 (опционально, для поддержки SOCKS5 прокси)
|
271
277
|
|
272
278
|
## Лицензия
|
273
279
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# GEngineAPI
|
2
2
|
|
3
3
|
Асинхронный модульный клиент для взаимодействия с API G-Engine.
|
4
4
|
|
@@ -10,6 +10,7 @@
|
|
10
10
|
- Автоматические повторные попытки для временных ошибок
|
11
11
|
- Поддержка JWT-аутентификации
|
12
12
|
- Поддержка прокси, включая SOCKS5
|
13
|
+
- Ферма клиентов с балансировкой нагрузки и стратегиями ротации
|
13
14
|
- Подробное логирование
|
14
15
|
- Строгая типизация с помощью аннотаций типов
|
15
16
|
- Класс-конфигурация для централизованной настройки и повторного использования
|
@@ -17,33 +18,13 @@
|
|
17
18
|
## Установка
|
18
19
|
|
19
20
|
```bash
|
20
|
-
pip install
|
21
|
+
pip install gengineapi
|
21
22
|
```
|
22
23
|
|
23
|
-
|
24
|
+
Для поддержки SOCKS5 прокси убедитесь, что установлен пакет `aiohttp-socks`:
|
24
25
|
|
25
26
|
```bash
|
26
|
-
pip install
|
27
|
-
```
|
28
|
-
|
29
|
-
## Структура проекта
|
30
|
-
|
31
|
-
```
|
32
|
-
gengine_client/
|
33
|
-
├── __init__.py # Экспорт основных классов
|
34
|
-
├── client.py # Основной класс клиента
|
35
|
-
├── http.py # HTTP клиент с поддержкой аутентификации
|
36
|
-
├── exceptions.py # Иерархия исключений API
|
37
|
-
├── config.py # Класс-конфигурация для настройки параметров
|
38
|
-
└── modules/ # Папка с модулями API
|
39
|
-
├── __init__.py
|
40
|
-
├── base.py # Базовый класс для всех модулей
|
41
|
-
├── payments.py # Модуль для работы с платежами
|
42
|
-
├── finances.py # Модуль для работы с финансами
|
43
|
-
├── auth.py # Модуль для аутентификации
|
44
|
-
├── users.py # Модуль для работы с пользователями
|
45
|
-
├── transactions.py # Модуль для работы с транзакциями
|
46
|
-
└── currencies.py # Модуль для работы с валютами
|
27
|
+
pip install aiohttp-socks
|
47
28
|
```
|
48
29
|
|
49
30
|
## Использование
|
@@ -52,7 +33,7 @@ gengine_client/
|
|
52
33
|
|
53
34
|
```python
|
54
35
|
import asyncio
|
55
|
-
from
|
36
|
+
from gengineapi import GEngineClient
|
56
37
|
|
57
38
|
async def main():
|
58
39
|
# Создаем клиент с существующим токеном
|
@@ -73,7 +54,7 @@ asyncio.run(main())
|
|
73
54
|
|
74
55
|
```python
|
75
56
|
import asyncio
|
76
|
-
from
|
57
|
+
from gengineapi import GEngineClient
|
77
58
|
|
78
59
|
async def main():
|
79
60
|
# Создаем клиент без токена
|
@@ -108,7 +89,7 @@ asyncio.run(main())
|
|
108
89
|
|
109
90
|
```python
|
110
91
|
import asyncio
|
111
|
-
from
|
92
|
+
from gengineapi import GEngineClient
|
112
93
|
|
113
94
|
async def main():
|
114
95
|
# Создаем клиент с использованием SOCKS5 прокси
|
@@ -138,7 +119,7 @@ asyncio.run(main())
|
|
138
119
|
|
139
120
|
```python
|
140
121
|
import asyncio
|
141
|
-
from
|
122
|
+
from gengineapi import GEngineConfig
|
142
123
|
|
143
124
|
async def main():
|
144
125
|
# Настройка параметров клиента
|
@@ -177,32 +158,52 @@ async def main():
|
|
177
158
|
asyncio.run(main())
|
178
159
|
```
|
179
160
|
|
180
|
-
###
|
161
|
+
### Использование фермы клиентов
|
162
|
+
|
163
|
+
Ферма клиентов позволяет управлять множеством клиентов с разными конфигурациями и стратегиями ротации:
|
181
164
|
|
182
165
|
```python
|
183
166
|
import asyncio
|
184
|
-
import
|
185
|
-
from gengine_client import GEngineConfig
|
186
|
-
|
187
|
-
# Установка переменных окружения
|
188
|
-
os.environ["GENGINE_BASE_URL"] = "https://api.example.com/api/v2"
|
189
|
-
os.environ["GENGINE_TOKEN"] = "env_jwt_token"
|
190
|
-
os.environ["GENGINE_TIMEOUT"] = "45"
|
191
|
-
os.environ["GENGINE_MAX_RETRIES"] = "5"
|
192
|
-
os.environ["GENGINE_PROXY"] = "socks5://127.0.0.1:9050" # Опционально - прокси
|
167
|
+
from gengineapi import ClientFarm
|
193
168
|
|
194
169
|
async def main():
|
195
|
-
#
|
196
|
-
|
170
|
+
# Создаем ферму клиентов
|
171
|
+
farm = ClientFarm()
|
197
172
|
|
198
|
-
#
|
199
|
-
|
173
|
+
# Добавляем несколько конфигураций с разными прокси
|
174
|
+
farm.create_config(
|
175
|
+
name="client1",
|
176
|
+
base_url="https://api.example.com/api/v2",
|
177
|
+
jwt_token="token1",
|
178
|
+
proxy="socks5://user1:pass1@host1:port1",
|
179
|
+
tags=["group1", "production"]
|
180
|
+
)
|
200
181
|
|
201
|
-
|
202
|
-
|
182
|
+
farm.create_config(
|
183
|
+
name="client2",
|
184
|
+
base_url="https://api.example.com/api/v2",
|
185
|
+
jwt_token="token2",
|
186
|
+
proxy="socks5://user2:pass2@host2:port2",
|
187
|
+
tags=["group1", "backup"]
|
188
|
+
)
|
203
189
|
|
204
|
-
#
|
205
|
-
|
190
|
+
# Устанавливаем стратегию выбора клиента
|
191
|
+
farm.set_selection_strategy("round_robin") # или "random", "least_errors", "least_recently_used"
|
192
|
+
|
193
|
+
# Получаем клиент по имени
|
194
|
+
client1 = await farm.get_client("client1")
|
195
|
+
await client1.users.get_me()
|
196
|
+
|
197
|
+
# Получаем следующий клиент согласно стратегии
|
198
|
+
client = await farm.get_next_client()
|
199
|
+
await client.currencies.get_rate(source="cb_rf", pair="USD:RUB")
|
200
|
+
|
201
|
+
# Получаем клиент по тегу
|
202
|
+
client = await farm.get_next_client(tag="production")
|
203
|
+
await client.transactions.get_transactions(limit=5)
|
204
|
+
|
205
|
+
# При завершении работы закрываем все клиенты
|
206
|
+
await farm.close_all()
|
206
207
|
|
207
208
|
asyncio.run(main())
|
208
209
|
```
|
@@ -213,7 +214,7 @@ asyncio.run(main())
|
|
213
214
|
import asyncio
|
214
215
|
import uuid
|
215
216
|
from decimal import Decimal
|
216
|
-
from
|
217
|
+
from gengineapi import GEngineClient
|
217
218
|
|
218
219
|
async def main():
|
219
220
|
async with GEngineClient(
|
@@ -244,19 +245,25 @@ async def main():
|
|
244
245
|
asyncio.run(main())
|
245
246
|
```
|
246
247
|
|
247
|
-
##
|
248
|
+
## Доступные модули API
|
249
|
+
|
250
|
+
- `payments` - создание и выполнение платежей
|
251
|
+
- `finances` - работа с финансовыми данными
|
252
|
+
- `auth` - аутентификация и управление токенами
|
253
|
+
- `users` - работа с пользователями и их балансами
|
254
|
+
- `transactions` - работа с транзакциями
|
255
|
+
- `currencies` - работа с курсами валют
|
248
256
|
|
249
|
-
|
257
|
+
## Дополнительная документация
|
250
258
|
|
251
|
-
|
252
|
-
- `old_examples/` - директория с устаревшими примерами
|
259
|
+
Ручки, которые дергаем - https://b2b-api.ggsel.com/api/v2/docs#
|
253
260
|
|
254
261
|
## Зависимости
|
255
262
|
|
256
263
|
- Python 3.7+
|
257
264
|
- aiohttp >= 3.8.0
|
258
265
|
- typing-extensions >= 4.0.0
|
259
|
-
- aiohttp-socks >= 0.7.1 (для поддержки SOCKS5 прокси)
|
266
|
+
- aiohttp-socks >= 0.7.1 (опционально, для поддержки SOCKS5 прокси)
|
260
267
|
|
261
268
|
## Лицензия
|
262
269
|
|
@@ -1,18 +1,11 @@
|
|
1
1
|
[project]
|
2
2
|
name = "gengineapi"
|
3
|
-
version = "0.1
|
4
|
-
description = "
|
3
|
+
version = "0.2.1"
|
4
|
+
description = "G-Engine API Client"
|
5
5
|
readme = "README.md"
|
6
6
|
requires-python = ">=3.13"
|
7
7
|
dependencies = [
|
8
8
|
"aiohttp>=3.8.0", # Для асинхронных HTTP-запросов и WebSocket
|
9
9
|
"typing-extensions>=4.0.0", # Для расширенных типов аннотаций
|
10
10
|
"aiohttp-socks>=0.7.1",
|
11
|
-
|
12
|
-
]
|
13
|
-
|
14
|
-
[[tool.uv.index]]
|
15
|
-
name = "testpypi"
|
16
|
-
url = "https://test.pypi.org/simple/"
|
17
|
-
publish-url = "https://test.pypi.org/legacy/"
|
18
|
-
explicit = true
|
11
|
+
]
|
@@ -19,6 +19,7 @@ from .exceptions import (
|
|
19
19
|
ApiTimeoutError,
|
20
20
|
ApiValidationError,
|
21
21
|
)
|
22
|
+
from .farm import ClientFarm, ClientConfig
|
22
23
|
from .http import AsyncHttpClient
|
23
24
|
|
24
25
|
__version__ = "1.0.0"
|
@@ -29,6 +30,9 @@ __all__ = [
|
|
29
30
|
'GEngineConfig',
|
30
31
|
# HTTP клиент
|
31
32
|
'AsyncHttpClient',
|
33
|
+
# Ферма клиентов
|
34
|
+
'ClientFarm',
|
35
|
+
'ClientConfig',
|
32
36
|
# Исключения
|
33
37
|
'ApiError',
|
34
38
|
'ApiConnectionError',
|
@@ -0,0 +1,464 @@
|
|
1
|
+
"""
|
2
|
+
Модуль, предоставляющий функциональность для управления фермой клиентов G-Engine API.
|
3
|
+
|
4
|
+
Позволяет создавать и управлять несколькими независимыми клиентами
|
5
|
+
с различными конфигурациями, прокси и токенами аутентификации.
|
6
|
+
"""
|
7
|
+
import asyncio
|
8
|
+
import logging
|
9
|
+
import uuid
|
10
|
+
from typing import Dict, Optional, List, Any
|
11
|
+
|
12
|
+
from .client import GEngineClient
|
13
|
+
|
14
|
+
|
15
|
+
class ClientConfig:
|
16
|
+
"""
|
17
|
+
Класс конфигурации для отдельного клиента.
|
18
|
+
|
19
|
+
Позволяет хранить и управлять параметрами для создания клиента.
|
20
|
+
|
21
|
+
Attributes:
|
22
|
+
name: Уникальное имя конфигурации
|
23
|
+
base_url: Базовый URL для API
|
24
|
+
jwt_token: JWT токен для аутентификации
|
25
|
+
timeout: Таймаут для запросов в секундах
|
26
|
+
max_retries: Максимальное количество повторных попыток
|
27
|
+
logger: Логгер для записи информации
|
28
|
+
proxy: Прокси для запросов
|
29
|
+
client: Экземпляр клиента, если он был создан
|
30
|
+
"""
|
31
|
+
|
32
|
+
def __init__(
|
33
|
+
self,
|
34
|
+
base_url: str,
|
35
|
+
jwt_token: Optional[str] = None,
|
36
|
+
timeout: int = 30,
|
37
|
+
max_retries: int = 3,
|
38
|
+
logger: Optional[logging.Logger] = None,
|
39
|
+
proxy: Optional[str] = None,
|
40
|
+
name: Optional[str] = None, # Уникальное имя конфига
|
41
|
+
tags: Optional[List[str]] = None, # Теги для группировки и фильтрации
|
42
|
+
) -> None:
|
43
|
+
"""
|
44
|
+
Инициализация конфигурации клиента.
|
45
|
+
|
46
|
+
Args:
|
47
|
+
base_url: Базовый URL для API
|
48
|
+
jwt_token: JWT токен для аутентификации (опционально)
|
49
|
+
timeout: Таймаут для запросов в секундах (по умолчанию 30)
|
50
|
+
max_retries: Максимальное количество повторных попыток (по умолчанию 3)
|
51
|
+
logger: Логгер для записи информации (опционально)
|
52
|
+
proxy: Прокси для запросов в формате 'socks5://user:pass@host:port' (опционально)
|
53
|
+
name: Уникальное имя конфигурации (опционально, генерируется автоматически)
|
54
|
+
tags: Список тегов для группировки и фильтрации (опционально)
|
55
|
+
"""
|
56
|
+
self.base_url = base_url
|
57
|
+
self.jwt_token = jwt_token
|
58
|
+
self.timeout = timeout
|
59
|
+
self.max_retries = max_retries
|
60
|
+
self.logger = logger
|
61
|
+
self.proxy = proxy
|
62
|
+
self.name = name or str(uuid.uuid4())
|
63
|
+
self.tags = tags or []
|
64
|
+
self.client: Optional[GEngineClient] = None
|
65
|
+
self.last_used: float = 0 # Время последнего использования (для ротации)
|
66
|
+
self.error_count: int = 0 # Счетчик ошибок
|
67
|
+
self.success_count: int = 0 # Счетчик успешных запросов
|
68
|
+
self.is_active: bool = True # Флаг активности конфигурации
|
69
|
+
|
70
|
+
async def get_client(self) -> GEngineClient:
|
71
|
+
"""
|
72
|
+
Возвращает клиент или создает новый, если он не существует.
|
73
|
+
|
74
|
+
Returns:
|
75
|
+
GEngineClient: Экземпляр клиента API
|
76
|
+
"""
|
77
|
+
if self.client is None:
|
78
|
+
self.client = GEngineClient(
|
79
|
+
base_url=self.base_url,
|
80
|
+
jwt_token=self.jwt_token,
|
81
|
+
timeout=self.timeout,
|
82
|
+
max_retries=self.max_retries,
|
83
|
+
logger=self.logger,
|
84
|
+
proxy=self.proxy
|
85
|
+
)
|
86
|
+
|
87
|
+
# Обновляем время последнего использования
|
88
|
+
import time
|
89
|
+
self.last_used = time.time()
|
90
|
+
|
91
|
+
return self.client
|
92
|
+
|
93
|
+
async def close(self) -> None:
|
94
|
+
"""Закрывает клиент."""
|
95
|
+
if self.client:
|
96
|
+
await self.client.close()
|
97
|
+
self.client = None
|
98
|
+
|
99
|
+
def update_token(self, jwt_token: str) -> None:
|
100
|
+
"""
|
101
|
+
Обновляет JWT токен в конфигурации и в клиенте, если он существует.
|
102
|
+
|
103
|
+
Args:
|
104
|
+
jwt_token: Новый JWT токен
|
105
|
+
"""
|
106
|
+
self.jwt_token = jwt_token
|
107
|
+
if self.client:
|
108
|
+
self.client.update_token(jwt_token)
|
109
|
+
|
110
|
+
def update_proxy(self, proxy: Optional[str] = None) -> None:
|
111
|
+
"""
|
112
|
+
Обновляет настройки прокси в конфигурации и в клиенте, если он существует.
|
113
|
+
|
114
|
+
Args:
|
115
|
+
proxy: Новый прокси или None для отключения прокси
|
116
|
+
"""
|
117
|
+
self.proxy = proxy
|
118
|
+
if self.client:
|
119
|
+
if hasattr(self.client, 'update_proxy'):
|
120
|
+
self.client.update_proxy(proxy)
|
121
|
+
else:
|
122
|
+
# Если клиент не поддерживает динамическое обновление прокси,
|
123
|
+
# закрываем его и создадим новый при следующем запросе
|
124
|
+
asyncio.create_task(self.close())
|
125
|
+
|
126
|
+
def deactivate(self) -> None:
|
127
|
+
"""Деактивирует конфигурацию."""
|
128
|
+
self.is_active = False
|
129
|
+
|
130
|
+
def activate(self) -> None:
|
131
|
+
"""Активирует конфигурацию."""
|
132
|
+
self.is_active = True
|
133
|
+
|
134
|
+
def to_dict(self) -> Dict[str, Any]:
|
135
|
+
"""
|
136
|
+
Преобразует конфигурацию в словарь.
|
137
|
+
|
138
|
+
Returns:
|
139
|
+
Dict[str, Any]: Словарь с параметрами конфигурации
|
140
|
+
"""
|
141
|
+
return {
|
142
|
+
"name": self.name,
|
143
|
+
"base_url": self.base_url,
|
144
|
+
"jwt_token": self.jwt_token,
|
145
|
+
"timeout": self.timeout,
|
146
|
+
"max_retries": self.max_retries,
|
147
|
+
"proxy": self.proxy,
|
148
|
+
"tags": self.tags,
|
149
|
+
"is_active": self.is_active,
|
150
|
+
"error_count": self.error_count,
|
151
|
+
"success_count": self.success_count,
|
152
|
+
"last_used": self.last_used,
|
153
|
+
}
|
154
|
+
|
155
|
+
|
156
|
+
class ClientFarm:
|
157
|
+
"""
|
158
|
+
Управляет фермой клиентов с разными конфигурациями.
|
159
|
+
|
160
|
+
Позволяет создавать, хранить и использовать множество клиентов
|
161
|
+
с разными настройками, токенами и прокси.
|
162
|
+
"""
|
163
|
+
|
164
|
+
def __init__(self, logger: Optional[logging.Logger] = None) -> None:
|
165
|
+
"""
|
166
|
+
Инициализация фермы клиентов.
|
167
|
+
|
168
|
+
Args:
|
169
|
+
logger: Логгер для записи информации (опционально)
|
170
|
+
"""
|
171
|
+
self.configs: Dict[str, ClientConfig] = {}
|
172
|
+
self.logger = logger or logging.getLogger(__name__)
|
173
|
+
self._selection_strategy: str = "round_robin" # Стратегия выбора клиента
|
174
|
+
self._last_used_index: int = -1 # Индекс последнего использованного клиента
|
175
|
+
|
176
|
+
def add_config(self, config: ClientConfig) -> None:
|
177
|
+
"""
|
178
|
+
Добавляет конфигурацию в ферму.
|
179
|
+
|
180
|
+
Args:
|
181
|
+
config: Конфигурация клиента
|
182
|
+
"""
|
183
|
+
self.configs[config.name] = config
|
184
|
+
self.logger.info(f"Добавлена конфигурация: {config.name}")
|
185
|
+
|
186
|
+
def create_config(self, **kwargs) -> ClientConfig:
|
187
|
+
"""
|
188
|
+
Создает и добавляет новую конфигурацию.
|
189
|
+
|
190
|
+
Args:
|
191
|
+
**kwargs: Параметры для создания конфигурации
|
192
|
+
|
193
|
+
Returns:
|
194
|
+
ClientConfig: Созданная конфигурация
|
195
|
+
"""
|
196
|
+
config = ClientConfig(**kwargs)
|
197
|
+
self.add_config(config)
|
198
|
+
return config
|
199
|
+
|
200
|
+
async def get_client(self, name: str) -> Optional[GEngineClient]:
|
201
|
+
"""
|
202
|
+
Возвращает клиент по имени конфигурации.
|
203
|
+
|
204
|
+
Args:
|
205
|
+
name: Имя конфигурации
|
206
|
+
|
207
|
+
Returns:
|
208
|
+
Optional[GEngineClient]: Экземпляр клиента или None, если конфигурация не найдена
|
209
|
+
"""
|
210
|
+
config = self.configs.get(name)
|
211
|
+
if config and config.is_active:
|
212
|
+
return await config.get_client()
|
213
|
+
return None
|
214
|
+
|
215
|
+
async def get_next_client(self, tag: Optional[str] = None) -> Optional[GEngineClient]:
|
216
|
+
"""
|
217
|
+
Возвращает следующий клиент согласно выбранной стратегии.
|
218
|
+
|
219
|
+
Args:
|
220
|
+
tag: Тег для фильтрации клиентов (опционально)
|
221
|
+
|
222
|
+
Returns:
|
223
|
+
Optional[GEngineClient]: Экземпляр клиента или None, если нет доступных клиентов
|
224
|
+
"""
|
225
|
+
active_configs = [
|
226
|
+
config for config in self.configs.values()
|
227
|
+
if config.is_active and (tag is None or tag in config.tags)
|
228
|
+
]
|
229
|
+
|
230
|
+
if not active_configs:
|
231
|
+
self.logger.warning("Нет доступных конфигураций клиентов")
|
232
|
+
return None
|
233
|
+
|
234
|
+
if self._selection_strategy == "round_robin":
|
235
|
+
# Стратегия Round Robin
|
236
|
+
self._last_used_index = (self._last_used_index + 1) % len(active_configs)
|
237
|
+
config = active_configs[self._last_used_index]
|
238
|
+
return await config.get_client()
|
239
|
+
|
240
|
+
elif self._selection_strategy == "random":
|
241
|
+
# Случайный выбор
|
242
|
+
import random
|
243
|
+
config = random.choice(active_configs)
|
244
|
+
return await config.get_client()
|
245
|
+
|
246
|
+
elif self._selection_strategy == "least_errors":
|
247
|
+
# Выбираем клиент с наименьшим количеством ошибок
|
248
|
+
config = min(active_configs, key=lambda c: c.error_count)
|
249
|
+
return await config.get_client()
|
250
|
+
|
251
|
+
elif self._selection_strategy == "least_recently_used":
|
252
|
+
# Выбираем наименее недавно использованный клиент
|
253
|
+
config = min(active_configs, key=lambda c: c.last_used)
|
254
|
+
return await config.get_client()
|
255
|
+
|
256
|
+
else:
|
257
|
+
# По умолчанию используем Round Robin
|
258
|
+
self._last_used_index = (self._last_used_index + 1) % len(active_configs)
|
259
|
+
config = active_configs[self._last_used_index]
|
260
|
+
return await config.get_client()
|
261
|
+
|
262
|
+
def set_selection_strategy(self, strategy: str) -> None:
|
263
|
+
"""
|
264
|
+
Устанавливает стратегию выбора клиента.
|
265
|
+
|
266
|
+
Args:
|
267
|
+
strategy: Стратегия выбора ('round_robin', 'random', 'least_errors', 'least_recently_used')
|
268
|
+
"""
|
269
|
+
valid_strategies = ["round_robin", "random", "least_errors", "least_recently_used"]
|
270
|
+
if strategy not in valid_strategies:
|
271
|
+
raise ValueError(f"Недопустимая стратегия выбора: {strategy}. "
|
272
|
+
f"Должна быть одна из: {', '.join(valid_strategies)}")
|
273
|
+
|
274
|
+
self._selection_strategy = strategy
|
275
|
+
self.logger.info(f"Установлена стратегия выбора клиента: {strategy}")
|
276
|
+
|
277
|
+
async def close_client(self, name: str) -> None:
|
278
|
+
"""
|
279
|
+
Закрывает клиент по имени конфигурации.
|
280
|
+
|
281
|
+
Args:
|
282
|
+
name: Имя конфигурации
|
283
|
+
"""
|
284
|
+
config = self.configs.get(name)
|
285
|
+
if config:
|
286
|
+
await config.close()
|
287
|
+
self.logger.info(f"Клиент закрыт: {name}")
|
288
|
+
|
289
|
+
async def close_all(self) -> None:
|
290
|
+
"""Закрывает все клиенты в ферме."""
|
291
|
+
for name, config in self.configs.items():
|
292
|
+
await config.close()
|
293
|
+
self.logger.info(f"Клиент закрыт: {name}")
|
294
|
+
|
295
|
+
def remove_config(self, name: str) -> None:
|
296
|
+
"""
|
297
|
+
Удаляет конфигурацию из фермы.
|
298
|
+
|
299
|
+
Args:
|
300
|
+
name: Имя конфигурации
|
301
|
+
"""
|
302
|
+
if name in self.configs:
|
303
|
+
config = self.configs[name]
|
304
|
+
# Запустим задачу на закрытие клиента, если он существует
|
305
|
+
if config.client:
|
306
|
+
asyncio.create_task(config.close())
|
307
|
+
del self.configs[name]
|
308
|
+
self.logger.info(f"Конфигурация удалена: {name}")
|
309
|
+
|
310
|
+
def get_configs_by_tag(self, tag: str) -> List[ClientConfig]:
|
311
|
+
"""
|
312
|
+
Возвращает список конфигураций с указанным тегом.
|
313
|
+
|
314
|
+
Args:
|
315
|
+
tag: Тег для фильтрации
|
316
|
+
|
317
|
+
Returns:
|
318
|
+
List[ClientConfig]: Список конфигураций с указанным тегом
|
319
|
+
"""
|
320
|
+
return [config for config in self.configs.values() if tag in config.tags]
|
321
|
+
|
322
|
+
def get_active_configs(self) -> List[ClientConfig]:
|
323
|
+
"""
|
324
|
+
Возвращает список активных конфигураций.
|
325
|
+
|
326
|
+
Returns:
|
327
|
+
List[ClientConfig]: Список активных конфигураций
|
328
|
+
"""
|
329
|
+
return [config for config in self.configs.values() if config.is_active]
|
330
|
+
|
331
|
+
def deactivate_config(self, name: str) -> None:
|
332
|
+
"""
|
333
|
+
Деактивирует конфигурацию.
|
334
|
+
|
335
|
+
Args:
|
336
|
+
name: Имя конфигурации
|
337
|
+
"""
|
338
|
+
if name in self.configs:
|
339
|
+
self.configs[name].deactivate()
|
340
|
+
self.logger.info(f"Конфигурация деактивирована: {name}")
|
341
|
+
|
342
|
+
def activate_config(self, name: str) -> None:
|
343
|
+
"""
|
344
|
+
Активирует конфигурацию.
|
345
|
+
|
346
|
+
Args:
|
347
|
+
name: Имя конфигурации
|
348
|
+
"""
|
349
|
+
if name in self.configs:
|
350
|
+
self.configs[name].activate()
|
351
|
+
self.logger.info(f"Конфигурация активирована: {name}")
|
352
|
+
|
353
|
+
def register_error(self, name: str) -> None:
|
354
|
+
"""
|
355
|
+
Регистрирует ошибку для указанной конфигурации.
|
356
|
+
|
357
|
+
Args:
|
358
|
+
name: Имя конфигурации
|
359
|
+
"""
|
360
|
+
if name in self.configs:
|
361
|
+
self.configs[name].error_count += 1
|
362
|
+
|
363
|
+
# Если превышен порог ошибок, деактивируем конфигурацию
|
364
|
+
if self.configs[name].error_count >= 10: # Пример порога
|
365
|
+
self.configs[name].deactivate()
|
366
|
+
self.logger.warning(f"Конфигурация деактивирована из-за ошибок: {name}")
|
367
|
+
|
368
|
+
def register_success(self, name: str) -> None:
|
369
|
+
"""
|
370
|
+
Регистрирует успешное использование указанной конфигурации.
|
371
|
+
|
372
|
+
Args:
|
373
|
+
name: Имя конфигурации
|
374
|
+
"""
|
375
|
+
if name in self.configs:
|
376
|
+
self.configs[name].success_count += 1
|
377
|
+
|
378
|
+
# Если клиент был деактивирован из-за ошибок, но успешно выполнил запрос,
|
379
|
+
# сбрасываем счетчик ошибок и активируем его снова
|
380
|
+
if not self.configs[name].is_active and self.configs[name].error_count > 0:
|
381
|
+
self.configs[name].error_count = 0
|
382
|
+
self.configs[name].activate()
|
383
|
+
self.logger.info(f"Конфигурация активирована после успешного запроса: {name}")
|
384
|
+
|
385
|
+
def get_stats(self) -> Dict[str, Dict[str, Any]]:
|
386
|
+
"""
|
387
|
+
Возвращает статистику по всем конфигурациям.
|
388
|
+
|
389
|
+
Returns:
|
390
|
+
Dict[str, Dict[str, Any]]: Словарь со статистикой
|
391
|
+
"""
|
392
|
+
return {name: config.to_dict() for name, config in self.configs.items()}
|
393
|
+
|
394
|
+
async def export_configs(self, file_path: str) -> None:
|
395
|
+
"""
|
396
|
+
Экспортирует конфигурации в JSON-файл.
|
397
|
+
|
398
|
+
Args:
|
399
|
+
file_path: Путь к файлу для экспорта
|
400
|
+
"""
|
401
|
+
import json
|
402
|
+
|
403
|
+
# Закрываем все клиенты перед экспортом
|
404
|
+
await self.close_all()
|
405
|
+
|
406
|
+
# Получаем данные конфигураций
|
407
|
+
configs_data = {name: config.to_dict() for name, config in self.configs.items()}
|
408
|
+
|
409
|
+
# Сохраняем в файл
|
410
|
+
with open(file_path, "w") as f:
|
411
|
+
json.dump(configs_data, f, indent=2)
|
412
|
+
|
413
|
+
self.logger.info(f"Конфигурации экспортированы в файл: {file_path}")
|
414
|
+
|
415
|
+
@classmethod
|
416
|
+
async def import_configs(cls, file_path: str, logger: Optional[logging.Logger] = None) -> "ClientFarm":
|
417
|
+
"""
|
418
|
+
Импортирует конфигурации из JSON-файла.
|
419
|
+
|
420
|
+
Args:
|
421
|
+
file_path: Путь к файлу с конфигурациями
|
422
|
+
logger: Логгер для записи информации (опционально)
|
423
|
+
|
424
|
+
Returns:
|
425
|
+
ClientFarm: Новый экземпляр фермы клиентов с импортированными конфигурациями
|
426
|
+
"""
|
427
|
+
import json
|
428
|
+
|
429
|
+
farm = cls(logger=logger)
|
430
|
+
|
431
|
+
try:
|
432
|
+
# Загружаем данные из файла
|
433
|
+
with open(file_path, "r") as f:
|
434
|
+
configs_data = json.load(f)
|
435
|
+
|
436
|
+
# Создаем конфигурации на основе данных
|
437
|
+
for name, data in configs_data.items():
|
438
|
+
# Извлекаем только параметры, необходимые для создания конфигурации
|
439
|
+
config_params = {
|
440
|
+
"name": data.get("name"),
|
441
|
+
"base_url": data.get("base_url"),
|
442
|
+
"jwt_token": data.get("jwt_token"),
|
443
|
+
"timeout": data.get("timeout"),
|
444
|
+
"max_retries": data.get("max_retries"),
|
445
|
+
"proxy": data.get("proxy"),
|
446
|
+
"tags": data.get("tags", []),
|
447
|
+
}
|
448
|
+
|
449
|
+
# Создаем конфигурацию
|
450
|
+
config = ClientConfig(**config_params)
|
451
|
+
|
452
|
+
# Устанавливаем дополнительные параметры
|
453
|
+
config.is_active = data.get("is_active", True)
|
454
|
+
config.error_count = data.get("error_count", 0)
|
455
|
+
config.success_count = data.get("success_count", 0)
|
456
|
+
|
457
|
+
# Добавляем конфигурацию в ферму
|
458
|
+
farm.add_config(config)
|
459
|
+
except Exception as e:
|
460
|
+
if logger:
|
461
|
+
logger.error(f"Ошибка при импорте конфигураций: {e}")
|
462
|
+
raise
|
463
|
+
|
464
|
+
return farm
|
@@ -1,15 +1,14 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: gengineapi
|
3
|
-
Version: 0.1
|
4
|
-
Summary:
|
3
|
+
Version: 0.2.1
|
4
|
+
Summary: G-Engine API Client
|
5
5
|
Requires-Python: >=3.13
|
6
6
|
Description-Content-Type: text/markdown
|
7
7
|
Requires-Dist: aiohttp>=3.8.0
|
8
8
|
Requires-Dist: typing-extensions>=4.0.0
|
9
9
|
Requires-Dist: aiohttp-socks>=0.7.1
|
10
|
-
Requires-Dist: uv-publish
|
11
10
|
|
12
|
-
#
|
11
|
+
# GEngineAPI
|
13
12
|
|
14
13
|
Асинхронный модульный клиент для взаимодействия с API G-Engine.
|
15
14
|
|
@@ -21,6 +20,7 @@ Requires-Dist: uv-publish
|
|
21
20
|
- Автоматические повторные попытки для временных ошибок
|
22
21
|
- Поддержка JWT-аутентификации
|
23
22
|
- Поддержка прокси, включая SOCKS5
|
23
|
+
- Ферма клиентов с балансировкой нагрузки и стратегиями ротации
|
24
24
|
- Подробное логирование
|
25
25
|
- Строгая типизация с помощью аннотаций типов
|
26
26
|
- Класс-конфигурация для централизованной настройки и повторного использования
|
@@ -28,33 +28,13 @@ Requires-Dist: uv-publish
|
|
28
28
|
## Установка
|
29
29
|
|
30
30
|
```bash
|
31
|
-
pip install
|
31
|
+
pip install gengineapi
|
32
32
|
```
|
33
33
|
|
34
|
-
|
34
|
+
Для поддержки SOCKS5 прокси убедитесь, что установлен пакет `aiohttp-socks`:
|
35
35
|
|
36
36
|
```bash
|
37
|
-
pip install
|
38
|
-
```
|
39
|
-
|
40
|
-
## Структура проекта
|
41
|
-
|
42
|
-
```
|
43
|
-
gengine_client/
|
44
|
-
├── __init__.py # Экспорт основных классов
|
45
|
-
├── client.py # Основной класс клиента
|
46
|
-
├── http.py # HTTP клиент с поддержкой аутентификации
|
47
|
-
├── exceptions.py # Иерархия исключений API
|
48
|
-
├── config.py # Класс-конфигурация для настройки параметров
|
49
|
-
└── modules/ # Папка с модулями API
|
50
|
-
├── __init__.py
|
51
|
-
├── base.py # Базовый класс для всех модулей
|
52
|
-
├── payments.py # Модуль для работы с платежами
|
53
|
-
├── finances.py # Модуль для работы с финансами
|
54
|
-
├── auth.py # Модуль для аутентификации
|
55
|
-
├── users.py # Модуль для работы с пользователями
|
56
|
-
├── transactions.py # Модуль для работы с транзакциями
|
57
|
-
└── currencies.py # Модуль для работы с валютами
|
37
|
+
pip install aiohttp-socks
|
58
38
|
```
|
59
39
|
|
60
40
|
## Использование
|
@@ -63,7 +43,7 @@ gengine_client/
|
|
63
43
|
|
64
44
|
```python
|
65
45
|
import asyncio
|
66
|
-
from
|
46
|
+
from gengineapi import GEngineClient
|
67
47
|
|
68
48
|
async def main():
|
69
49
|
# Создаем клиент с существующим токеном
|
@@ -84,7 +64,7 @@ asyncio.run(main())
|
|
84
64
|
|
85
65
|
```python
|
86
66
|
import asyncio
|
87
|
-
from
|
67
|
+
from gengineapi import GEngineClient
|
88
68
|
|
89
69
|
async def main():
|
90
70
|
# Создаем клиент без токена
|
@@ -119,7 +99,7 @@ asyncio.run(main())
|
|
119
99
|
|
120
100
|
```python
|
121
101
|
import asyncio
|
122
|
-
from
|
102
|
+
from gengineapi import GEngineClient
|
123
103
|
|
124
104
|
async def main():
|
125
105
|
# Создаем клиент с использованием SOCKS5 прокси
|
@@ -149,7 +129,7 @@ asyncio.run(main())
|
|
149
129
|
|
150
130
|
```python
|
151
131
|
import asyncio
|
152
|
-
from
|
132
|
+
from gengineapi import GEngineConfig
|
153
133
|
|
154
134
|
async def main():
|
155
135
|
# Настройка параметров клиента
|
@@ -188,32 +168,52 @@ async def main():
|
|
188
168
|
asyncio.run(main())
|
189
169
|
```
|
190
170
|
|
191
|
-
###
|
171
|
+
### Использование фермы клиентов
|
172
|
+
|
173
|
+
Ферма клиентов позволяет управлять множеством клиентов с разными конфигурациями и стратегиями ротации:
|
192
174
|
|
193
175
|
```python
|
194
176
|
import asyncio
|
195
|
-
import
|
196
|
-
from gengine_client import GEngineConfig
|
197
|
-
|
198
|
-
# Установка переменных окружения
|
199
|
-
os.environ["GENGINE_BASE_URL"] = "https://api.example.com/api/v2"
|
200
|
-
os.environ["GENGINE_TOKEN"] = "env_jwt_token"
|
201
|
-
os.environ["GENGINE_TIMEOUT"] = "45"
|
202
|
-
os.environ["GENGINE_MAX_RETRIES"] = "5"
|
203
|
-
os.environ["GENGINE_PROXY"] = "socks5://127.0.0.1:9050" # Опционально - прокси
|
177
|
+
from gengineapi import ClientFarm
|
204
178
|
|
205
179
|
async def main():
|
206
|
-
#
|
207
|
-
|
180
|
+
# Создаем ферму клиентов
|
181
|
+
farm = ClientFarm()
|
208
182
|
|
209
|
-
#
|
210
|
-
|
183
|
+
# Добавляем несколько конфигураций с разными прокси
|
184
|
+
farm.create_config(
|
185
|
+
name="client1",
|
186
|
+
base_url="https://api.example.com/api/v2",
|
187
|
+
jwt_token="token1",
|
188
|
+
proxy="socks5://user1:pass1@host1:port1",
|
189
|
+
tags=["group1", "production"]
|
190
|
+
)
|
211
191
|
|
212
|
-
|
213
|
-
|
192
|
+
farm.create_config(
|
193
|
+
name="client2",
|
194
|
+
base_url="https://api.example.com/api/v2",
|
195
|
+
jwt_token="token2",
|
196
|
+
proxy="socks5://user2:pass2@host2:port2",
|
197
|
+
tags=["group1", "backup"]
|
198
|
+
)
|
214
199
|
|
215
|
-
#
|
216
|
-
|
200
|
+
# Устанавливаем стратегию выбора клиента
|
201
|
+
farm.set_selection_strategy("round_robin") # или "random", "least_errors", "least_recently_used"
|
202
|
+
|
203
|
+
# Получаем клиент по имени
|
204
|
+
client1 = await farm.get_client("client1")
|
205
|
+
await client1.users.get_me()
|
206
|
+
|
207
|
+
# Получаем следующий клиент согласно стратегии
|
208
|
+
client = await farm.get_next_client()
|
209
|
+
await client.currencies.get_rate(source="cb_rf", pair="USD:RUB")
|
210
|
+
|
211
|
+
# Получаем клиент по тегу
|
212
|
+
client = await farm.get_next_client(tag="production")
|
213
|
+
await client.transactions.get_transactions(limit=5)
|
214
|
+
|
215
|
+
# При завершении работы закрываем все клиенты
|
216
|
+
await farm.close_all()
|
217
217
|
|
218
218
|
asyncio.run(main())
|
219
219
|
```
|
@@ -224,7 +224,7 @@ asyncio.run(main())
|
|
224
224
|
import asyncio
|
225
225
|
import uuid
|
226
226
|
from decimal import Decimal
|
227
|
-
from
|
227
|
+
from gengineapi import GEngineClient
|
228
228
|
|
229
229
|
async def main():
|
230
230
|
async with GEngineClient(
|
@@ -255,19 +255,25 @@ async def main():
|
|
255
255
|
asyncio.run(main())
|
256
256
|
```
|
257
257
|
|
258
|
-
##
|
258
|
+
## Доступные модули API
|
259
|
+
|
260
|
+
- `payments` - создание и выполнение платежей
|
261
|
+
- `finances` - работа с финансовыми данными
|
262
|
+
- `auth` - аутентификация и управление токенами
|
263
|
+
- `users` - работа с пользователями и их балансами
|
264
|
+
- `transactions` - работа с транзакциями
|
265
|
+
- `currencies` - работа с курсами валют
|
259
266
|
|
260
|
-
|
267
|
+
## Дополнительная документация
|
261
268
|
|
262
|
-
|
263
|
-
- `old_examples/` - директория с устаревшими примерами
|
269
|
+
Ручки, которые дергаем - https://b2b-api.ggsel.com/api/v2/docs#
|
264
270
|
|
265
271
|
## Зависимости
|
266
272
|
|
267
273
|
- Python 3.7+
|
268
274
|
- aiohttp >= 3.8.0
|
269
275
|
- typing-extensions >= 4.0.0
|
270
|
-
- aiohttp-socks >= 0.7.1 (для поддержки SOCKS5 прокси)
|
276
|
+
- aiohttp-socks >= 0.7.1 (опционально, для поддержки SOCKS5 прокси)
|
271
277
|
|
272
278
|
## Лицензия
|
273
279
|
|
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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|