Files
pit-router/app/socketio/handlers.py

183 lines
5.5 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.
"""
Socket.IO 事件处理
"""
from flask_socketio import emit, join_room, leave_room
from flask_jwt_extended import decode_token
from datetime import datetime
import json
from app.extensions import redis_client
# 连接管理器
class ConnectionManager:
def __init__(self):
self.user_sockets = {} # user_id -> socket_id
self.agent_sockets = {} # agent_id -> socket_id
self.socket_sessions = {} # socket_id -> session_id
connection_manager = ConnectionManager()
def register_handlers(socketio):
"""注册 Socket.IO 事件处理器"""
@socketio.on('connect')
def handle_connect():
"""客户端连接"""
print('Client connected')
# 发送认证请求
emit('auth', {'message': 'Please authenticate'})
@socketio.on('disconnect')
def handle_disconnect():
"""客户端断开连接"""
from flask import request
sid = request.sid
print(f'Client disconnected: {sid}')
# 清理连接
if sid in connection_manager.socket_sessions:
del connection_manager.socket_sessions[sid]
@socketio.on('auth')
def handle_auth(data):
"""处理认证"""
from flask import request
sid = request.sid
token = data.get('token')
if not token:
emit('auth_error', {'code': 'MISSING_TOKEN', 'message': 'Token is required'})
return
try:
# 验证 JWT Token
decoded = decode_token(token)
user_id = decoded['sub']
# 保存连接信息
connection_manager.user_sockets[user_id] = sid
# 存储到 Redis
redis_client.hset(f'socket:{sid}', mapping={
'user_id': user_id,
'connected_at': datetime.utcnow().isoformat()
})
redis_client.expire(f'socket:{sid}', 86400)
emit('authenticated', {
'user_id': user_id,
'socket_id': sid
})
except Exception as e:
emit('auth_error', {'code': 'INVALID_TOKEN', 'message': str(e)})
@socketio.on('ping')
def handle_ping(data):
"""心跳响应"""
emit('pong', {'timestamp': datetime.utcnow().timestamp()})
@socketio.on('session.create')
def handle_session_create(data):
"""创建会话"""
from app.models import db, Session, Agent
user_id = data.get('user_id')
title = data.get('title', 'New Session')
agent_id = data.get('agent_id')
# 如果没有指定 Agent分配一个
if not agent_id:
agent = Agent.query.filter_by(status='online').first()
if agent:
agent_id = agent.id
session = Session(
user_id=user_id,
primary_agent_id=agent_id,
title=title
)
db.session.add(session)
db.session.commit()
emit('session.created', {
'session_id': session.id,
'agent_id': agent_id
})
@socketio.on('session.join')
def handle_session_join(data):
"""加入会话"""
from flask import request
from app.models import Session
sid = request.sid
session_id = data.get('session_id')
# 加入房间
join_room(session_id)
connection_manager.socket_sessions[sid] = session_id
session = Session.query.get(session_id)
if session:
emit('session.joined', {
'session_id': session_id,
'participants': [session.user_id, session.primary_agent_id]
})
@socketio.on('message.send')
def handle_message_send(data):
"""发送消息"""
from flask import request
from app.models import db, Message, Session
sid = request.sid
session_id = data.get('session_id')
content = data.get('content')
sender_type = data.get('sender_type', 'user')
sender_id = data.get('sender_id')
# 创建消息
message = Message(
session_id=session_id,
sender_type=sender_type,
sender_id=sender_id,
content=content,
status='sent'
)
db.session.add(message)
# 更新会话
session = Session.query.get(session_id)
if session:
session.message_count += 1
session.last_active_at = datetime.utcnow()
db.session.commit()
# 广播消息到房间
emit('message', {
'message_id': message.id,
'session_id': session_id,
'sender': {'type': sender_type, 'id': sender_id},
'content': content,
'timestamp': datetime.utcnow().isoformat()
}, room=session_id)
@socketio.on('message.ack')
def handle_message_ack(data):
"""消息确认"""
from app.models import db, Message
message_id = data.get('message_id')
status = data.get('status')
message = Message.query.get(message_id)
if message:
message.ack_status = status
if status == 'acknowledged':
message.status = 'delivered'
message.delivered_at = datetime.utcnow()
db.session.commit()
emit('message.acked', {'message_id': message_id, 'status': status})