xync-client 0.0.25.dev19__tar.gz → 0.0.25.dev20__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 (75) hide show
  1. {xync_client-0.0.25.dev19/xync_client.egg-info → xync_client-0.0.25.dev20}/PKG-INFO +1 -1
  2. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/tests/TestEx.py +1 -1
  3. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Abc/Agent.py +3 -3
  4. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/TgWallet/agent.py +34 -19
  5. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/TgWallet/auth.py +3 -5
  6. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/TgWallet/ex.py +2 -2
  7. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/TgWallet/pyro.py +0 -1
  8. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20/xync_client.egg-info}/PKG-INFO +1 -1
  9. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/.env.sample +0 -0
  10. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/.gitignore +0 -0
  11. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/.pre-commit-config.yaml +0 -0
  12. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/README.md +0 -0
  13. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/makefile +0 -0
  14. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/pyproject.toml +0 -0
  15. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/setup.cfg +0 -0
  16. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/tests/TestAgent.py +0 -0
  17. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/tests/TestAsset.py +0 -0
  18. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/tests/TestOrder.py +0 -0
  19. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/tests/_todo_refact/Binance/test_binance.py +0 -0
  20. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/tests/_todo_refact/Bybit/test_bybit.py +0 -0
  21. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/tests/_todo_refact/Bybit/test_bybit_p2p.py +0 -0
  22. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/tests/_todo_refact/Gate/test_gate.py +0 -0
  23. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/tests/_todo_refact/Htx/test_htx_p2p.py +0 -0
  24. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/tests/_todo_refact/Wallet/test_agent.py +0 -0
  25. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/tests/_todo_refact/Wallet/test_ex.py +0 -0
  26. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/tests/_todo_refact/__init__.py +0 -0
  27. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/tests/_todo_refact/_test_ex.py +0 -0
  28. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Abc/Asset.py +0 -0
  29. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Abc/AuthTrait.py +0 -0
  30. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Abc/Base.py +0 -0
  31. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Abc/BaseTest.py +0 -0
  32. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Abc/Ex.py +0 -0
  33. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Abc/InAgent.py +0 -0
  34. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Abc/Order.py +0 -0
  35. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Binance/__init__.py +0 -0
  36. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Binance/binance_async.py +0 -0
  37. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Binance/earn_api.py +0 -0
  38. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Binance/ex.py +0 -0
  39. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Binance/exceptions.py +0 -0
  40. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Binance/sapi.py +0 -0
  41. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Binance/web_c2c.py +0 -0
  42. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/BingX/__init__.py +0 -0
  43. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/BingX/agent.py +0 -0
  44. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/BingX/base.py +0 -0
  45. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/BingX/ex.py +0 -0
  46. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/BingX/req.mjs +0 -0
  47. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/BingX/sign.js +0 -0
  48. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/BingX/test/main.py +0 -0
  49. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/BitGet/__init__.py +0 -0
  50. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/BitGet/agent.py +0 -0
  51. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/BitGet/ex.py +0 -0
  52. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/BitGet/req.mjs +0 -0
  53. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Bybit/agent.py +0 -0
  54. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Bybit/ex.py +0 -0
  55. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Bybit/web_earn.py +0 -0
  56. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Bybit/web_p2p.py +0 -0
  57. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Gate/ex.py +0 -0
  58. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Gate/premarket.py +0 -0
  59. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Htx/agent.py +0 -0
  60. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Htx/earn.py +0 -0
  61. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Htx/ex.py +0 -0
  62. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/KuCoin/pub.py +0 -0
  63. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/KuCoin/web.py +0 -0
  64. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/Okx/ex.py +0 -0
  65. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/TgWallet/asset.py +0 -0
  66. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/TgWallet/inAgent.py +0 -0
  67. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/TgWallet/order.py +0 -0
  68. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/TgWallet/pyd.py +0 -0
  69. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/TgWallet/web.py +0 -0
  70. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/__init__.py +0 -0
  71. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client/loader.py +0 -0
  72. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client.egg-info/SOURCES.txt +0 -0
  73. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client.egg-info/dependency_links.txt +0 -0
  74. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client.egg-info/requires.txt +0 -0
  75. {xync_client-0.0.25.dev19 → xync_client-0.0.25.dev20}/xync_client.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: xync-client
3
- Version: 0.0.25.dev19
3
+ Version: 0.0.25.dev20
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
@@ -18,7 +18,7 @@ class TestEx(BaseTest):
18
18
  @pytest.fixture
19
19
  async def clients(self) -> list[BaseClient]:
20
20
  exs = await Ex.filter(status__gt=ExStatus.plan)
