2025-04-09 16:54:34 +08:00
|
|
|
from typing import TypeGuard, override
|
|
|
|
|
|
|
|
|
|
from app.subroutines.http import Response, SimpleRequest, SimpleResponse
|
|
|
|
|
from app.types_ import (
|
|
|
|
|
AnyScope,
|
|
|
|
|
AsyncCallable,
|
|
|
|
|
HTTPScope,
|
|
|
|
|
PassthroughDecorator,
|
|
|
|
|
Receive,
|
|
|
|
|
ReceiveHTTP,
|
|
|
|
|
RouteMapping,
|
|
|
|
|
Send,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
from .base import RouteComponent as _RouteComponent
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class HTTPComponent(
|
|
|
|
|
_RouteComponent[HTTPScope, ReceiveHTTP, dict[str, RouteMapping[Response]], Response]
|
|
|
|
|
):
|
|
|
|
|
routes: dict[str, RouteMapping[Response]]
|
|
|
|
|
|
|
|
|
|
def __init__(self) -> None:
|
|
|
|
|
self.routes = {}
|
|
|
|
|
super().__init__()
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
async def condition(self, scope: AnyScope) -> TypeGuard[HTTPScope]:
|
|
|
|
|
return scope["type"] == "http"
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
async def handle(
|
|
|
|
|
self, scope: HTTPScope, receive: Receive[ReceiveHTTP], send: Send
|
|
|
|
|
) -> None:
|
|
|
|
|
req = SimpleRequest()
|
|
|
|
|
while not req.receive(await receive()):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
print(scope, req.body)
|
|
|
|
|
resp = await self.route_dispatch(scope, receive, send)
|
|
|
|
|
if resp is None:
|
|
|
|
|
resp = Response(status=404, body=b"404 Not Found\n")
|
|
|
|
|
|
|
|
|
|
async with SimpleResponse(send).prepare(
|
|
|
|
|
resp.status, headers=resp.headers
|
|
|
|
|
) as rsp:
|
|
|
|
|
await rsp.finish(resp.body if resp.body is not None else b"")
|
|
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
async def route_dispatch(
|
|
|
|
|
self, scope: HTTPScope, receive: Receive[ReceiveHTTP], send: Send
|
|
|
|
|
) -> Response | None:
|
|
|
|
|
for k, callee in self.routes[scope["method"].upper()].items():
|
|
|
|
|
if scope["path"] == k: # temporary impl.
|
|
|
|
|
return await callee()
|
|
|
|
|
|
2025-04-11 15:04:22 +08:00
|
|
|
@override
|
|
|
|
|
def route_install(self, route: str, target: AsyncCallable[..., Response], *, type_: str | None = None) -> None:
|
|
|
|
|
"""Install route target for specific type and route."""
|
|
|
|
|
if type_ is None:
|
|
|
|
|
raise ValueError("Route type `type_` is unset.")
|
|
|
|
|
self.routes.setdefault(type_, {})[route] = target
|
|
|
|
|
|
2025-04-09 16:54:34 +08:00
|
|
|
def route[T: AsyncCallable[..., Response]](
|
|
|
|
|
self,
|
|
|
|
|
route: str,
|
|
|
|
|
*,
|
|
|
|
|
get: bool = False,
|
|
|
|
|
post: bool = False,
|
|
|
|
|
put: bool = False,
|
|
|
|
|
delete: bool = False,
|
2025-04-15 16:36:23 +08:00
|
|
|
head: bool = False,
|
2025-04-09 16:54:34 +08:00
|
|
|
) -> PassthroughDecorator[T]:
|
|
|
|
|
def __wrap_route(fn: T) -> T:
|
|
|
|
|
if get:
|
2025-04-11 15:04:22 +08:00
|
|
|
self.route_install(route, fn, type_="GET")
|
2025-04-09 16:54:34 +08:00
|
|
|
if post:
|
2025-04-11 15:04:22 +08:00
|
|
|
self.route_install(route, fn, type_="POST")
|
2025-04-09 16:54:34 +08:00
|
|
|
if put:
|
2025-04-11 15:04:22 +08:00
|
|
|
self.route_install(route, fn, type_="PUT")
|
2025-04-09 16:54:34 +08:00
|
|
|
if delete:
|
2025-04-11 15:04:22 +08:00
|
|
|
self.route_install(route, fn, type_="DELETE")
|
2025-04-15 16:36:23 +08:00
|
|
|
if head:
|
|
|
|
|
self.route_install(route, fn, type_="HEAD")
|
2025-04-09 16:54:34 +08:00
|
|
|
return fn
|
|
|
|
|
|
|
|
|
|
return __wrap_route
|
|
|
|
|
|
|
|
|
|
def get[T: AsyncCallable[..., Response]](
|
|
|
|
|
self, route: str
|
|
|
|
|
) -> PassthroughDecorator[T]:
|
|
|
|
|
return self.route(route, get=True)
|
|
|
|
|
|
|
|
|
|
def post[T: AsyncCallable[..., Response]](
|
|
|
|
|
self, route: str
|
|
|
|
|
) -> PassthroughDecorator[T]:
|
|
|
|
|
return self.route(route, post=True)
|
|
|
|
|
|
|
|
|
|
def put[T: AsyncCallable[..., Response]](
|
|
|
|
|
self, route: str
|
|
|
|
|
) -> PassthroughDecorator[T]:
|
|
|
|
|
return self.route(route, put=True)
|
|
|
|
|
|
|
|
|
|
def delete[T: AsyncCallable[..., Response]](
|
|
|
|
|
self, route: str
|
|
|
|
|
) -> PassthroughDecorator[T]:
|
|
|
|
|
return self.route(route, delete=True)
|