GNServer 0.0.0.0.30__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,121 +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
52
 
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
-
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
- class Unauthorized(_BaseEXception):
95
- def __init__(self, message: Optional[str] = None, payload: PayloadType = None):
96
- """
97
- # Требуется авторизация
98
- """
99
- super().__init__('401', "Unauthorized", message=message, payload=payload)
100
-
101
- class NotFound(_BaseEXception):
102
- def __init__(self, message: Optional[str] = None, payload: PayloadType = None):
103
- """
104
- # Ресурс не найден
105
- """
106
- super().__init__('404', "Not Found", message=message, payload=payload)
107
-
108
-
109
- class MethodNotAllowed(_BaseEXception):
110
- def __init__(self, message: Optional[str] = None, payload: PayloadType = None):
111
- """
112
- # Метод запроса не поддерживается данным ресурсом
113
- """
114
- super().__init__('405', "Method Not Allowed", message=message, payload=payload)
115
-
116
-
117
- class Conflict(_BaseEXception):
118
- def __init__(self, message: Optional[str] = None, payload: PayloadType = None):
119
- """
120
- # Конфликт состояния ресурса (например, дубликат)
121
- """
122
- super().__init__('409', "Conflict", message=message, payload=payload)
123
-
124
-
125
- class InternalServerError(_BaseEXception):
126
- def __init__(self, message: Optional[str] = None, payload: PayloadType = None):
127
- """
128
- # Внутренняя ошибка сервера
129
- """
130
- super().__init__('500', "Internal Server Error", message=message, payload=payload)
131
-
132
-
133
- class NotImplemented(_BaseEXception):
134
- def __init__(self, message: Optional[str] = None, payload: PayloadType = None):
135
- """
136
- # Метод или функционал ещё не реализован
137
- """
138
- super().__init__('501', "Not Implemented", message=message, payload=payload)
139
-
140
-
141
- class BadGateway(_BaseEXception):
142
- def __init__(self, message: Optional[str] = None, payload: PayloadType = None):
143
- """
144
- # Ошибка шлюза или прокси при обращении к апстриму
145
- """
146
- super().__init__('502', "Bad Gateway", message=message, payload=payload)
147
-
148
-
149
- class ServiceUnavailable(_BaseEXception):
150
- def __init__(self, message: Optional[str] = None, payload: PayloadType = None):
151
- """
152
- # Сервис временно недоступен
153
- """
154
- super().__init__('503', "Service Unavailable", message=message, payload=payload)
155
-
156
-
157
- class GatewayTimeout(_BaseEXception):
158
- def __init__(self, message: Optional[str] = None, payload: PayloadType = None):
159
- """
160
- # Таймаут при обращении к апстриму
161
- """
162
- super().__init__('504', "Gateway Timeout", message=message, payload=payload)
163
53
 
164
54
  def guess_type(filename: str) -> str:
