GNServer 0.0.0.0.29__py3-none-any.whl → 0.0.0.0.31__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.
GNServer/_app.py CHANGED
@@ -2,32 +2,36 @@
2
2
 
3
3
 
4
4
  import re
5
+ import os
5
6
  import sys
6
7
  import uuid
7
- import anyio
8
8
  import decimal
9
9
  import asyncio
10
10
  import inspect
11
11
  import traceback
12
12
  import datetime
13
- import KeyisBClient
14
- from typing import Any, Awaitable, Callable, Dict, List, Optional, Pattern, Tuple, Union, AsyncGenerator
13
+ from typing import Any, Callable, Dict, List, Optional, Pattern, Tuple, Union, AsyncGenerator
15
14
  from dataclasses import dataclass
16
15
  from aioquic.asyncio.server import serve
17
16
  from aioquic.asyncio.protocol import QuicConnectionProtocol
18
17
  from aioquic.quic.configuration import QuicConfiguration
19
18
  from aioquic.quic.events import QuicEvent, StreamDataReceived
20
19
  from typing import Any, AsyncGenerator, Union, get_origin, get_args
21
- from urllib.parse import parse_qs
22
20
 
23
- from KeyisBClient import gn
24
- import aiofiles
25
- import sys
26
- import os
21
+
22
+ from gnobjects.net.objects import GNRequest, GNResponse, FileObject, CORSObject, TemplateObject
23
+ from gnobjects.net.fastcommands import AllGNFastCommands, GNFastCommand
24
+
25
+
26
+
27
+
28
+
29
+
30
+
27
31
 
28
32
  try:
29
33
  if not sys.platform.startswith("win"):
30
- import uvloop
34
+ import uvloop # type: ignore
31
35
  asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
32
36
  except ImportError:
33
37
  print("uvloop не установлен")
@@ -45,115 +49,7 @@ console = logging.StreamHandler()
45
49
  console.setLevel(logging.INFO)
46
50
  console.setFormatter(logging.Formatter("[GNServer] %(name)s: %(levelname)s: %(message)s"))
47
51
 
48
- PayloadType = Optional[Union[int, str, list, tuple, dict]]
49
-
50
- class _BaseEXception(Exception):
51
- def __init__(self, code: str, name="", message: Optional[str] = None, payload: PayloadType = None):
52
- self._code = code
53
- self._name = name
54
- self._message = message
55
- self._payload = payload
56
-
57
- def assembly(self):
58
- """
59
- Собирает ошибку в ответ типа `GNResponse`
60
- """
61
- payload: dict = {'name': self._name}
62
-
63
- if self._message is not None:
64
- payload['message'] = self._message
65
-
66
- if self._payload is not None:
67
- payload['payload'] = self._payload
68
-
69
- return gn.GNResponse(f'gn:error:{self._code}', payload=payload)
70
-
71
-
72
- class GNExceptions:
73
- class UnprocessableEntity(_BaseEXception):
74
- def __init__(self, message: Optional[str] = None, payload: PayloadType = None):
75
- """
76
- # Некорректные данные
77
- """
78
- super().__init__('422', "Unprocessable Entity", message=message, payload=payload)
79
-
80
- class BadRequest(_BaseEXception):
81
- def __init__(self, message: Optional[str] = None, payload: PayloadType = None):
82
- """
83
- # неправильного синтаксис url или параметров
84
- """
85
- super().__init__('400', "Bad Request", message=message, payload=payload)
86
52
 
