Spaces:
Sleeping
Sleeping
| const express = require("express"); | |
| const http = require("http"); | |
| const { Server } = require("socket.io"); | |
| const cors = require("cors"); | |
| const app = express(); | |
| app.use(cors()); | |
| app.use(express.json()); | |
| app.get("/health", (req, res) => res.json({ status: "ok", uptime: process.uptime() })); | |
| const server = http.createServer(app); | |
| const io = new Server(server, { | |
| cors: { origin: "*", methods: ["GET", "POST"] }, | |
| }); | |
| const rooms = {}; | |
| function getRoom(roomId) { | |
| if (!rooms[roomId]) { | |
| rooms[roomId] = { | |
| users: {}, | |
| canvasElements: [], | |
| code: { content: "// Start coding together...\n", language: "javascript" }, | |
| messages: [], | |
| }; | |
| } | |
| return rooms[roomId]; | |
| } | |
| io.on("connection", (socket) => { | |
| let currentRoom = null; | |
| let currentUser = null; | |
| socket.on("join-room", ({ roomId, user }) => { | |
| currentRoom = roomId; | |
| currentUser = { ...user, socketId: socket.id }; | |
| socket.join(roomId); | |
| const room = getRoom(roomId); | |
| room.users[socket.id] = currentUser; | |
| socket.emit("room-state", { | |
| canvasElements: room.canvasElements, | |
| code: room.code, | |
| messages: room.messages, | |
| users: Object.values(room.users), | |
| }); | |
| socket.to(roomId).emit("user-joined", currentUser); | |
| io.to(roomId).emit("room-users", Object.values(room.users)); | |
| console.log(`[${roomId}] ${user.name} joined`); | |
| }); | |
| socket.on("canvas-elements", (elements) => { | |
| if (!currentRoom) return; | |
| rooms[currentRoom].canvasElements = elements; | |
| socket.to(currentRoom).emit("canvas-elements", elements); | |
| }); | |
| socket.on("canvas-clear", () => { | |
| if (!currentRoom) return; | |
| rooms[currentRoom].canvasElements = []; | |
| io.to(currentRoom).emit("canvas-clear"); | |
| }); | |
| socket.on("code-change", ({ content, language }) => { | |
| if (!currentRoom) return; | |
| rooms[currentRoom].code = { content, language }; | |
| socket.to(currentRoom).emit("code-update", { content, language }); | |
| }); | |
| socket.on("cursor-move", ({ x, y }) => { | |
| if (!currentRoom || !currentUser) return; | |
| socket.to(currentRoom).emit("cursor-update", { | |
| socketId: socket.id, | |
| name: currentUser.name, | |
| color: currentUser.color, | |
| x, | |
| y, | |
| }); | |
| }); | |
| socket.on("send-message", (msg) => { | |
| if (!currentRoom) return; | |
| const fullMsg = { ...msg, id: Date.now().toString() }; | |
| rooms[currentRoom].messages.push(fullMsg); | |
| if (rooms[currentRoom].messages.length > 200) { | |
| rooms[currentRoom].messages = rooms[currentRoom].messages.slice(-200); | |
| } | |
| io.to(currentRoom).emit("receive-message", fullMsg); | |
| }); | |
| socket.on("disconnect", () => { | |
| if (!currentRoom) return; | |
| const room = rooms[currentRoom]; | |
| if (!room) return; | |
| delete room.users[socket.id]; | |
| io.to(currentRoom).emit("user-left", socket.id); | |
| io.to(currentRoom).emit("room-users", Object.values(room.users)); | |
| if (Object.keys(room.users).length === 0) { | |
| setTimeout(() => { | |
| if (rooms[currentRoom] && Object.keys(rooms[currentRoom].users).length === 0) { | |
| delete rooms[currentRoom]; | |
| console.log(`[${currentRoom}] Room closed (empty)`); | |
| } | |
| }, 300000); | |
| } | |
| console.log(`[${currentRoom}] ${currentUser?.name || socket.id} left`); | |
| }); | |
| }); | |
| const PORT = process.env.PORT || 3001; | |
| server.listen(PORT, () => console.log(`Canvas2Code server running on :${PORT}`)); | |