# 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)