File size: 1,672 Bytes
ae4ceef
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import { Server as SocketServer } from 'socket.io';
import { Server as HttpServer } from 'http';
import jwt from 'jsonwebtoken';

let io: SocketServer | null = null;
const JWT_SECRET = process.env.JWT_SECRET || 'codex_secret_fallback';

export const initSocket = (server: HttpServer) => {
  io = new SocketServer(server, {
    cors: {
      origin: '*',
      methods: ['GET', 'POST']
    }
  });

  // 增加 JWT 鉴权中间件
  io.use((socket, next) => {
    const token = socket.handshake.auth.token || socket.handshake.headers.token;
    if (!token) return next(new Error('未授权'));

    try {
      const decoded = jwt.verify(token, JWT_SECRET) as any;
      (socket as any).user = decoded;
      next();
    } catch (err) {
      next(new Error('Token 无效'));
    }
  });

  io.on('connection', (socket) => {
    const user = (socket as any).user;
    console.log(`[Socket] 用户已认证并连接: ${user.email} (ID: ${socket.id})`);

    // 自动加入用户专属房间
    socket.join(`user:${user.userId}`);

    socket.on('disconnect', () => {
      console.log(`[Socket] 用户断开: ${user.email}`);
    });
  });

  return io;
};

export const getIO = () => {
  if (!io) throw new Error('Socket.io 未初始化');
  return io;
};

/**
 * 推送实时通知给特定用户
 */
export const notifyUser = (userId: string, event: string, data: any) => {
  if (io) {
    io.to(`user:${userId}`).emit(event, data);
  }
};

/**
 * 推送广播给所有管理员
 */
export const broadcastAdmin = (event: string, data: any) => {
  if (io) {
    // 假设管理员在一个特定的房间,或者直接广播
    io.emit(`admin:${event}`, data);
  }
};