21
- [await ex.fetch_related("contragents__agent") for ex in exs if ex.type_ == ExType.tg]
21
+ [await ex.fetch_related("actors__agent") for ex in exs if ex.type_ == ExType.tg]
22
22
  clients: list[BaseExClient] = [ex.client() for ex in exs]
23
23
  yield clients
24
24
  [await cl.close() for cl in clients]
@@ -13,7 +13,7 @@ from xync_client.Abc.Base import BaseClient
13
13
  class BaseAgentClient(BaseClient):
14
14
  def __init__(self, agent: Agent):
15
15
  self.agent: Agent = agent
16
- super().__init__(self.agent.contragent.ex) # , "host_p2p"
16
+ super().__init__(self.agent.actor.ex) # , "host_p2p"
17
17
  self.ex_client: BaseExClient = self.ex.client()
18
18
 
19
19
  @abstractmethod
@@ -97,12 +97,12 @@ class BaseAgentClient(BaseClient):
97
97
  async def fiat_f2in(self, fiat_new: FiatNew) -> FiatPydIn:
98
98
  if not (_pmcur := await Pmcur.get_or_none(cur_id=fiat_new.cur_id, pm_id=fiat_new.pm_id)):
99
99
  raise HTTPException(FailReason.body, f"No Pmcur with cur#{fiat_new.cur_id} and pm#{fiat_new.pm_id}", 404)
100
- # cred = await Cred.create({"exid": }, pmcur=pmcur, contragent=self.agent.contragent)
100
+ # cred = await Cred.create({"exid": }, pmcur=pmcur, actor=self.agent.actor)
101
101
  # df = {"detail": fiat_pyd.detail, "name": fiat_pyd.name, "amount": fiat_pyd.amount, "target": fiat_pyd.target}
102
102
  # unq = {"pmcur": pmcur, "user_id": uid}
103
103
 
104
104
  # async def fiat_new(self, fiat: FiatNew) -> Fiat:
105
- # contragent = await Contragent.get_or_create({"name": }, ex=self.ex_client.ex, exid=self.agent.contragent.exid)
105
+ # actor = await Actor.get_or_create({"name": }, ex=self.ex_client.ex, exid=self.agent.actor.exid)
106
106
  # FiatPydIn()
107
107
  # fiat_db: Fiat = (await self.fiat_pyd2db(fiat, self.agent.user_id))[0]
108
108
  # if not (fiatex := Fiatex.get_or_none(fiat=fiat_db, ex=self.agent.ex)):
@@ -43,7 +43,7 @@ from xync_schema.models import (
43
43
  Coinex,
44
44
  Pm,
45
45
  Order,
46
- Contragent,
46
+ Actor,
47
47
  )
48
48
  from xync_schema.pydantic import FiatNew, BaseAdPydIn, AdBuyPydIn, AdSalePydIn, CredPydIn, OrderPydIn
49
49
 
@@ -81,8 +81,22 @@ class AgentClient(BaseAgentClient, AuthClient):
81
81
  orders = await self._post("/p2p/public-api/v2/offer/order/get", {"orderId": oid})
82
82
  return orders["data"]
83
83
 
84
- @staticmethod
85
- async def order_ad2epydin(ad: Ad, amount: float, cred_id: int) -> OrderEpydIn:
84
+ async def order_ad2epydin(self, ad: Ad, amount: float, cred_id: int = None) -> OrderEpydIn:
85
+ if not cred_id: # i am taker
86
+ iam_maker = self.agent.actor_id == ad.maker_id
87
+ iam_seller = ad.direction.sell == iam_maker
88
+ cred_filter = (
89
+ {"actor__agent__user_id": self.agent.user_id}
90
+ if iam_seller
91
+ else { # its a buy ad, i am taker
92
+ "actor": ad.maker
93
+ }
94
+ )
95
+ await Cred.filter(
96
+ **cred_filter,
97
+ pmcur__pms__in=ad.pms,
98
+ # todo: ordering and filtering by fiat.amount-target
99
+ ).first() if iam_seller else 0
86
100
  await ad.fetch_related("direction__pairex__pair__cur")
