52 lines
1.9 KiB
Python
52 lines
1.9 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
from urllib import error, request
|
|
|
|
from django.conf import settings
|
|
|
|
from .renderer import RenderError, validate_certificate_context
|
|
|
|
|
|
MAX_PDF_BYTES = 5 * 1024 * 1024
|
|
|
|
|
|
def render_certificate_via_service(context: dict, output_path: str) -> str:
|
|
"""Validate and send render request to internal renderer service."""
|
|
validated = validate_certificate_context(context)
|
|
|
|
service_url = getattr(settings, "CERTIFICATE_RENDERER_URL", "http://certificate-renderer:8090/render")
|
|
timeout = int(getattr(settings, "CERTIFICATE_RENDERER_TIMEOUT_SECONDS", 20))
|
|
token = getattr(settings, "CERTIFICATE_RENDERER_TOKEN", "")
|
|
|
|
payload = json.dumps({"context": validated}).encode("utf-8")
|
|
req = request.Request(service_url, data=payload, method="POST")
|
|
req.add_header("Content-Type", "application/json")
|
|
req.add_header("Accept", "application/pdf")
|
|
if token:
|
|
req.add_header("X-Renderer-Token", token)
|
|
|
|
try:
|
|
with request.urlopen(req, timeout=timeout) as response:
|
|
if response.status != 200:
|
|
raise RenderError(f"renderer returned HTTP {response.status}")
|
|
content_type = response.headers.get("Content-Type", "")
|
|
if "application/pdf" not in content_type:
|
|
raise RenderError(f"renderer returned invalid content-type: {content_type}")
|
|
|
|
pdf_bytes = response.read(MAX_PDF_BYTES + 1)
|
|
except error.HTTPError as exc:
|
|
detail = exc.read(1024).decode("utf-8", errors="replace")
|
|
raise RenderError(f"renderer HTTPError {exc.code}: {detail}")
|
|
except error.URLError as exc:
|
|
raise RenderError(f"renderer not reachable: {exc.reason}")
|
|
|
|
if len(pdf_bytes) > MAX_PDF_BYTES:
|
|
raise RenderError("renderer returned oversized PDF")
|
|
|
|
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
|
with open(output_path, "wb") as f:
|
|
f.write(pdf_bytes)
|
|
return output_path
|