1
0
forked from erp-dev/erp
Files
erpnew/notifier/message_api.py

132 lines
3.7 KiB
Python

from __future__ import annotations
import json
from dataclasses import dataclass
from urllib.parse import urljoin
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen
from django.conf import settings
@dataclass(frozen=True)
class MessageAPIResponse:
errcode: int
errmsg: str
raw: dict
@property
def ok(self) -> bool:
return int(self.errcode) == 0
def _request_json(
*,
url: str,
method: str = "GET",
payload: dict | None = None,
timeout_seconds: float = 10.0,
headers: dict | None = None,
) -> dict:
data = None
request_headers = dict(headers or {})
if payload is not None:
data = json.dumps(payload, ensure_ascii=False).encode("utf-8")
request_headers.setdefault("Content-Type", "application/json")
req = Request(url=url, data=data, headers=request_headers, method=method)
try:
with urlopen(req, timeout=float(timeout_seconds)) as resp:
body = resp.read().decode("utf-8", errors="replace")
except HTTPError as exc:
body = ""
try:
body = exc.read().decode("utf-8", errors="replace")
except Exception:
pass
raise RuntimeError(f"Message API HTTPError: status={exc.code}, body={body}") from exc
except URLError as exc:
raise RuntimeError(f"Message API URLError: {exc}") from exc
try:
return json.loads(body) if body else {}
except Exception as exc:
raise RuntimeError(f"Message API 响应不是合法 JSON: {body}") from exc
def _get_message_api_base_url() -> str:
base_url = str(getattr(settings, "MESSAGE_API_BASE_URL", "") or "").strip().rstrip("/")
if not base_url:
raise ValueError("MESSAGE_API_BASE_URL 未配置")
return base_url
def _get_message_api_authorization() -> str:
authorization = str(getattr(settings, "MESSAGE_API_AUTHORIZATION", "") or "").strip()
if not authorization:
raise ValueError("MESSAGE_API_AUTHORIZATION 未配置")
return authorization
def _build_url(path: str) -> str:
return urljoin(f"{_get_message_api_base_url()}/", path.lstrip("/"))
def _post_message_api(*, path: str, payload: dict, timeout_seconds: float) -> dict:
raw = _request_json(
url=_build_url(path),
method="POST",
payload=payload,
timeout_seconds=timeout_seconds,
headers={
"Authorization": _get_message_api_authorization(),
"Content-Type": "application/json",
},
)
return raw
def send_message_api_text_message(
*,
agent_id: int,
content: str,
user_ids: list[str] | None = None,
timeout_seconds: float = 10.0,
) -> MessageAPIResponse:
payload = {
"agent_id": int(agent_id),
"content": str(content or "").strip(),
}
if user_ids:
payload["user_ids"] = user_ids
raw = _post_message_api(path="/api/message/send", payload=payload, timeout_seconds=timeout_seconds)
return MessageAPIResponse(
errcode=int(raw.get("errcode") or 0),
errmsg=str(raw.get("errmsg") or ""),
raw=raw,
)
def send_message_api_news_to_agents(
*,
agent_ids: list[int],
title: str,
description: str,
url: str,
image_url: str,
user_ids: list[str] | None = None,
timeout_seconds: float = 10.0,
) -> list[dict]:
payload = {
"agent_ids": [int(agent_id) for agent_id in agent_ids],
"title": title,
"description": description,
"url": url,
"image_url": image_url,
}
if user_ids:
payload["user_ids"] = user_ids
raw = _post_message_api(path="/api/message/send/news", payload=payload, timeout_seconds=timeout_seconds)
return raw.get("results") or []