87
101
  return OrderEpydIn(
88
102
  offerId=ad.exid,
@@ -103,16 +117,12 @@ class AgentClient(BaseAgentClient, AuthClient):
103
117
 
104
118
  async def order_epyd2pydin(self, order: OrderEpyd) -> OrderPydIn:
105
119
  ad = await Ad.get(exid=order.offerId, direction__pairex__ex=self.ex)
106
- cred = await Cred.get(exid=order.paymentDetails.id, contragent__ex=self.ex)
107
- iam_maker = self.agent.contragent == ad.maker
120
+ cred = await Cred.get(exid=order.paymentDetails.id, actor__ex=self.ex)
121
+ iam_maker = self.agent.actor == ad.maker
108
122
  taker = (
109
- (
110
- await Contragent.get(
111
- exid=(order.seller if order.is_sell == iam_maker else order.buyer).userId, ex=self.ex
112
- )
113
- )
123
+ (await Actor.get(exid=(order.seller if order.is_sell == iam_maker else order.buyer).userId, ex=self.ex))
114
124
  if iam_maker
115
- else self.agent.contragent
125
+ else self.agent.actor
116
126
  )
117
127
  return OrderPydIn(
118
128
  exid=order.id,
@@ -185,7 +195,7 @@ class AgentClient(BaseAgentClient, AuthClient):
185
195
  cred_pin = CredPydIn(
186
196
  exid=fiat.id,
187
197
  pmcur=pmcur,
188
- contragent=self.agent.contragent,
198
+ actor=self.agent.actor,
189
199
  name=fiat.name,
190
200
  )
191
201
  for val in fiat.attributes.values:
@@ -266,7 +276,7 @@ class AgentClient(BaseAgentClient, AuthClient):
266
276
 
267
277
  async def ad_epyd2pydin(self, ad_: OneAdTakerMakerSale | OneAdMakerBuy | OneAdTakerBuy) -> AdBuyPydIn | AdSalePydIn:
268
278
  ad_in: BaseAdPydIn = await self.ex_client.ad_common_epyd2pydin(ad_)
269
- ad_in.maker = self.agent.contragent
279
+ ad_in.maker = self.agent.actor
270
280
  if isinstance(ad_, _PmsTrait):
271
281
  return AdBuyPydIn(
272
282
  **ad_in.model_dump(),
@@ -292,7 +302,7 @@ class AgentClient(BaseAgentClient, AuthClient):
292
302
  async def my_ad(self, ad_id: int) -> OneAdMakerBuy | OneAdTakerMakerSale:
293
303
  ad = await self._post("/p2p/public-api/v2/offer/get-user-own", {"offerId": ad_id})
294
304
  ad: dict = ad["data"]
295
- assert ad["user"]["userId"] == self.agent.contragent.exid, "Not your ad"
305
+ assert ad["user"]["userId"] == self.agent.actor.exid, "Not your ad"
296
306
  model = OneAdTakerMakerSale if ad["type"] == "SALE" else OneAdMakerBuy
297
307
  return model(**ad)
298
308
 
@@ -301,7 +311,7 @@ class AgentClient(BaseAgentClient, AuthClient):
301
311
  ) -> AdMakerNewSale | AdMakerNewBuy:
302
312
  coinex = await Coinex.get(coin=coin, ex=self.ex)
303
313
  curex = await Curex.get(ex=self.ex, cur=cur)
304
- creds = await Cred.filter(contragent__agent__user_id=self.agent.user_id, pmcur__cur=cur).limit(5)
314
+ creds = await Cred.filter(actor__agent__user_id=self.agent.user_id, pmcur__cur=cur).limit(5)
305
315
  # todo: ordering and filtering by fiat.amount-target
306
316
  ad_ein = _AdNew(
307
317
  type="SALE" if is_sell else "PURCHASE",
@@ -320,7 +330,7 @@ class AgentClient(BaseAgentClient, AuthClient):
320
330
  if ad_ein.type == "SALE":
321
331
  ad_ein = AdMakerNewSale(**ad_ein.model_dump(exclude_none=True), paymentDetailsIds=[c.exid for c in creds])
322
332
  else:
323
- pmexs = await Pmex.filter(ex=self.agent.contragent.ex, pm__pmcurs__id__in=[c.pmcur_id for c in creds])
333
+ pmexs = await Pmex.filter(ex=self.agent.actor.ex, pm__pmcurs__id__in=[c.pmcur_id for c in creds])
324
334
  ad_ein = AdMakerNewBuy(**ad_ein.model_dump(exclude_none=True), paymentMethodCodes=[p.exid for p in pmexs])
325
335
  return ad_ein
326
336
 
@@ -414,10 +424,10 @@ async def main():
414
424
  maker: Agent
415
425
  taker: Agent
416
426
  maker, taker = (
417
- await Agent.filter(contragent__ex_id=34, auth__isnull=False, user__status__gte=UserStatus.MEMBER)
427
+ await Agent.filter(actor__ex_id=34, auth__isnull=False, user__status__gte=UserStatus.MEMBER)
418
428
  .order_by("user_id")
419
429
  .limit(2)
420
- .prefetch_related("contragent__ex")
430
+ .prefetch_related("actor__ex")
421
431
  )
422
432
  mcl: AgentClient = maker.client()
423
433
  tcl: AgentClient = taker.client()
@@ -436,10 +446,15 @@ async def main():
436
446
  await tcl.ad_switch(sad.id, True)
437
447
  await mcl.ad_switch(bad.id, True)
438
448
  sad_in = await tcl.ad_epyd2pydin(sad)
439
- await Ad.create(**sad_in.model_dump(exclude_none=True))
449
+ sad_db = await Ad.create(**sad_in.model_dump(exclude_none=True))
440
450
  bad_in = await mcl.ad_epyd2pydin(bad)
441
451
  await Ad.create(**bad_in.model_dump(exclude_none=True))
442
452
 
453
+ order_epin: OrderEpydIn = await tcl.order_ad2epydin(sad_db, float(sad.orderAmountLimits.min))
454
+ new_order: OrderEpyd = await tcl.order_request(order_epin)
455
+ order_pin: OrderPydIn = await tcl.order_epyd2pydin(new_order)
456
+ _order_db = await tcl.order_pydin2db(order_pin)
457
+
443
458
  # order_epin: OrderEpydIn = await tcl.order_ad2epydin(ad_db, float(mad.orderAmountLimits.min), cred_ids[0])
444
459
  # new_order: OrderEpyd = await tcl.order_request(order_epin)
445
460
  # order_pin: OrderPydIn = await tcl.order_epyd2pydin(new_order)
@@ -9,13 +9,11 @@ from xync_client.TgWallet.pyro import PyroClient
9
9
  class AuthClient(BaseAuthTrait, BaseClient):
10
10
  async def _get_auth_hdrs(self) -> dict[str, str]:
11
11
  if not self.agent:
12
- self.agent = (
13
- await Agent.filter(contragent__ex=self.ex, auth__isnull=False).prefetch_related("contragent").first()
14
- )
12
+ self.agent = await Agent.filter(actor__ex=self.ex, auth__isnull=False).prefetch_related("actor").first()
15
13
  pyro = PyroClient(self.agent)
16
14
  init_data = await pyro.get_init_data()
17
15
  tokens = HttpClient("walletbot.me")._post("/api/v1/users/auth/", init_data)
18
- self.agent.contragent.exid = tokens["user_id"]
19
- await self.agent.contragent.save()
16
+ self.agent.actor.exid = tokens["user_id"]
17
+ await self.agent.actor.save()
20
18
  pref = "" if self.__class__.__name__ == "AssetClient" else "Bearer "
21
19
  return {"Wallet-Authorization": tokens["jwt"], "Authorization": pref + tokens["value"]}
@@ -4,7 +4,7 @@ from x_model import init_db
4
4
  from xync_schema.pydantic import PmPyd, PmexBankPyd, CurEpyd, CoinEpyd, BaseAdPydIn, AdBuyPydIn
5
5
 
6
6
  from xync_schema import models
7
- from xync_schema.models import Ex, Direction, Pair, Coin, Cur, Pm, Contragent, PairEx
7
+ from xync_schema.models import Ex, Direction, Pair, Coin, Cur, Pm, Actor, PairEx
8
8
 
9
9
  from xync_client.TgWallet.pyd import (
10
10
  PmEpydRoot,
@@ -123,7 +123,7 @@ class ExClient(BaseExClient, AuthClient):
123
123
 
124
124
  async def ad_taker_epyd2pydin(self, ad: _TakerOne) -> AdBuyPydIn:
125
125
  adx: BaseAdPydIn = await self.ad_common_epyd2pydin(ad)
126
- adx.maker = (await Contragent.update_or_create({"name": ad.user.nickname}, ex=self.ex, exid=ad.user.userId))[0]
126
+ adx.maker = (await Actor.update_or_create({"name": ad.user.nickname}, ex=self.ex, exid=ad.user.userId))[0]
127
127
  pms = ad.paymentMethods if isinstance(ad, _PmsTrait) else [pd.paymentMethod for pd in ad.paymentDetails]
128
128
  return AdBuyPydIn(
129
129
  **adx.model_dump(), pms_=await Pm.filter(pmexs__ex=self.ex, pmexs__exid__in=[p.code for p in pms])
@@ -11,7 +11,6 @@ from xync_schema.models import Agent
11
11
 
12
12
  class PyroClient:
13
13
  def __init__(self, agent: Agent):
14
- self.agent = agent
15
14
  self.app: Client = Client(str(agent.user_id), TG_API_ID, TG_API_HASH, session_string=agent.auth["sess"])
16
15
 
17
16
  async def get_init_data(self) -> dict:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: xync-client
3
- Version: 0.0.25.dev19
3
+ Version: 0.0.25.dev20
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