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.
Files changed (98) hide show
  1. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/.gitignore +2 -1
  2. {xync_client-0.0.25.dev112/xync_client.egg-info → xync_client-0.0.25.dev116}/PKG-INFO +1 -1
  3. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Abc/Ex.py +51 -33
  4. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Abc/InAgent.py +6 -1
  5. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Binance/ex.py +6 -3
  6. xync_client-0.0.25.dev116/xync_client/Bybit/InAgent.py +42 -0
  7. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Bybit/agent.py +0 -4
  8. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Bybit/ws.py +32 -1
  9. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Mexc/ex.py +40 -23
  10. xync_client-0.0.25.dev116/xync_client/TgWallet/pyro.py +144 -0
  11. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116/xync_client.egg-info}/PKG-INFO +1 -1
  12. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client.egg-info/SOURCES.txt +1 -0
  13. xync_client-0.0.25.dev112/xync_client/TgWallet/pyro.py +0 -156
  14. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/.env.sample +0 -0
  15. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/.pre-commit-config.yaml +0 -0
  16. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/README.md +0 -0
  17. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/makefile +0 -0
  18. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/pyproject.toml +0 -0
  19. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/setup.cfg +0 -0
  20. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/TestAgent.py +0 -0
  21. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/TestAsset.py +0 -0
  22. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/TestEx.py +0 -0
  23. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/TestOrder.py +0 -0
  24. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/_todo_refact/Binance/test_binance.py +0 -0
  25. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/_todo_refact/Bybit/test_bybit.py +0 -0
  26. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/_todo_refact/Bybit/test_bybit_p2p.py +0 -0
  27. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/_todo_refact/Gate/test_gate.py +0 -0
  28. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/_todo_refact/Htx/test_htx_p2p.py +0 -0
  29. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/_todo_refact/Wallet/test_agent.py +0 -0
  30. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/_todo_refact/Wallet/test_ex.py +0 -0
  31. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/_todo_refact/__init__.py +0 -0
  32. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/tests/_todo_refact/_test_ex.py +0 -0
  33. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Abc/Agent.py +0 -0
  34. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Abc/Asset.py +0 -0
  35. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Abc/AuthTrait.py +0 -0
  36. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Abc/Base.py +0 -0
  37. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Abc/BaseTest.py +0 -0
  38. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Abc/Order.py +0 -0
  39. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Abc/types.py +0 -0
  40. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Binance/__init__.py +0 -0
  41. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Binance/binance_async.py +0 -0
  42. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Binance/earn_api.py +0 -0
  43. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Binance/etype/ad.py +0 -0
  44. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Binance/etype/pm.py +0 -0
  45. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Binance/exceptions.py +0 -0
  46. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Binance/sapi.py +0 -0
  47. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Binance/web_c2c.py +0 -0
  48. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BingX/__init__.py +0 -0
  49. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BingX/agent.py +0 -0
  50. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BingX/base.py +0 -0
  51. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BingX/etype/ad.py +0 -0
  52. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BingX/etype/pm.py +0 -0
  53. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BingX/ex.py +0 -0
  54. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BingX/req.mjs +0 -0
  55. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BingX/sign.js +0 -0
  56. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BitGet/__init__.py +0 -0
  57. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BitGet/agent.py +0 -0
  58. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BitGet/etype/ad.py +0 -0
  59. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BitGet/ex.py +0 -0
  60. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BitGet/req.mjs +0 -0
  61. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/BitPapa/ex.py +0 -0
  62. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Bybit/etype/ad.py +0 -0
  63. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Bybit/ex.py +0 -0
  64. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Bybit/web_earn.py +0 -0
  65. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Bybit/web_p2p.py +0 -0
  66. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Gate/etype/ad.py +0 -0
  67. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Gate/ex.py +0 -0
  68. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Gate/premarket.py +0 -0
  69. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Htx/agent.py +0 -0
  70. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Htx/earn.py +0 -0
  71. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Htx/etype/__init__.py +0 -0
  72. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Htx/etype/ad.py +0 -0
  73. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Htx/etype/cred.py +0 -0
  74. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Htx/etype/pm.py +0 -0
  75. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Htx/ex.py +0 -0
  76. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/KuCoin/etype/ad.py +0 -0
  77. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/KuCoin/etype/pm.py +0 -0
  78. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/KuCoin/ex.py +0 -0
  79. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/KuCoin/web.py +0 -0
  80. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Mexc/etype/ad.py +0 -0
  81. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Mexc/etype/pm.py +0 -0
  82. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Okx/etype/ad.py +0 -0
  83. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Okx/etype/pm.py +0 -0
  84. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/Okx/ex.py +0 -0
  85. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/TgWallet/agent.py +0 -0
  86. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/TgWallet/asset.py +0 -0
  87. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/TgWallet/auth.py +0 -0
  88. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/TgWallet/ex.py +0 -0
  89. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/TgWallet/inAgent.py +0 -0
  90. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/TgWallet/order.py +0 -0
  91. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/TgWallet/pyd.py +0 -0
  92. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/TgWallet/web.py +0 -0
  93. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/__init__.py +0 -0
  94. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/loader.py +0 -0
  95. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client/pm_unifier.py +0 -0
  96. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client.egg-info/dependency_links.txt +0 -0
  97. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client.egg-info/requires.txt +0 -0
  98. {xync_client-0.0.25.dev112 → xync_client-0.0.25.dev116}/xync_client.egg-info/top_level.txt +0 -0
