xync-client 0.0.57.dev9__tar.gz → 0.0.57.dev10__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 (112) hide show
  1. {xync_client-0.0.57.dev9/xync_client.egg-info → xync_client-0.0.57.dev10}/PKG-INFO +1 -1
  2. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Bybit/agent.py +52 -33
  3. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10/xync_client.egg-info}/PKG-INFO +1 -1
  4. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/.env.sample +0 -0
  5. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/.gitignore +0 -0
  6. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/.pre-commit-config.yaml +0 -0
  7. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/README.md +0 -0
  8. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/makefile +0 -0
  9. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/pyproject.toml +0 -0
  10. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/setup.cfg +0 -0
  11. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/tests/TestAgent.py +0 -0
  12. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/tests/TestAsset.py +0 -0
  13. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/tests/TestEx.py +0 -0
  14. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/tests/TestOrder.py +0 -0
  15. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/tests/_todo_refact/Binance/test_binance.py +0 -0
  16. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/tests/_todo_refact/Bybit/test_bybit.py +0 -0
  17. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/tests/_todo_refact/Bybit/test_bybit_p2p.py +0 -0
  18. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/tests/_todo_refact/Gate/test_gate.py +0 -0
  19. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/tests/_todo_refact/Htx/test_htx_p2p.py +0 -0
  20. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/tests/_todo_refact/Wallet/test_agent.py +0 -0
  21. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/tests/_todo_refact/Wallet/test_ex.py +0 -0
  22. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/tests/_todo_refact/__init__.py +0 -0
  23. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/tests/_todo_refact/_test_ex.py +0 -0
  24. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Abc/Agent.py +0 -0
  25. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Abc/Asset.py +0 -0
  26. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Abc/Auth.py +0 -0
  27. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Abc/BaseTest.py +0 -0
  28. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Abc/Ex.py +0 -0
  29. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Abc/InAgent.py +0 -0
  30. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Abc/Order.py +0 -0
  31. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Abc/xtype.py +0 -0
  32. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Binance/__init__.py +0 -0
  33. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Binance/binance_async.py +0 -0
  34. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Binance/earn_api.py +0 -0
  35. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Binance/etype/ad.py +0 -0
  36. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Binance/etype/pm.py +0 -0
  37. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Binance/ex.py +0 -0
  38. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Binance/exceptions.py +0 -0
  39. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Binance/sapi.py +0 -0
  40. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Binance/web_c2c.py +0 -0
  41. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/BingX/__init__.py +0 -0
  42. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/BingX/agent.py +0 -0
  43. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/BingX/base.py +0 -0
  44. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/BingX/etype/ad.py +0 -0
  45. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/BingX/etype/pm.py +0 -0
  46. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/BingX/ex.py +0 -0
  47. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/BingX/req.mjs +0 -0
  48. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/BingX/sign.js +0 -0
  49. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/BitGet/__init__.py +0 -0
  50. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/BitGet/agent.py +0 -0
  51. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/BitGet/etype/ad.py +0 -0
  52. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/BitGet/ex.py +0 -0
  53. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/BitPapa/ex.py +0 -0
  54. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Bybit/InAgent.py +0 -0
  55. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Bybit/etype/ad.py +0 -0
  56. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Bybit/etype/cred.py +0 -0
  57. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Bybit/etype/order.py +0 -0
  58. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Bybit/ex.py +0 -0
  59. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Bybit/order.py +0 -0
  60. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Bybit/web_earn.py +0 -0
  61. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Bybit/web_p2p.py +0 -0
  62. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Bybit/ws.py +0 -0
  63. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Gate/etype/ad.py +0 -0
  64. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Gate/ex.py +0 -0
  65. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Gate/premarket.py +0 -0
  66. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Gmail/__init__.py +0 -0
  67. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Htx/agent.py +0 -0
  68. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Htx/earn.py +0 -0
  69. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Htx/etype/__init__.py +0 -0
  70. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Htx/etype/ad.py +0 -0
  71. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Htx/etype/cred.py +0 -0
  72. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Htx/etype/pm.py +0 -0
  73. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Htx/etype/test.py +0 -0
  74. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Htx/ex.py +0 -0
  75. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/KuCoin/etype/ad.py +0 -0
  76. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/KuCoin/etype/pm.py +0 -0
  77. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/KuCoin/ex.py +0 -0
  78. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/KuCoin/web.py +0 -0
  79. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Mexc/etype/ad.py +0 -0
  80. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Mexc/etype/pm.py +0 -0
  81. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Mexc/ex.py +0 -0
  82. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Okx/etype/ad.py +0 -0
  83. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Okx/etype/pm.py +0 -0
  84. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Okx/ex.py +0 -0
  85. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Pms/.gitignore +0 -0
  86. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Pms/Alfa/__init__.py +0 -0
  87. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Pms/Alfa/state.json +0 -0
  88. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Pms/Ozon/__init__.py +0 -0
  89. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Pms/Sber/__init__.py +0 -0
  90. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Pms/Tinkoff/__init__.py +0 -0
  91. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Pms/Tinkoff/state.json +0 -0
  92. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Pms/Volet/__init__.py +0 -0
  93. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Pms/Volet/_todo_req/req.mjs +0 -0
  94. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Pms/Volet/_todo_req/req.py +0 -0
  95. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Pms/Volet/api.py +0 -0
  96. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/Pms/Volet/pl.py +0 -0
  97. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/TgWallet/agent.py +0 -0
  98. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/TgWallet/asset.py +0 -0
  99. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/TgWallet/auth.py +0 -0
  100. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/TgWallet/ex.py +0 -0
  101. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/TgWallet/inAgent.py +0 -0
  102. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/TgWallet/order.py +0 -0
  103. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/TgWallet/pyd.py +0 -0
  104. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/TgWallet/pyro.py +0 -0
  105. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/TgWallet/web.py +0 -0
  106. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/__init__.py +0 -0
  107. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/loader.py +0 -0
  108. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client/pm_unifier.py +0 -0
  109. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client.egg-info/SOURCES.txt +0 -0
  110. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client.egg-info/dependency_links.txt +0 -0
  111. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client.egg-info/requires.txt +0 -0
  112. {xync_client-0.0.57.dev9 → xync_client-0.0.57.dev10}/xync_client.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xync-client
