Files
hydrogen/reporting/transports/webhook.py
2026-07-11 23:54:36 +07:00

70 lines
2.2 KiB
Python

import json
from enum import StrEnum
from urllib.request import Request, urlopen
from pydantic import AnyHttpUrl, BaseModel, Field
from core.base import TypedTransport
from reporting.models import RenderedReport
class WebhookMethod(StrEnum):
POST = "POST"
PUT = "PUT"
PATCH = "PATCH"
class WebhookPayloadMode(StrEnum):
RENDERED = "rendered"
ENVELOPE = "envelope"
class WebhookTransportConfig(BaseModel):
url: AnyHttpUrl = Field()
method: WebhookMethod = Field(WebhookMethod.POST)
headers: dict[str, str] = Field(default_factory=dict)
timeout_seconds: float = Field(10.0, gt=0)
payload_mode: WebhookPayloadMode = Field(WebhookPayloadMode.RENDERED)
class WebhookTransport(TypedTransport[WebhookTransportConfig]):
transport_type = "webhook"
config_model = WebhookTransportConfig
def publish_typed(
self, rendered_report: RenderedReport, transport: WebhookTransportConfig
) -> str:
body, headers = self._build_request(rendered_report, transport)
request = Request(
url=str(transport.url),
data=body,
headers=headers,
method=transport.method.value,
)
with urlopen(request, timeout=transport.timeout_seconds) as response:
return f"{response.status} {transport.url}"
def _build_request(
self,
rendered_report: RenderedReport,
transport: WebhookTransportConfig,
) -> tuple[bytes, dict[str, str]]:
headers = dict(transport.headers)
if transport.payload_mode is WebhookPayloadMode.ENVELOPE:
payload = json.dumps(
{
"format": rendered_report.format_name,
"content_type": rendered_report.media_type,
"file_extension": rendered_report.file_extension,
"content": rendered_report.content,
},
ensure_ascii=True,
).encode("utf-8")
headers.setdefault("Content-Type", "application/json")
return payload, headers
headers.setdefault("Content-Type", rendered_report.media_type)
return rendered_report.content.encode("utf-8"), headers