Skip to content

Commit 0fb85c3

Browse files
committed
feat: enhance logging and error handling in collab server
1 parent afb650d commit 0fb85c3

1 file changed

Lines changed: 133 additions & 120 deletions

File tree

src/index.ts

Lines changed: 133 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,136 +1,149 @@
1-
import { Server as SocketIO } from "socket.io";
1+
import {Server as SocketIO} from "socket.io";
2+
import logger from "./logger";
23

34
type UserToFollow = {
4-
socketId: string;
5-
username: string;
5+
socketId: string;
6+
username: string;
67
};
78
type OnUserFollowedPayload = {
8-
userToFollow: UserToFollow;
9-
action: "FOLLOW" | "UNFOLLOW";
9+
userToFollow: UserToFollow;
10+
action: "FOLLOW" | "UNFOLLOW";
1011
};
1112

1213
const port = process.env.PORT || 3002; // default port to listen
13-
14-
console.log("Trying to use port %s", port);
15-
16-
try {
17-
const io = new SocketIO({
18-
transports: ["websocket", "polling"],
19-
cors: {
20-
allowedHeaders: ["Content-Type", "Authorization"],
21-
origin: process.env.CORS_ORIGIN || "*",
22-
credentials: true,
23-
},
24-
allowEIO3: true,
25-
});
26-
27-
io.on("connection", (socket) => {
28-
console.log("connection established!");
29-
30-
io.to(`${socket.id}`).emit("init-room");
31-
32-
socket.on("join-room", async (roomID) => {
33-
console.log(`${socket.id} has joined ${roomID}`);
34-
35-
await socket.join(roomID);
36-
37-
const sockets = await io.in(roomID).fetchSockets();
38-
if (sockets.length <= 1) {
39-
io.to(`${socket.id}`).emit("first-in-room");
40-
} else {
41-
console.log(`${socket.id} new-user emitted to room ${roomID}`);
42-
socket.broadcast.to(roomID).emit("new-user", socket.id);
43-
}
44-
45-
io.in(roomID).emit(
46-
"room-user-change",
47-
sockets.map((socket) => socket.id),
48-
);
49-
});
50-
51-
socket.on(
52-
"server-broadcast",
53-
(roomID: string, encryptedData: ArrayBuffer, iv: Uint8Array) => {
54-
console.log(`${socket.id} sends update to ${roomID}`);
55-
socket.broadcast.to(roomID).emit("client-broadcast", encryptedData, iv);
56-
},
57-
);
58-
59-
socket.on(
60-
"server-volatile-broadcast",
61-
(roomID: string, encryptedData: ArrayBuffer, iv: Uint8Array) => {
62-
console.log(`${socket.id} sends volatile update to ${roomID}`);
63-
socket.volatile.broadcast
64-
.to(roomID)
65-
.emit("client-broadcast", encryptedData, iv);
66-
},
67-
);
68-
69-
socket.on("user-follow", async (payload: OnUserFollowedPayload) => {
70-
const roomID = `follow@${payload.userToFollow.socketId}`;
71-
72-
switch (payload.action) {
73-
case "FOLLOW": {
74-
await socket.join(roomID);
75-
76-
const sockets = await io.in(roomID).fetchSockets();
77-
const followedBy = sockets.map((socket) => socket.id);
78-
79-
io.to(payload.userToFollow.socketId).emit(
80-
"user-follow-room-change",
81-
followedBy,
82-
);
83-
84-
break;
85-
}
86-
case "UNFOLLOW": {
87-
await socket.leave(roomID);
88-
89-
const sockets = await io.in(roomID).fetchSockets();
90-
const followedBy = sockets.map((socket) => socket.id);
91-
92-
io.to(payload.userToFollow.socketId).emit(
93-
"user-follow-room-change",
94-
followedBy,
95-
);
96-
97-
break;
14+
const roomPrefix = "follow@"
15+
16+
function withErrorHandling<T extends (...args: any[]) => any>(handler: T) {
17+
return async (...args: Parameters<T>) => {
18+
try {
19+
await handler(...args);
20+
} catch (error) {
21+
logger.error(`Server-error: ${error instanceof Error ? error.stack : error}`);
9822
}
99-
}
100-
});
101-
102-
socket.on("disconnecting", async () => {
103-
console.log(`${socket.id} has disconnected`);
104-
for (const roomID of Array.from(socket.rooms)) {
105-
const otherClients = (await io.in(roomID).fetchSockets()).filter(
106-
(_socket) => _socket.id !== socket.id,
107-
);
108-
109-
const isFollowRoom = roomID.startsWith("follow@");
23+
};
24+
}
11025

111-
if (!isFollowRoom && otherClients.length > 0) {
112-
socket.broadcast.to(roomID).emit(
113-
"room-user-change",
114-
otherClients.map((socket) => socket.id),
115-
);
116-
}
26+
logger.info(`Trying to use port ${port}`);
11727

118-
if (isFollowRoom && otherClients.length === 0) {
119-
const socketId = roomID.replace("follow@", "");
120-
io.to(socketId).emit("broadcast-unfollow");
121-
}
122-
}
28+
try {
29+
const io = new SocketIO({
30+
transports: ["websocket", "polling"],
31+
cors: {
32+
allowedHeaders: ["Content-Type", "Authorization"],
33+
origin: process.env.CORS_ORIGIN || "*",
34+
credentials: true,
35+
},
36+
allowEIO3: true,
12337
});
12438

125-
socket.on("disconnect", () => {
126-
socket.removeAllListeners();
127-
socket.disconnect();
39+
io.on("connection", (socket) => {
40+
logger.info("connection established!");
41+
42+
io.to(`${socket.id}`).emit("init-room");
43+
44+
socket.on("join-room", withErrorHandling(async (roomID) => {
45+
logger.info(`${socket.id} has joined ${roomID}`);
46+
47+
await socket.join(roomID);
48+
49+
const sockets = await io.in(roomID).fetchSockets();
50+
if (sockets.length <= 1) {
51+
io.to(`${socket.id}`).emit("first-in-room");
52+
} else {
53+
logger.info(`${socket.id} new-user emitted to room ${roomID}`);
54+
socket.broadcast.to(roomID).emit("new-user", socket.id);
55+
}
56+
57+
io.in(roomID).emit(
58+
"room-user-change",
59+
sockets.map((socket) => socket.id),
60+
);
61+
}));
62+
63+
socket.on(
64+
"server-broadcast", withErrorHandling(
65+
(roomID: string, encryptedData: ArrayBuffer, iv: Uint8Array) => {
66+
logger.info(`${socket.id} sends update to ${roomID}`);
67+
socket.broadcast.to(roomID).emit("client-broadcast", encryptedData, iv);
68+
},
69+
));
70+
71+
socket.on(
72+
"server-volatile-broadcast", withErrorHandling(
73+
(roomID: string, encryptedData: ArrayBuffer, iv: Uint8Array) => {
74+
logger.info(`${socket.id} sends volatile update to ${roomID}`);
75+
socket.volatile.broadcast
76+
.to(roomID)
77+
.emit("client-broadcast", encryptedData, iv);
78+
},
79+
));
80+
81+
socket.on("user-follow", withErrorHandling(async (payload: OnUserFollowedPayload) => {
82+
const roomID = `${roomPrefix}${payload.userToFollow.socketId}`;
83+
84+
switch (payload.action) {
85+
case "FOLLOW": {
86+
await socket.join(roomID);
87+
88+
const sockets = await io.in(roomID).fetchSockets();
89+
const followedBy = sockets.map((socket) => socket.id);
90+
91+
io.to(payload.userToFollow.socketId).emit(
92+
"user-follow-room-change",
93+
followedBy,
94+
);
95+
96+
break;
97+
}
98+
case "UNFOLLOW": {
99+
await socket.leave(roomID);
100+
101+
const sockets = await io.in(roomID).fetchSockets();
102+
const followedBy = sockets.map((socket) => socket.id);
103+
104+
io.to(payload.userToFollow.socketId).emit(
105+
"user-follow-room-change",
106+
followedBy,
107+
);
108+
109+
break;
110+
}
111+
}
112+
}));
113+
114+
socket.on("disconnecting", withErrorHandling(async () => {
115+
logger.info(`${socket.id} is preparing to disconnect...`);
116+
for (const roomID of Array.from(socket.rooms)) {
117+
const otherClients = (await io.in(roomID).fetchSockets()).filter(
118+
(_socket) => _socket.id !== socket.id,
119+
);
120+
121+
const isFollowRoom = roomID.startsWith(roomPrefix);
122+
123+
if (!isFollowRoom && otherClients.length > 0) {
124+
socket.broadcast.to(roomID).emit(
125+
"room-user-change",
126+
otherClients.map((socket) => socket.id),
127+
);
128+
}
129+
130+
if (isFollowRoom && otherClients.length === 0) {
131+
const socketId = roomID.replace(roomPrefix, "");
132+
io.to(socketId).emit("broadcast-unfollow");
133+
}
134+
}
135+
}));
136+
137+
socket.on("disconnect", withErrorHandling(() => {
138+
//socket.removeAllListeners();
139+
//socket.disconnect();
140+
logger.info(`... ${socket.id} disconnected`);
141+
}));
128142
});
129-
});
130143

131-
console.log("Starting server...");
132-
io.listen(Number(port));
133-
console.log("... started!");
144+
logger.info("Starting server...");
145+
io.listen(Number(port));
146+
logger.info("... started!");
134147
} catch (error) {
135-
console.error(error);
148+
logger.error(`Server-error: ${error instanceof Error ? error.stack : error}`);
136149
}

0 commit comments

Comments
 (0)