-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.js
More file actions
114 lines (95 loc) · 3.5 KB
/
Copy pathserver.js
File metadata and controls
114 lines (95 loc) · 3.5 KB
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
const { createServer } = require("http");
const next = require("next");
const { Server } = require("socket.io");
const { getToken } = require("next-auth/jwt");
const dev = process.env.NODE_ENV !== "production";
const hostname = process.env.HOSTNAME || "0.0.0.0";
const port = parseInt(process.env.PORT || "3000", 10);
const app = next({ dev, hostname, port });
const handle = app.getRequestHandler();
app.prepare().then(() => {
const httpServer = createServer();
// 1. Socket.io BEFORE Next.js to intercept /api/socketio requests first
const allowedOrigin = process.env.NEXTAUTH_URL || process.env.NEXT_PUBLIC_APP_URL || "*";
const io = new Server(httpServer, {
path: "/api/socketio",
cors: {
origin: dev ? "*" : allowedOrigin,
methods: ["GET", "POST"],
credentials: true,
},
});
// Middleware Socket.io : vérifie le JWT NextAuth avant toute connexion
io.use(async (socket, next) => {
try {
// Le cookie de session est transmis automatiquement par le navigateur
const req = socket.request;
const token = await getToken({
req,
secret: process.env.NEXTAUTH_SECRET,
secureCookie: process.env.NEXTAUTH_URL?.startsWith("https://") ?? false,
});
if (!token || !token.id) {
return next(new Error("Non authentifié"));
}
// Attacher l'identité vérifiée au socket
socket.data.userId = token.id;
socket.data.userName = token.name || token.email || "Anonyme";
next();
} catch (err) {
next(new Error("Erreur d'authentification"));
}
});
const cardRooms = new Map();
io.on("connection", (socket) => {
const { userId, userName } = socket.data;
socket.on("join-card", ({ cardId }) => {
if (!cardId || typeof cardId !== "string") return;
socket.join(`card:${cardId}`);
if (!cardRooms.has(cardId)) cardRooms.set(cardId, new Map());
cardRooms.get(cardId).set(socket.id, { id: userId, name: userName });
const members = Array.from(cardRooms.get(cardId).values());
io.to(`card:${cardId}`).emit("members-updated", members);
});
socket.on("check-cell", ({ cardId, cellId, checked }) => {
if (!cardId || !cellId || typeof checked !== "boolean") return;
// Le nom vient du serveur, pas du client
socket.to(`card:${cardId}`).emit("cell-updated", { cellId, checked, userName });
});
socket.on("bingo", ({ cardId, pattern }) => {
if (!cardId) return;
// Aux autres joueurs seulement — le local a déjà fêté au clic
socket.to(`card:${cardId}`).emit("bingo-achieved", { userName, pattern });
});
socket.on("disconnect", () => {
for (const [cardId, members] of cardRooms.entries()) {
if (members.has(socket.id)) {
members.delete(socket.id);
io.to(`card:${cardId}`).emit("members-updated", Array.from(members.values()));
}
}
});
});
global.io = io;
// 2. Next.js handler AFTER Socket.io
httpServer.on("request", async (req, res) => {
if (req.url && req.url.startsWith("/api/socketio")) return;
try {
await handle(req, res);
} catch (err) {
console.error("Error occurred handling", req.url, err);
res.statusCode = 500;
res.end("internal server error");
}
});
httpServer
.once("error", (err) => {
console.error(err);
process.exit(1);
})
.listen(port, hostname, () => {
console.log(
`> Ready on http://${hostname === "0.0.0.0" ? "localhost" : hostname}:${port}`
);
});
});