forked from sparckles/Robyn
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrouter.py
160 lines (124 loc) · 4.79 KB
/
router.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
from abc import ABC, abstractmethod
from functools import wraps
from asyncio import iscoroutinefunction
from inspect import signature
from typing import Callable, Dict, List, Tuple, Union
from types import CoroutineType
from robyn.ws import WS
Route = Tuple[str, str, Callable, bool, int, bool]
MiddlewareRoute = Tuple[str, str, Callable, bool, int]
class BaseRouter(ABC):
@abstractmethod
def add_route(*args) -> Union[Callable, CoroutineType, WS]:
...
class Router(BaseRouter):
def __init__(self) -> None:
super().__init__()
self.routes = []
def _format_response(self, res):
# handle file handlers
response = {}
if type(res) == dict:
if "status_code" not in res:
res["status_code"] = "200"
response = res
else:
if type(res["status_code"]) == int:
res["status_code"] = str(res["status_code"])
response = {"status_code": "200", "body": res["body"], **res}
else:
response = {"status_code": "200", "body": res, "type": "text"}
return response
def add_route(
self, route_type: str, endpoint: str, handler: Callable, const: bool
) -> Union[Callable, CoroutineType]:
@wraps(handler)
async def async_inner_handler(*args):
response = self._format_response(await handler(*args))
return response
@wraps(handler)
def inner_handler(*args):
response = self._format_response(handler(*args))
return response
number_of_params = len(signature(handler).parameters)
if iscoroutinefunction(handler):
self.routes.append(
(
route_type,
endpoint,
async_inner_handler,
True,
number_of_params,
const,
)
)
return async_inner_handler
else:
self.routes.append(
(route_type, endpoint, inner_handler, False, number_of_params, const)
)
return inner_handler
def get_routes(self) -> List[Route]:
return self.routes
class MiddlewareRouter(BaseRouter):
def __init__(self) -> None:
super().__init__()
self.routes = []
def add_route(self, route_type: str, endpoint: str, handler: Callable, number_of_params=0) -> None:
print(route_type, handler, signature(handler).parameters, number_of_params)
self.routes.append(
(
route_type,
endpoint,
handler,
iscoroutinefunction(handler),
number_of_params,
)
)
return handler
# These inner function is basically a wrapper arround the closure(decorator)
# being returned.
# It takes in a handler and converts it in into a closure
# and returns the arguments.
# Arguments are returned as they could be modified by the middlewares.
def add_after_request(self, endpoint: str) -> Callable[..., None]:
def inner(handler): # number_of_params
async def async_inner_handler(*args):
await handler(*args)
return args
@wraps(handler)
def inner_handler(*args):
handler(*args)
return args
number_of_params = len(signature(handler).parameters)
if iscoroutinefunction(handler):
self.add_route("AFTER_REQUEST", endpoint, async_inner_handler, number_of_params)
else:
self.add_route("AFTER_REQUEST", endpoint, inner_handler, number_of_params)
return inner
def add_before_request(self, endpoint: str) -> Callable[..., None]:
def inner(handler):
@wraps(handler)
async def async_inner_handler(*args):
await handler(*args)
return args
@wraps(handler)
def inner_handler(*args):
handler(*args)
return args
number_of_params = len(signature(handler).parameters)
if iscoroutinefunction(handler):
self.add_route("BEFORE_REQUEST", endpoint, async_inner_handler, number_of_params)
else:
self.add_route("BEFORE_REQUEST", endpoint, inner_handler, number_of_params)
return inner
def get_routes(self) -> List[MiddlewareRoute]:
return self.routes
class WebSocketRouter(BaseRouter):
def __init__(self) -> None:
super().__init__()
self.routes = {}
def add_route(self, endpoint: str, web_socket: WS) -> None:
self.routes[endpoint] = web_socket
def get_routes(self) -> Dict[str, WS]:
return self.routes