Rooms and Connections
When Priya posts a message in Team 4’s room, the server has to send it on the WebSocket of every member of that room who has Courselore open. So for each room, the server needs to know which open connections belong to the room’s members.
The server keeps a set for each room, in memory:
Team 4's room -> { Priya's connection, Marcus's connection, ... }
General -> { Priya's connection, Marcus's connection, ... }
When Marcus’s WebSocket opens, the server authenticates the handshake and learns that the connection belongs to Marcus. It finds the rooms Marcus may read in course 7: the course’s public rooms, and the private rooms Marcus is a member of. It adds the connection to the set of each of those rooms. When the connection closes, the server removes it from every set.
Sending a new message
Here is the POST handler:
app.post("/rooms/:roomId/messages", async (req, res) => {
const message = await saveMessage(req.params.roomId, req.body);
res.status(201).json(message);
sendToRoom(req.params.roomId, { type: "message.created", message });
});
After the server saves the message and answers Priya, sendToRoom sends the message on every connection in the room’s set. Typing events go to the same set, but the server does not save them.
This is a sketch. A real server also authenticates the POST and checks that Priya may post in the room.
Removing a member
The server finds Marcus’s rooms only once, when Marcus’s WebSocket opens. Suppose an instructor removes Marcus from Team 4’s room while the WebSocket is open. The server deletes Marcus’s row from chat_room_members, but Marcus’s connection is still in the room’s set. Every message posted in the room still reaches Marcus’s screen.
So removing a member must also remove the member’s connections from the room’s set. There may be more than one, if Marcus has Courselore open in two tabs.