xync-client 0.0.25.dev111__tar.gz → 0.0.25.dev116__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.
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/.gitignore +2 -1
- {xync_client-0.0.25.dev111/xync_client.egg-info → xync_client-0.0.25.dev116}/PKG-INFO +1 -1
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Abc/Agent.py +2 -2
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Abc/Base.py +2 -2
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Abc/Ex.py +55 -34
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Abc/InAgent.py +6 -1
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Binance/ex.py +6 -3
- xync_client-0.0.25.dev116/xync_client/Bybit/InAgent.py +42 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Bybit/agent.py +32 -9
- xync_client-0.0.25.dev116/xync_client/Bybit/ws.py +68 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Mexc/ex.py +40 -23
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/TgWallet/agent.py +1 -0
- xync_client-0.0.25.dev116/xync_client/TgWallet/pyro.py +144 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116/xync_client.egg-info}/PKG-INFO +1 -1
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client.egg-info/SOURCES.txt +2 -0
- xync_client-0.0.25.dev111/xync_client/TgWallet/pyro.py +0 -156
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/.env.sample +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/.pre-commit-config.yaml +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/README.md +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/makefile +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/pyproject.toml +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/setup.cfg +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/tests/TestAgent.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/tests/TestAsset.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/tests/TestEx.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/tests/TestOrder.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/tests/_todo_refact/Binance/test_binance.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/tests/_todo_refact/Bybit/test_bybit.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/tests/_todo_refact/Bybit/test_bybit_p2p.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/tests/_todo_refact/Gate/test_gate.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/tests/_todo_refact/Htx/test_htx_p2p.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/tests/_todo_refact/Wallet/test_agent.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/tests/_todo_refact/Wallet/test_ex.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/tests/_todo_refact/__init__.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/tests/_todo_refact/_test_ex.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Abc/Asset.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Abc/AuthTrait.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Abc/BaseTest.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Abc/Order.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Abc/types.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Binance/__init__.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Binance/binance_async.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Binance/earn_api.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Binance/etype/ad.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Binance/etype/pm.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Binance/exceptions.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Binance/sapi.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Binance/web_c2c.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/BingX/__init__.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/BingX/agent.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/BingX/base.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/BingX/etype/ad.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/BingX/etype/pm.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/BingX/ex.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/BingX/req.mjs +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/BingX/sign.js +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/BitGet/__init__.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/BitGet/agent.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/BitGet/etype/ad.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/BitGet/ex.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/BitGet/req.mjs +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/BitPapa/ex.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Bybit/etype/ad.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Bybit/ex.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Bybit/web_earn.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Bybit/web_p2p.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Gate/etype/ad.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Gate/ex.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Gate/premarket.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Htx/agent.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Htx/earn.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Htx/etype/__init__.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Htx/etype/ad.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Htx/etype/cred.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Htx/etype/pm.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Htx/ex.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/KuCoin/etype/ad.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/KuCoin/etype/pm.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/KuCoin/ex.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/KuCoin/web.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Mexc/etype/ad.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Mexc/etype/pm.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Okx/etype/ad.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Okx/etype/pm.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Okx/ex.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/TgWallet/asset.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/TgWallet/auth.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/TgWallet/ex.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/TgWallet/inAgent.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/TgWallet/order.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/TgWallet/pyd.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/TgWallet/web.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/__init__.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/loader.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/pm_unifier.py +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client.egg-info/dependency_links.txt +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client.egg-info/requires.txt +0 -0
- {xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client.egg-info/top_level.txt +0 -0
|
@@ -11,9 +11,9 @@ from xync_client.Abc.types import CredExOut
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class BaseAgentClient(BaseClient):
|
|
14
|
-
def __init__(self, agent: Agent):
|
|
14
|
+
def __init__(self, agent: Agent, headers: dict[str, str] = None, cookies: dict[str, str] = None):
|
|
15
15
|
self.agent: Agent = agent
|
|
16
|
-
super().__init__(self.agent.actor.ex
|
|
16
|
+
super().__init__(self.agent.actor.ex, "host_p2p", headers, cookies)
|
|
17
17
|
self.ex_client: BaseExClient = self.ex.client()
|
|
18
18
|
|
|
19
19
|
# 0: Получшение ордеров в статусе status, по монете coin, в валюте coin, в направлении is_sell: bool
|
|
@@ -10,6 +10,6 @@ MapOfIdsList = dict[int | str, list[int | str]]
|
|
|
10
10
|
class BaseClient(Client):
|
|
11
11
|
ex: Ex
|
|
12
12
|
|
|
13
|
-
def __init__(self, ex: Ex, attr: str = "host_p2p"):
|
|
13
|
+
def __init__(self, ex: Ex, attr: str = "host_p2p", headers: dict[str, str] = None, cookies: dict[str, str] = None):
|
|
14
14
|
self.ex = ex
|
|
15
|
-
super().__init__(getattr(ex, attr))
|
|
15
|
+
super().__init__(getattr(ex, attr), headers, cookies)
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from abc import abstractmethod
|
|
3
|
+
from asyncio import sleep
|
|
3
4
|
|
|
4
5
|
import msgspec
|
|
6
|
+
from aiohttp import ClientSession
|
|
5
7
|
from msgspec import Struct
|
|
6
8
|
from tortoise.exceptions import MultipleObjectsReturned, IntegrityError
|
|
7
9
|
from xync_schema import models
|
|
10
|
+
from xync_schema.enums import FileType
|
|
8
11
|
from xync_schema.types import CurEx, CoinEx, BaseAd, BaseAdIn
|
|
9
12
|
|
|
10
13
|
from xync_client.Abc.Base import BaseClient, MapOfIdsList
|
|
@@ -17,6 +20,11 @@ from xync_client.pm_unifier import PmUnifier, PmUni
|
|
|
17
20
|
class BaseExClient(BaseClient):
|
|
18
21
|
cur_map: dict[int, str] = {}
|
|
19
22
|
unifier_class: type = PmUnifier
|
|
23
|
+
logo_map = {
|
|
24
|
+
"Binance": "bin.bnbstatic.com",
|
|
25
|
+
"Gate": "www.gate.io",
|
|
26
|
+
"Mexc": "www.mexc.com/api/file/download",
|
|
27
|
+
}
|
|
20
28
|
|
|
21
29
|
@abstractmethod
|
|
22
30
|
def pm_type_map(self, typ: models.Pmex) -> str: ...
|
|
@@ -66,7 +74,6 @@ class BaseExClient(BaseClient):
|
|
|
66
74
|
|
|
67
75
|
# Импорт Pm-ов (с Pmcur-, Pmex- и Pmcurex-ами) и валют (с Curex-ами) с биржи в бд
|
|
68
76
|
async def set_pmcurexs(self):
|
|
69
|
-
PyroClient(bot)
|
|
70
77
|
# Curs
|
|
71
78
|
cur_pyds: dict[str, CurEx] = await self.curs()
|
|
72
79
|
curs: dict[int | str, models.Cur] = {
|
|
@@ -121,69 +128,66 @@ class BaseExClient(BaseClient):
|
|
|
121
128
|
# todo: curexcountry
|
|
122
129
|
|
|
123
130
|
# Pms
|
|
124
|
-
|
|
131
|
+
pmexs_epyds: dict[int | str, PmEx] = {
|
|
125
132
|
k: v for k, v in sorted((await self.pms()).items(), key=lambda x: x[1].name)
|
|
126
133
|
} # sort by name
|
|
127
134
|
pms: dict[int | str, models.Pm] = dict({})
|
|
128
135
|
prev = 0, "", "", None # id, normd-name, orig-name
|
|
129
136
|
cntrs = [c.lower() for c in await models.Country.all().values_list("name", flat=True)]
|
|
130
137
|
uni = self.unifier_class(cntrs)
|
|
131
|
-
for k,
|
|
132
|
-
pmu: PmUni = uni(
|
|
138
|
+
for k, pmex in pmexs_epyds.items():
|
|
139
|
+
pmu: PmUni = uni(pmex.name)
|
|
133
140
|
country_id = (
|
|
134
141
|
await models.Country.get(name__iexact=cnt).values_list("id", flat=True)
|
|
135
142
|
if (cnt := pmu.country)
|
|
136
143
|
else None
|
|
137
144
|
)
|
|
138
|
-
if prev[2] ==
|
|
139
|
-
logging.warning(f"Pm: '{
|
|
145
|
+
if prev[2] == pmex.name and pmu.country == prev[3]: # оригинальное имя не уникально на этой бирже
|
|
146
|
+
logging.warning(f"Pm: '{pmex.name}' duplicated with ids {prev[0]}: {k} on {self.ex.name}")
|
|
140
147
|
# новый Pm не добавляем, а берем старый с этим названием
|
|
141
148
|
pm_ = pms.get(prev[0], await models.Pm.get_or_none(norm=prev[1], country_id=country_id))
|
|
142
149
|
# и добавляем Pmex для него
|
|
143
|
-
await models.Pmex.update_or_create({"name":
|
|
150
|
+
await models.Pmex.update_or_create({"name": pmex.name}, ex=self.ex, exid=k, pm=pm_)
|
|
144
151
|
elif (
|
|
145
152
|
prev[1] == pmu.norm and pmu.country == prev[3]
|
|
146
153
|
): # 2 разных оригинальных имени на этой бирже совпали при нормализации
|
|
147
154
|
logging.error(
|
|
148
|
-
f"Pm: {
|
|
155
|
+
f"Pm: {pmex.name}&{prev[2]} overnormd as {pmu.norm} with ids {prev[0]}: {k} on {self.ex.name}"
|
|
149
156
|
)
|
|
150
157
|
# новый Pm не добавляем, только Pmex для него
|
|
151
158
|
# новый Pm не добавляем, а берем старый с этим названием
|
|
152
159
|
pm_ = pms.get(prev[0], await models.Pm.get_or_none(norm=prev[1], country_id=country_id))
|
|
153
160
|
# и добавляем.обновляем Pmex для него
|
|
154
|
-
await models.Pmex.update_or_create({"pm": pm_}, ex=self.ex, exid=k, name=
|
|
161
|
+
await models.Pmex.update_or_create({"pm": pm_}, ex=self.ex, exid=k, name=pmex.name)
|
|
155
162
|
else:
|
|
156
|
-
pmin = models.Pm.validate({**pmu.model_dump(), "country_id": country_id, "typ":
|
|
157
|
-
# # logo
|
|
158
|
-
# if pm.logo and not await models.File.exists(name=pm.logo):
|
|
159
|
-
# if not pm.logo.startswith("https:"):
|
|
160
|
-
# if not pm.logo.startswith("/"):
|
|
161
|
-
# pm.logo = "/" + pm.logo
|
|
162
|
-
# pm.logo = "https://" + pm.logo
|
|
163
|
-
# async with ClientSession() as ss:
|
|
164
|
-
# resp = await ss.get(pm.logo)
|
|
165
|
-
# if resp.ok:
|
|
166
|
-
# byts = await resp.read()
|
|
167
|
-
# upf, ref = await pyro.save_file(byts, resp.content_type)
|
|
168
|
-
# await sleep(1)
|
|
169
|
-
# typ = FileType[resp.content_type.split("/")[-1]]
|
|
170
|
-
# file, _ = await models.File.update_or_create(
|
|
171
|
-
# {"ref": ref, "size": len(byts), "typ": typ}, name=pm.logo
|
|
172
|
-
# )
|
|
173
|
-
# # fil = await pyro.get_file(file.ref) # check
|
|
174
|
-
# pmin.logo_id = file.id
|
|
175
|
-
# # /logo
|
|
163
|
+
pmin = models.Pm.validate({**pmu.model_dump(), "country_id": country_id, "typ": pmex.typ})
|
|
176
164
|
try:
|
|
177
165
|
pms[k], _ = await models.Pm.update_or_create(**pmin.df_unq())
|
|
178
166
|
except (MultipleObjectsReturned, IntegrityError) as e:
|
|
179
167
|
raise e
|
|
180
|
-
prev = k, pmu.norm,
|
|
168
|
+
prev = k, pmu.norm, pmex.name, pmu.country
|
|
169
|
+
|
|
181
170
|
# Pmexs
|
|
182
|
-
|
|
183
|
-
await
|
|
171
|
+
pbot = PyroClient(bot)
|
|
172
|
+
await pbot.app.start()
|
|
173
|
+
async with ClientSession(headers=getattr(self, "logo_headers", None)) as ss:
|
|
174
|
+
pmexs = [
|
|
175
|
+
models.Pmex(
|
|
176
|
+
# todo: refact logo
|
|
177
|
+
exid=k,
|
|
178
|
+
ex=self.ex,
|
|
179
|
+
pm=pm,
|
|
180
|
+
name=pmexs_epyds[k].name,
|
|
181
|
+
logo=await self.logo_save(pmexs_epyds[k].logo, pbot, ss),
|
|
182
|
+
)
|
|
183
|
+
for k, pm in pms.items()
|
|
184
|
+
]
|
|
185
|
+
await pbot.app.stop()
|
|
186
|
+
|
|
187
|
+
await models.Pmex.bulk_create(pmexs, on_conflict=["ex_id", "exid"], update_fields=["pm_id", "logo_id", "name"])
|
|
184
188
|
# Pmex banks
|
|
185
|
-
for k,
|
|
186
|
-
if banks :=
|
|
189
|
+
for k, pmex in pmexs_epyds.items():
|
|
190
|
+
if banks := pmex.banks:
|
|
187
191
|
pmex = await models.Pmex.get(ex=self.ex, exid=k) # pm=pms[k],
|
|
188
192
|
for b in banks:
|
|
189
193
|
await models.PmexBank.update_or_create({"name": b.name}, exid=b.exid, pmex=pmex)
|
|
@@ -203,6 +207,23 @@ class BaseExClient(BaseClient):
|
|
|
203
207
|
# pmcurexs = [Pmcurex(pmcur=pmcur, ex=self.ex) for pmcur in pmcurs]
|
|
204
208
|
# await Pmcurex.bulk_create(pmcurexs)
|
|
205
209
|
|
|
210
|
+
async def logo_save(self, url: str | None, pbot: PyroClient, ss: ClientSession) -> models.File | None:
|
|
211
|
+
if url or (file := None):
|
|
212
|
+
if not (file := await models.File.get_or_none(name=url)):
|
|
213
|
+
if not url.startswith("https:"):
|
|
214
|
+
if not url.startswith("/"):
|
|
215
|
+
url = "/" + url
|
|
216
|
+
url = "https://" + self.logo_map[self.ex.name] + url
|
|
217
|
+
resp = await ss.get(url)
|
|
218
|
+
if resp.ok:
|
|
219
|
+
byts = await resp.read()
|
|
220
|
+
upf, ref = await pbot.save_file(byts, resp.content_type)
|
|
221
|
+
await sleep(0.34)
|
|
222
|
+
typ = FileType[resp.content_type.split("/")[-1]]
|
|
223
|
+
file, _ = await models.File.update_or_create({"ref": ref, "size": len(byts), "typ": typ}, name=url)
|
|
224
|
+
# fr = await pbot.get_file(file.ref) # check
|
|
225
|
+
return file
|
|
226
|
+
|
|
206
227
|
# Импорт монет (с Coinex-ами) с биржи в бд
|
|
207
228
|
async def set_coinexs(self):
|
|
208
229
|
coins: dict[str, CoinEx] = await self.coins()
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
from abc import abstractmethod
|
|
2
2
|
|
|
3
|
+
from xync_schema.models import Agent
|
|
4
|
+
|
|
5
|
+
from xync_client.Abc.Agent import BaseAgentClient
|
|
6
|
+
|
|
3
7
|
|
|
4
8
|
class BaseInAgentClient:
|
|
5
|
-
def __init__(self):
|
|
9
|
+
def __init__(self, agent: Agent):
|
|
10
|
+
self.agent_client: BaseAgentClient = agent.client()
|
|
6
11
|
|
|
7
12
|
@abstractmethod
|
|
8
13
|
async def start_listen(self) -> bool: ...
|
|
@@ -22,7 +22,7 @@ class ExClient(BaseExClient):
|
|
|
22
22
|
class BinanceUnifier(PmUnifier):
|
|
23
23
|
pm_map = {
|
|
24
24
|
"Banque de développement local (BDL)": "Banque de développement local (BDL)",
|
|
25
|
-
"Viettel Money": "ViettelPay"
|
|
25
|
+
"Viettel Money": "ViettelPay",
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
unifier_class = BinanceUnifier
|
|
@@ -41,7 +41,10 @@ class ExClient(BaseExClient):
|
|
|
41
41
|
|
|
42
42
|
async def curs(self) -> dict[int, types.CurEx]:
|
|
43
43
|
curs = await self._post("/bapi/c2c/v1/friendly/c2c/trade-rule/fiat-list")
|
|
44
|
-
return {
|
|
44
|
+
return {
|
|
45
|
+
c["currencyCode"]: types.CurEx(exid=c["currencyCode"], ticker=c["currencyCode"], scale=c["currencyScale"])
|
|
46
|
+
for c in curs["data"]
|
|
47
|
+
}
|
|
45
48
|
|
|
46
49
|
async def coins(self) -> dict[int, types.CoinEx]:
|
|
47
50
|
for cur in (await self.curs()).keys():
|
|
@@ -131,10 +134,10 @@ async def main():
|
|
|
131
134
|
_ = await init_db(PG_DSN, models)
|
|
132
135
|
ex = await Ex.get(name="Binance")
|
|
133
136
|
cl = ExClient(ex)
|
|
137
|
+
await cl.set_pmcurexs()
|
|
134
138
|
await cl.pairs()
|
|
135
139
|
await cl.pms()
|
|
136
140
|
await cl.ads("ETH", "GEL", False)
|
|
137
|
-
await cl.set_pmcurexs()
|
|
138
141
|
await cl.close()
|
|
139
142
|
|
|
140
143
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from asyncio import run
|
|
2
|
+
|
|
3
|
+
from x_model import init_db
|
|
4
|
+
from xync_schema import models
|
|
5
|
+
|
|
6
|
+
from xync_client.Abc.InAgent import BaseInAgentClient
|
|
7
|
+
from xync_client.Bybit.agent import AgentClient
|
|
8
|
+
from xync_client.Bybit.ws import prv
|
|
9
|
+
from xync_client.TgWallet.pyro import PyroClient
|
|
10
|
+
from xync_client.loader import PG_DSN, bot
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class InAgentClient(BaseInAgentClient):
|
|
14
|
+
agent_client: AgentClient
|
|
15
|
+
|
|
16
|
+
async def start_listen(self):
|
|
17
|
+
t = await self.agent_client.ott()
|
|
18
|
+
ts = int(float(t["time_now"]) * 1000)
|
|
19
|
+
await prv(self.agent_client.agent.auth["deviceId"], t["result"], ts, listen)
|
|
20
|
+
|
|
21
|
+
# 3N: [T] - Уведомление об одобрении запроса на сделку
|
|
22
|
+
async def request_accepted_notify(self) -> int: ... # id
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def listen(data: dict):
|
|
26
|
+
print(data)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
async def main():
|
|
30
|
+
_ = await init_db(PG_DSN, models, True)
|
|
31
|
+
pbot = PyroClient(bot)
|
|
32
|
+
await pbot.app.start()
|
|
33
|
+
await pbot.app.create_channel("tc")
|
|
34
|
+
await pbot.app.stop()
|
|
35
|
+
|
|
36
|
+
agent = await models.Agent.filter(actor__ex_id=9, auth__isnull=False).prefetch_related("actor__ex").first()
|
|
37
|
+
cl: InAgentClient = agent.in_client()
|
|
38
|
+
await cl.agent_client.close()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
if __name__ == "__main__":
|
|
42
|
+
run(main())
|
|
@@ -1,12 +1,16 @@
|
|
|
1
|
+
from asyncio import run
|
|
1
2
|
from enum import IntEnum
|
|
2
3
|
from time import sleep
|
|
3
4
|
|
|
4
5
|
import pyotp
|
|
6
|
+
from x_model import init_db
|
|
7
|
+
from xync_schema import models
|
|
8
|
+
|
|
5
9
|
from xync_client.Abc.Base import FlatDict
|
|
6
10
|
from xync_schema.models import Cur
|
|
7
11
|
|
|
8
12
|
from xync_client.Abc.Agent import BaseAgentClient
|
|
9
|
-
from xync_client.loader import BYT2FA
|
|
13
|
+
from xync_client.loader import BYT2FA, PG_DSN
|
|
10
14
|
|
|
11
15
|
|
|
12
16
|
class NoMakerException(Exception):
|
|
@@ -18,7 +22,7 @@ class AdsStatus(IntEnum):
|
|
|
18
22
|
WORKING = 1
|
|
19
23
|
|
|
20
24
|
|
|
21
|
-
class
|
|
25
|
+
class AgentClient(BaseAgentClient): # Bybit client
|
|
22
26
|
host = "api2.bybit.com"
|
|
23
27
|
headers = {"cookie": ";"} # rewrite token for public methods
|
|
24
28
|
|
|
@@ -109,31 +113,35 @@ class ExClient(BaseAgentClient): # Bybit client
|
|
|
109
113
|
return fiat
|
|
110
114
|
return list_methods[1]
|
|
111
115
|
|
|
116
|
+
async def ott(self):
|
|
117
|
+
t = await self._post("/user/private/ott")
|
|
118
|
+
return t
|
|
119
|
+
|
|
112
120
|
# 27
|
|
113
|
-
def fiat_upd(self, fiat_id: int, detail: str, name: str = None) -> dict:
|
|
121
|
+
async def fiat_upd(self, fiat_id: int, detail: str, name: str = None) -> dict:
|
|
114
122
|
fiat = self.get_payment_method(fiat_id)
|
|
115
123
|
fiat["realName"] = name
|
|
116
124
|
fiat["accountNo"] = detail
|
|
117
125
|
result = await self._post("/fiat/otc/user/payment/new_update", fiat)
|
|
118
126
|
srt = result["result"]["securityRiskToken"]
|
|
119
|
-
self._check_2fa(srt)
|
|
127
|
+
await self._check_2fa(srt)
|
|
120
128
|
fiat["securityRiskToken"] = srt
|
|
121
129
|
result2 = await self._post("/fiat/otc/user/payment/new_update", fiat)
|
|
122
130
|
return result2
|
|
123
131
|
|
|
124
132
|
# 28
|
|
125
|
-
def fiat_del(self, fiat_id: int) -> dict:
|
|
133
|
+
async def fiat_del(self, fiat_id: int) -> dict | str:
|
|
126
134
|
data = {"id": fiat_id, "securityRiskToken": ""}
|
|
127
135
|
method = await self._post("/fiat/otc/user/payment/new_delete", data)
|
|
128
136
|
srt = method["result"]["securityRiskToken"]
|
|
129
|
-
self._check_2fa(srt)
|
|
137
|
+
await self._check_2fa(srt)
|
|
130
138
|
data["securityRiskToken"] = srt
|
|
131
139
|
delete = await self._post("/fiat/otc/user/payment/new_delete", data)
|
|
132
140
|
return delete
|
|
133
141
|
|
|
134
|
-
def switch_ads(self, new_status: AdsStatus) -> dict:
|
|
142
|
+
async def switch_ads(self, new_status: AdsStatus) -> dict:
|
|
135
143
|
data = {"workStatus": new_status.name}
|
|
136
|
-
res = self._post("/fiat/otc/maker/work-config/switch", data)
|
|
144
|
+
res = await self._post("/fiat/otc/maker/work-config/switch", data)
|
|
137
145
|
return res
|
|
138
146
|
|
|
139
147
|
def online_ads(self) -> str:
|
|
@@ -145,7 +153,7 @@ class ExClient(BaseAgentClient): # Bybit client
|
|
|
145
153
|
ads = [ad for ad in list_ads if set(ad["payments"]) - {"5", "51"}]
|
|
146
154
|
return float(ads[0]["price"])
|
|
147
155
|
|
|
148
|
-
def my_fiats(self, cur: Cur = None):
|
|
156
|
+
async def my_fiats(self, cur: Cur = None):
|
|
149
157
|
upm = await self._post("/fiat/otc/user/payment/list")
|
|
150
158
|
return upm["result"]
|
|
151
159
|
|
|
@@ -296,3 +304,18 @@ class ExClient(BaseAgentClient): # Bybit client
|
|
|
296
304
|
"size": 10,
|
|
297
305
|
},
|
|
298
306
|
)
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def listen(data: dict):
|
|
310
|
+
print(data)
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
async def main():
|
|
314
|
+
_ = await init_db(PG_DSN, models, True)
|
|
315
|
+
agent = await models.Agent.filter(actor__ex_id=9, auth__isnull=False).prefetch_related("actor__ex").first()
|
|
316
|
+
cl: AgentClient = agent.client()
|
|
317
|
+
await cl.close()
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
if __name__ == "__main__":
|
|
321
|
+
run(main())
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import hmac
|
|
2
|
+
import json
|
|
3
|
+
import websockets
|
|
4
|
+
from time import time
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
async def pub():
|
|
8
|
+
async with websockets.connect("wss://stream.bybit.com/v5/public/spot") as websocket:
|
|
9
|
+
sub_msg = json.dumps(
|
|
10
|
+
{"op": "subscribe", "req_id": "1", "args": ["tickers.BTCUSDT", "tickers.ETHUSDT", "tickers.TONUSDT"]}
|
|
11
|
+
)
|
|
12
|
+
await websocket.send(sub_msg)
|
|
13
|
+
p = {}
|
|
14
|
+
while resp := await websocket.recv():
|
|
15
|
+
if data := json.loads(resp).get("data"):
|
|
16
|
+
p[data["symbol"]] = data["lastPrice"]
|
|
17
|
+
print(f"BTC: {p.get('BTCUSDT')}\nETH: {p.get('ETHUSDT')}\nTON: {p.get('TONUSDT')}", end="\033[F\033[F")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
async def priv(key: str, sec: str):
|
|
21
|
+
async with websockets.connect("wss://stream.bybit.com/v5/private") as websocket:
|
|
22
|
+
expires = int((time() + 5) * 1000)
|
|
23
|
+
# Generate signature.
|
|
24
|
+
signature = str(
|
|
25
|
+
hmac.new(bytes(sec, "utf-8"), bytes(f"GET/realtime{expires}", "utf-8"), digestmod="sha256").hexdigest()
|
|
26
|
+
)
|
|
27
|
+
auth_msg = json.dumps({"op": "auth", "args": [key, expires, signature]})
|
|
28
|
+
await websocket.send(auth_msg)
|
|
29
|
+
await websocket.send(json.dumps({"req_id": "100001", "op": "ping"}))
|
|
30
|
+
sub_msg = json.dumps({"op": "subscribe", "args": ["wallet"]})
|
|
31
|
+
await websocket.send(sub_msg)
|
|
32
|
+
while resp := await websocket.recv():
|
|
33
|
+
if data := json.loads(resp).get("data"):
|
|
34
|
+
print(data)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
async def prv(did: str, tok: str, ts: int, cb: callable):
|
|
38
|
+
u = f"wss://ws2.bybit.com/private?appid=bybit&os=web&deviceid={did}×tamp={ts}"
|
|
39
|
+
async with websockets.connect(u) as websocket:
|
|
40
|
+
auth_msg = json.dumps({"req_id": did, "op": "login", "args": [tok]})
|
|
41
|
+
await websocket.send(auth_msg)
|
|
42
|
+
|
|
43
|
+
sub_msg = json.dumps({"op": "subscribe", "args": ["FIAT_OTC_TOPIC", "FIAT_OTC_ONLINE_TOPIC"]})
|
|
44
|
+
await websocket.send(sub_msg)
|
|
45
|
+
sub_msg = json.dumps({"op": "input", "args": ["FIAT_OTC_TOPIC", '{"topic":"SUPER_DEAL"}']})
|
|
46
|
+
await websocket.send(sub_msg)
|
|
47
|
+
sub_msg = json.dumps({"op": "input", "args": ["FIAT_OTC_TOPIC", '{"topic":"OTC_ORDER_STATUS"}']})
|
|
48
|
+
await websocket.send(sub_msg)
|
|
49
|
+
sub_msg = json.dumps({"op": "input", "args": ["FIAT_OTC_TOPIC", '{"topic":"WEB_THREE_SELL"}']})
|
|
50
|
+
await websocket.send(sub_msg)
|
|
51
|
+
sub_msg = json.dumps({"op": "input", "args": ["FIAT_OTC_TOPIC", '{"topic":"APPEALED_CHANGE"}']})
|
|
52
|
+
await websocket.send(sub_msg)
|
|
53
|
+
|
|
54
|
+
sub_msg = json.dumps({"op": "subscribe", "args": ["fiat.cashier.order"]})
|
|
55
|
+
await websocket.send(sub_msg)
|
|
56
|
+
sub_msg = json.dumps({"op": "subscribe", "args": ["fiat.cashier.order-eftd-complete-privilege-event"]})
|
|
57
|
+
await websocket.send(sub_msg)
|
|
58
|
+
sub_msg = json.dumps({"op": "subscribe", "args": ["fiat.cashier.order-savings-product-event"]})
|
|
59
|
+
await websocket.send(sub_msg)
|
|
60
|
+
sub_msg = json.dumps({"op": "subscribe", "args": ["fiat.deal-core.order-savings-complete-event"]})
|
|
61
|
+
await websocket.send(sub_msg)
|
|
62
|
+
|
|
63
|
+
sub_msg = json.dumps({"op": "subscribe", "args": ["FIAT_OTC_TOPIC", "FIAT_OTC_ONLINE_TOPIC"]})
|
|
64
|
+
await websocket.send(sub_msg)
|
|
65
|
+
|
|
66
|
+
while resp := await websocket.recv():
|
|
67
|
+
if data := json.loads(resp).get("data"):
|
|
68
|
+
cb(data)
|
|
@@ -13,24 +13,39 @@ from xync_schema import types
|
|
|
13
13
|
from xync_schema import models
|
|
14
14
|
from xync_schema.models import Ex
|
|
15
15
|
|
|
16
|
+
|
|
16
17
|
class ExClient(BaseExClient):
|
|
18
|
+
logo_headers = {
|
|
19
|
+
"accept-language": "ru,en;q=0.9",
|
|
20
|
+
"priority": "u=0, i",
|
|
21
|
+
"sec-ch-ua": '"Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="134"',
|
|
22
|
+
"sec-ch-ua-mobile": "?0",
|
|
23
|
+
"sec-ch-ua-platform": '"macOS"',
|
|
24
|
+
"sec-fetch-site": "none", # work from CURL, not work from aiohttp with no this header
|
|
25
|
+
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36",
|
|
26
|
+
}
|
|
27
|
+
|
|
17
28
|
class MexcUnifier(PmUnifier):
|
|
18
29
|
pm_map = {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
30
|
+
"Philippine National Bank (PNB)": "Philippines National Bank (PNB)",
|
|
31
|
+
"Al-Rajhi Bank": "Al Rajhi Bank",
|
|
32
|
+
"SBP - Fast Bank Transfer": "SBP",
|
|
33
|
+
"Touch 'n Go": "Touch n Go",
|
|
23
34
|
}
|
|
35
|
+
|
|
24
36
|
unifier_class = MexcUnifier
|
|
25
37
|
|
|
26
38
|
async def _pms(self, cur) -> list[pm.PmE]:
|
|
27
|
-
pms = requests.get("https://p2p.mexc.com/api/payment/method", params={
|
|
39
|
+
pms = requests.get("https://p2p.mexc.com/api/payment/method", params={"currency": cur}).json()
|
|
28
40
|
return [pm.PmE(**_pm) for _pm in pms["data"]]
|
|
29
41
|
|
|
30
42
|
# 19: Список поддерживаемых валют тейкера
|
|
31
43
|
async def curs(self) -> dict[str, types.CurEx]: # {cur.ticker: cur}
|
|
32
|
-
_curs = requests.get(
|
|
33
|
-
return {
|
|
44
|
+
_curs = requests.get("https://p2p.mexc.com/api/common/currency").json()
|
|
45
|
+
return {
|
|
46
|
+
cur["currency"]: types.CurEx(exid=cur["currency"], ticker=cur["currency"], scale=cur["scale"])
|
|
47
|
+
for cur in _curs["data"]
|
|
48
|
+
}
|
|
34
49
|
|
|
35
50
|
# 20: Список платежных методов
|
|
36
51
|
async def pms(self, cur: models.Cur = None) -> dict[int | str, PmEx]: # {pm.exid: pm}
|
|
@@ -47,8 +62,11 @@ class ExClient(BaseExClient):
|
|
|
47
62
|
|
|
48
63
|
# 22: Список торгуемых монет (с ограничениям по валютам, если есть)
|
|
49
64
|
async def coins(self) -> dict[str, types.CoinEx]: # {coin.ticker: coin}
|
|
50
|
-
coins = requests.get(
|
|
51
|
-
return {
|
|
65
|
+
coins = requests.get("https://p2p.mexc.com/api/common/coins").json()
|
|
66
|
+
return {
|
|
67
|
+
coin["coinId"]: types.CoinEx(exid=coin["coinId"], ticker=coin["coinName"], scale=coin["quantityScale"])
|
|
68
|
+
for coin in coins["data"]
|
|
69
|
+
}
|
|
52
70
|
|
|
53
71
|
# 23: Список пар валюта/монет
|
|
54
72
|
async def pairs(self) -> tuple[MapOfIdsList, MapOfIdsList]:
|
|
@@ -59,27 +77,26 @@ class ExClient(BaseExClient):
|
|
|
59
77
|
|
|
60
78
|
# 24: Список объяв по (buy/sell, cur, coin, pm)
|
|
61
79
|
async def ads(
|
|
62
|
-
|
|
80
|
+
self, coin_exid: str, cur_exid: str, is_sell: bool, pm_exids: list[str | int] = None, amount: int = None
|
|
63
81
|
) -> list[ad.Ad]: # {ad.id: ad}
|
|
64
82
|
params = {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
83
|
+
"allowTrade": "false",
|
|
84
|
+
"amount": amount or "",
|
|
85
|
+
"blockTrade": "false",
|
|
86
|
+
"coinId": coin_exid,
|
|
87
|
+
"countryCode": "",
|
|
88
|
+
"currency": cur_exid,
|
|
89
|
+
"follow": "false",
|
|
90
|
+
"haveTrade": "false",
|
|
91
|
+
"page": "1",
|
|
92
|
+
"payMethod": pm_exids or "",
|
|
93
|
+
"tradeType": "SELL" if is_sell else "BUY",
|
|
76
94
|
}
|
|
77
95
|
|
|
78
96
|
ads = requests.get("https://p2p.mexc.com/api/market", params=params).json()
|
|
79
97
|
return [ad.Ad(**_ad) for _ad in ads["data"]]
|
|
80
98
|
|
|
81
99
|
|
|
82
|
-
|
|
83
100
|
async def main():
|
|
84
101
|
_ = await init_db(PG_DSN, models, True)
|
|
85
102
|
ex = await Ex.get(name="Mexc")
|
|
@@ -93,6 +110,6 @@ async def main():
|
|
|
93
110
|
_pms = await cl.pms()
|
|
94
111
|
await cl.close()
|
|
95
112
|
|
|
113
|
+
|
|
96
114
|
if __name__ == "__main__":
|
|
97
115
|
run(main())
|
|
98
|
-
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
from asyncio import run, sleep
|
|
2
|
+
from io import BytesIO
|
|
3
|
+
from urllib.parse import parse_qs
|
|
4
|
+
|
|
5
|
+
from aiogram import Bot
|
|
6
|
+
from pyrogram import Client
|
|
7
|
+
from pyrogram.errors import UserNotParticipant
|
|
8
|
+
from pyrogram.raw import functions
|
|
9
|
+
from pyrogram.raw.functions.messages import UploadMedia
|
|
10
|
+
from pyrogram.raw.functions.photos import GetUserPhotos
|
|
11
|
+
from pyrogram.raw.functions.upload import GetFile
|
|
12
|
+
from pyrogram.raw.types import (
|
|
13
|
+
InputPeerSelf,
|
|
14
|
+
InputMediaUploadedDocument,
|
|
15
|
+
MessageMediaDocument,
|
|
16
|
+
InputMediaUploadedPhoto,
|
|
17
|
+
MessageMediaPhoto,
|
|
18
|
+
InputDocumentFileLocation,
|
|
19
|
+
InputPhotoFileLocation,
|
|
20
|
+
)
|
|
21
|
+
from pyrogram.raw.types.photos import Photos
|
|
22
|
+
from pyrogram.raw.types.upload import File
|
|
23
|
+
from pyrogram.types import Chat, ChatPrivileges
|
|
24
|
+
from x_model import init_db
|
|
25
|
+
from xync_client.loader import TG_API_ID, TG_API_HASH, PG_DSN
|
|
26
|
+
from xync_schema import models
|
|
27
|
+
from xync_schema.models import Agent
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class PyroClient:
|
|
31
|
+
max_privs = ChatPrivileges(
|
|
32
|
+
can_manage_chat=True, # default
|
|
33
|
+
can_delete_messages=True,
|
|
34
|
+
can_delete_stories=True, # Channels only
|
|
35
|
+
can_manage_video_chats=True, # Groups and supergroups only
|
|
36
|
+
can_restrict_members=True,
|
|
37
|
+
can_promote_members=True,
|
|
38
|
+
can_change_info=True,
|
|
39
|
+
can_post_messages=True, # Channels only
|
|
40
|
+
can_post_stories=True, # Channels only
|
|
41
|
+
can_edit_messages=True, # Channels only
|
|
42
|
+
can_edit_stories=True, # Channels only
|
|
43
|
+
can_invite_users=True,
|
|
44
|
+
can_pin_messages=True, # Groups and supergroups only
|
|
45
|
+
can_manage_topics=True, # Supergroups only
|
|
46
|
+
is_anonymous=True,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
def __init__(self, ab: Agent | Bot):
|
|
50
|
+
name = str(ab.actor.person.user.id) if isinstance(ab, Agent) else str(ab.id)
|
|
51
|
+
auth = {"session_string": ab.auth["sess"]} if isinstance(ab, Agent) else {"bot_token": ab.token}
|
|
52
|
+
self.app: Client = Client(name, TG_API_ID, TG_API_HASH, **auth)
|
|
53
|
+
|
|
54
|
+
@staticmethod
|
|
55
|
+
def ref_enc(ph_id: int, access_hash: int, ref: bytes) -> bytes:
|
|
56
|
+
return ph_id.to_bytes(8, "big") + access_hash.to_bytes(8, "big", signed=True) + ref
|
|
57
|
+
|
|
58
|
+
@staticmethod
|
|
59
|
+
def ref_dec(full_ref: bytes) -> tuple[int, int, bytes]:
|
|
60
|
+
pid, ah = int.from_bytes(full_ref[:8], "big"), int.from_bytes(full_ref[8:16], "big", signed=True)
|
|
61
|
+
return pid, ah, full_ref[16:]
|
|
62
|
+
|
|
63
|
+
async def get_init_data(self) -> dict:
|
|
64
|
+
bot = await self.app.resolve_peer("wallet")
|
|
65
|
+
res = await self.app.invoke(functions.messages.RequestWebView(peer=InputPeerSelf(), bot=bot, platform="ios"))
|
|
66
|
+
raw = parse_qs(res.url)["tgWebAppUserId"][0].split("#tgWebAppData=")[1]
|
|
67
|
+
j = parse_qs(raw)
|
|
68
|
+
return {
|
|
69
|
+
"web_view_init_data": {
|
|
70
|
+
"query_id": j["query_id"][0],
|
|
71
|
+
"user": j["user"][0],
|
|
72
|
+
"auth_date": j["auth_date"][0],
|
|
73
|
+
"hash": j["hash"][0],
|
|
74
|
+
},
|
|
75
|
+
"web_view_init_data_raw": raw,
|
|
76
|
+
"ep": "menu",
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async def create_orders_forum(self, uid: str | int) -> tuple[int, bool]:
|
|
80
|
+
await self.app.get_me()
|
|
81
|
+
chat: Chat = await self.app.create_supergroup("Xync Orders", "Xync Orders")
|
|
82
|
+
if not (await self.app.toggle_forum_topics(chat_id=chat.id, enabled=True)):
|
|
83
|
+
await self.app.delete_channel(chat.id)
|
|
84
|
+
await chat.leave()
|
|
85
|
+
raise Exception(f"Chat {chat.id} for {self.app.me.username} not converted to forum")
|
|
86
|
+
await chat.add_members(["XyncNetBot"]) # , "xync_bot"
|
|
87
|
+
await chat.promote_member("XyncNetBot", self.max_privs)
|
|
88
|
+
added = await chat.add_members([uid])
|
|
89
|
+
try:
|
|
90
|
+
await sleep(1, await chat.get_member(uid))
|
|
91
|
+
except UserNotParticipant:
|
|
92
|
+
added = False
|
|
93
|
+
# await chat.leave()
|
|
94
|
+
return chat.id, added
|
|
95
|
+
|
|
96
|
+
async def get_user_photos(self, uid: str | int) -> Photos:
|
|
97
|
+
try:
|
|
98
|
+
peer = await self.app.resolve_peer(uid)
|
|
99
|
+
except Exception as e:
|
|
100
|
+
raise e
|
|
101
|
+
return await self.app.invoke(GetUserPhotos(user_id=peer, offset=0, limit=1, max_id=-1))
|
|
102
|
+
|
|
103
|
+
async def send(self, uid, txt):
|
|
104
|
+
try:
|
|
105
|
+
return await self.app.send_message(uid, txt)
|
|
106
|
+
except Exception as e:
|
|
107
|
+
raise e
|
|
108
|
+
|
|
109
|
+
async def save_file(self, byts: bytes, ctype: str) -> tuple[MessageMediaDocument, bytes]:
|
|
110
|
+
in_file = await self.app.save_file(BytesIO(byts))
|
|
111
|
+
imud = InputMediaUploadedDocument(file=in_file, mime_type=ctype, attributes=[])
|
|
112
|
+
upf: MessageMediaDocument = await self.app.invoke(UploadMedia(peer=InputPeerSelf(), media=imud))
|
|
113
|
+
return upf, (
|
|
114
|
+
upf.document.id.to_bytes(8, "big")
|
|
115
|
+
+ upf.document.access_hash.to_bytes(8, "big", signed=True)
|
|
116
|
+
+ upf.document.file_reference
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
async def save_photo(self, file: bytes) -> tuple[MessageMediaPhoto, bytes]:
|
|
120
|
+
in_file = await self.app.save_file(BytesIO(file))
|
|
121
|
+
upm = UploadMedia(peer=InputPeerSelf(), media=InputMediaUploadedPhoto(file=in_file))
|
|
122
|
+
upp: MessageMediaPhoto = await self.app.invoke(upm)
|
|
123
|
+
return upp, self.ref_enc(upp.photo.id, upp.photo.access_hash, upp.photo.file_reference)
|
|
124
|
+
|
|
125
|
+
async def get_file(self, fid: bytes) -> File:
|
|
126
|
+
pid, ah, ref = self.ref_dec(fid)
|
|
127
|
+
loc = InputDocumentFileLocation(id=pid, access_hash=ah, file_reference=ref, thumb_size="x")
|
|
128
|
+
return await self.app.invoke(GetFile(location=loc, offset=0, limit=512 * 1024))
|
|
129
|
+
|
|
130
|
+
async def get_photo(self, fid: bytes, st: str) -> File:
|
|
131
|
+
pid, ah, ref = self.ref_dec(fid)
|
|
132
|
+
loc = InputPhotoFileLocation(id=pid, access_hash=ah, file_reference=ref, thumb_size=st)
|
|
133
|
+
return await self.app.invoke(GetFile(location=loc, offset=0, limit=512 * 1024))
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
async def main():
|
|
137
|
+
_ = await init_db(PG_DSN, models, True)
|
|
138
|
+
agent: Agent = await Agent.filter(auth__isnull=False, ex__name="TgWallet").prefetch_related("ex").first()
|
|
139
|
+
pcl = PyroClient(agent)
|
|
140
|
+
await pcl.create_orders_forum(agent.actor.user_id)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
if __name__ == "__main__":
|
|
144
|
+
run(main())
|
|
@@ -57,10 +57,12 @@ xync_client/BitGet/ex.py
|
|
|
57
57
|
xync_client/BitGet/req.mjs
|
|
58
58
|
xync_client/BitGet/etype/ad.py
|
|
59
59
|
xync_client/BitPapa/ex.py
|
|
60
|
+
xync_client/Bybit/InAgent.py
|
|
60
61
|
xync_client/Bybit/agent.py
|
|
61
62
|
xync_client/Bybit/ex.py
|
|
62
63
|
xync_client/Bybit/web_earn.py
|
|
63
64
|
xync_client/Bybit/web_p2p.py
|
|
65
|
+
xync_client/Bybit/ws.py
|
|
64
66
|
xync_client/Bybit/etype/ad.py
|
|
65
67
|
xync_client/Gate/ex.py
|
|
66
68
|
xync_client/Gate/premarket.py
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
from asyncio import run, sleep
|
|
2
|
-
from io import BytesIO
|
|
3
|
-
from urllib.parse import parse_qs
|
|
4
|
-
|
|
5
|
-
from aiogram import Bot
|
|
6
|
-
from pyrogram import Client
|
|
7
|
-
from pyrogram.errors import UserNotParticipant
|
|
8
|
-
from pyrogram.raw import functions
|
|
9
|
-
from pyrogram.raw.base.upload import File
|
|
10
|
-
from pyrogram.raw.functions.messages import UploadMedia
|
|
11
|
-
from pyrogram.raw.functions.photos import GetUserPhotos
|
|
12
|
-
from pyrogram.raw.functions.upload import GetFile
|
|
13
|
-
from pyrogram.raw.types import (
|
|
14
|
-
InputPeerSelf,
|
|
15
|
-
InputMediaUploadedDocument,
|
|
16
|
-
MessageMediaDocument,
|
|
17
|
-
InputMediaUploadedPhoto,
|
|
18
|
-
MessageMediaPhoto,
|
|
19
|
-
InputDocumentFileLocation,
|
|
20
|
-
InputPhotoFileLocation,
|
|
21
|
-
)
|
|
22
|
-
from pyrogram.raw.types.photos import Photos
|
|
23
|
-
from pyrogram.types import Chat, ChatPrivileges
|
|
24
|
-
from x_model import init_db
|
|
25
|
-
from xync_client.loader import TG_API_ID, TG_API_HASH, PG_DSN
|
|
26
|
-
from xync_schema import models
|
|
27
|
-
from xync_schema.models import Agent
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class PyroClient:
|
|
31
|
-
max_privs = ChatPrivileges(
|
|
32
|
-
can_manage_chat=True, # default
|
|
33
|
-
can_delete_messages=True,
|
|
34
|
-
can_delete_stories=True, # Channels only
|
|
35
|
-
can_manage_video_chats=True, # Groups and supergroups only
|
|
36
|
-
can_restrict_members=True,
|
|
37
|
-
can_promote_members=True,
|
|
38
|
-
can_change_info=True,
|
|
39
|
-
can_post_messages=True, # Channels only
|
|
40
|
-
can_post_stories=True, # Channels only
|
|
41
|
-
can_edit_messages=True, # Channels only
|
|
42
|
-
can_edit_stories=True, # Channels only
|
|
43
|
-
can_invite_users=True,
|
|
44
|
-
can_pin_messages=True, # Groups and supergroups only
|
|
45
|
-
can_manage_topics=True, # Supergroups only
|
|
46
|
-
is_anonymous=True,
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
def __init__(self, ab: Agent | Bot):
|
|
50
|
-
name = str(ab.actor.person.user.id) if isinstance(ab, Agent) else str(ab.id)
|
|
51
|
-
auth = {"session_string": ab.auth["sess"]} if isinstance(ab, Agent) else {"bot_token": ab.token}
|
|
52
|
-
self.app: Client = Client(name, TG_API_ID, TG_API_HASH, **auth)
|
|
53
|
-
|
|
54
|
-
async def get_init_data(self) -> dict:
|
|
55
|
-
async with self.app as app:
|
|
56
|
-
app: Client
|
|
57
|
-
bot = await app.resolve_peer("wallet")
|
|
58
|
-
res = await app.invoke(functions.messages.RequestWebView(peer=InputPeerSelf(), bot=bot, platform="ios"))
|
|
59
|
-
raw = parse_qs(res.url)["tgWebAppUserId"][0].split("#tgWebAppData=")[1]
|
|
60
|
-
j = parse_qs(raw)
|
|
61
|
-
return {
|
|
62
|
-
"web_view_init_data": {
|
|
63
|
-
"query_id": j["query_id"][0],
|
|
64
|
-
"user": j["user"][0],
|
|
65
|
-
"auth_date": j["auth_date"][0],
|
|
66
|
-
"hash": j["hash"][0],
|
|
67
|
-
},
|
|
68
|
-
"web_view_init_data_raw": raw,
|
|
69
|
-
"ep": "menu",
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
async def create_orders_forum(self, uid: str | int) -> tuple[int, bool]:
|
|
73
|
-
async with self.app as app:
|
|
74
|
-
app: Client
|
|
75
|
-
await app.get_me()
|
|
76
|
-
chat: Chat = await app.create_supergroup("Xync Orders", "Xync Orders")
|
|
77
|
-
if not (await app.toggle_forum_topics(chat_id=chat.id, enabled=True)):
|
|
78
|
-
await app.delete_channel(chat.id)
|
|
79
|
-
await chat.leave()
|
|
80
|
-
raise Exception(f"Chat {chat.id} for {app.me.username} not converted to forum")
|
|
81
|
-
await chat.add_members(["XyncNetBot"]) # , "xync_bot"
|
|
82
|
-
await chat.promote_member("XyncNetBot", self.max_privs)
|
|
83
|
-
added = await chat.add_members([uid])
|
|
84
|
-
try:
|
|
85
|
-
await sleep(1, await chat.get_member(uid))
|
|
86
|
-
except UserNotParticipant:
|
|
87
|
-
added = False
|
|
88
|
-
# await chat.leave()
|
|
89
|
-
return chat.id, added
|
|
90
|
-
|
|
91
|
-
async def get_user_photos(self, uid: str | int) -> Photos:
|
|
92
|
-
async with self.app as app:
|
|
93
|
-
app: Client
|
|
94
|
-
try:
|
|
95
|
-
peer = await app.resolve_peer(uid)
|
|
96
|
-
except Exception as e:
|
|
97
|
-
raise e
|
|
98
|
-
return await app.invoke(GetUserPhotos(user_id=peer, offset=0, limit=1, max_id=-1))
|
|
99
|
-
|
|
100
|
-
async def send_message(self, uid, txt):
|
|
101
|
-
async with self.app as app:
|
|
102
|
-
app: Client
|
|
103
|
-
try:
|
|
104
|
-
return await app.send_message(uid, txt)
|
|
105
|
-
except Exception as e:
|
|
106
|
-
raise e
|
|
107
|
-
|
|
108
|
-
async def save_file(self, byts: bytes, ctype: str) -> tuple[MessageMediaDocument, bytes]:
|
|
109
|
-
async with self.app as app:
|
|
110
|
-
in_file = await app.save_file(BytesIO(byts))
|
|
111
|
-
imud = InputMediaUploadedDocument(file=in_file, mime_type=ctype, attributes=[])
|
|
112
|
-
upf: MessageMediaDocument = await app.invoke(UploadMedia(peer=InputPeerSelf(), media=imud))
|
|
113
|
-
return upf, (
|
|
114
|
-
upf.document.id.to_bytes(8, "big")
|
|
115
|
-
+ upf.document.access_hash.to_bytes(8, "big", signed=True)
|
|
116
|
-
+ upf.document.file_reference
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
@staticmethod
|
|
120
|
-
def ref_enc(ph_id: int, access_hash: int, ref: bytes) -> bytes:
|
|
121
|
-
return ph_id.to_bytes(8, "big") + access_hash.to_bytes(8, "big", signed=True) + ref
|
|
122
|
-
|
|
123
|
-
@staticmethod
|
|
124
|
-
def ref_dec(full_ref: bytes) -> tuple[int, int, bytes]:
|
|
125
|
-
pid, ah = int.from_bytes(full_ref[:8], "big"), int.from_bytes(full_ref[8:16], "big", signed=True)
|
|
126
|
-
return pid, ah, full_ref[16:]
|
|
127
|
-
|
|
128
|
-
async def save_photo(self, file: bytes) -> tuple[MessageMediaPhoto, bytes]:
|
|
129
|
-
async with self.app as app:
|
|
130
|
-
in_file = await app.save_file(BytesIO(file))
|
|
131
|
-
upm = UploadMedia(peer=InputPeerSelf(), media=InputMediaUploadedPhoto(file=in_file))
|
|
132
|
-
upp: MessageMediaPhoto = await app.invoke(upm)
|
|
133
|
-
return upp, self.ref_enc(upp.photo.id, upp.photo.access_hash, upp.photo.file_reference)
|
|
134
|
-
|
|
135
|
-
async def get_file(self, fid: bytes) -> File:
|
|
136
|
-
async with self.app as app:
|
|
137
|
-
pid, ah, ref = self.ref_dec(fid)
|
|
138
|
-
loc = InputDocumentFileLocation(id=pid, access_hash=ah, file_reference=ref, thumb_size="x")
|
|
139
|
-
return await app.invoke(GetFile(location=loc, offset=0, limit=512 * 1024))
|
|
140
|
-
|
|
141
|
-
async def get_photo(self, fid: bytes, st: str) -> File:
|
|
142
|
-
async with self.app as app:
|
|
143
|
-
pid, ah, ref = self.ref_dec(fid)
|
|
144
|
-
loc = InputPhotoFileLocation(id=pid, access_hash=ah, file_reference=ref, thumb_size=st)
|
|
145
|
-
return await app.invoke(GetFile(location=loc, offset=0, limit=512 * 1024))
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
async def main():
|
|
149
|
-
_ = await init_db(PG_DSN, models, True)
|
|
150
|
-
agent: Agent = await Agent.filter(auth__isnull=False, ex__name="TgWallet").prefetch_related("ex").first()
|
|
151
|
-
pcl = PyroClient(agent)
|
|
152
|
-
await pcl.create_orders_forum(agent.actor.user_id)
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if __name__ == "__main__":
|
|
156
|
-
run(main())
|
|
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
|
{xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/tests/_todo_refact/Binance/test_binance.py
RENAMED
|
File without changes
|
{xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/tests/_todo_refact/Bybit/test_bybit.py
RENAMED
|
File without changes
|
{xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/tests/_todo_refact/Bybit/test_bybit_p2p.py
RENAMED
|
File without changes
|
{xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/tests/_todo_refact/Gate/test_gate.py
RENAMED
|
File without changes
|
{xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/tests/_todo_refact/Htx/test_htx_p2p.py
RENAMED
|
File without changes
|
{xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/tests/_todo_refact/Wallet/test_agent.py
RENAMED
|
File without changes
|
{xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/tests/_todo_refact/Wallet/test_ex.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
|
{xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client/Binance/binance_async.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
|
|
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
|
|
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
|
|
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
|
{xync_client-0.0.25.dev111 → xync_client-0.0.25.dev116}/xync_client.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|