77 lines
2.3 KiB
Python
77 lines
2.3 KiB
Python
"""Webhook推送器"""
|
||
import requests
|
||
import time
|
||
from typing import List
|
||
|
||
|
||
class WebhookSender:
|
||
"""企微Webhook推送器"""
|
||
|
||
MAX_BYTES = 4096 # 企微消息最大字节数
|
||
|
||
def __init__(self, webhook_url: str, logger):
|
||
self.webhook_url = webhook_url
|
||
self.logger = logger
|
||
|
||
def send_markdown(self, content: str, mentioned_list: List[str]) -> bool:
|
||
"""发送Markdown消息,自动分段"""
|
||
messages = self._split_by_bytes(content)
|
||
|
||
for msg in messages:
|
||
if not self._send_single(msg, mentioned_list):
|
||
return False
|
||
time.sleep(1) # 避免频率限制
|
||
|
||
return True
|
||
|
||
def _split_by_bytes(self, content: str) -> List[str]:
|
||
"""按字节长度分段,不切断单个用户的过期单"""
|
||
lines = content.split('\n')
|
||
messages = []
|
||
current = []
|
||
current_bytes = 0
|
||
|
||
for line in lines:
|
||
line_bytes = len(line.encode('utf-8')) + 1 # +1 for \n
|
||
|
||
if current_bytes + line_bytes > self.MAX_BYTES and current:
|
||
messages.append('\n'.join(current))
|
||
current = [line]
|
||
current_bytes = line_bytes
|
||
else:
|
||
current.append(line)
|
||
current_bytes += line_bytes
|
||
|
||
if current:
|
||
messages.append('\n'.join(current))
|
||
|
||
return messages
|
||
|
||
def _send_single(self, content: str, mentioned_list: List[str]) -> bool:
|
||
"""发送单条消息"""
|
||
payload = {
|
||
"msgtype": "markdown",
|
||
"markdown": {
|
||
"content": content
|
||
},
|
||
"mentioned_list": mentioned_list
|
||
}
|
||
|
||
for attempt in range(3):
|
||
try:
|
||
response = requests.post(self.webhook_url, json=payload, timeout=10)
|
||
response.raise_for_status()
|
||
result = response.json()
|
||
|
||
self.logger.log_api_call("wework", "webhook/send", payload, result, result.get('errcode') == 0)
|
||
|
||
if result.get('errcode') == 0:
|
||
return True
|
||
except Exception as e:
|
||
self.logger.log_api_call("wework", "webhook/send", payload, {}, False, str(e))
|
||
|
||
if attempt < 2:
|
||
time.sleep(30)
|
||
|
||
return False
|