3
- Version: 0.0.57.dev9
3
+ Version: 0.0.57.dev10
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
@@ -11,7 +11,7 @@ import pyotp
11
11
  from asyncpg import ConnectionDoesNotExistError
12
12
  from bybit_p2p import P2P
13
13
  from bybit_p2p._exceptions import FailedRequestError
14
- from tortoise.expressions import F
14
+ from tortoise.expressions import F, Q
15
15
  from urllib3.exceptions import ReadTimeoutError
16
16
  from x_model import init_db
17
17
  from xync_schema import models
@@ -634,43 +634,46 @@ class AgentClient(BaseAgentClient): # Bybit client
634
634
 
635
635
  async def cond_upsert(self, ad: Ad, rname: str = None, dr: Direction = None) -> tuple[models.Ad, bool]:
636
636
  sim = None
637
- # если точно такого условия еще нет в бд
637
+ # если точно такое условие уже есть в бд, ниче делать не надо
638
638
  if not (cleaned := clean(ad.remark)) or cleaned in {oc[0] for oc in self.all_conds.values()}:
639
639
  return None, False
640
- # если такая объява уже есть, просто заменяем текст ее условия
641
- if ad_db := await models.Ad.get_or_none(exid=ad.id).prefetch_related("cond__ads__maker"):
640
+ # если эта объява уже есть в бд
641
+ if ad_db := await models.Ad.get_or_none(exid=ad.id).prefetch_related("cond__ads__maker", "maker"):
642
642
  # у измененного условия этой объявы есть другие объявы?
643
643
  if rest_ads := set(ad_db.cond.ads) - {ad_db}:
644
+ # другие объявы этого условия принадлежат другим юзерам
644
645
  if rest_uids := {ra.maker_id for ra in rest_ads} - {ad_db.maker_id}:
645
- # todo: дописать проверку на измененность этого условия в других ads
646
- logging.exception("у измененного cond этой ad есть другие ads где оно не изменилось", rest_uids)
647
- if cond := await Cond.get_or_none(raw_txt=cleaned):
648
- if not rest_ads:
649
- self.all_conds.pop(ad_db.cond_id)
650
- await ad_db.cond.delete()
651
- ad_db.cond_id = cond.id
652
- await ad_db.save()
653
- else:
654
- if rest_ads and rest_uids:
655
- logging.error(rest_uids)
656
- # щас переписывается условие во всех объявах даже если они разных юзеров
657
- ad_db.cond.last_ver = ad_db.cond.raw_txt
658
- ad_db.cond.raw_txt = cleaned
659
- uids = {ra.maker.exid for ra in ad_db.cond.ads}
660
- self.all_conds[ad_db.cond_id] = cleaned, uids
661
- await ad_db.cond.save()
646
+ # создадим новое условие и присвоим его только текущей объяве
647
+ new_cond = await Cond.create(raw_txt=cleaned)
648
+ await self.sim_new(new_cond.id, get_sim(cleaned, ad_db.cond.raw_txt), ad_db.cond_id)
649
+ ad_db.cond_id = new_cond.id
650
+ self.all_conds[ad_db.cond_id] = cleaned, {ad_db.maker.exid}
651
+ await ad_db.save()
652
+ return ad_db, True
653
+ # проверка на всякий что точно нет такого условия
654
+ if new_cond := await Cond.get_or_none(raw_txt=cleaned):
655
+ logging.exception("!!!!!!!!!", rest_uids)
656
+ # если других объяв со старым условием этой обявы нет, либо они все этого же юзера
657
+ # обновляем условие (в тч во всех ЕГО объявах)
658
+ ad_db.cond.last_ver = ad_db.cond.raw_txt
659
+ ad_db.cond.raw_txt = cleaned
660
+ if sim_db := await CondSim.get_or_none(Q(join_type="OR", cond=ad_db.cond, cond_rel=ad_db.cond)):
661
+ sim_db.similarity = get_sim(cleaned, ad_db.cond.last_ver)
662
+ await sim_db.save()
663
+ self.all_conds[ad_db.cond_id] = cleaned, {ad_db.maker.exid}
664
+ await ad_db.cond.save()
665
+
666
+ await self.sim_upd(ad_db.cond_id, cleaned)
662
667
  return ad_db, False
