"""念念回音服务""" 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