xync-client 0.0.164__py3-none-any.whl → 0.0.179.dev4__py3-none-any.whl

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.
@@ -1,7 +1,6 @@
1
1
  import asyncio
2
2
  import json
3
3
  import logging
4
- import re
5
4
  from asyncio import sleep, gather
6
5
  from asyncio.tasks import create_task
7
6
  from datetime import datetime, timedelta, timezone
@@ -9,7 +8,6 @@ from difflib import SequenceMatcher
9
8
  from enum import IntEnum
10
9
  from hashlib import sha256
11
10
  from http.client import HTTPException
12
- from math import floor
13
11
  from typing import Literal
14
12
  from uuid import uuid4
15
13
 
@@ -19,29 +17,26 @@ from aiohttp.http_exceptions import HttpProcessingError
19
17
  from bybit_p2p import P2P
20
18
  from bybit_p2p._exceptions import FailedRequestError
21
19
  from payeer_api import PayeerAPI
22
- from pyro_client.client.file import FileClient
20
+ from pydantic import ValidationError
23
21
  from tortoise import BaseDBAsyncClient
24
- from tortoise.exceptions import IntegrityError
25
- from tortoise.expressions import Q
26
- from tortoise.functions import Count
27
22
  from tortoise.signals import post_save
28
23
  from tortoise.timezone import now
29
24
  from tortoise.transactions import in_transaction
25
+ from websockets import ConnectionClosedError
30
26
  from x_client import df_hdrs
31
27
  from x_model import init_db
32
- from x_model.func import ArrayAgg
33
28
  from xync_bot import XyncBot
34
29
 
35
30
  from xync_client.Bybit.ex import ExClient
36
31
  from xync_schema import models
37
32
  from xync_schema.enums import OrderStatus, AgentStatus
38
33
 
39
- from xync_schema.models import Actor, PmCur, Agent
34
+ from xync_schema.models import Agent
40
35
 
41
36
  from xync_client.Abc.Agent import BaseAgentClient
