Files
aiagent/backend/app/services/push_service.py
renjianbo beff3fac8d fix: delete agent 500 error + dynamic personality + deployment guide
- Fix delete agent 500: clean up FK records (agent_llm_logs, permissions,
  schedules, executions, team_members) and unbind goals/tasks before delete
- Remove hardcoded personality templates in Android, replace with dynamic
  system prompt generation from name + description
- Set promptSectionsEnabled=false to bypass PromptComposer for personality
- Add Tencent Cloud Linux deployment guide (Docker Compose)
- Accumulated backend service updates, frontend UI fixes, Android app changes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-29 01:17:21 +08:00

125 lines
3.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""浏览器推送通知服务 — Web Push Protocol (RFC 8291)"""
from __future__ import annotations
import json
import logging
from typing import Optional
from app.core.database import SessionLocal
from app.models.push_subscription import PushSubscription
logger = logging.getLogger(__name__)
async def send_push_to_user(
user_id: str,
title: str,
body: str = "",
url: str = "/",
require_interaction: bool = False,
) -> int:
"""向指定用户的所有设备发送推送通知。返回成功发送数。"""
db = SessionLocal()
sent = 0
try:
subs = (
db.query(PushSubscription)
.filter(PushSubscription.user_id == user_id)
.all()
)
for sub in subs:
ok = await _send_webpush(
endpoint=sub.endpoint,
p256dh=sub.p256dh,
auth=sub.auth,
title=title,
body=body,
url=url,
require_interaction=require_interaction,
)
if ok:
sent += 1
return sent
finally:
db.close()
async def broadcast_push(
title: str,
body: str = "",
url: str = "/",
) -> int:
"""向所有已订阅用户广播推送通知。"""
db = SessionLocal()
sent = 0
try:
subs = db.query(PushSubscription).all()
for sub in subs:
ok = await _send_webpush(
endpoint=sub.endpoint,
p256dh=sub.p256dh,
auth=sub.auth,
title=title,
body=body,
url=url,
require_interaction=False,
)
if ok:
sent += 1
return sent
finally:
db.close()
async def _send_webpush(
endpoint: str,
p256dh: str,
auth: str,
title: str,
body: str,
url: str = "/",
require_interaction: bool = False,
) -> bool:
"""发送单条 Web Push 消息。使用 pywebpush 或直接 HTTP POST。"""
payload = json.dumps({
"title": title,
"body": body,
"data": {"url": url},
"requireInteraction": require_interaction,
"icon": "/icons/icon-192.png",
"badge": "/icons/icon-192.png",
})
try:
# 尝试 pywebpush如果已安装
try:
from pywebpush import WebPusher, WebPushException
wp = WebPusher({
"endpoint": endpoint,
"keys": {"p256dh": p256dh, "auth": auth},
})
wp.send(payload, timeout=10)
return True
except ImportError:
pass
# Fallback: 直接 HTTP POST不加密仅用于开发环境
import aiohttp
async with aiohttp.ClientSession() as session:
async with session.post(
endpoint,
data=payload,
headers={
"Content-Type": "application/json",
"TTL": "86400",
},
timeout=aiohttp.ClientTimeout(total=10),
) as resp:
ok = resp.status in (200, 201, 204)
if not ok:
logger.warning("Push 发送失败: status=%d", resp.status)
return ok
except Exception as e:
logger.error("Push 发送异常: %s", e)
return False