87
- class Forbidden(_BaseEXception):
88
- def __init__(self, message: Optional[str] = None, payload: PayloadType = None):
89
- """
90
- # Доступ запрещён, даже при наличии авторизации
91
- """
92
- super().__init__('403', "Forbidden", message=message, payload=payload)
93
-
94
-
95
- class NotFound(_BaseEXception):
96
- def __init__(self, message: Optional[str] = None, payload: PayloadType = None):
97
- """
98
- # Ресурс не найден
99
- """
100
- super().__init__('404', "Not Found", message=message, payload=payload)
101
-
102
-
103
- class MethodNotAllowed(_BaseEXception):
104
- def __init__(self, message: Optional[str] = None, payload: PayloadType = None):
105
- """
106
- # Метод запроса не поддерживается данным ресурсом
107
- """
108
- super().__init__('405', "Method Not Allowed", message=message, payload=payload)
109
-
110
-
111
- class Conflict(_BaseEXception):
112
- def __init__(self, message: Optional[str] = None, payload: PayloadType = None):
113
- """
114
- # Конфликт состояния ресурса (например, дубликат)
115
- """
116
- super().__init__('409', "Conflict", message=message, payload=payload)
117
-
118
-
119
- class InternalServerError(_BaseEXception):
120
- def __init__(self, message: Optional[str] = None, payload: PayloadType = None):
121
- """
122
- # Внутренняя ошибка сервера
123
- """
124
- super().__init__('500', "Internal Server Error", message=message, payload=payload)
125
-
126
-
127
- class NotImplemented(_BaseEXception):
128
- def __init__(self, message: Optional[str] = None, payload: PayloadType = None):
129
- """
130
- # Метод или функционал ещё не реализован
131
- """
132
- super().__init__('501', "Not Implemented", message=message, payload=payload)
133
-
134
-
135
- class BadGateway(_BaseEXception):
136
- def __init__(self, message: Optional[str] = None, payload: PayloadType = None):
137
- """
138
- # Ошибка шлюза или прокси при обращении к апстриму
139
- """
140
- super().__init__('502', "Bad Gateway", message=message, payload=payload)
141
-
142
-
143
- class ServiceUnavailable(_BaseEXception):
144
- def __init__(self, message: Optional[str] = None, payload: PayloadType = None):
145
- """
146
- # Сервис временно недоступен
147
- """
148
- super().__init__('503', "Service Unavailable", message=message, payload=payload)
149
-
150
-
151
- class GatewayTimeout(_BaseEXception):
152
- def __init__(self, message: Optional[str] = None, payload: PayloadType = None):
153
- """
154
- # Таймаут при обращении к апстриму
155
- """
156
- super().__init__('504', "Gateway Timeout", message=message, payload=payload)
157
53
 
158
54
  def guess_type(filename: str) -> str:
159
55
  """
@@ -404,7 +300,7 @@ class Route:
404
300
  param_types: dict[str, Callable[[str], Any]]
405
301
  handler: Callable[..., Any]
406
302
  name: str
407
- cors: Optional[gn.CORSObject]
303
+ cors: Optional[CORSObject]
408
304
 
409
305
  _PARAM_REGEX: dict[str, str] = {
410
306
  "str": r"[^/]+",
@@ -495,12 +391,12 @@ def _ensure_async(fn: Callable[..., Any]) -> Callable[..., Any]:
495
391
  class App:
496
392
  def __init__(self):
497
393
  self._routes: List[Route] = []
498
- self._cors: Optional[gn.CORSObject] = None
499
- self._events: Dict[str, Dict[str, Union[str, Callable]]] = {}
394
+ self._cors: Optional[CORSObject] = None
395
+ self._events: Dict[str, List[Dict[str, Union[Any, Callable]]]] = {}
500
396
 
501
- self.domain: str = None
397
+ self.domain: str = None # type: ignore
502
398
 
503
- def route(self, method: str, path: str, cors: Optional[gn.CORSObject] = None):
399
+ def route(self, method: str, path: str, cors: Optional[CORSObject] = None):
504
400
  if path == '/':
505
401
  path = ''
506
402
  def decorator(fn: Callable[..., Any]):
@@ -519,25 +415,25 @@ class App:
519
415
  return fn
520
416
  return decorator
521
417
 
522
- def get(self, path: str, *, cors: Optional[gn.CORSObject] = None):
418
+ def get(self, path: str, *, cors: Optional[CORSObject] = None):
523
419
  return self.route("GET", path, cors)
524
420
 
525
- def post(self, path: str, *, cors: Optional[gn.CORSObject] = None):
421
+ def post(self, path: str, *, cors: Optional[CORSObject] = None):
526
422
  return self.route("POST", path, cors)
527
423
 
528
- def put(self, path: str, *, cors: Optional[gn.CORSObject] = None):
424
+ def put(self, path: str, *, cors: Optional[CORSObject] = None):
529
425
  return self.route("PUT", path, cors)
530
426
 
531
- def delete(self, path: str, *, cors: Optional[gn.CORSObject] = None):
427
+ def delete(self, path: str, *, cors: Optional[CORSObject] = None):
532
428
  return self.route("DELETE", path, cors)
533
429
 
534
430
 
535
- def setRouteCors(self, cors: Optional[gn.CORSObject] = None):
431
+ def setRouteCors(self, cors: Optional[CORSObject] = None):
536
432
  self._cors = cors
537
433
 
538
434
 
539
435
  def addEventListener(self, name: str):
540
- def decorator(fn: Callable[Optional[dict], Any]):
436
+ def decorator(fn: Callable[[Optional[dict]], Any]):
541
437
  events = self._events.get(name, [])
542
438
  events.append({
543
439
  'func': fn,
@@ -557,12 +453,12 @@ class App:
557
453
  is_async = data['async']
558
454
 
559
455
  if not is_async:
560
- if payload in data['parameters']:
456
+ if payload in data['parameters']: # type: ignore
561
457
  func(payload=payload)
562
458
  else:
563
459
  func()
564
460
  else:
565
- if payload in data['parameters']:
461
+ if payload in data['parameters']: # type: ignore
566
462
  await func(payload=payload)
567
463
  else:
568
464
  await func()
@@ -573,8 +469,8 @@ class App:
573
469
 
574
470
 
575
471
  async def dispatchRequest(
576
- self, request: gn.GNRequest
577
- ) -> Union[gn.GNResponse, AsyncGenerator[gn.GNResponse, None]]:
472
+ self, request: GNRequest
473
+ ) -> Union[GNResponse, AsyncGenerator[GNResponse, None]]:
578
474
  path = request.url.path
579
475
  method = request.method.upper()
580
476
  cand = {path, path.rstrip("/") or "/", f"{path}/"}
@@ -589,13 +485,13 @@ class App:
589
485
  if r.method != method:
590
486
  continue
591
487
 
592
- if r.cors is not None and r.cors._allow_origins is not None:
488
+ if r.cors is not None and r.cors.allow_origins is not None:
593
489
  if request._origin is None:
594
- return gn.GNResponse("gn:backend:801", {'error': 'Cors error. Route has cors but request has no origin url.'})
595
- if not resolve_cors(request._origin, r.cors._allow_origins):
596
- return gn.GNResponse("gn:backend:802", {'error': 'Cors error: origin'})
597
- if request.method not in r.cors._allow_methods and '*' not in r.cors._allow_methods:
598
- return gn.GNResponse("gn:backend:803", {'error': 'Cors error: method'})
490
+ return GNResponse("gn:backend:801", {'error': 'Cors error. Route has cors but request has no origin url.'})
491
+ if not resolve_cors(request._origin, r.cors.allow_origins):
492
+ return GNResponse("gn:backend:802", {'error': 'Cors error: origin'})
493
+ if request.method not in r.cors.allow_methods and '*' not in r.cors.allow_methods:
494
+ return GNResponse("gn:backend:803", {'error': 'Cors error: method'})
599
495
 
600
496
  sig = inspect.signature(r.handler)
601
497
  def _ann(name: str):
@@ -607,7 +503,7 @@ class App:
607
503
  for name, val in m.groupdict().items()
608
504
  }
609
505
 
610
- for qn, qvals in parse_qs(request.url.query, keep_blank_values=True).items():
506
+ for qn, qvals in request.url.params.items():
611
507
  if qn in kw:
612
508
  continue
613
509
  raw = qvals if len(qvals) > 1 else qvals[0]
@@ -623,21 +519,21 @@ class App:
623
519
  return r.handler(**kw)
624
520
 
625
521
  result = await r.handler(**kw)
626
- if isinstance(result, gn.GNResponse):
522
+ if isinstance(result, GNResponse):
627
523
  if r.cors is None:
628
524
  if result._cors is None:
629
525
  result._cors = self._cors
630
526
  else:
631
527
  result._cors = r.cors
632
528
 
633
- if result._cors is not None and result._cors != r.cors and result._cors._allow_origins is not None:
529
+ if result._cors is not None and result._cors != r.cors and result._cors.allow_origins is not None:
634
530
  if request._origin is None:
635
- print(result._cors._allow_origins)
636
- return gn.GNResponse("gn:backend:801", {'error': 'Cors error. Route has cors but request has no origin url. [2]'})
637
- if not resolve_cors(request._origin, result._cors._allow_origins):
638
- return gn.GNResponse("gn:backend:802", {'error': 'Cors error: origin'})
639
- if request.method not in result._cors._allow_methods and '*' not in result._cors._allow_methods:
640
- return gn.GNResponse("gn:backend:803", {'error': 'Cors error: method'})
531
+ print(result._cors.allow_origins)
532
+ return GNResponse("gn:backend:801", {'error': 'Cors error. Route has cors but request has no origin url. [2]'})
533
+ if not resolve_cors(request._origin, result._cors.allow_origins):
534
+ return GNResponse("gn:backend:802", {'error': 'Cors error: origin'})
535
+ if request.method not in result._cors.allow_methods and '*' not in result._cors.allow_methods:
536
+ return GNResponse("gn:backend:803", {'error': 'Cors error: method'})
641
537
  return result
642
538
  else:
643
539
  raise TypeError(
@@ -645,11 +541,11 @@ class App:
645
541
  )
646
542
 
647
543
  if allowed:
648
- raise GNExceptions.MethodNotAllowed()
649
- raise GNExceptions.NotFound()
544
+ raise AllGNFastCommands.MethodNotAllowed()
545
+ raise AllGNFastCommands.NotFound()
650
546
 
651
547
 
652
- def fastFile(self, path: str, file_path: str, cors: Optional[gn.CORSObject] = None, template: Optional[gn.TemplateObject] = None, payload: Optional[dict] = None):
548
+ def fastFile(self, path: str, file_path: str, cors: Optional[CORSObject] = None, template: Optional[TemplateObject] = None, payload: Optional[dict] = None):
653
549
  @self.get(path)
654
550
  async def r_static():
655
551
  nonlocal file_path
@@ -657,13 +553,13 @@ class App:
657
553
  file_path = file_path[:-1]
658
554
 
659
555
  if not os.path.isfile(file_path):
660
- raise GNExceptions.NotFound()
556
+ raise AllGNFastCommands.NotFound()
661
557
 
662
- fileObject = gn.FileObject(file_path, template)
663
- return gn.GNResponse('ok', payload=payload, files=fileObject, cors=cors)
558
+ fileObject = FileObject(file_path, template)
559
+ return GNResponse('ok', payload=payload, files=fileObject, cors=cors)
664
560
 
665
561
 
666
- def static(self, path: str, dir_path: str, cors: Optional[gn.CORSObject] = None, template: Optional[gn.TemplateObject] = None, payload: Optional[dict] = None):
562
+ def static(self, path: str, dir_path: str, cors: Optional[CORSObject] = None, template: Optional[TemplateObject] = None, payload: Optional[dict] = None):
667
563
  @self.get(f"{path}/{{_path:path}}")
668
564
  async def r_static(_path: str):
669
565
  file_path = os.path.join(dir_path, _path)
@@ -672,21 +568,21 @@ class App:
672
568
  file_path = file_path[:-1]
673
569
 
674
570
  if not os.path.isfile(file_path):
675
- raise GNExceptions.NotFound()
571
+ raise AllGNFastCommands.NotFound()
676
572
 
677
- fileObject = gn.FileObject(file_path, template)
678
- return gn.GNResponse('ok', payload=payload, files=fileObject, cors=cors)
573
+ fileObject = FileObject(file_path, template)
574
+ return GNResponse('ok', payload=payload, files=fileObject, cors=cors)
679
575
 
680
576
 
681
577
 
682
578
 
683
579
  def _init_sys_routes(self):
684
- @self.post('/!gn-vm-host/ping', cors=gn.CORSObject(None))
685
- async def r_ping(request: gn.GNRequest):
580
+ @self.post('/!gn-vm-host/ping', cors=CORSObject())
581
+ async def r_ping(request: GNRequest):
686
582
 
687
583
  if request.client.ip != '127.0.0.1':
688
- raise GNExceptions.Forbidden()
689
- return gn.GNResponse('ok', {'time': datetime.datetime.now(datetime.UTC).isoformat()})
584
+ raise AllGNFastCommands.Forbidden()
585
+ return GNResponse('ok', {'time': datetime.datetime.now(datetime.UTC).isoformat()})
690
586
 
691
587
 
692
588
 
@@ -695,7 +591,7 @@ class App:
695
591
  super().__init__(*a, **kw)
696
592
  self._api = api
697
593
  self._buffer: Dict[int, bytearray] = {}
698
- self._streams: Dict[int, Tuple[asyncio.Queue[Optional[gn.GNRequest]], bool]] = {}
594
+ self._streams: Dict[int, Tuple[asyncio.Queue[Optional[GNRequest]], bool]] = {}
699
595
 
700
596
  def quic_event_received(self, event: QuicEvent):
701
597
  if isinstance(event, StreamDataReceived):
@@ -710,7 +606,7 @@ class App:
710
606
 
711
607
 
712
608
  # получаем длинну пакета
713
- mode, stream, lenght = gn.GNRequest.type(buf)
609
+ mode, stream, lenght = GNRequest.type(buf)
714
610
 
715
611
  if mode not in (1, 2): # не наш пакет
716
612
  logger.debug(f'Пакет отклонен: mode пакета {mode}. Разрешен 1, 2')
@@ -718,13 +614,13 @@ class App:
718
614
 
719
615
  if not stream: # если не стрим, то ждем конец quic стрима и запускаем обработку ответа
720
616
  if event.end_stream:
721
- request = gn.GNRequest.deserialize(buf, mode)
617
+ request = GNRequest.deserialize(buf, mode)
722
618
  # request.stream_id = event.stream_id
723
619
  # loop = asyncio.get_event_loop()
724
620
  # request.fut = loop.create_future()
725
621
 
726
622
 
727
- request.stream_id = event.stream_id
623
+ request.stream_id = event.stream_id # type: ignore
728
624
  asyncio.create_task(self._handle_request(request, mode))
729
625
  logger.debug(f'Отправлена задача разрешения пакета {request} route -> {request.route}')
730
626
 
@@ -744,11 +640,11 @@ class App:
744
640
  del buf[:lenght]
745
641
 
746
642
  # формируем запрос
747
- request = gn.GNRequest.deserialize(data, mode)
643
+ request = GNRequest.deserialize(data, mode)
748
644
 
749
645
  logger.debug(request, f'event.stream_id -> {event.stream_id}')
750
646
 
751
- request.stream_id = event.stream_id
647
+ request.stream_id = event.stream_id # type: ignore
752
648
 
753
649
  queue, inapi = self._streams.setdefault(event.stream_id, (asyncio.Queue(), False))
754
650
 
@@ -780,10 +676,10 @@ class App:
780
676
  break
781
677
  yield chunk
782
678
 
783
- request._stream = w
679
+ request._stream = w # type: ignore
784
680
  asyncio.create_task(self._handle_request(request, mode))
785
681
 
786
- async def _handle_request(self, request: gn.GNRequest, mode: int):
682
+ async def _handle_request(self, request: GNRequest, mode: int):
787
683
 
788
684
  request.client._data['remote_addr'] = self._quic._network_paths[0].addr
789
685
 
@@ -794,43 +690,36 @@ class App:
794
690
  if inspect.isasyncgen(response):
795
691
  async for chunk in response: # type: ignore[misc]
796
692
  chunk._stream = True
797
- chunk = await self.resolve_response(chunk)
798
- self._quic.send_stream_data(request.stream_id, chunk.serialize(mode), end_stream=False)
799
- self.transmit()
693
+ await self.sendResponse(request, chunk, mode, False)
800
694
 
801
- l = gn.GNResponse('gn:end-stream')
802
- l._stream = True
803
- l = self.resolve_response(l)
804
- self._quic.send_stream_data(request.stream_id, l.serialize(mode), end_stream=True)
805
- self.transmit()
695
+ resp = GNResponse('gn:end-stream')
696
+ resp._stream = True
697
+
698
+ await self.sendResponse(request, resp, mode)
806
699
  return
807
700
 
701
+ if not isinstance(response, GNResponse):
702
+ await self.sendResponse(request, AllGNFastCommands.InternalServerError(), mode)
703
+ return
808
704
 
809
- response = await self.resolve_response(response)
810
- self._quic.send_stream_data(request.stream_id, response.serialize(mode), end_stream=True)
811
- logger.debug(f'Отправлен на сервер ответ -> {response.command} {response.payload if response.payload and len((response.payload)) < 200 else ''}')
812
- self.transmit()
705
+ await self.sendResponse(request, response, mode)
706
+ logger.debug(f'Отправлен на сервер ответ -> {response.command} {response.payload if response.payload and len(str(response.payload)) < 200 else ''}')
813
707
  except Exception as e:
814
- if isinstance(e, _BaseEXception):
815
- e: GNExceptions.UnprocessableEntity = e
816
- r = e.assembly()
817
- return r
708
+ if isinstance(e, GNFastCommand):
709
+ await self.sendResponse(request, e, mode)
818
710
  else:
819
711
  logger.error('GNServer: error\n' + traceback.format_exc())
820
712
 
821
- response = gn.GNResponse('gn:backend:500')
822
- self._quic.send_stream_data(request.stream_id, response.serialize(mode), end_stream=True)
823
- self.transmit()
713
+ await self.sendResponse(request, AllGNFastCommands.InternalServerError(), mode)
824
714
 
825
- async def resolve_response(self, response: gn.GNResponse) -> gn.GNResponse:
826
- await response.assembly()
827
-
828
- return response
829
715
 
830
716
 
831
-
717
+ async def sendResponse(self, request: GNRequest, response: GNResponse, mode: int, end_stream: bool = True):
718
+ await response.assembly()
832
719
 
833
720
 
721
+ self._quic.send_stream_data(request.stream_id, response.serialize(mode), end_stream=end_stream) # type: ignore
722
+ self.transmit()
834
723
 
835
724
  def run(
836
725
  self,
@@ -858,7 +747,7 @@ class App:
858
747
  cfg = QuicConfiguration(
859
748
  alpn_protocols=["gn:backend"], is_client=False, idle_timeout=idle_timeout
860
749
  )
861
- cfg.load_cert_chain(cert_path, key_path)
750
+ cfg.load_cert_chain(cert_path, key_path) # type: ignore
862
751
 
863
752
  async def _main():
864
753