42
- from xync_client.Abc.xtype import FlatDict, BaseOrderReq, AdUpd, GetAds
43
- from xync_client.Bybit.etype.ad import AdPostRequest, AdUpdateRequest, Ad, AdStatus, MyAd
44
- from xync_client.Bybit.etype.cred import CredEpyd
37
+ from xync_client.Abc.xtype import FlatDict, BaseOrderReq, AdUpdReq, GetAdsReq
38
+ from xync_client.Bybit.etype.ad import AdPostRequest, AdRequest, Ad, AdStatusReq, MyAd
39
+ from xync_client.Bybit.etype.cred import CredEpyd, PaymentTerm, CredEx
45
40
  from xync_client.Bybit.etype.order import (
46
41
  OrderRequest,
47
42
  PreOrderResp,
@@ -60,7 +55,7 @@ from xync_client.Bybit.etype.order import (
60
55
  SellerCancelChange,
61
56
  )
62
57
  from xync_client.Pms.Payeer.agent import PmAgentClient
63
- from xync_client.loader import TORM, NET_TOKEN, PAY_TOKEN, PRX
58
+ from xync_client.loader import TORM, PAY_TOKEN, PRX
64
59
 
65
60
 
66
61
  class NoMakerException(Exception):
@@ -77,23 +72,26 @@ class AgentClient(BaseAgentClient): # Bybit client
77
72
  # rewrite token for public methods
78
73
  api: P2P
79
74
  orders: dict[int, tuple[models.Order, OrderFull]] = {} # pending
75
+ cdx_cls: type[CredEx] = CredEx
80
76
 
81
77
  def __init__(
82
78
  self,
83
79
  agent: Agent,
84
80
  ex_client: ExClient,
85
- fbot: FileClient,
86
- bbot: XyncBot,
87
81
  pm_clients: dict[int, PmAgentClient] = None,
88
82
  **kwargs,
89
83
  ):
90
- super().__init__(agent, ex_client, fbot, bbot, pm_clients, **kwargs)
84
+ super().__init__(agent, ex_client, pm_clients, **kwargs)
91
85
  self.sec_hdrs = {
92
86
  "accept-language": "ru,en;q=0.9",
93
87
  "gdfp": agent.auth["Risktoken"],
94
88
  "tx-id": agent.auth["Risktoken"],
95
89
  }
96
- self.api = P2P(testnet=False, api_key=agent.auth["key"], api_secret=agent.auth["sec"])
90
+ self.api = P2P(
91
+ testnet=False,
92
+ api_key=agent.auth["key"],
93
+ api_secret=agent.auth["sec"], # , proxies=kwargs.get("proxies")
94
+ )
97
95
  self.hist: dict | None = None
98
96
  self.completed_orders: list[int] | None = None
99
97
 
@@ -122,95 +120,11 @@ class AgentClient(BaseAgentClient): # Bybit client
122
120
  def get_payment_method(self, fiat_id: int) -> CredEpyd:
123
121
  return self.creds()[fiat_id]
124
122
 
125
- def creds(self) -> dict[int, CredEpyd]:
123
+ async def _get_creds(self) -> list[PaymentTerm]:
126
124
  data = self.api.get_user_payment_types()
127
125
  if data["ret_code"] > 0:
128
126
  return data
129
- return {credex["id"]: CredEpyd.model_validate(credex) for credex in data["result"]}
130
-
131
- async def cred_epyd2db(self, ecdx: CredEpyd, pers_id: int = None, cur_id: int = None) -> models.CredEx | None:
132
- if ecdx.paymentType in (416,): # what is 416??
133
- return None
134
- if not (
135
- pmex := await models.PmEx.get_or_none(exid=ecdx.paymentType, ex=self.ex_client.ex).prefetch_related(
136
- "pm__curs"
137
- )
138
- ):
139
- raise HTTPException(f"No PmEx {ecdx.paymentType} on ex#{self.ex_client.ex.name}", 404)
140
- if cred_old := await models.Cred.get_or_none(credexs__exid=ecdx.id, credexs__ex=self.actor.ex).prefetch_related(
141
- "pmcur"
142
- ):
143
- cur_id = cred_old.pmcur.cur_id
144
- elif not cur_id: # is new Cred
145
- cur_id = (
146
- pmex.pm.df_cur_id
147
- or await self.guess_cur(ecdx, len(pmex.pm.curs) > 1 and pmex.pm.curs)
148
- or (pmex.pm.country_id and (await pmex.pm.country).cur_id)
149
- # or (ecdx.currencyBalance and await models.Cur.get_or_none(ticker=ecdx.currencyBalance[0])) # это че еще за хуйня?
150
- )
151
- if not cur_id:
152
- raise Exception(f"Set default cur for {pmex.name}")
153
- if not (pmcur := await models.PmCur.get_or_none(cur_id=cur_id, pm_id=pmex.pm_id)):
154
- raise HTTPException(f"No PmCur with cur#{cur_id} and pm#{ecdx.paymentType}", 404)
155
- xtr = ecdx.branchName
156
- if ecdx.bankName:
157
- xtr += (" | " if xtr else "") + ecdx.bankName
158
- elif ecdx.payMessage:
159
- xtr += (" | " if xtr else "") + ecdx.payMessage
160
- elif ecdx.qrcode:
161
- xtr += (" | " if xtr else "") + ecdx.qrcode
162
- elif ecdx.paymentExt1:
163
- xtr += (" | " if xtr else "") + ecdx.paymentExt1
164
- try:
165
- cred_db, _ = await models.Cred.update_or_create(
166
- {
167
- "name": ecdx.realName,
168
- "extra": xtr,
169
- },
170
- pmcur=pmcur,
171
- person_id=pers_id or self.actor.person_id,
172
- detail=ecdx.accountNo or ecdx.payMessage,
173
- )
174
- if cred_db.ovr_pm_id is None and (cred_db.detail.startswith("XyncPay") or xtr.startswith("XyncPay")):
175
- cred_db.ovr_pm_id = 0
176
- await cred_db.save()
177
- credex_in = models.CredEx.validate({"exid": ecdx.id, "cred_id": cred_db.id, "ex_id": self.actor.ex.id})
178
- credex_db, _ = await models.CredEx.update_or_create(**credex_in.df_unq())
179
- except IntegrityError as e:
180
- raise e
181
- return credex_db
182
-
183
- async def guess_cur(self, ecdx: CredEpyd, curs: list[models.Cur]):
184
- mbs = ecdx.bankName.split(", ")
185
- mbs += ecdx.branchName.split(" / ")
186
- mbs = {mb.lower(): mb for mb in mbs}
187
- if (
188
- pms := await models.Pm.filter(Q(join_type="OR", pmexs__name__in=mbs.values(), norm__in=mbs.keys()))
189
- .group_by("pmcurs__cur_id", "pmcurs__cur__ticker")
190
- .annotate(ccnt=Count("id"), names=ArrayAgg("norm"))
191
- .order_by("-ccnt", "pmcurs__cur__ticker")
192
- .values("pmcurs__cur_id", "names", "ccnt")
193
- ):
194
- return pms[0]["pmcurs__cur_id"]
195
- curs = {c.ticker: c.id for c in curs or await models.Cur.all()}
196
- for cur, cid in curs.items():
197
- if re.search(re.compile(rf"\({cur}\)$"), ecdx.bankName):
198
- return cid
199
- if re.search(re.compile(rf"\({cur}\)$"), ecdx.branchName):
200
- return cid
201
- if re.search(re.compile(rf"\({cur}\)$"), ecdx.accountNo):
202
- return cid
203
- if re.search(re.compile(rf"\({cur}\)$"), ecdx.payMessage):
204
- return cid
205
- if re.search(re.compile(rf"\({cur}\)$"), ecdx.paymentExt1):
206
- return cid
207
- return None
208
-
209
- # 25: Список реквизитов моих платежных методов
210
- async def set_creds(self) -> list[models.CredEx]:
211
- credexs_epyd: dict[int, CredEpyd] = self.creds()
212
- credexs: list[models.CredEx] = [await self.cred_epyd2db(f) for f in credexs_epyd.values()]
213
- return credexs
127
+ return [PaymentTerm.model_validate(credex) for credex in data["result"] if credex["id"] != "-1"]
214
128
 
215
129
  async def ott(self):
216
130
  t = await self._post("/x-api/user/private/ott")
@@ -238,7 +152,7 @@ class AgentClient(BaseAgentClient): # Bybit client
238
152
  delete = await self._post("/x-api/fiat/otc/user/payment/new_delete", data)
239
153
  return delete
240
154
 
241
- async def switch_ads(self, new_status: AdStatus) -> dict:
155
+ async def switch_ads(self, new_status: AdStatusReq) -> dict:
242
156
  data = {"workStatus": new_status.name} # todo: переделать на апи, там status 0 -> 1
243
157
  res = await self._post("/x-api/fiat/otc/maker/work-config/switch", data)
244
158
  return res
@@ -248,26 +162,16 @@ class AgentClient(BaseAgentClient): # Bybit client
248
162
  ads = [ad for ad in list_ads if set(ad["payments"]) - {"5", "51"}]
249
163
  return float(ads[0]["price"])
250
164
 
251
- def my_ads(self, active: bool = True, page: int = 1) -> list[MyAd]:
252
- resp = self.api.get_ads_list(size="30", page=str(page), status=AdStatus.active if active else AdStatus.sold_out)
165
+ async def get_my_ads(self, active: bool = True, page: int = 1) -> list[MyAd]:
166
+ resp = self.api.get_ads_list(
167
+ size="30", page=str(page), status=AdStatusReq.active if active else AdStatusReq.sold_out
168
+ )
253
169
  ads = [MyAd.model_validate(ad) for ad in resp["result"]["items"]]
254
- if resp["result"]["count"] > 30 * page:
255
- ads.extend(self.my_ads(active, page + 1))
170
+ # todo: вернуть, что бы спарсил все объявы, а не только первые 30
171
+ # if resp["result"]["count"] > 30 * page:
172
+ # ads.extend(await self.get_my_ads(active, page + 1))
256
173
  return ads
257
174
 
258
- async def export_my_ads(self, active: bool = None) -> int: # upserted)
259
- ads = self.my_ads(True)
260
- if not active:
261
- ads += self.my_ads(False)
262
- for ad in ads:
263
- ad_db = await self.ex_client.ad_load(ad, maker=self.actor)
264
- mad_db, _ = await models.MyAd.update_or_create(ad=ad_db)
265
- exids = [pt.id for pt in ad.paymentTerms]
266
- credexs = await models.CredEx.filter(ex_id=self.actor.ex_id, exid__in=exids).prefetch_related("cred")
267
- await mad_db.credexs.clear()
268
- await mad_db.credexs.add(*credexs)
269
- return len(ads)
270
-
271
175
  async def ads_share(self, cur_id: int = None) -> int:
272
176
  mq = models.MyAd.hot_mads_query([4]).filter(ad__maker=self.actor)
273
177
  if cur_id:
@@ -276,7 +180,9 @@ class AgentClient(BaseAgentClient): # Bybit client
276
180
  return len([await self.ad_share(mad.id) for mad in mads])
277
181
 
278
182
  async def ad_share(self, maid: int):
279
- myad = await models.MyAd.get(id=maid).prefetch_related("ad__pair_side__pair__coin", "ad__pair_side__pair__cur")
183
+ myad = await models.MyAd.get(id=maid).prefetch_related(
184
+ "ad__pair_side__pair__coin", "ad__pair_side__pair__cur", "ad__maker"
185
+ )
280
186
  if myad.hex and myad.shared_at + timedelta(minutes=55) > now(): # check expired
281
187
  # check validity
282
188
  data = await self._post("/x-api/fiat/otc/item/shareItem/info", {"shareCode": myad.hex.hex()})
@@ -373,8 +279,8 @@ class AgentClient(BaseAgentClient): # Bybit client
373
279
  data = self.api.post_new_ad(**ad.model_dump())
374
280
  return data["result"]["itemId"] if data["ret_code"] == 0 else data
375
281
 
376
- async def _ad_upd(self, req: AdUpd):
377
- upd = AdUpdateRequest({})
282
+ async def _ad_upd(self, req: AdUpdReq):
283
+ upd = AdRequest({})
378
284
  params = upd.model_dump()
379
285
  data = self.api.update_ad(**params)
380
286
  return data["result"] if data["ret_code"] == 0 else data
@@ -411,16 +317,16 @@ class AgentClient(BaseAgentClient): # Bybit client
411
317
  res = res["result"]
412
318
  return PreOrderResp.model_validate(res)
413
319
 
414
- async def _order_request(self, bor: BaseOrderReq) -> OrderResp:
320
+ async def _order_request(self, bor: BaseOrderReq, bbot: XyncBot) -> OrderResp:
415
321
  por: PreOrderResp = await self.__preorder_request(bor.ad_id)
416
322
  req = OrderRequest(
417
323
  itemId=por.id,
418
324
  tokenId=bor.coin_exid,
419
325
  currencyId=bor.cur_exid,
420
326
  side="1" if bor.is_sell else "0",
421
- amount=f"{bor.fiat_amount:.2f}".rstrip("0").rstrip("."),
327
+ amount=f"{bor.amount:.2f}".rstrip("0").rstrip("."),
422
328
  curPrice=por.curPrice,
423
- quantity=str(round(bor.fiat_amount / float(por.price), bor.coin_scale)),
329
+ quantity=str(round(bor.amount / float(por.price), bor.coin_scale)),
424
330
  flag="amount",
425
331
  # online="0"
426
332
  )
@@ -433,9 +339,9 @@ class AgentClient(BaseAgentClient): # Bybit client
433
339
  )
