ForcePilot/backend/package/yuxi/channels/adapters/synologychat/webhook_send.py
Kris 1f78c44b03 refactor: 整理并清理项目中的冗余代码与格式问题
这是一个批量整理提交,包含以下主要改动:
1.  删除多处冗余的空行和未使用的导入
2.  修复文件末尾缺少换行符的问题
3.  调整部分模块的导入顺序与代码排版
4.  修复部分配置默认值与策略逻辑
5.  新增多个功能模块与辅助工具
6.  完善异常处理与日志记录
7.  修复速率限制、消息缓存、权限校验等逻辑bug
8.  废弃部分旧有API与配置项并添加警告提示
2026-05-12 14:51:53 +08:00

66 lines
2.4 KiB
Python

"""Incoming Webhook sender for Synology Chat.
Provides an alternative send path via Synology Chat's Incoming Webhook URL,
as a lighter-weight alternative to the DSM API direct connection.
"""
from __future__ import annotations
from typing import Any
import httpx
from yuxi.channels.adapters.synologychat.send import assert_safe_media_url
from yuxi.channels.models import DeliveryResult
from yuxi.utils.logging_config import logger
async def send_via_incoming_webhook(
webhook_url: str,
text: str,
file_url: str | None = None,
timeout: float = 30.0,
client: httpx.AsyncClient | None = None,
) -> DeliveryResult:
if not webhook_url:
return DeliveryResult(success=False, error="Incoming webhook URL not configured")
try:
await assert_safe_media_url(webhook_url)
except Exception as e:
return DeliveryResult(success=False, error=f"SSRF check failed: {e}")
payload: dict[str, Any] = {"text": text}
if file_url:
payload["file_url"] = file_url
async def _do_send(http_client: httpx.AsyncClient) -> DeliveryResult:
response = await http_client.post(webhook_url, data=payload)
response.raise_for_status()
result = response.json()
if result.get("success"):
return DeliveryResult(success=True, message_id=result.get("data", {}).get("message_id"))
return DeliveryResult(
success=False,
error=f"Webhook send failed: {result.get('error', {})}",
)
try:
if client:
return await _do_send(client)
async with httpx.AsyncClient(timeout=httpx.Timeout(timeout)) as new_client:
return await _do_send(new_client)
except httpx.TimeoutException:
return DeliveryResult(success=False, error="Incoming webhook request timed out")
except httpx.HTTPStatusError as e:
return DeliveryResult(success=False, error=f"Incoming webhook HTTP {e.response.status_code}")
except Exception as e:
logger.error(f"[SynologyChat] Incoming webhook send failed: {e}")
return DeliveryResult(success=False, error=str(e))
def build_webhook_url(dsm_url: str, webhook_token: str) -> str:
"""Build a Synology Chat Incoming Webhook URL from DSM URL and token."""
base = dsm_url.rstrip("/")
return f"{base}/webapi/entry.cgi?api=SYNO.Chat.External&method=incoming&version=1&token={webhook_token}"