xync-client 0.0.25.dev112__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.dev112 → xync_client-0.0.25.dev116}/.gitignore +2 -1
- {xync_client-0.0.25.dev112/xync_client.egg-info → xync_client-0.0.25.dev116}/PKG-INFO +1 -1
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Abc/Ex.py +51 -33
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Abc/InAgent.py +6 -1
- {xync_client-0.0.25.dev112 → 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.dev112 → xync_client-0.0.25.dev116}/xync_client/Bybit/agent.py +0 -4
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Bybit/ws.py +32 -1
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Mexc/ex.py +40 -23
- xync_client-0.0.25.dev116/xync_client/TgWallet/pyro.py +144 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116/xync_client.egg-info}/PKG-INFO +1 -1
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client.egg-info/SOURCES.txt +1 -0
- xync_client-0.0.25.dev112/xync_client/TgWallet/pyro.py +0 -156
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/.env.sample +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/.pre-commit-config.yaml +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/README.md +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/makefile +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/pyproject.toml +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/setup.cfg +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/TestAgent.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/TestAsset.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/TestEx.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/TestOrder.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/_todo_refact/Binance/test_binance.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/_todo_refact/Bybit/test_bybit.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/_todo_refact/Bybit/test_bybit_p2p.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/_todo_refact/Gate/test_gate.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/_todo_refact/Htx/test_htx_p2p.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/_todo_refact/Wallet/test_agent.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/_todo_refact/Wallet/test_ex.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/_todo_refact/__init__.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/_todo_refact/_test_ex.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Abc/Agent.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Abc/Asset.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Abc/AuthTrait.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Abc/Base.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Abc/BaseTest.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Abc/Order.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Abc/types.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Binance/__init__.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Binance/binance_async.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Binance/earn_api.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Binance/etype/ad.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Binance/etype/pm.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Binance/exceptions.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Binance/sapi.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Binance/web_c2c.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BingX/__init__.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BingX/agent.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BingX/base.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BingX/etype/ad.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BingX/etype/pm.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BingX/ex.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BingX/req.mjs +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BingX/sign.js +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BitGet/__init__.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BitGet/agent.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BitGet/etype/ad.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BitGet/ex.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BitGet/req.mjs +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BitPapa/ex.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Bybit/etype/ad.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Bybit/ex.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Bybit/web_earn.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Bybit/web_p2p.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Gate/etype/ad.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Gate/ex.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Gate/premarket.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Htx/agent.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Htx/earn.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Htx/etype/__init__.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Htx/etype/ad.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Htx/etype/cred.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Htx/etype/pm.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Htx/ex.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/KuCoin/etype/ad.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/KuCoin/etype/pm.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/KuCoin/ex.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/KuCoin/web.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Mexc/etype/ad.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Mexc/etype/pm.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Okx/etype/ad.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Okx/etype/pm.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Okx/ex.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/TgWallet/agent.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/TgWallet/asset.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/TgWallet/auth.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/TgWallet/ex.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/TgWallet/inAgent.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/TgWallet/order.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/TgWallet/pyd.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/TgWallet/web.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/__init__.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/loader.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/pm_unifier.py +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client.egg-info/dependency_links.txt +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client.egg-info/requires.txt +0 -0
- {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client.egg-info/top_level.txt +0 -0
|
@@ -20,6 +20,11 @@ from xync_client.pm_unifier import PmUnifier, PmUni
|
|
|
20
20
|
class BaseExClient(BaseClient):
|
|
21
21
|
cur_map: dict[int, str] = {}
|
|
22
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
|
+
}
|
|
23
28
|
|
|
24
29
|
@abstractmethod
|
|
25
30
|
def pm_type_map(self, typ: models.Pmex) -> str: ...
|
|
@@ -69,7 +74,6 @@ class BaseExClient(BaseClient):
|
|
|
69
74
|
|
|
70
75
|
# Импорт Pm-ов (с Pmcur-, Pmex- и Pmcurex-ами) и валют (с Curex-ами) с биржи в бд
|
|
71
76
|
async def set_pmcurexs(self):
|
|
72
|
-
pbot = PyroClient(bot)
|
|
73
77
|
# Curs
|
|
74
78
|
cur_pyds: dict[str, CurEx] = await self.curs()
|
|
75
79
|
curs: dict[int | str, models.Cur] = {
|
|
@@ -124,69 +128,66 @@ class BaseExClient(BaseClient):
|
|
|
124
128
|
# todo: curexcountry
|
|
125
129
|
|
|
126
130
|
# Pms
|
|
127
|
-
|
|
131
|
+
pmexs_epyds: dict[int | str, PmEx] = {
|
|
128
132
|
k: v for k, v in sorted((await self.pms()).items(), key=lambda x: x[1].name)
|
|
129
133
|
} # sort by name
|
|
130
134
|
pms: dict[int | str, models.Pm] = dict({})
|
|
131
135
|
prev = 0, "", "", None # id, normd-name, orig-name
|
|
132
136
|
cntrs = [c.lower() for c in await models.Country.all().values_list("name", flat=True)]
|
|
133
137
|
uni = self.unifier_class(cntrs)
|
|
134
|
-
for k,
|
|
135
|
-
pmu: PmUni = uni(
|
|
138
|
+
for k, pmex in pmexs_epyds.items():
|
|
139
|
+
pmu: PmUni = uni(pmex.name)
|
|
136
140
|
country_id = (
|
|
137
141
|
await models.Country.get(name__iexact=cnt).values_list("id", flat=True)
|
|
138
142
|
if (cnt := pmu.country)
|
|
139
143
|
else None
|
|
140
144
|
)
|
|
141
|
-
if prev[2] ==
|
|
142
|
-
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}")
|
|
143
147
|
# новый Pm не добавляем, а берем старый с этим названием
|
|
144
148
|
pm_ = pms.get(prev[0], await models.Pm.get_or_none(norm=prev[1], country_id=country_id))
|
|
145
149
|
# и добавляем Pmex для него
|
|
146
|
-
await models.Pmex.update_or_create({"name":
|
|
150
|
+
await models.Pmex.update_or_create({"name": pmex.name}, ex=self.ex, exid=k, pm=pm_)
|
|
147
151
|
elif (
|
|
148
152
|
prev[1] == pmu.norm and pmu.country == prev[3]
|
|
149
153
|
): # 2 разных оригинальных имени на этой бирже совпали при нормализации
|
|
150
154
|
logging.error(
|
|
151
|
-
f"Pm: {
|
|
155
|
+
f"Pm: {pmex.name}&{prev[2]} overnormd as {pmu.norm} with ids {prev[0]}: {k} on {self.ex.name}"
|
|
152
156
|
)
|
|
153
157
|
# новый Pm не добавляем, только Pmex для него
|
|
154
158
|
# новый Pm не добавляем, а берем старый с этим названием
|
|
155
159
|
pm_ = pms.get(prev[0], await models.Pm.get_or_none(norm=prev[1], country_id=country_id))
|
|
156
160
|
# и добавляем.обновляем Pmex для него
|
|
157
|
-
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)
|
|
158
162
|
else:
|
|
159
|
-
pmin = models.Pm.validate({**pmu.model_dump(), "country_id": country_id, "typ":
|
|
160
|
-
# logo
|
|
161
|
-
if pm.logo or (file := None):
|
|
162
|
-
if not (file := await models.File.get_or_none(name=pm.logo)):
|
|
163
|
-
if not pm.logo.startswith("https:"):
|
|
164
|
-
if not pm.logo.startswith("/"):
|
|
165
|
-
pm.logo = "/" + pm.logo
|
|
166
|
-
pm.logo = "https://" + pm.logo
|
|
167
|
-
async with ClientSession() as ss:
|
|
168
|
-
resp = await ss.get(pm.logo)
|
|
169
|
-
if resp.ok:
|
|
170
|
-
byts = await resp.read()
|
|
171
|
-
upf, ref = await pbot.save_file(byts, resp.content_type)
|
|
172
|
-
await sleep(1)
|
|
173
|
-
typ = FileType[resp.content_type.split("/")[-1]]
|
|
174
|
-
file, _ = await models.File.update_or_create(
|
|
175
|
-
{"ref": ref, "size": len(byts), "typ": typ}, name=pm.logo
|
|
176
|
-
)
|
|
177
|
-
await pbot.get_file(file.ref) # check
|
|
178
|
-
# /logo
|
|
163
|
+
pmin = models.Pm.validate({**pmu.model_dump(), "country_id": country_id, "typ": pmex.typ})
|
|
179
164
|
try:
|
|
180
165
|
pms[k], _ = await models.Pm.update_or_create(**pmin.df_unq())
|
|
181
166
|
except (MultipleObjectsReturned, IntegrityError) as e:
|
|
182
167
|
raise e
|
|
183
|
-
prev = k, pmu.norm,
|
|
168
|
+
prev = k, pmu.norm, pmex.name, pmu.country
|
|
169
|
+
|
|
184
170
|
# Pmexs
|
|
185
|
-
|
|
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
|
+
|
|
186
187
|
await models.Pmex.bulk_create(pmexs, on_conflict=["ex_id", "exid"], update_fields=["pm_id", "logo_id", "name"])
|
|
187
188
|
# Pmex banks
|
|
188
|
-
for k,
|
|
189
|
-
if banks :=
|
|
189
|
+
for k, pmex in pmexs_epyds.items():
|
|
190
|
+
if banks := pmex.banks:
|
|
190
191
|
pmex = await models.Pmex.get(ex=self.ex, exid=k) # pm=pms[k],
|
|
191
192
|
for b in banks:
|
|
192
193
|
await models.PmexBank.update_or_create({"name": b.name}, exid=b.exid, pmex=pmex)
|
|
@@ -206,6 +207,23 @@ class BaseExClient(BaseClient):
|
|
|
206
207
|
# pmcurexs = [Pmcurex(pmcur=pmcur, ex=self.ex) for pmcur in pmcurs]
|
|
207
208
|
# await Pmcurex.bulk_create(pmcurexs)
|
|
208
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
|
+
|
|
209
227
|
# Импорт монет (с Coinex-ами) с биржи в бд
|
|
210
228
|
async def set_coinexs(self):
|
|
211
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())
|
|
@@ -10,7 +10,6 @@ from xync_client.Abc.Base import FlatDict
|
|
|
10
10
|
from xync_schema.models import Cur
|
|
11
11
|
|
|
12
12
|
from xync_client.Abc.Agent import BaseAgentClient
|
|
13
|
-
from xync_client.Bybit.ws import prv
|
|
14
13
|
from xync_client.loader import BYT2FA, PG_DSN
|
|
15
14
|
|
|
16
15
|
|
|
@@ -315,9 +314,6 @@ async def main():
|
|
|
315
314
|
_ = await init_db(PG_DSN, models, True)
|
|
316
315
|
agent = await models.Agent.filter(actor__ex_id=9, auth__isnull=False).prefetch_related("actor__ex").first()
|
|
317
316
|
cl: AgentClient = agent.client()
|
|
318
|
-
t = await cl.ott()
|
|
319
|
-
ts = int(float(t["time_now"]) * 1000)
|
|
320
|
-
await prv(agent.auth["deviceId"], t["result"], ts, listen)
|
|
321
317
|
await cl.close()
|
|
322
318
|
|
|
323
319
|
|
|
@@ -1,6 +1,37 @@
|
|
|
1
|
+
import hmac
|
|
1
2
|
import json
|
|
2
|
-
|
|
3
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)
|
|
4
35
|
|
|
5
36
|
|
|
6
37
|
async def prv(did: str, tok: str, ts: int, cb: callable):
|
|
@@ -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())
|
|
@@ -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.dev112 → xync_client-0.0.25.dev116}/tests/_todo_refact/Binance/test_binance.py
RENAMED
|
File without changes
|
{xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/_todo_refact/Bybit/test_bybit.py
RENAMED
|
File without changes
|
{xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/_todo_refact/Bybit/test_bybit_p2p.py
RENAMED
|
File without changes
|
{xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/_todo_refact/Gate/test_gate.py
RENAMED
|
File without changes
|
{xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/_todo_refact/Htx/test_htx_p2p.py
RENAMED
|
File without changes
|
{xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/_todo_refact/Wallet/test_agent.py
RENAMED
|
File without changes
|
{xync_client-0.0.25.dev112 → 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
|
|
File without changes
|
|
File without changes
|
{xync_client-0.0.25.dev112 → 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
|
|
File without changes
|
{xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|