663
668
 
664
669
  # находим все старые тексты похожие на 90% и более
665
- if sim_connds := {
670
+ if _sims := {
666
671
  old_cid: (txt, sim)
667
672
  for old_cid, (txt, uids) in self.all_conds.items()
668
- if len(cleaned) > 15
669
- and ad.userId not in uids
670
- and (sim := int((SequenceMatcher(None, cleaned, txt).ratio() - 0.9) * 10_000)) > 0
673
+ if len(cleaned) > 15 and ad.userId not in uids and (sim := get_sim(cleaned, txt))
671
674
  }:
672
675
  # если есть, берем самый похожий из них
673
- old_cid, (txt, sim) = max(sim_connds.items(), key=lambda x: x[1])
676
+ old_cid, (txt, sim) = max(_sims.items(), key=lambda x: x[1][1])
674
677
  old_ads = await models.Ad.filter(cond_id=old_cid, maker__exid=int(ad.userId)).prefetch_related("cond")
675
678
  for old_ad in old_ads:
676
679
  # и у этого чела есть объява с почти таким же текстом
@@ -682,8 +685,8 @@ class AgentClient(BaseAgentClient): # Bybit client
682
685
  # но это не она, значит у него есть другая объява с похожим, но чуть отличающимся текстом
683
686
  logging.warning(f"ad#{ad.id}-cond#{old_cid} txt updated:\n{txt}\n|\n|\nV\n{cleaned}")
684
687
 
685
- cond = await Cond.create(raw_txt=cleaned)
686
- self.all_conds[cond.id] = cond.raw_txt, {ad.userId}
688
+ new_cond = await Cond.create(raw_txt=cleaned)
689
+ self.all_conds[new_cond.id] = new_cond.raw_txt, {ad.userId}
687
690
  act_df = {"name": ad.nickName}
688
691
  if rname:
689
692
  act_df |= {"person": await Person.get_or_create(name=rname)}
@@ -693,7 +696,7 @@ class AgentClient(BaseAgentClient): # Bybit client
693
696
  amount=float(ad.quantity) * float(ad.price),
694
697
  min_fiat=ad.minAmount,
695
698
  max_fiat=ad.maxAmount,
696
- cond=cond,
699
+ cond=new_cond,
697
700
  exid=int(ad.id),
698
701
  direction=dr
699
702
  or await Direction.get(
@@ -705,14 +708,25 @@ class AgentClient(BaseAgentClient): # Bybit client
705
708
  maker=actor,
706
709
  )
707
710
 
708
- if sim and sim_connds: # если нашелся похожий текст у другого юзера, добавим связь с % похожести
709
- await CondSim.update_or_create({"similarity": sim, "cond_rel_id": old_cid}, cond_id=cond.id)
710
- self.cond_sims[cond.id] = old_cid, sim
711
- self.sim_conds[old_cid].add(cond.id)
711
+ # если нашелся похожий текст у другого юзера, добавим связь с % похожести
712
+ if sim:
713
+ await self.sim_new(new_cond.id, sim, old_cid)
712
714
 
713
715
  await ad_db.fetch_related("cond")
714
716
  return ad_db, True
715
717
 
718
+ async def sim_new(self, new_cid: int, sim: int, old_cid: int):
719
+ if not sim:
720
+ return None
721
+ return await CondSim.create(cond_id=new_cid, similarity=sim, cond_rel_id=old_cid)
722
+
723
+ async def sim_upd(self, cid: int, new_txt: int):
724
+ for sim_db in (_sims := await CondSim.filter(Q(join_type="OR", cond_id=cid, cond_rel_id=cid))):
725
+ (op,) = {sim_db.cond_id, sim_db.cond_rel_id} - {cid}
726
+ op_cond = await Cond[op]
727
+ sim_db.similarity = get_sim(new_txt, op_cond.raw_txt)
728
+ await sim_db.save()
729
+
716
730
  #
717
731
  # async def cond_upsert(
718
732
  # self, ad: Ad, rname: str = None, dr: Direction = None, cid: int = 0
@@ -806,6 +820,11 @@ class AgentClient(BaseAgentClient): # Bybit client
806
820
  await self.cond_upsert(ad, dr=dr, cid=ad_db.cond_id)
807
821
 
808
822
 
823
+ def get_sim(s1, s2) -> int:
824
+ sim = int((SequenceMatcher(None, s1, s2).ratio() - 0.9) * 10_000)
825
+ return sim if sim > 0 else 0
826
+
827
+
809
828
  def detailed_diff(str1, str2):
810
829
  matcher = SequenceMatcher(None, str1, str2)
811
830
  result = []
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xync-client
3
- Version: 0.0.57.dev9
3
+ Version: 0.0.57.dev10
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