434
340
  req = OrderSellRequest(**req.model_dump(), paymentType=bor.pmex_exid, paymentId=str(credex.exid))
435
341
  # вот непосредственно сам запрос на ордер
436
- return await self.__order_create(req, bor)
342
+ return await self.__order_create(req, bor, bbot)
437
343
 
438
- async def __order_create(self, req: OrderRequest | OrderSellRequest, bor: BaseOrderReq) -> OrderResp:
344
+ async def __order_create(self, req: OrderRequest | OrderSellRequest, bor: BaseOrderReq, bbot: XyncBot) -> OrderResp:
439
345
  hdrs = {"Risktoken": self.sec_hdrs["gdfp"]}
440
346
  res: dict = await self._post("/x-api/fiat/otc/order/create", json=req.model_dump(), hdrs=hdrs)
441
347
  if res["ret_code"] == 0:
@@ -444,16 +350,16 @@ class AgentClient(BaseAgentClient): # Bybit client
444
350
  logging.error(req.model_dump(), "POST", self.session._base_url)
445
351
  raise HTTPException()
446
352
  elif res["ret_code"] == 912120030 or res["ret_msg"] == "The price has changed, please try again later.":
447
- resp = await self._order_request(bor)
353
+ resp = await self._order_request(bor, bbot)
448
354
  else:
449
355
  logging.exception(res)
450
356
  if not resp.orderId and resp.needSecurityRisk:
451
357
  if rc := await self._check_2fa(resp.securityRiskToken):
452
- await self.bbot.send(self.actor.person.user.username_id, f"Bybit 2fa: {rc}")
358
+ await bbot.send(self.actor.person.user.username_id, f"Bybit 2fa: {rc}")
453
359
  raise Exception(f"Bybit 2fa: {rc}")
454
360
  # еще раз уже с токеном
455
361
  req.securityRiskToken = resp.securityRiskToken
456
- resp = await self.__order_create(req, bor)
362
+ resp = await self.__order_create(req, bor, bbot)
457
363
  return resp
458
364
 
459
365
  async def cancel_order(self, order_id: str) -> bool:
@@ -531,155 +437,6 @@ class AgentClient(BaseAgentClient): # Bybit client
531
437
  },
532
438
  )
533
439
 
534
- async def create_order_db(self, order: OrderFull) -> models.Order:
535
- curex = await models.CurEx.get_or_none(ex=self.ex_client.ex, exid=order.currencyId).prefetch_related("cur")
536
- cur_scale = (curex.scale if curex.scale is not None else curex.cur.scale) if curex else 2
537
- coinex = await models.CoinEx.get(ex=self.ex_client.ex, exid=order.tokenId).prefetch_related("coin")
538
- coin_scale = coinex.scale if coinex.scale is not None else coinex.cur.scale
539
- sb_names = order.sellerRealName, order.buyerRealName
540
- im_maker = int(int(order.makerUserId) == self.actor.exid)
541
- taker_id = (order.userId, order.targetUserId)[im_maker]
542
- taker_name = sb_names[order.side] # todo: double check
543
- taker_person = await self.ex_client.person_name_update(taker_name, taker_id)
544
- seller_person = (
545
- self.actor.person
546
- if order.side
547
- else await self.ex_client.person_name_update(order.sellerRealName, int(order.targetUserId))
548
- )
549
- taker_nick = (self.actor.name, order.targetNickName)[im_maker] # todo: check
550
- ad_db = await models.Ad.get(exid=order.itemId)
551
- if not ad_db:
552
- ad = self.get_ad(order.itemId)
553
- # ad_db, cond_isnew = await self.ex_client.cond_load(ad, force=True, rname=maker_name[order.side])
554
- ad_db = await self.ex_client.ad_load(ad, maker=self.actor)
555
- ecredex: CredEpyd = order.confirmedPayTerm
556
-
557
- if ecredex.paymentType == 0 and im_maker and order.side:
558
- ecredex = order.paymentTermList[0]
559
- if ecredex.paymentType:
560
- if ecredex.paymentType == 51:
561
- ecredex.accountNo = ecredex.accountNo.replace("p", "P").replace("р", "P").replace("Р", "P")
562
- # if not re.match(r"^([Pp])\d{7,10}$", ecredex.accountNo):
563
- # msgs = self.api.get_chat_messages(orderId=order.id, size=100)["result"]["result"]
564
- # msgs = [m["message"] for m in msgs if m["roleType"] == "user" and m["userId"] == order.targetUserId]
565
- # msgs = [g.group() for m in msgs if (g := re.match(r"([PpРр])\d{7,10}\b", m))]
566
- # crd = await models.Cred.get_or_none(
567
- # detail=ecredex.accountNo, credexs__exid=ecredex.id, credexs__ex=self.ex_client.ex
568
- # )
569
- # if not msgs and re.match(r"^\d{7,10}$", ecredex.accountNo):
570
- # ecredex.accountNo = "P" + ecredex.accountNo
571
- # elif msgs:
572
- # ecredex.accountNo = msgs[-1]
573
- # else:
574
- # ...
575
- # if crd:
576
- # crd.detail = ecredex.accountNo
577
- # await crd.save(update_fields=["detail"])
578
- if not (credex := await models.CredEx.get_or_none(exid=ecredex.id, ex=self.ex_client.ex)):
579
- # cur_id = await Cur.get(ticker=ad.currencyId).values_list('id', flat=True)
580
- # await self.cred_epyd2db(ecredex, ad_db.maker.person_id, cur_id)
581
- if (
582
- await PmCur.filter(
583
- pm__pmexs__ex=self.ex_client.ex,
584
- pm__pmexs__exid=ecredex.paymentType,
585
- cur__ticker=order.currencyId,
586
- ).count()
587
- != 1
588
- ):
589
- ...
590
- if not (
591
- pmcur := await PmCur.get_or_none(
592
- pm__pmexs__ex=self.ex_client.ex,
593
- pm__pmexs__exid=ecredex.paymentType,
594
- cur__ticker=order.currencyId,
595
- )
596
- ):
597
- ...
598
- if not (
599
- crd := await models.Cred.get_or_none(pmcur=pmcur, person=seller_person, detail=ecredex.accountNo)
600
- ):
601
- extr = ", ".join(
602
- x
603
- for xtr in [
604
- ecredex.bankName,
605
- ecredex.branchName,
606
- ecredex.qrcode,
607
- ecredex.payMessage,
608
- ecredex.paymentExt1,
609
- ]
610
- if (x := xtr.strip())
611
- )
612
- crd = await models.Cred.create(
613
- detail=ecredex.accountNo,
614
- pmcur=pmcur,
615
- person=seller_person,
616
- name=ecredex.realName,
617
- extra=extr,
618
- )
619
- credex = await models.CredEx.create(exid=ecredex.id, ex=self.ex_client.ex, cred=crd)
620
- try:
621
- taker, _ = await Actor.get_or_create(
622
- {"name": taker_nick, "person": taker_person}, ex=self.ex_client.ex, exid=taker_id
623
- )
624
- except IntegrityError as e:
625
- logging.error(e)
626
- odb, _ = await models.Order.update_or_create(
627
- {
628
- "amount": float(order.amount) * 10**cur_scale,
629
- "quantity": float(order.quantity) * 10**coin_scale,
630
- "status": OrderStatus[Status(order.status).name],
631
- "created_at": ms2utc(order.createDate),
632
- "payed_at": order.transferDate != "0" and ms2utc(order.transferDate) or None,
633
- "confirmed_at": Status(order.status) == Status.completed and ms2utc(order.transferDate) or None,
634
- "appealed_at": order.status == 30 and ms2utc(order.transferDate) or None,
635
- "cred_id": ecredex.paymentType and credex.cred_id or None,
636
- "taker": taker,
637
- "ad": ad_db,
638
- },
639
- exid=order.id,
640
- )
641
- if order.status == Status.completed and ecredex.paymentType == 51:
642
- await odb.fetch_related("cred", "transfer")
643
- if odb.cred.detail != ecredex.accountNo:
644
- ...
645
- frm = (odb.created_at + timedelta(minutes=180 - 1)).isoformat(sep=" ").split("+")[0]
646
- to = ((odb.payed_at or odb.created_at) + timedelta(minutes=180 + 30)).isoformat(sep=" ").split("+")[0]
647
- tsa = [
648
- t
649
- for tid, t in (self.hist.items() if self.hist else [])
650
- if (ecredex.accountNo == t["to"] and t["from"] != "@merchant" and frm < t["date"] < to)
651
- ]
652
- buyer_person = (
653
- self.actor.person
654
- if not order.side
655
- else await self.ex_client.person_name_update(order.buyerRealName, int(order.targetUserId))
656
- )
657
- ts = [t for t in tsa if floor(fa := float(order.amount)) <= float(t["creditedAmount"]) <= round(fa)]
658
- if len(ts) != 1:
659
- if len(tsa) > 1:
660
- summ = sum(float(t["creditedAmount"]) for t in tsa)
661
- if floor(fa) <= summ <= round(fa):
662
- for tr in tsa:
663
- am = int(float(tr["creditedAmount"]) * 100)
664
- await models.Transfer.create(
665
- pmid=tr["id"], order=odb, amount=am, sender_acc=tr["from"], created_at=tr["date"]
666
- )
667
- else:
668
- bcred, _ = await models.Cred.get_or_create(
669
- {"detail": ts[0]["from"]}, person=buyer_person, pmcur_id=odb.cred.pmcur_id
670
- )
671
- am = int(float(ts[0]["creditedAmount"]) * 100)
672
- try:
673
- await models.Transfer.create(
674
- pmid=ts[0]["id"], order=odb, amount=am, sender_acc=ts[0]["from"], created_at=ts[0]["date"]
675
- )
676
- except IntegrityError as e:
677
- logging.error(e)
678
- ...
679
-
680
- await odb.fetch_related("ad")
681
- return odb
682
-
683
440
  async def get_api_orders(
684
441
  self,
685
442
  page: int = 1,
@@ -708,7 +465,7 @@ class AgentClient(BaseAgentClient): # Bybit client
708
465
  if o.status != Status.completed.value or oid in self.completed_orders:
709
466
  continue
710
467
  order = await self.get_order_full(o.id)
711
- order_db = await self.create_order_db(order)
468
+ order_db = await self.order_save(order)
712
469
  await sleep(1)
713
470
  dmsgs = self.api.get_chat_messages(orderId=oid, size=200)["result"]["result"][::-1]
714
471
  msgs = [Message.model_validate(m) for m in dmsgs if m["msgType"] in (1, 2, 7, 8)]
@@ -742,7 +499,7 @@ class AgentClient(BaseAgentClient): # Bybit client
742
499
  # if round(cpc * new_premium / cpm, 2) == m
743
500
  # mad.premium = new_premium.to_eng_string()
744
501
 
745
- async def take_ad(self, req: TakeAdReq):
502
+ async def take_ad(self, req: TakeAdReq, bbot: XyncBot):
746
503
  if req.price and req.is_sell and req.cur_:
747
504
  ... # todo call the get_ad_details() only if lack of data
748
505
  # res = self.api.get_ad_details(itemId=req.ad_id)["result"]
@@ -771,29 +528,29 @@ class AgentClient(BaseAgentClient): # Bybit client
771
528
 
772
529
  bor = BaseOrderReq(
773
530
  ad_id=str(req.ad_id),
774
- fiat_amount=req.amount,
531
+ amount=req.amount,
775
532
  is_sell=req.is_sell,
776
533
  cur_exid=curex.exid,
777
534
  coin_exid=coinex.exid,
778
535
  coin_scale=coinex.scale,
779
536
  pmex_exid=pmexid,
780
537
  )
781
- resp: OrderResp = await self._order_request(bor)
538
+ resp: OrderResp = await self._order_request(bor, bbot)
782
539
  return resp
783
540
 
784
- async def watch_payeer(self, mcs: dict[int, "AgentClient"]):
541
+ async def watch_payeer(self, mcs: dict[int, "AgentClient"], bbot: XyncBot):
785
542
  await models.CoinEx.get(coin_id=1, ex=self.actor.ex).prefetch_related("coin")
786
543
  await models.CurEx.get(cur_id=1, ex=self.actor.ex).prefetch_related("cur")
787
544
  post_pmexs = set(await models.PmEx.filter(pm_id=366, ex=self.actor.ex).prefetch_related("pm"))
788
545
  i = 0
789
546
  while True:
790
547
  try:
791
- breq = GetAds(coin_id=1, cur_id=1, is_sell=False, limit=50)
548
+ breq = GetAdsReq(coin_id=1, cur_id=1, is_sell=False, limit=50)
792
549
  bs = await self.ex_client.ads(breq, post_pmexs=post_pmexs)
793
550
  bs = [b for b in bs if float(b.price) < 100 or int(b.userId) in mcs.keys()]
794
551
  if bs:
795
552
  ad: Ad = bs[0]
796
- await self.bbot.send(
553
+ await bbot.send(
797
554
  193017646,
798
555
  f"price: {ad.price}\nnick: {ad.nickName}\nprice: {ad.price}"
799
556
  f"\nqty: {ad.quantity} [{ad.minAmount}-{ad.maxAmount}]",
@@ -807,10 +564,10 @@ class AgentClient(BaseAgentClient): # Bybit client
807
564
  coin_id=1,
808
565
  cur_id=1,
809
566
  )
810
- ord_resp: OrderResp = await self.take_ad(req)
567
+ ord_resp: OrderResp = await self.take_ad(req, bbot)
811
568
  # order: OrderFull = OrderFull(**self.api.get_order_details(orderId=ord_resp.orderId)["result"])
812
569
  order: OrderFull = await self.get_order_info(ord_resp.orderId)
813
- odb = await self.create_order_db(order)
570
+ odb = await self.order_save(order)
814
571
  t = await models.Transfer(order=odb, amount=odb.amount, updated_at=now())
815
572
  await t.fetch_related("order__cred__pmcur__cur")
816
573
  # res = await self.pm_clients[366].send(t)
@@ -826,12 +583,12 @@ class AgentClient(BaseAgentClient): # Bybit client
826
583
 
827
584
  await sleep(5)
828
585
 
829
- sreq = GetAds(coin_id=1, cur_id=1, is_sell=True, limit=50, kwargs={"post_pmexs": post_pmexs})
586
+ sreq = GetAdsReq(coin_id=1, cur_id=1, is_sell=True, limit=50, kwargs={"post_pmexs": post_pmexs})
830
587
  ss = await self.ex_client.ads(sreq, post_pmexs=post_pmexs)
831
588
  ss = [s for s in ss if float(s.price) > 92 or int(s.userId) in mcs.keys()]
832
589
  if ss:
833
590
  ad: Ad = ss[0]
834
- await self.bbot.send(
591
+ await bbot.send(
835
592
  193017646,
836
593
  f"price: {ad.price}\nnick: {ad.nickName}\nprice: {ad.price}"
837
594
  f"\nqty: {ad.quantity} [{ad.minAmount}-{ad.maxAmount}]",
@@ -845,10 +602,10 @@ class AgentClient(BaseAgentClient): # Bybit client
845
602
  coin_id=1,
846
603
  cur_id=1,
847
604
  )
848
- ord_resp: OrderResp = await self.take_ad(req)
605
+ ord_resp: OrderResp = await self.take_ad(req, bbot)
849
606
  # order: OrderFull = OrderFull(**self.api.get_order_details(orderId=ord_resp.orderId)["result"])
850
607
  order: OrderFull = await self.get_order_info(ord_resp.orderId)
851
- odb = await self.create_order_db(order)
608
+ odb = await self.order_save(order)
852
609
  # t = await models.Transfer(order=odb, amount=odb.amount, updated_at=now())
853
610
  # await t.fetch_related("order__cred__pmcur__cur")
854
611
  # res = await self.pm_clients[366].check_in(t)
@@ -879,7 +636,7 @@ class AgentClient(BaseAgentClient): # Bybit client
879
636
  req = TakeAdReq(ad_id="1856989782009487360", amount=am, pm_id=366)
880
637
  ord_resp: OrderResp = await self.take_ad(req)
881
638
  order: OrderFull = await self.get_order_full(int(ord_resp.orderId))
882
- odb = await self.create_order_db(order)
639
+ odb = await self.order_save(order)
883
640
  t = await models.Transfer(order=odb, amount=odb.amount, updated_at=now())
884
641
  await t.fetch_related("order__cred__pmcur__cur")
885
642
  await self.pm_clients[366].send(t)
@@ -926,21 +683,31 @@ class AgentClient(BaseAgentClient): # Bybit client
926
683
 
927
684
  sub_msg = json.dumps({"op": "subscribe", "args": ["FIAT_OTC_TOPIC", "FIAT_OTC_ONLINE_TOPIC"]})
928
685
  await websocket.send(sub_msg)
929
- while resp := await websocket.recv():
930
- if data := json.loads(resp):
931
- logging.info(f" {now().strftime('%H:%M:%S')} upd: {data.get('topic')}:{data.get('type')}")
932
- await self.proc(data)
686
+ try:
687
+ while resp := await websocket.recv():
688
+ if data := json.loads(resp):
689
+ logging.info(f" {now().strftime('%H:%M:%S')} upd: {data.get('topic')}:{data.get('type')}")
690
+ await self.proc(data)
691
+ except ConnectionClosedError as e:
692
+ logging.warning(e)
693
+ await self._start_listen()
933
694
 
934
695
  async def proc(self, data: dict):
935
696
  match data.get("topic"):
936
697
  case "OTC_ORDER_STATUS":
937
698
  match data["type"]:
938
699
  case "STATUS_CHANGE":
939
- upd = StatusChange.model_validate(data["data"])
940
- order_db, order = await self.load_order(upd.id)
700
+ try:
701
+ upd = StatusChange.model_validate(data["data"])
702
+ except ValidationError as e:
703
+ logging.error(data["data"])
704
+ raise e
705
+ if not upd.status:
706
+ logging.warning(data["data"])
707
+ order_db, order = await self.load_order(upd.exid)
941
708
  match upd.status:
942
- case Status.ws_new:
943
- logging.info(f"Order {upd.id} CREATED at {upd.createDate}")
709
+ case OrderStatus.created:
710
+ logging.info(f"Order {upd.exid} CREATED at {upd.created_at}")
944
711
  # await self.got_new_order(order_db, order)
945
712
 
946
713
  # # сразу уменьшаем доступный остаток монеты/валюты
@@ -951,8 +718,8 @@ class AgentClient(BaseAgentClient): # Bybit client
951
718
  # return
952
719
  # await order_db.fetch_related("ad__pair_side__pair", "cred__pmcur__cur")
953
720
  # await self.send_payment(order_db)
954
- case Status.created:
955
- if upd.side == 0: # я продавец, ждем когда покупатель оплатит
721
+ # case OrderStatus.created:
722
+ if upd.ad__pair_side__is_sell == 0: # я продавец, ждем когда покупатель оплатит
956
723
  # check_payment() # again
957
724
  ...
958
725
  # if not (pmacdx := await self.get_pma_by_cdex(order)):
@@ -990,7 +757,7 @@ class AgentClient(BaseAgentClient): # Bybit client
990
757
  # for o in pos.get("items", [])
991
758
  # if (
992
759
  # o["amount"] == order.amount
993
- # and o["id"] != upd.id
760
+ # and o["id"] != upd.exid
994
761
  # and int(order.createDate) < int(o["createDate"]) + 15 * 60 * 1000
995
762
  # # get full_order from o, and cred or pm from full_order:
996
763
  # and self.api.get_order_details(orderId=o["id"])["result"][
@@ -1017,53 +784,54 @@ class AgentClient(BaseAgentClient): # Bybit client
1017
784
  # return
1018
785
  #
1019
786
  # # !!! ОТПРАВЛЯЕМ ДЕНЬГИ !!!
1020
- # self.api.release_assets(orderId=upd.id)
787
+ # self.api.release_assets(orderId=upd.exid)
1021
788
  # logging.info(
1022
789
  # f"Order {order.id} created, paid before #{tid}:{am} at {order.createDate}, and RELEASED at {now()}"
1023
790
  # )
1024
- elif upd.side == 1: # я покупатель - ждем мою оплату
791
+ elif upd.ad__pair_side__is_sell == 1: # я покупатель - ждем мою оплату
1025
792
  # pay()
1026
- logging.warning(f"Order {upd.id} CREATED2 at {now()}")
793
+ logging.warning(f"Order {upd.exid} CREATED2 at {now()}")
1027
794
 
1028
- case Status.paid:
795
+ case OrderStatus.paid:
1029
796
  if order_db.status == OrderStatus.paid:
1030
797
  return
1031
798
  await order_db.update_from_dict(
1032
799
  {
1033
800
  "status": OrderStatus.paid,
1034
- "payed_at": datetime.fromtimestamp(float(order.transferDate) / 1000),
801
+ "payed_at": order.payed_at,
1035
802
  }
1036
803
  ).save()
1037
- logging.info(f"Order {order.id} payed at {order_db.payed_at}")
804
+ logging.info(f"Order {order.exid} payed at {order_db.payed_at}")
1038
805
 
1039
- case Status.appealed_by_seller: # just any appealed
806
+ case OrderStatus.appealed_by_seller: # just any appealed
1040
807
  # todo: appealed by WHO? щас наугад стоит by_seller
1041
808
  await order_db.update_from_dict(
1042
809
  {
1043
810
  "status": OrderStatus.appealed_by_seller,
1044
- "appealed_at": datetime.fromtimestamp(float(order.updateDate) / 1000),
811
+ "appealed_at": order.appealed_at,
1045
812
  }
1046
813
  ).save()
1047
- logging.info(f"Order {order.id} appealed at {order_db.appealed_at}")
814
+ logging.info(f"Order {order.exid} appealed at {order_db.appealed_at}")
1048
815
 
1049
- case Status.canceled:
816
+ case OrderStatus.canceled:
1050
817
  await order_db.update_from_dict({"status": OrderStatus.canceled}).save()
1051
- logging.info(f"Order {order.id} canceled at {datetime.now()}")
818
+ logging.info(f"Order {order.exid} canceled at {datetime.now()}")
1052
819
  # await self.money_upd(order_db)
1053
820
 
1054
- case Status.completed:
821
+ case OrderStatus.completed:
1055
822
  await order_db.refresh_from_db()
1056
823
  if order_db.status != OrderStatus.completed:
1057
824
  await order_db.update_from_dict(
1058
825
  {
1059
826
  "status": OrderStatus.completed,
1060
- "confirmed_at": datetime.fromtimestamp(float(order.updateDate) / 1000),
827
+ "confirmed_at": order.confirmed_at,
1061
828
  }
1062
829
  ).save(update_fields=["status", "confirmed_at"])
1063
830
  # await self.money_upd(order_db)
1064
-
831
+ case OrderStatus.appeal_disputed:
832
+ logging.info(f"Order {order.exid} appeal_disputed at {datetime.now()}")
1065
833
  case _:
1066
- logging.warning(f"Order {order.id} UNKNOWN STATUS {datetime.now()}")
834
+ logging.warning(f"Order {order.exid} UNKNOWN STATUS {datetime.now()}")
1067
835
  case "COUNT_DOWN":
1068
836
  upd = CountDown.model_validate(data["data"])
1069
837
 
@@ -1080,7 +848,7 @@ class AgentClient(BaseAgentClient): # Bybit client
1080
848
  # msg, _ = await models.Msg.update_or_create(
1081
849
  # {
1082
850
  # "to_maker": upd.userId == self.actor.exid and im_taker,
1083
- # "sent_at": datetime.fromtimestamp(float(upd.createDate) / 1000),
851
+ # "sent_at": upd.createDate,
1084
852
  # },
1085
853
  # txt=upd.message,
1086
854
  # order=order_db,
@@ -1112,29 +880,19 @@ class AgentClient(BaseAgentClient): # Bybit client
1112
880
  # self.listen(data)
1113
881
  case "SELLER_CANCEL_CHANGE":
1114
882
  upd = SellerCancelChange.model_validate(data["data"])
883
+ order_db, order = await self.load_order(upd.id)
884
+ await order_db.cancel_request(self.agent.actor_id)
1115
885
  case None:
1116
886
  if not data.get("success"):
1117
- logging.error(data, "NOT SUCCESS!")
887
+ raise HTTPException(401 if data["ret_msg"] == "Request not authorized" else data)
1118
888
  else:
1119
889
  return # success login, subscribes, input
1120
890
  case _:
1121
891
  logging.warning(data, "UNKNOWN TOPIC")
1122
892
 
1123
- async def get_order_full(self, oid: int) -> OrderFull:
1124
- order = self.api.get_order_details(orderId=oid)
1125
- return OrderFull.model_validate(order["result"])
1126
-
1127
- async def load_order(self, oid: int) -> tuple[models.Order, OrderFull]:
1128
- if not self.orders.get(oid):
1129
- order = await self.get_order_full(oid)
1130
- if not (
1131
- order_db := await models.Order.get_or_none(exid=oid, ad__maker__ex=self.actor.ex).prefetch_related(
1132
- "ad__pair_side__pair", "cred__pmcur__cur"
1133
- )
1134
- ):
1135
- order_db = await self.create_order_db(order)
1136
- self.orders[oid] = order_db, order
1137
- return self.orders[oid]
893
+ async def _get_order_full(self, order_exid: int) -> OrderFull:
894
+ order_dict: dict = self.api.get_order_details(orderId=order_exid)["result"]
895
+ return OrderFull.model_validate(order_dict)
1138
896
 
1139
897
  async def money_upd(self, odb: models.Order):
1140
898
  # обновляем остаток монеты
@@ -1301,7 +1059,7 @@ async def main():
1301
1059
  cn = await init_db(TORM)
1302
1060
 
1303
1061
  agent = (
1304
- await models.Agent.filter(actor__ex_id=4, auth__isnull=False, status__gt=AgentStatus.off, id=5)
1062
+ await models.Agent.filter(actor__ex_id=4, auth__isnull=False, status__gt=AgentStatus.off, id=2)
1305
1063
  .prefetch_related(
1306
1064
  "actor__ex",
1307
1065
  "actor__person__user__gmail",
@@ -1311,16 +1069,14 @@ async def main():
1311
1069
  )
1312
1070
  .first()
1313
1071
  )
1314
- filebot = FileClient(NET_TOKEN)
1315
- # await filebot.start()
1316
1072
  # b.add_handler(MessageHandler(cond_start_handler, command("cond")))
1317
1073
  ex = await models.Ex.get(name="Bybit")
1318
- ecl: ExClient = ex.client(filebot)
1074
+ prx = PRX and "http://" + PRX
1075
+ ecl: ExClient = ex.client(proxy=prx)
1319
1076
  abot = XyncBot(PAY_TOKEN, cn)
1320
1077
  # pmas = await models.PmAgent.filter(active=True, user_id=1).prefetch_related("pm", "user__gmail")
1321
1078
  # pm_clients = {pma.pm_id: pma.client(abot) for pma in pmas}
1322
- prx = PRX and "http://" + PRX
1323
- cl: AgentClient = agent.client(ecl, filebot, abot, proxy=prx)
1079
+ cl: AgentClient = agent.client(ecl, proxy=prx)
1324
1080
 
1325
1081
  # req = TakeAdReq(ad_id=1955696985964089344, amount=504, pm_id=128)
1326
1082
  # await cl.take_ad(req)
@@ -1328,11 +1084,13 @@ async def main():
1328
1084
  # await cl.actual_cond()
1329
1085
  # cl.get_api_orders(), # 10, 1738357200000, 1742504399999
1330
1086
 
1087
+ # await cl.ex_client.set_coins()
1088
+ # await cl.ex_client.set_curs()
1331
1089
  # await cl.ex_client.set_pairs()
1332
1090
  # await cl.ex_client.set_pms()
1333
1091
 
1334
- await cl.set_creds()
1335
- await cl.export_my_ads()
1092
+ # await cl.load_creds()
1093
+ # await cl.load_my_ads()
1336
1094
 
1337
1095
  my_ad = await models.MyAd[5]
1338
1096
  await cl.ad_share(my_ad.id)
@@ -1346,11 +1104,11 @@ async def main():
1346
1104
  "actor__my_ads__pair_side__pair__cur",
1347
1105
  "actor__my_ads__pms",
1348
1106
  )
1349
- mcs = {m.actor.exid: m.client(ecl, filebot, abot) for m in ms}
1107
+ mcs = {m.actor.exid: m.client(ecl) for m in ms}
1350
1108
 
1351
1109
  await gather(
1352
1110
  # create_task(cl.start()),
1353
- create_task(cl.watch_payeer(mcs)),
1111
+ create_task(cl.watch_payeer(mcs, abot)),
1354
1112
  )
1355
1113
  # ensure_future(cl.start(True))
1356
1114
  # await cl.boost_acc()
@@ -1380,8 +1138,7 @@ async def main():
1380
1138
  # await cl.get_api_orders() # 43, 1741294800000, 1749157199999)
1381
1139
 
1382
1140
  # await cl.cancel_order(res.orderId)
1383
- await filebot.stop()
1384
- await cl.close()
1141
+ await cl.stop()
1385
1142
 
1386
1143
 
1387
1144
  if __name__ == "__main__":