@@ -8,4 +8,5 @@ __pycache__
8
8
  /build
9
9
  .vscode
10
10
  /xync_client/Gate/res.js
11
- /tests/res.js
11
+ /tests/res.js
12
+ *.session*
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xync-client
3
- Version: 0.0.25.dev112
3
+ Version: 0.0.25.dev116
4
4
  Author-email: Mike Artemiev <mixartemev@gmail.com>
5
5
  Project-URL: Homepage, https://gitlab.com/XyncNet/client
6
6
  Project-URL: Repository, https://gitlab.com/XyncNet/client
@@ -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
- pms_epyds: dict[int | str, PmEx] = {
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, pm in pms_epyds.items():
135
- pmu: PmUni = uni(pm.name)
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] == pm.name and pmu.country == prev[3]: # оригинальное имя не уникально на этой бирже
142
- logging.warning(f"Pm: '{pm.name}' duplicated with ids {prev[0]}: {k} on {self.ex.name}")
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": pm.name}, ex=self.ex, exid=k, pm=pm_)
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: {pm.name}&{prev[2]} overnormd as {pmu.norm} with ids {prev[0]}: {k} on {self.ex.name}"
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=pm.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": pm.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, pm.name, pmu.country
168
+ prev = k, pmu.norm, pmex.name, pmu.country
169
+
184
170
  # Pmexs
185
- pmexs = [models.Pmex(exid=k, ex=self.ex, pm=pm, name=pms_epyds[k].name, logo=file) for k, pm in pms.items()]
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, pm in pms_epyds.items():
189
- if banks := pm.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 {c["currencyCode"]: types.CurEx(exid=c["currencyCode"], ticker=c["currencyCode"], scale=c["currencyScale"]) for c in curs["data"]}
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
- "Philippine National Bank (PNB)": "Philippines National Bank (PNB)",
20
- "Al-Rajhi Bank": "Al Rajhi Bank",
21
- "SBP - Fast Bank Transfer": "SBP",
22
- "Touch 'n Go": "Touch n Go"
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={'currency': cur}).json()
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('https://p2p.mexc.com/api/common/currency').json()
33
- return {cur["currency"]: types.CurEx(exid=cur["currency"], ticker=cur["currency"], scale=cur["scale"]) for cur in _curs["data"]}
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('https://p2p.mexc.com/api/common/coins').json()
51
- return {coin["coinId"]:types.CoinEx(exid=coin["coinId"], ticker=coin["coinName"],scale=coin["quantityScale"]) for coin in coins["data"]}
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
- self, coin_exid: str, cur_exid: str, is_sell: bool, pm_exids: list[str | int] = None, amount: int = None
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
- 'allowTrade': 'false',
66
- 'amount': amount or "",
67
- 'blockTrade': 'false',
68
- 'coinId': coin_exid,
69
- 'countryCode': '',
70
- 'currency': cur_exid,
71
- 'follow': 'false',
72
- 'haveTrade': 'false',
73
- 'page': '1',
74
- 'payMethod': pm_exids or "",
75
- 'tradeType': 'SELL' if is_sell else "BUY",
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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xync-client
3
- Version: 0.0.25.dev112
3
+ Version: 0.0.25.dev116
4
4
  Author-email: Mike Artemiev <mixartemev@gmail.com>
5
5
  Project-URL: Homepage, https://gitlab.com/XyncNet/client
6
6
  Project-URL: Repository, https://gitlab.com/XyncNet/client
@@ -57,6 +57,7 @@ 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
@@ -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())