feat(chat): 聊天功能

This commit is contained in:
xingc
2025-04-03 17:27:05 +08:00
parent 70e0e5b034
commit 4d06b97cf4
4 changed files with 385 additions and 0 deletions

View File

@@ -0,0 +1,119 @@
# -*- coding = utf-8 -*-
# @Time : 2025/3/1 下午4:40
# @File : handlers.py
# @Software : PyCharm
# @Author : xingc
# @Desc :
import logging
from datetime import datetime
from typing import List, Dict
import redis.asyncio as aioredis
from fastapi import WebSocket
from sqlalchemy.ext.asyncio import AsyncSession
from core.db.crud import CRUD
from core.db.models import ReadStatus, User, Chat, Message
from .managers import SocketManager
from . import schema
logger = logging.getLogger(__name__)
socket_manager = SocketManager()
@socket_manager.handler('chat.new_message')
async def send_new_message(
websocket: WebSocket,
db_session: AsyncSession,
cache: aioredis.Redis,
chats: dict,
current_user: User,
incoming_message: schema.Message,
):
chat_guid: str = str(incoming_message.chat_guid)
chat: Chat | None = await CRUD(db_session, Chat).get(filters={'chat_guid': chat_guid})
# 判断是否为新聊天
if not chats or chat_guid not in chats:
if chat:
chats[chat_guid] = chat.id
await socket_manager.add_user_to_chat(chat_guid, websocket)
else:
await socket_manager.send_error('聊天尚未添加', websocket)
return
chat_id = chats.get(chat_guid)
try:
message = Message(
guid=incoming_message.message_guid,
user_id=current_user.user_id,
chat_id=chat_id,
message_type=incoming_message.message_type,
content=incoming_message.body,
)
db_session.add(message)
await db_session.flush()
chat.updated_at = datetime.now()
db_session.add(chat)
await db_session.commit()
await db_session.refresh(message, attribute_names=["user", "chat"])
await db_session.refresh(chat, attribute_names=["users"])
except Exception as exc_info:
await db_session.rollback()
logger.exception(f"[new_message] Exception, rolling back session, detail: {exc_info}")
raise exc_info
send_message_schema = schema.MessageOut(
type='chat.new_message',
message_id=message.id,
message_guid=message.guid,
message_type=message.message_type,
chat_guid=chat.guid,
user_id=current_user.user_id,
content=message.content,
created_at=message.created_at,
friend_user=current_user,
)
await socket_manager.broadcast_to_chat(chat_guid, send_message_schema.dict())
@socket_manager.handler('chat.refresh_unread_messages')
async def refresh_unread_messages(
websocket: WebSocket,
db_session: AsyncSession,
cache: aioredis.Redis,
current_user: User,
message: schema.Message,
):
pass
@socket_manager.handler('chat.message_read')
async def read_message(
websocket: WebSocket,
db_session: AsyncSession,
cache: aioredis.Redis,
current_user: User,
message: schema.Message,
):
last_read_message_id: str | None = message.body
if not last_read_message_id:
return
db_crud = CRUD(db_session, ReadStatus)
condition = {
'user_id': current_user.user_id,
'chat_guid': message.chat_guid,
}
result = await db_crud.update(filters=condition, data={'last_read_message_id': last_read_message_id})
if result is None:
await db_crud.create(
data={
**condition,
'last_read_message_id': last_read_message_id
},
filters=condition
)