|
# retoor <retoor@molodetz.nl>
|
|
|
|
import logging
|
|
|
|
from fastapi import APIRouter, Request, WebSocket
|
|
from starlette.responses import Response
|
|
|
|
from devplacepy.services.audit import record as audit
|
|
from devplacepy.services.containers import api, forward, store
|
|
from devplacepy.utils import not_found
|
|
|
|
logger = logging.getLogger(__name__)
|
|
router = APIRouter()
|
|
|
|
METHODS = forward.METHODS
|
|
|
|
|
|
def _resolve(slug: str):
|
|
instance = store.find_instance_by_ingress(slug)
|
|
if not instance or instance.get("status") != store.ST_RUNNING:
|
|
return None, None, None
|
|
host, port = api.proxy_target(instance)
|
|
return instance, host, port
|
|
|
|
|
|
@router.api_route("/{slug}", methods=METHODS)
|
|
@router.api_route("/{slug}/{path:path}", methods=METHODS)
|
|
async def proxy_http(request: Request, slug: str, path: str = ""):
|
|
instance, host, port = _resolve(slug)
|
|
if instance is None:
|
|
raise not_found("No running container is published at this address")
|
|
if not host or not port:
|
|
return Response(
|
|
"the published container has no reachable port", status_code=502
|
|
)
|
|
audit.record(
|
|
request,
|
|
"proxy.access",
|
|
target_type="instance",
|
|
target_uid=instance["uid"],
|
|
target_label=instance.get("name"),
|
|
metadata={"slug": slug, "path": path, "method": request.method},
|
|
summary=f"request proxied to instance {instance.get('name')} via ingress {slug}",
|
|
links=[audit.instance(instance["uid"], instance.get("name"))],
|
|
)
|
|
return await forward.proxy_http(
|
|
request, host, port, path, prefix=f"/p/{slug}", timeout=60.0
|
|
)
|
|
|
|
|
|
@router.websocket("/{slug}")
|
|
@router.websocket("/{slug}/{path:path}")
|
|
async def proxy_ws(websocket: WebSocket, slug: str, path: str = ""):
|
|
instance, host, port = _resolve(slug)
|
|
if instance is None or not host or not port:
|
|
await websocket.close(code=1011)
|
|
return
|
|
await websocket.accept()
|
|
audit.record(
|
|
websocket,
|
|
"proxy.access",
|
|
user=None,
|
|
target_type="instance",
|
|
target_uid=instance["uid"],
|
|
target_label=instance.get("name"),
|
|
metadata={"slug": slug, "path": path, "protocol": "websocket"},
|
|
summary=f"websocket proxied to instance {instance.get('name')} via ingress {slug}",
|
|
links=[audit.instance(instance["uid"], instance.get("name"))],
|
|
)
|
|
await forward.proxy_ws(websocket, host, port, path, accepted=True)
|