Files
chat/backend/app/services/echo_service.py
T
2026-06-14 09:25:59 +08:00

98 lines
3.5 KiB
Python

"""念念回音服务"""
import hashlib
import uuid
from datetime import datetime
from sqlalchemy import select, or_
from sqlalchemy.ext.asyncio import AsyncSession
from app.models.miss_echo import MissEcho
from app.models.user import User
from app.websocket.events import EventType
from app.websocket.manager import manager
class EchoService:
def __init__(self, db: AsyncSession):
self.db = db
async def send_echo(self, from_user_id: str, to_user_id: str,
message: str | None = None) -> dict:
"""发送一片回音叶"""
if from_user_id == to_user_id:
raise ValueError("不能给自己回音")
# 校验目标用户存在
target_result = await self.db.execute(select(User).where(User.id == to_user_id))
if not target_result.scalars().first():
raise ValueError("目标用户不存在")
# 派生叶子种子
today = datetime.utcnow().strftime("%Y%m%d")
seed = hashlib.md5(f"echo:{from_user_id}:{to_user_id}:{today}".encode()).hexdigest()[:16]
is_online = manager.is_online(to_user_id)
echo = MissEcho(
id=str(uuid.uuid4()),
from_user_id=from_user_id,
to_user_id=to_user_id,
leaf_seed=seed,
message=message,
delivered_online=is_online,
)
self.db.add(echo)
await self.db.flush()
# 发送者信息
from_result = await self.db.execute(select(User).where(User.id == from_user_id))
from_user = from_result.scalars().first()
payload = {
"id": echo.id,
"from_user_id": from_user_id,
"from_username": from_user.username if from_user else "未知",
"from_nickname": from_user.nickname if from_user else None,
"from_avatar": from_user.avatar_url if from_user else None,
"leaf_seed": seed,
"message": message,
"delivered_online": is_online,
"created_at": echo.created_at.isoformat(),
}
# 在线则实时推送,离线则在用户下次打开时收到(落入花园)
if is_online:
await manager.send_to_user(to_user_id, EventType.ECHO_SEND, payload)
return payload
async def get_echoes(self, user_id: str, limit: int = 30) -> list[dict]:
"""获取我收到的回音(花园里飘落的叶子)"""
result = await self.db.execute(
select(MissEcho).where(
or_(
MissEcho.to_user_id == user_id,
MissEcho.from_user_id == user_id,
)
).order_by(MissEcho.created_at.desc()).limit(limit)
)
echoes = []
for e in result.scalars().all():
from_result = await self.db.execute(select(User).where(User.id == e.from_user_id))
fu = from_result.scalars().first()
echoes.append({
"id": e.id,
"from_user_id": e.from_user_id,
"to_user_id": e.to_user_id,
"from_username": fu.username if fu else "未知",
"from_nickname": fu.nickname if fu else None,
"from_avatar": fu.avatar_url if fu else None,
"leaf_seed": e.leaf_seed,
"message": e.message,
"delivered_online": e.delivered_online,
"is_received": e.to_user_id == user_id,
"created_at": e.created_at.isoformat(),
})
return echoes