File size: 4,799 Bytes
abc1805
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
const { createServer } = require("http");
const { Server } = require("socket.io");

const httpServer = createServer();
const io = new Server(httpServer, {
    cors: {
        origin: "*",
        methods: ["GET", "POST"],
    },
});

// Track room users: RoomId -> UserId -> SocketCount
const roomUsers = new Map();
// Track room limits: RoomId -> Limit
const roomLimits = new Map();
// Track nicknames: SocketId -> Nickname
const socketNicknames = new Map();

io.on("connection", (socket) => {
    console.log("Client connected:", socket.id);
    const userId = socket.handshake.auth.userId;

    if (!userId) {
        console.log("No userId provided, ignoring");
        return;
    }

    socket.on("join-room", async ({ roomId, nickname, userLimit }) => {
        // Set limit if provided (room creation)
        if (userLimit && !roomLimits.has(roomId)) {
            roomLimits.set(roomId, userLimit);
        }

        // Check limit
        const currentLimit = roomLimits.get(roomId) || 10; // Default 10
        const users = roomUsers.get(roomId);
        const currentUniqueUsers = users ? users.size : 0;

        // If user is NEW to the room (not just a refresh) and room is full
        const isNewUser = !users || !users.has(userId);

        if (isNewUser && currentUniqueUsers >= currentLimit) {
            socket.emit("error", "Room is full");
            return;
        }

        socket.join(roomId);
        if (nickname) {
            socketNicknames.set(socket.id, nickname);
        }
        console.log(`Socket ${socket.id} (User ${userId}) joined room ${roomId}`);

        // Initialize room tracking if needed
        if (!roomUsers.has(roomId)) {
            roomUsers.set(roomId, new Map());
        }
        const roomUserMap = roomUsers.get(roomId);

        // Increment socket count for this user
        const currentCount = roomUserMap.get(userId) || 0;
        roomUserMap.set(userId, currentCount + 1);

        // ALWAYS notify others about the new socket for Key Exchange
        // Include nickname in the event
        socket.to(roomId).emit("user-joined", { socketId: socket.id, userId, nickname });

        // Broadcast new unique user count to EVERYONE (including sender)
        io.to(roomId).emit("room-info", { count: roomUserMap.size, limit: currentLimit });
    });

    socket.on("send-message", (data) => {
        // data: { roomId, encryptedMessage, senderId, messageId }
        // Broadcast to others in the room
        socket.to(data.roomId).emit("receive-message", data);
    });

    socket.on("message-delivered", (data) => {
        // data: { roomId, messageId, senderId, recipientId }
        io.to(data.roomId).emit("message-status", {
            messageId: data.messageId,
            status: "delivered",
            recipientId: data.recipientId,
            originalSenderId: data.senderId
        });
    });

    socket.on("message-read", (data) => {
        io.to(data.roomId).emit("message-status", {
            messageId: data.messageId,
            status: "read",
            recipientId: data.recipientId,
            originalSenderId: data.senderId
        });
    });

    socket.on("signal", (data) => {
        // WebRTC/Key Exchange signaling
        // data: { target, signal, sender }
        io.to(data.target).emit("signal", {
            sender: socket.id,
            signal: data.signal,
        });
    });

    socket.on("disconnecting", () => {
        for (const roomId of socket.rooms) {
            if (roomId !== socket.id) {
                const users = roomUsers.get(roomId);
                if (users) {
                    const currentCount = users.get(userId) || 0;
                    if (currentCount > 1) {
                        users.set(userId, currentCount - 1);
                    } else {
                        users.delete(userId);
                        if (users.size === 0) {
                            roomUsers.delete(roomId);
                            roomLimits.delete(roomId);
                        }
                    }

                    // Always notify about socket leaving for Key Cleanup
                    socket.to(roomId).emit("user-left", { socketId: socket.id, userId });
                    socketNicknames.delete(socket.id);

                    // Broadcast new count
                    io.to(roomId).emit("room-info", { count: users.size });
                }
            }
        }
    });

    socket.on("disconnect", () => {
        console.log("Client disconnected:", socket.id);
    });
});

httpServer.listen(3001, () => {
    console.log("Test server ready on http://localhost:3001");
});