165
55
  """
@@ -410,7 +300,7 @@ class Route:
410
300
  param_types: dict[str, Callable[[str], Any]]
411
301
  handler: Callable[..., Any]
412
302
  name: str
413
- cors: Optional[gn.CORSObject]
303
+ cors: Optional[CORSObject]
414
304
 
415
305
  _PARAM_REGEX: dict[str, str] = {
416
306
  "str": r"[^/]+",
@@ -501,12 +391,12 @@ def _ensure_async(fn: Callable[..., Any]) -> Callable[..., Any]:
501
391
  class App:
502
392
  def __init__(self):
503
393
  self._routes: List[Route] = []
504
- self._cors: Optional[gn.CORSObject] = None
505
- 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]]]] = {}
506
396
 
507
- self.domain: str = None
397
+ self.domain: str = None # type: ignore
508
398
 
509
- def route(self, method: str, path: str, cors: Optional[gn.CORSObject] = None):
399
+ def route(self, method: str, path: str, cors: Optional[CORSObject] = None):
510
400
  if path == '/':
511
401
  path = ''
512
402
  def decorator(fn: Callable[..., Any]):
@@ -525,25 +415,25 @@ class App:
525
415
  return fn
526
416
  return decorator
527
417
 
528
- def get(self, path: str, *, cors: Optional[gn.CORSObject] = None):
418
+ def get(self, path: str, *, cors: Optional[CORSObject] = None):
529
419
  return self.route("GET", path, cors)
530
420
 
531
- def post(self, path: str, *, cors: Optional[gn.CORSObject] = None):
421
+ def post(self, path: str, *, cors: Optional[CORSObject] = None):
532
422
  return self.route("POST", path, cors)
533
423
 
534
- def put(self, path: str, *, cors: Optional[gn.CORSObject] = None):
424
+ def put(self, path: str, *, cors: Optional[CORSObject] = None):
535
425
  return self.route("PUT", path, cors)
536
426
 
537
- def delete(self, path: str, *, cors: Optional[gn.CORSObject] = None):
427
+ def delete(self, path: str, *, cors: Optional[CORSObject] = None):
538
428
  return self.route("DELETE", path, cors)
539
429
 
540
430
 
541
- def setRouteCors(self, cors: Optional[gn.CORSObject] = None):
431
+ def setRouteCors(self, cors: Optional[CORSObject] = None):
542
432
  self._cors = cors
543
433
 
544
434
 
545
435
  def addEventListener(self, name: str):
546
- def decorator(fn: Callable[Optional[dict], Any]):
436
+ def decorator(fn: Callable[[Optional[dict]], Any]):
547
437
  events = self._events.get(name, [])
548
438
  events.append({
549
439
  'func': fn,
@@ -563,12 +453,12 @@ class App:
563
453
  is_async = data['async']
564
454
 
565
455
  if not is_async:
566
- if payload in data['parameters']:
456
+ if payload in data['parameters']: # type: ignore
567
457
  func(payload=payload)
568
458
  else:
569
459
  func()
570
460
  else:
571
- if payload in data['parameters']:
461
+ if payload in data['parameters']: # type: ignore
572
462
  await func(payload=payload)
573
463
  else:
574
464
  await func()
@@ -579,8 +469,8 @@ class App:
579
469
 
580
470
 
581
471
  async def dispatchRequest(
582
- self, request: gn.GNRequest
583
- ) -> Union[gn.GNResponse, AsyncGenerator[gn.GNResponse, None]]:
472
+ self, request: GNRequest
473
+ ) -> Union[GNResponse, AsyncGenerator[GNResponse, None]]:
584
474
  path = request.url.path
585
475
  method = request.method.upper()
586
476
  cand = {path, path.rstrip("/") or "/", f"{path}/"}
@@ -595,13 +485,13 @@ class App:
595
485
  if r.method != method:
596
486
  continue
597
487
 
598
- 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:
599
489
  if request._origin is None:
600
- return gn.GNResponse("gn:backend:801", {'error': 'Cors error. Route has cors but request has no origin url.'})
601
- if not resolve_cors(request._origin, r.cors._allow_origins):
602
- return gn.GNResponse("gn:backend:802", {'error': 'Cors error: origin'})
603
- if request.method not in r.cors._allow_methods and '*' not in r.cors._allow_methods:
604
- 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'})
605
495
 
606
496
  sig = inspect.signature(r.handler)
607
497
  def _ann(name: str):
@@ -613,7 +503,7 @@ class App:
613
503
  for name, val in m.groupdict().items()
614
504
  }
615
505
 
616
- for qn, qvals in parse_qs(request.url.query, keep_blank_values=True).items():
506
+ for qn, qvals in request.url.params.items():
617
507
  if qn in kw:
618
508
  continue
619
509
  raw = qvals if len(qvals) > 1 else qvals[0]
@@ -629,21 +519,21 @@ class App:
629
519
  return r.handler(**kw)
630
520
 
631
521
  result = await r.handler(**kw)
632
- if isinstance(result, gn.GNResponse):
522
+ if isinstance(result, GNResponse):
633
523
  if r.cors is None:
634
524
  if result._cors is None:
635
525
  result._cors = self._cors
636
526
  else:
637
527
  result._cors = r.cors
638
528
 
639
- 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:
640
530
  if request._origin is None:
641
- print(result._cors._allow_origins)
642
- return gn.GNResponse("gn:backend:801", {'error': 'Cors error. Route has cors but request has no origin url. [2]'})
643
- if not resolve_cors(request._origin, result._cors._allow_origins):
644
- return gn.GNResponse("gn:backend:802", {'error': 'Cors error: origin'})
645
- if request.method not in result._cors._allow_methods and '*' not in result._cors._allow_methods:
646
- 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'})
647
537
  return result
648
538
  else:
649
539
  raise TypeError(
@@ -651,11 +541,11 @@ class App:
651
541
  )
652
542
 
653
543
  if allowed:
654
- raise GNExceptions.MethodNotAllowed()
655
- raise GNExceptions.NotFound()
544
+ raise AllGNFastCommands.MethodNotAllowed()
545
+ raise AllGNFastCommands.NotFound()
656
546
 
657
547
 
658
- 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):
659
549
  @self.get(path)
660
550
  async def r_static():
661
551
  nonlocal file_path
@@ -663,13 +553,13 @@ class App:
663
553
  file_path = file_path[:-1]
664
554
 
665
555
  if not os.path.isfile(file_path):
666
- raise GNExceptions.NotFound()
556
+ raise AllGNFastCommands.NotFound()
667
557
 
668
- fileObject = gn.FileObject(file_path, template)
669
- 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)
670
560
 
671
561
 
672
- 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):
673
563
  @self.get(f"{path}/{{_path:path}}")
674
564
  async def r_static(_path: str):
675
565
  file_path = os.path.join(dir_path, _path)
@@ -678,21 +568,21 @@ class App:
678
568
  file_path = file_path[:-1]
679
569
 
680
570
  if not os.path.isfile(file_path):
681
- raise GNExceptions.NotFound()
571
+ raise AllGNFastCommands.NotFound()
682
572
 
683
- fileObject = gn.FileObject(file_path, template)
684
- 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)
685
575
 
686
576
 
687
577
 
688
578
 
689
579
  def _init_sys_routes(self):
690
- @self.post('/!gn-vm-host/ping', cors=gn.CORSObject(None))
691
- async def r_ping(request: gn.GNRequest):
580
+ @self.post('/!gn-vm-host/ping', cors=CORSObject())
581
+ async def r_ping(request: GNRequest):
692
582
 
693
583
  if request.client.ip != '127.0.0.1':
694
- raise GNExceptions.Forbidden()
695
- 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()})
696
586
 
697
587
 
698
588
 
@@ -701,7 +591,7 @@ class App:
701
591
  super().__init__(*a, **kw)
702
592
  self._api = api
703
593
  self._buffer: Dict[int, bytearray] = {}
704
- self._streams: Dict[int, Tuple[asyncio.Queue[Optional[gn.GNRequest]], bool]] = {}
594
+ self._streams: Dict[int, Tuple[asyncio.Queue[Optional[GNRequest]], bool]] = {}
705
595
 
706
596
  def quic_event_received(self, event: QuicEvent):
707
597
  if isinstance(event, StreamDataReceived):
@@ -716,7 +606,7 @@ class App:
716
606
 
717
607
 
718
608
  # получаем длинну пакета
719
- mode, stream, lenght = gn.GNRequest.type(buf)
609
+ mode, stream, lenght = GNRequest.type(buf)
720
610
 
721
611
  if mode not in (1, 2): # не наш пакет
722
612
  logger.debug(f'Пакет отклонен: mode пакета {mode}. Разрешен 1, 2')
@@ -724,13 +614,13 @@ class App:
724
614
 
725
615
  if not stream: # если не стрим, то ждем конец quic стрима и запускаем обработку ответа
726
616
  if event.end_stream:
727
- request = gn.GNRequest.deserialize(buf, mode)
617
+ request = GNRequest.deserialize(buf, mode)
728
618
  # request.stream_id = event.stream_id
729
619
  # loop = asyncio.get_event_loop()
730
620
  # request.fut = loop.create_future()
731
621
 
732
622
 
733
- request.stream_id = event.stream_id
623
+ request.stream_id = event.stream_id # type: ignore
734
624
  asyncio.create_task(self._handle_request(request, mode))
735
625
  logger.debug(f'Отправлена задача разрешения пакета {request} route -> {request.route}')
736
626
 
@@ -750,11 +640,11 @@ class App:
750
640
  del buf[:lenght]
751
641
 
752
642
  # формируем запрос
753
- request = gn.GNRequest.deserialize(data, mode)
643
+ request = GNRequest.deserialize(data, mode)
754
644
 
755
645
  logger.debug(request, f'event.stream_id -> {event.stream_id}')
756
646
 
757
- request.stream_id = event.stream_id
647
+ request.stream_id = event.stream_id # type: ignore
758
648
 
759
649
  queue, inapi = self._streams.setdefault(event.stream_id, (asyncio.Queue(), False))
760
650
 
@@ -786,10 +676,10 @@ class App:
786
676
  break
787
677
  yield chunk
788
678
 
789
- request._stream = w
679
+ request._stream = w # type: ignore
790
680
  asyncio.create_task(self._handle_request(request, mode))
791
681
 
792
- async def _handle_request(self, request: gn.GNRequest, mode: int):
682
+ async def _handle_request(self, request: GNRequest, mode: int):
793
683
 
794
684
  request.client._data['remote_addr'] = self._quic._network_paths[0].addr
795
685
 
@@ -800,43 +690,36 @@ class App:
800
690
  if inspect.isasyncgen(response):
801
691
  async for chunk in response: # type: ignore[misc]
802
692
  chunk._stream = True
803
- chunk = await self.resolve_response(chunk)
804
- self._quic.send_stream_data(request.stream_id, chunk.serialize(mode), end_stream=False)
805
- self.transmit()
693
+ await self.sendResponse(request, chunk, mode, False)
806
694
 
807
- l = gn.GNResponse('gn:end-stream')
808
- l._stream = True
809
- l = self.resolve_response(l)
810
- self._quic.send_stream_data(request.stream_id, l.serialize(mode), end_stream=True)
811
- self.transmit()
695
+ resp = GNResponse('gn:end-stream')
696
+ resp._stream = True
697
+
698
+ await self.sendResponse(request, resp, mode)
812
699
  return
813
700
 
701
+ if not isinstance(response, GNResponse):
702
+ await self.sendResponse(request, AllGNFastCommands.InternalServerError(), mode)
703
+ return
814
704
 
815
- response = await self.resolve_response(response)
816
- self._quic.send_stream_data(request.stream_id, response.serialize(mode), end_stream=True)
817
- logger.debug(f'Отправлен на сервер ответ -> {response.command} {response.payload if response.payload and len((response.payload)) < 200 else ''}')
818
- 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 ''}')
819
707
  except Exception as e:
820
- if isinstance(e, _BaseEXception):
821
- e: GNExceptions.UnprocessableEntity = e
822
- r = e.assembly()
823
- return r
708
+ if isinstance(e, GNFastCommand):
709
+ await self.sendResponse(request, e, mode)
824
710
  else:
825
711
  logger.error('GNServer: error\n' + traceback.format_exc())
826
712
 
827
- response = gn.GNResponse('gn:backend:500')
828
- self._quic.send_stream_data(request.stream_id, response.serialize(mode), end_stream=True)
829
- self.transmit()
713
+ await self.sendResponse(request, AllGNFastCommands.InternalServerError(), mode)
830
714
 
831
- async def resolve_response(self, response: gn.GNResponse) -> gn.GNResponse:
832
- await response.assembly()
833
-
834
- return response
835
715
 
836
716
 
837
-
717
+ async def sendResponse(self, request: GNRequest, response: GNResponse, mode: int, end_stream: bool = True):
718
+ await response.assembly()
838
719
 
839
720
 
721
+ self._quic.send_stream_data(request.stream_id, response.serialize(mode), end_stream=end_stream) # type: ignore
722
+ self.transmit()
840
723
 
841
724
  def run(
842
725
  self,
@@ -864,7 +747,7 @@ class App:
864
747
  cfg = QuicConfiguration(
865
748
  alpn_protocols=["gn:backend"], is_client=False, idle_timeout=idle_timeout
866
749
  )
867
- cfg.load_cert_chain(cert_path, key_path)
750
+ cfg.load_cert_chain(cert_path, key_path) # type: ignore
868
751
 
869
752
  async def _main():
870
753